Für unseren brainbeats-Katalog wollten wir für das Filtern, Suchen und Drucken eine AngularJS-App bauen. Jetzt stellte sich die Frage, wie man AngularJS sauber in WordPress integrieren kann. Die Anforderungen an eine "saubere Integration" sind folgende:
Eine AngularJS-App besteht in der Regel aus sehr vielen einzelnen Source-Files. Zum einen die Angular-Bibliotheken wie Angular selbst und die nötigen ng-Module (UI-Router, animate, cookies, sanitizer usw.). Zum anderen die Controller, Module, Direktiven etc., die man in separate Dateien aufsplitten sollte.
Die App selbst habe ich unabhängig vom WordPress als eigenes Projekt auf Basis des Code Generators cc-angular entwickelt. Hierfür musste ich lediglich den Request zum Laden der brainbeats mocken:
$http({ method: 'GET', url: '/wp-admin/admin-ajax.php', params: { action: 'brainbeats_list' } }).success(function(data) { deferred.resolve(data); }).error(function() { deferred.resolve({ 'brainBeats': [ { ... } ] }); });
Anschließend konnte ich fokussiert auf die App die brainbeats-Anwendung mit Unit-Tests und Live-Reload komfortabel lokal entwickeln.
In cc-angular ist natürlich auch ein Build-Task konfiguriert, der alle Javascript-Sourcen und die HTML-Templates in einer Datei konkateniert und minimiert (ngAnnotate und uglify) sowie alle LESS-Dateien kompiliert und in einer minimierten CSS-Datei speichert. Zum bootstrap der Angular-App müssen also nur zwei Dateien eingebunden werden, die Javascript- und die CSS-Datei. Um eine möglichst große Variabilität bei der Einbettung der App zu haben, musste ein Shortcode her, der alles Nötige mit sich bringt.
Der komplette PHP-Code wird in einer Klasse mit statischen Methoden gekapselt:
class brainbeat { static $add_script; static function init() { add_shortcode('brainbeats', array(__CLASS__, 'handle_shortcode')); add_action('init', array(__CLASS__, 'register_script')); add_action('wp_footer', array(__CLASS__, 'print_script')); if (is_admin()) { add_action('wp_ajax_brainbeats_list', array(__CLASS__, 'brainbeats_list_callback')); add_action('wp_ajax_nopriv_brainbeats_list', array(__CLASS__, 'brainbeats_list_callback')); } } static function handle_shortcode($atts) { self::$add_script = true; return '<div class="brainbeats-overview" ng-app="brainbeats"><div ui-view=""></div></div>'; } static function register_script() { $path = get_template_directory_uri() . "childtheme/brainbeats/"; wp_register_script('brainbeat-script', $path . '/app.full.min.js', array('jquery'), '1.0', true); } static function print_script() { if (!self::$add_script) return; wp_print_scripts('brainbeat-script'); } static function brainbeats_list_callback() {} } brainbeat::init();
Der Interessante Teil hierbei ist, dass der Shortcode-Handler die $add_script-Variable auf true setzt und eine Action definiert wurde, die bei der Ausgabe des Footer getriggert wird und gegebenenfalls das Script ausgibt. wp_enqueue_script() kann nicht verwendet werden, da zum Zeitpunkt der Shortcode-Ausführung dieser Hook schon gelaufen ist.
Der Shortcode gibt ein <div> zurück, in dem ng-app und im Kind-Element ui-view definiert sind, wodurch die Angular App gestartet wird.
Dem Aufmerksamen Leser wird nicht entgangen sein, dass das CSS hier nirgends auftaucht. Hier habe ich angular-css verwendet, ein Modul, um CSS dynamisch nachzuladen. Hiermit kann man CSS-Files je Route oder Direktive festlegen und das Modul sorgt dafür, dass diese nachgeladen werden, wenn sie benötigt werden.
Also haben wir jetzt eine AngularJS-App, die dank cc-angular aus 2 Dateien besteht, welche nur eingebunden werden, wenn der Shortcode brainbeats verwendet wird. Das könnte sogar schon genug Funktionalität für ein WordPress-Plugin werden, mit dem man ein Shortcode zu JS-File Mapping plus CSS File im Backend konfiguriert.
Rufen Sie uns an: 030 – 555 74 70 0