Ressourcen Sparen bei Ajax Calls in WordPress

Bei meiner arbeit am Plugin BackWPup habe ich nach einer Möglichkeit gesucht Ressourcen zu sparen bei Ajax Calls und bei der Auftrags Ausführung. Die einzeige große Einsparung die ich bisher gefunden habe ist es die Übersetzungen anderer Plugins nicht mit zu laden das die enorm viel Speicher verbrauchen. Dies bringt in meiner test Installation mit 20 Plugins eine Einsparung von 31 MB auf 25,5 MB Script speicher. Da die Dateien auch nicht geöffnet werden wird das auch noch eine Einsparung bringen die ich im Moment nicht beziffern kann.

Hier die Umsetzung:
Wichtig ist hierbei das ich nur die Übersetzungen nicht lade wenn es sich um Calls meines Plugins handelt.

define('PLUGIN_MENU_PAGES', 'page1,page2');
if (defined('DOING_AJAX') and DOING_AJAX and in_array($_POST['backwpupajaxpage'],explode(',',PLUGIN_MENU_PAGES)))
add_filter('override_load_textdomain', create_function('$default, $domain, $mofile','if ($domain=="textdomain") return $default; else return true;'),1,3);

Zusätzlich musste ich noch einbauen das mein Plugin als erstes geladen wird:

define('PLGUNINNAME_PLUGIN_BASENAME',plugin_basename(__FILE__));

public function pluginname_first_plugin($newvalue, $oldvalue) {
if (!is_array($newvalue))
return $newvalue;
for ($i=0; $i<count ($newvalue);$i++) {
if ($newvalue[$i]==PLGUNINNAME_PLUGIN_BASENAME)
unset($newvalue[$i]);
}
array_unshift($newvalue,PLGUNINNAME_PLUGIN_BASENAME);
return $newvalue;
}
add_filter('pre_update_option_active_plugins', 'pluginname_first_plugin',1,2);

Vielleicht kennt ja noch jemand eine Lösung die Ressourcen weiter zu optimieren und die WordPress eigene Ajax Behandlung zu nutzen...

Update:
mit einer etwas geänderten Funktion ist es nicht mehr notwendig das Plugin nach vorne zu schieben ;)

define('PLUGIN_MENU_PAGES', 'page1,page2');
function overide_textdomain($default, $domain, $mofile) {
if ( (defined( 'DOING_CRON' ) && DOING_CRON) && in_array($_POST['backwpupajaxpage'],explode(',',PLUGIN_MENU_PAGES))) {
global $l10n;
if ($domain=='owntextdomainname') {
foreach (array_keys($l10n) as $domainkey)
unset($l10n[$domainkey]);
} else {
return true;
}
}
return $default;
}
add_filter('override_load_textdomain','overide_textdomain');

Update: Ich glaub das best ist es wenn in WordPress der WP-Performance-Gettext-Patch integriert wird. Nach meinen Tests bring das am meisten. Der Speicher verbrauch geht dann auf ca 17MB runter.

7 Gedanken zu „Ressourcen Sparen bei Ajax Calls in WordPress

  1. Ralf

    // Stop most of WordPress from being loaded if we just want the basics.
    if ( SHORTINIT )
    return false;
    Quelle: wp-settings.php

    define( 'SHORTINIT', TRUE );
    Verhindert das Laden der l10n-Bibliothek.

    Antworten
      1. Ralf

        Warum muss die Übersetzung im Ajax-Call erfolgen? Du kannst die Texte vorher übersetzen und im Ajax-Call lediglich die Daten abholen.
        Wenn es gar nicht anders geht, kannst du die Übersetzten Texte im Cache ablegen. Bei späteren Ajax-Calls kann dann auf die Localization verzichtet werden.

        Was kommt nach l10n.php denn noch das du benötigst? Bis zum Laden von l10n müsste eigentlich alles da sein. Und l10n enthält lediglich die Locale-API. Die Übersetzungen sind also bereits (theoretisch) möglich, sie wird nur nicht durchgeführt da die API nicht geladen ist.

        Nutzt du Caching? Besser als ein optimierter Ajax-Call ist gar kein Ajax-Call.

        Vorauszusetzen dass das eigene Plugin an erster Stelle steht, halte ich für eine ganz schlechte Lösung. Was ist wenn ein anderes Plugin das gleiche versucht? Noch schlimmer, was ist wenn du die gleiche Technik in einen anderen deiner Plugins verwendest. Zwanghafte Voraussetzungen (das MUSS so sein damit es funktioniert) führen zwangsweise zu Race Conditions.

        Generell: Warum definierst du eine Globale Konstante die 3 Zeilen später genutzt wird? Da globale Konstanten nicht vom Garbage Collector gelöscht werden können, sind sie über die ganze Laufzeit präsent. Selbst dann, wenn sie nicht (mehr) genutzt werden. Bei einer Variablen ist das noch nicht tragisch, entwickelt sich so etwas zum Programmierstil, sind schnell mal ein halbes oder mehr Megabyte an Speicher verschwendet. Wegen einem Loch geht der Kahn nicht unter. Bei 1.000 Löchern sieht die Sache schon anders aus.
        In globale Konstanten gehört nur das rein, und wirklich nur das, was man anderen Scripten (Plugins/Themes/WordPress) mitteilen MUSS. Alles andere bitte in normale Variablen damit sie vom GC erfasst werden können.

        include_once(dirname(__FILE__).'/core/job.php');
        Ist das eigentlich leicht zu pflegen? Ich meine, was machst du wenn das Verzeichnis 'core' mal umbenannt werden muss?
        Hier wäre doch ein Autoloader und ein schlichtes
        new BackWPup_job; deutlich effektier.

        include_once(dirname(__FILE__).'/admin/ajax_'.$_POST['backwpupajaxpage'].'.php'); ist nicht dein Ernst, oder!?!?!

        Antworten
        1. Daniel Hüsken Artikelautor

          Hallo Ralf,

          erst mal danke für die Antwort.
          Ich denke ich werde mir noch mal einige Sachen durch den Kopf gehen lassen….

          Caching nutze ich, aber werde ich wohl an an paar stellen mehr in zufunkt einsetzen.
          Für mich heßt das bei Ajax das ich den WordPress Beckend Ajax (admin-ajax.php) nicht nutzen kann sondern es selber realisiere muss da ich sonst SHORTINIT gar nicht einsetzen kann.

          Wenn man SHORTINIT einsetzt werden auch keine Plugins mehr geladen man hat keine Benutzerverwaltung und somit auch die WordPress eigenen Nonces nicht. (zumindest soweit ich das bei meinem letzten test gesehen habe.)

          Du hast natürlich recht das eigen Plugin an erster stelle zu schieben mach ich auch sehr ungern.

          Die Konstanten die ich definiert habe nutze ich nicht nur in der Datei und warum soll ich sie nicht nutzen wenn ich sie eh brauche.
          Ich setzte sie auch nur so wenig wie möglich ein und kann Sie sicher noch um 1-2 reduzieren. Mehr als 10 Konstanten nutze ich bisher im ganzen Plugin nicht.

          Autoloader werde ich mir mal ansehen.

          ich dachte eigentlich ich hätte das in der Zeile vorher ausreichend geprüft. Aber auch hier werd ich mir noch mal ein Paar Gedanken zu machen, oder hast du was wie man das richtig löst und z.B. auch einen ABSPATH ohne Probleme für eigenen Ajax übergeben kann.

          Antworten
          1. Ralf

            $_POST & $_GET sollte man zumindest mit filter_input bearbeiten. Was auf deinem Server gut geht, muss ja auf anderen nicht zwangsläufig genauso gut gehen.
            Auch hier hilft natürlich der Autoloader wieder ungemein. Anstatt Dateien direkt zu inkludieren, einfach eine Instanz einer Klasse erzeugen. Und das geht dann recht einfach über:

            $regexp = '/(teststring|hello|world|foo|bar|test)/';

            $options = array( 'options' => array( 'regexp' => $regexp ) );

            $request = filter_input( INPUT_POST, 'backwpupajaxpage', FILTER_SANITIZE_STRING )
            &&
            filter_input( INPUT_POST, 'backwpupajaxpage', FILTER_VALIDATE_REGEXP, $options );

            if( $request ){
            $class = 'Ajax_Call_' . ucfirst( strtolower( $request ) );
            new $class;
            }

            Filter_input säubert erst einmal ‘backwpupajaxpage’ und prüft dann ob der String mit dem RegExp übereinstimmt (ist dieser String im RegExp vorhanden?).
            Danach wird der String in Kleinbuchstaben umgewandelt, der erste Buchstabe wieder in Großbuchstaben umgewandelt und aus dem ganzen ein Klassenname gebacken (Ajax_Call_Xxxx). Damit kann der Autoloader dann ganz einfach arbeiten.
            Ungefilterte POST&GET-Daten verwenden ist ein NoGo in Zeiten von PHP5.

            z.B. auch einen ABSPATH ohne Probleme für eigenen Ajax übergeben kann.

            indem man dem Ajax-Request den ABSPATH einfach als Parameter mitgibt? Zum Beispiel als GET-Parameter: $ajax_url = 'some_script.php?abspath=' . ABSPATH . '&some_other=';

            Wenn man SHORTINIT einsetzt werden auch keine Plugins mehr geladen

            Das ist ja eigentlich auch Sinn der Sache. Schreibe deine Ajax-Calls doch so, dass sie weitestgehend auf WordPress verzichten können. Oder anders ausgedrückt: Das was unbedingt WP-Funktionen benötigt, wird VOR dem Ajax-Call berechnet und in einem Cache gespeichert. Der Ajax-Call fischt dann nur noch die Daten aus dem Cache.

            Ich würde anstatt globaler Konstanten eher einen Daten-Container verwenden den ich an die zu instanzierende Klasse durchschleife. Hier wäre es dann ganz sinvoll wenn du backwpup.php gleich als Klasse schreibst:

            backwpup.php:
            <?php
            class DataContainer{ // some vars to define }

            class BackWPup extends DataContainer{ // some code }

            class-my_class.php:
            <?php
            class My_Class extends BackWPup{ // mettigel }

            Dadurch das BackWPup DataContainer erweitert (nicht von DataContainer erbt), stehen dort die Variablen-Definitionen von DataContainer zur Verfügung (z.B. über parent::MYCONST, $this->$version, self::MYCONST, usw). Wenn nun My_Class BackWPup erweitert, stehen dort logischerweise auch die in DataContainer definierten Variablen zur Verfügung. Und natürlich alles was in BackWPup an Variablen definiert wurde. Theoretisch kannst du den DataContainer weg lassen, durch den DataContainer lässt sich das Script aber deutlich einfacher warten. Du kannst auch mit wenig Aufwand eine andere Konfiguration verwenden indem du einen anderen DataContainer verwendest.

            PS: Ist nicht böse gemeint, aber lies dir doch mal ein paar Regeln zu Coding-Standards durch (z.B. das hier: http://codex.inpsyde.com/ ) oder im WP-Codex ( http://codex.wordpress.org/WordPress_Coding_Standards )
            Dein Code ist sehr schwer zu lesen und oft ist nicht wirklich klar was da gerade passiert.

          2. Daniel Hüsken Artikelautor

            Hallo Ralf,

            danke erstmal ich werde mir viel davon zu herzen nehmen.

            Ich hab übrigens einen Großteil der konstanten eben schon entfernt. So das ich zur Zeit nur noch eine brauche.

          3. Daniel Hüsken Artikelautor

            Nochmal danke.
            Ich hab mir den PHP Autolader jetzt mal angesehen und bin begeistert. Ich Stricke gerade das Plugin so um das das meiste darüber läuft.

            jetzt kann ich auch einfach die add_action für die ajax Klassen hinzufügen da sie ja eh erst geladen werden wenn die Klasse gerufen wird somit brauche ich keine includes mehr beim ajax.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>