Wordpress v provozu

posted 14.02.2014

V malé digitální agentuře, kde jsem se před lety začal věnovat webu, jsme Wordpress používali jako univerzální platformu pro každou zakázku, co přišla. Stále je to uživatelsky nejpřívětivější redakční systém, je zadarmo, nainstaluje ho každý programátor-elév za patnáct minut a kodér měl hotovou šablonu z grafického návrhu za pár hodin.

Časem jsme to dotáhli na stovky webů, každý vždy běžel jako nová instalace. Bylo velikou náhodou pokud se potkali dvě stejné verze setinkové verze. Když se k tomu přičetly navázané verze plug-inů a potřeba hromadně aktualizovat vše najednou, bylo zaděláno na problém. K tomu, abych se podobným problémum vyvaroval, mi pomohlo několik následujících postupů.

Jádro nechte bez úprav

První chyba, která zkomplikuje i ty nejtriviálnější aktualizace, je zásah do jádra Wordpressu. Adresáře wp-admin/, wp-include/ a cokoliv v kořenovém adresáři by měly být nedoknutelné. Zatím jsem ještě nenarazil na úpravu, která by se nedala navěsit jako hook nebo filter. Seznam míst, kam se lze v aplikaci navěsit nemá konce.

Oddělte obsah a verzujte

První bod rozšířím o to, že by vám nemělo vadit, pokud vám někdo smaže celý Wordpress adresář. Na první pohled může následující adresářová struktura vypadat komplikovaně, při updatech a verzování ji ale oceníte. Uživatelský obsah zahrabaný ve třetí úrovni struktury ve wp-content/ mi vždy přišla jako jedna z nejprotivnějších věcí na WP.
|-- plugins/
|-- themes/
|-- uploads/
|-- wordpress/
|   | ...
|   |-- wp-content/
|       |-- themes/  -> ../../themes
|       |-- plugins/ -> ../../plugins
|       |-- uploads/ -> ../../uploads
|-- wp-config.php
První krok je přesun souboru wp-config.php o adresář výš, Wordpress ho automaticky prohledává jako první alternativní možnost umístění. Druhým je přesunutí veškerého netovárního obsahu mimo Wordpress. Nejjednodušším řešením je po rozbalení všechny adresáře ve wp-content/ nasymlinkovat mimo. Aktualizace pak spočívá v nahrání nového balíku a obnovení symlinků, což se dá zautomatizovat do pětiřádkového skriptu. Obsah se už nemění pod rukama, takže se vzhled a pluginy dají pohodlně verzovat a web nasadit bez potíží jinde nebo obnovit ze zálohy.

Testujte každý řádek

Není jediný důvod netestovat kód napsaný nad rámec základní funkcionality. Widgety, filtry, hooky, ty všechny se dají relativně pohodlně testovat v PHPUnitu. Některé testy budou povahou integrační, je ale snadné je rozdělit do dvou skupin a ty integrační (které budou přistupovat do databáze) spouštět jen před mergováním. K nastavení pomůžou tři nástroje: samotné unit testy Wordpressu z jejich SVN, WP CLI a PHPUnit.
mkdir -p tests/{tests-lib,wordpress}
cd tests
svn checkout --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ tests-lib/
wp core download --path=wordpress
cp tests-lib/wp-tests-config-sample.php tests-lib/wp-tests-config.php
tests-lib/wp-tests-config.php je potřeba upravit, aby cesta k WP vedla o adresář výše a mohl se připojit k testovací databázi. Do PHPUnitu zaveďte následující bootstrap.php a přidejte ho do konfigurace:
<?php
define('TESTS_LIB', __DIR__ . '/tests-lib');
require_once TESTS_LIB . '/includes/functions.php';
require_once TESTS_LIB . '/includes/bootstrap.php';
Na konec už jen přikládám ukázku testu, který ověřuje, že widget vypisuje děti zvolené stránky s URL special_parent.
<?php
class MyWidgetTest extends WP_UnitTestCase {
	function testWidget() {
        $parentId = $this->factory->post->create(array(
            'post_type' => 'page',
            'post_title' => 'Parent Post',
            'post_name'	=> 'special_parent'
        ));
        $pages = $this->factory->post->create_many(3, array(
            'post_type' => 'page',
            'post_parent' => $parentId
        ));
        $page = get_post($parentId);
        $child = get_post(next($pages));
        ob_start();
        $widget = new MyWidget;
        $widget->widget(array(), array());
        $content = ob_get_clean();
        $this->assertContains('Všechny podstránky bez rodiče', $content);
        $this->assertNotContains($page->post_title, $content);
        $this->assertContains($child->post_title, $content);
    }
}

Automatizujte s WP CLI

WP CLI jsem už zmínil v části o testování. Umí skoro vše, co byste běžně naklikali přes administraci, skrz příkazovou řádku. Díky němu lze instalaci Wordpressu automatizovat a pohodlně s ním cestovat přes různé prostředí. Dá se nainstalovat přes composer a je samotný napsaný v PHP, další závislosti nemá. Kompletní nasazování pak může vyřešit podobný skript:
cd /srv/www/
git clone vvondra:wp.git wp
cd wp
composer install

if [ ! -d "$DIRECTORY" ]; then
	wp core download --path=wordpress  
fi

cd wordpress
if ! $(wp core is-installed); then
    wp core config
    wp core install
    wp option update foo bar
    wp theme activate my_theme
fi

# a tak dále, vč. import obsahu apod.