Auch in WordPress bleibt man nicht konstant in der PHP-Welt und so müssen Einstellungen, Daten aus der Datenbank an Scripte übergeben werden. In vielen Plugins findet man Lösungen in dem die wp-load.php geladen wird und damit der Zugriff auf alle Funktionen von WordPress. Vor geraumer Zeit hat Otto (Samuel Wood) auf diesen Umstand schon aufmerksam gemacht und der Artikel zeigt Lösungsansätze. Noch immer kommen dazu Fragen auf und noch immer erscheinen Plugins, die die wp-load.php genau auf Grund solcher Probleme laden.
Eine ähnliche Problematik stellt sich, wenn man den Source der Scripte nicht einfach in den Footer-Bereich von WordPress schreibt, sondern sauber in eine Datei auslagert und via wp_enqueue_script() inkludiert. Nur so kann WordPress diese Scripte mit verwalten, packen und optimiert ausliefern. Daher möchte ich in zwie Beispielen aufzeigen, wie man Daten von PHP an JS übergibt.
Die ersten Schnipsel nutzen die Übergabe von Werten via JSON; wobei ich die Werte aus der Datenbank mit den gängigen Mitteln in PHP hole und das Script direkt im head der Seite die Werte als Objekt ablegt.
add_action( 'admin_enqueue_scripts', 'fb_print_scripts' );
function fb_print_scripts() {
global $current_screen;
if ( isset( $current_screen -> id ) && ! in_array( $current_screen -> id, array( 'post', 'page' ) ) )
return;
if ( is_plugin_active_for_network( plugin_basename( __FILE__ ) ) )
$options = get_site_option( 'my_options_id' );
else
$options = get_option( 'my_options_id' );
if ( ! $options )
return;
?>
<script type="text/javascript">
var my_json_object = <?php echo htmlspecialchars( json_encode( $options ) ); ?>;
</script>
<?php
}
Die obige Funktion gibt nun die Werte aus der Datenbank als JSON-Objekt in den head im Backend, da im ersten Schritt der Funktion die Seite abgefragt wird. Mittes $current_screen wird geprüft, so dass nur ausgeliefert wird, wenn man auf der definierten Seiten (post, page) ist.
Der folgende Schritt ist üblich und best practice in WordPress um Scripte einzubringen. Dabei inkludiere ich das JS-File, welches dann auf das JSON-Objekt zugreift.
add_action( 'admin_enqueue_scripts', 'fb_admin_enqueue_scripts' );
function fb_admin_enqueue_scripts( $where ) {
if ( ! in_array( $where, array( 'post.php', 'post-new.php', ) )
return;
$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '.dev' : '';
wp_enqueue_script(
self :: get_textdomain() . '_script',
plugins_url( '/js/my_script' . $suffix. '.js', __FILE__ ),
array( 'jquery', 'my_other_script' ),
'',
TRUE
);
}
Im Script wird dann direkt auf das Objekt zugegriffen, welches verarbeitet wird.
jQuery( document ).ready( function( $ ) {
if ( typeof my_json_object == 'undefined' )
return;
// debug in console of Browser
console.dir( my_json_object );
});
Eine weitere Lösung soll im Folgebeitrag der diesjährigen Serie vorgestellt werden; der Link folgt. - hier nun der Link, nach dem der Artikel online ist.
Weil du gerade das Thema Daten aus der Datenbank holen ansprichst - WordPress kann komplexe Datenkonstrukte (arrays) serialized in der Datenbank ablegen.
Ich tendiere immer mehr dazu, Arrays nicht mit serialized() in einen String zu konvertieren sondern hier das JSON-Format anzuwenden. Liegen Daten bereits im JSON-Format in der Datenbank, können Daten bei einem Ajax-Call viel schneller und direkter übergeben und von beiden Sprachen (PHP und Js) weiter verarbeitet werden.
Beispiel:
---------
add_action( 'wp_print_scripts', 'rr_print_scripts' );
function rr_print_scripts() {
$my_array = array( 'elm1', 'elm2', 'elm3' );
$my_array = json_encode($my_array);
?>
var my_json_object = ;
<?php
}
Wollte nur mal darauf hinweisen.
@Rene: aber genau das tue ich doch, oder? direkt aus der DB hole ich die serialisierten Daten und übergebe sie mit jsonencode() an JS.
Das stimmt, aber ich wollte nur verdeutlichen das die serialisierten Daten aus deiner DB scheinbar schon JSON sind. Das geht nicht klar hervor.
@Rene: nein, sind sie nicht, sie sind serialisiert. Du machst doch mit json_encode() ein JSON-Objekt daraus und dann kannst du wunderbar drauf zugreifen.
Siehst du, dann halte ich meinen Einwand doch für gerechtfertigt.
Warum Arrays Serialisieren wenn ich sie doch gleich als Json-String ablegen kann?
Den Gedanken von Rene kann ich folgen. Ich hab letztens ein Plugin geschrieben und nach Tutorial die Daten als PHP-Array serialisiert in der Datenbank abgelegt und entsprechend geladen (, beim Laden jedoch häufig das unserialize() vergessen). Es scheint es mir logisch, den Schritt der Serialisierung zu umgehen, indem man die Daten gleich im JSON-Format abspeichert.
Nichtsdestotrotz muss ich dann aber immernoch json_decode verwenden, oder? So richtig schlau werd ich nun nicht daraus, welche Variante besser ist...
Allerdings muss ich dann trotzdem noch mit json_encode / json_decode arbeiten...
@Alex: du brauchst nicht un/serialisieren beim Ablegen von Daten, das macht WordPress im Standard; darum muss man sich als Entwickler nicht kümmern. update_option legt serialisiert ab, wenn ein Array kommt und ebenso kümmert sich get_option() darum, dass ein Array zurück kommt. Gleiches gilt für die Settings-API.
Frank, ich schlage den Einsatz von
htmlspecialchars()vor:var my_json_object = <?php echo htmlspecialchars (json_encode( $options ) ); ?>;
vor.
Damit entfällt das Risiko von XSS-Angriffen: Falls du in den Optionen auch Strings speicherst, die vom Benutzern eingegeben werden können, könnte der JSON-String auch HTML-Elemente enthalten.
Die würden dann ungefiltert an den Browser des Blogadmins ausgegeben werden.
@Robert: richtig; ich habe in meiner aktuellen Anwendung html-Elemente zugelassen, daher lasse ich dies offen.
Ist die andere Lösung zufällig ein "Mißbrauch" von
wp_localize_script? Ich las da neulich was in den Kommentaren bei WpTuts+@Chris: ja, ist möglich wobei dies nicht unbedingt zu empfehlen ist; ich führe das dann kurz aus. Prinzipiell geht es, aber die Funktion hat Probleme mit mehrdimensionalen Arrays.
Aber inzwischen ist das doch garnicht mehr der Fall oder ich glaub die Funktion gibt es garnicht mehr ? Hat vielleicht jemand genauere Infos für mich ? Bin Dankbar für jede Antwort
Guter Beitrag
Gruß Andi
@Andi: alles noch da, alles noch wie im Artikel beschrieben.