Categorieën
WordPress

Unit tests voor WordPress plugins

Een aantal WordPress plugins die we ontwikkelen bij Pronamic worden steeds complexer. Om de verschillende functionaliteiten van deze plugins bij elke release goed te testen kan het interessant zijn om gebruik te maken van unit testing. Met behulp van PHPUnit kunnen eenvoudig tests gedefinieerd worden en vervolgens automatisch uitgevoerd worden. Er zijn een aantal zeer interessante tools beschikbaar waarmee deze tests eenvoudig opgezet kunnen worden.

svn co https://unit-tests.svn.wordpress.org/trunk wordpress-tests
export WP_TESTS_DIR="/Users/remco/wp/wordpress-tests"
Categorieën
PHP WordPress

Zoeken naar enter na afsluitende ?> PHP tag

Als WordPress ontwikkelaar kom ik regelmatig thema’s tegen waarin in functie bestanden zoals functions.php een afsluiten ?> PHP tag wordt gebruikt. Deze afsluitende PHP-tag kan problemen geven als daar nog een spatie of lege regel achter staat. Als je de broncode van een website bekijkt zie je dan vaak bovenaan voor de DOCTYPE declaratie een spatie of een lege regel.

?>

Hierdoor kunnen probleem ontstaan met bijvoorbeeld de XML-RPC-server of XML-sitemaps binnen WordPress. Binnen Eclipse kan gelukkig eenvoudig gezocht worden met behulp van reguliere expressies. Met behulp van de volgende zoekopdracht kan ik dergelijke problemen eenvoudig opspeuren binnen een Eclipse-project:

\?>\s\z

De \s zal overeenkomen met white space en de \z met het einde van het bestand.

We adviseren zelf altijd om PHP niet af te sluiten met een ?> PHP-tag, dit levert vaak meer problemen op dan dat je er profijt van hebt.

Categorieën
WordPress

WordPress optimaliseren door WPEngine

WPEngine is naar mijn idee één van de weinige partijen die echt goed weten wat er komt kijken bij het hosten van WordPress websites. Ze bieden een krachtige hosting oplossing aan die schaalbaar is voor de grotere WordPress websites. Ook bieden ze veel informatie over welke WordPress plugins je beter niet kunt gebruiken en hoe je je WordPress website kunt optimaliseren.

Mark Kelnar (@renderandserve) geeft in een presentatie tijdens WordCamp Atlanta 2012 een aantal WordPress optimalisatie tips. De presentatie is terug te vinden op de volgende pagina en zeker de moeite waard om eens door te lezen:

http://wpengine.com/optimizing-wordpress/

WPEngine heeft een zeer krachtige hosting omgeving voor WordPress neergezet. Volgens raheemm draaien de WPEngine diensten op de volgende configuratie:

  • NGINX (reverse proxy)
  • Apache (webserver)
  • APC (PHP Accelerator)
  • CDN ingebakken in de architectuur
  • Ongelooflijk krachtige hardware

Ik denk dat veel Nederlandse WordPress hossting providers nog veel kunnen leren van de manier waarop WPEngine WordPress hosting aanbiedt.

Categorieën
PHP WooCommerce WordPress

Nederlandse vertaling WooCommerce 2.0.5

In WooCommerce versie 2.0.5 kunnen de vertalingen voor de WordPress beheerdersomgeving ingeladen vanuit een eigen bestand. Op die manier hoeven niet alle WooCommerce vertalingen altijd geladen te worden. In de WooCommerce ‘load_plugin_textdomain’ function is duidelijk te zien hoe dit is opgezet.

Om de vertalingen zo efficiënt mogelijk op te zetten moeten er 2 .PO of .POT bestanden aangemaakt worden. Normaliter scande ik altijd met behulp van Poedit naar alle vertaalbare teksten binnen een plugin. Echter kan ik met Poedit niet onderscheid maken tussen vertalingen binnen de admin omgeving.

Er zijn meerdere gebruikers van Poedit die wel graag van een dergelijke functionaliteit gebruik willen maken. De ontwikkelaar van Poedit geeft echter in een ticket het volgende aan:

 The scanning feature of Poedit is intended for basic, simple uses. If you have more demanding needs, they you should write a proper makefile and call xgettext in it to create a POT file from your sources; then use Poedit just to translate PO catalogs and update them from that POT file.

At this time, I don’t want additional complications in this part of Poedit. Maybe later, when all the other, more serious, problems are fixed.

Ik ben me daarom gaan verdiepen in de werking van xgettext:

Uiteindelijk heb ik de volgende twee commando’s geschreven waarmee we de WooCommerce vertalingen kunnen opdelen in verschillende bestanden.

WooCommerce admin

find ./admin -iname "*.php" -type f | xgettext \
--from-code=UTF-8 \
--keyword=__ \
--keyword=_e \
--keyword=_n:1,2 \
--keyword=_x:1,2c \
--keyword=_ex:1,2c \
--keyword=_nx:1,2,4c \
--default-domain=woocommerce \
--language=PHP \
--copyright-holder="Remco Tolsma" \
--package-name=WooCommerce \
--package-version=2.0.5 \
--msgid-bugs-address="Remco Tolsma <[email protected]>" \
--files-from=- \
--output=woocommerce-admin.pot

WooCommerce

find ./ -iname "*.php" -type f | xgettext \
--from-code=UTF-8 \
--keyword=__ \
--keyword=_e \
--keyword=_n:1,2 \
--keyword=_x:1,2c \
--keyword=_ex:1,2c \
--keyword=_nx:1,2,4c \
--default-domain=woocommerce \
--language=PHP \
--copyright-holder="Remco Tolsma" \
--package-name=WooCommerce \
--package-version=2.0.5 \
--msgid-bugs-address="Remco Tolsma <[email protected]>" \
--files-from=- \
--exclude-file=woocommerce-admin.pot \
--output=woocommerce.pot

Bovenstaande commando’s bestaan uit  2 delen, een ‘find’ commando waarmee alle PHP-bestanden binnen de plugin worden gevonden. En een ‘xgettext’ commando die alle vertalingen binnen deze bestanden op zoekt. Hier worden de WordPress vertaalfuncties als ‘keyword’ meegegeven.

Mocht je overigens bij het uitvoeren van het tweede commando een “Segmentation” fout krijgen dan moet je misschien je gettext pakket updaten. Ik kreeg op mijn Mac deze fout met gettext versie 0.18.1. Na het updaten van gettext via MacPorts naar versie 0.18.2 was dit probleem opgelost:

sudo port selfupdate
sudo port upgrade outdated

Vervolgens hebben we de gegenereerde .POT-bestanden toegevoegd aan onze GlotPress installatie.

Omgeving Aantal teksten
WooCommerce 1391
WooCommerce admin 1112

Waar in WooCommerce 1.6.6 nog 2058 teksten in één bestand stonden en altijd geladen werden is dit met deze wijziging bijna gehalveerd. Deze verbetering hebben we ook verwerkt in de “WooCommerce (nl)” plugin. Met behulp van een Makefile kunnen we eenvoudig de 2 .POT-bestanden aanmaken:

WOOCOMMERCE_DIR=../woocommerce/

# Make POT files
extract:
	cd $(WOOCOMMERCE_DIR) && \
	find ./admin -iname "*.php" -type f | xgettext \
	--from-code=UTF-8 \
	--keyword=__ \
	--keyword=_e \
	--keyword=_n:1,2 \
	--keyword=_x:1,2c \
	--keyword=_ex:1,2c \
	--keyword=_nx:1,2,4c \
	--default-domain=woocommerce \
	--language=PHP \
	--copyright-holder="Remco Tolsma" \
	--package-name=WooCommerce \
	--package-version=2.0.5 \
	--msgid-bugs-address="Remco Tolsma <[email protected]>" \
	--files-from=- \
	--output=$(CURDIR)/languages/woocommerce/woocommerce-admin.pot \

	cd $(WOOCOMMERCE_DIR) && \
	find ./ -iname "*.php" -type f | xgettext \
	--from-code=UTF-8 \
	--keyword=__ \
	--keyword=_e \
	--keyword=_n:1,2 \
	--keyword=_x:1,2c \
	--keyword=_ex:1,2c \
	--keyword=_nx:1,2,4c \
	--default-domain=woocommerce \
	--language=PHP \
	--copyright-holder="Remco Tolsma" \
	--package-name=WooCommerce \
	--package-version=2.0.5 \
	--msgid-bugs-address="Remco Tolsma <[email protected]>" \
	--files-from=- \
	--exclude-file=$(CURDIR)/languages/woocommerce/woocommerce-admin.pot \
	--output=$(CURDIR)/languages/woocommerce/woocommerce.pot
Categorieën
PHP WordPress

W3 Total Cache mobile check

Gebruikers van de “W3 Total Cache” plugin weten dat je per “User Agent Groups”, ook wel browser groepen, verschillende pagina caches kunt hanteren. Dit is erg handig voor als je WordPress website voor mobiele apparaten anders is opgebouwd dan voor desktop browsers. Met de wp_is_mobile() functie kun je dan eenvoudig je WordPress thema aanpassen voor mobiele appareten.

W3 Total Cache mobile User Agent Groups

We liepen echter tegen problemen dat de wp_is_mobile() functie check niet overeenkwam met de standaard W3 Total Cache “User Agent Groups”. Hierdoor werd soms op desktop browsers toch de mobiele versie van de website weergegeven. Daarom zijn we opzoek gegaan naar een manier om de W3 Total Cache check te gebruiken.

Na het doorzoeken van de W3 Total Cache code kwamen uit op de volgende classes en functies:

Aan de hand hiervan hebben we de volgende help functie kunnen schrijven:

if ( ! function_exists( 'is_mobile' ) ) { 
	function is_mobile() {
		$is_mobile = false;

		if ( class_exists( 'W3_Mobile' ) ) {
			$w3_mobile = new W3_Mobile();

			$group = $w3_mobile->get_group();

			$is_mobile = $group !== false;
		}

		return $is_mobile;
	}
}

 

Categorieën
E-commerce PHP WooCommerce WordPress

WooCommerce teksten wijzigen

In het bericht “WooCommerce ‘Toevoegen aan winkelwagen’ tekst wijzigen” schreef ik al hoe je een specifieke WooCommerce tekst kon wijzigen. Helaas zijn met behulp van deze oplossing niet alle WooCommerce teksten te wijzigen. Toch komt het wel eens voor dat ook andere teksten gewijzigd moet worden. Binnen bepaalde webwinkels is “Bestellen” bijvoorbeeld een betere vertaling voor  “Checkout”  in plaats van “Afrekenen”.

Met behulp van de volgende code kunnen alle WooCommerce teksten eenvoudig aangepast worden.

/**
 * Translate WooCommerce text
 *
 * @link http://codex.wordpress.org/Plugin_API/Filter_Reference/gettext
 */
function prefix_translate_woocommerce( $translated_text, $text, $domain ) {
	if ( $domain == 'woocommerce' ) {
		switch ( $text ) {
			case 'Checkout &rarr;' :
				$translated_text = 'Bestellen';
				break;
			case 'Add to Cart' :
			case 'Add to cart' :
				$translated_text = 'Bestellen';
				break;
		}
	}

	return $translated_text;
}

add_filter( 'gettext', 'prefix_translate_woocommerce', 20, 3 );
Categorieën
SQL WordPress

WordPress database prefix wijzigen

Voor het wijzigen van de WordPress database prefix zijn verschillende plugins beschikbaar. Deze plugins wijzigen echter niet altijd alle prefixes. De WordPress database prefix wordt namelijk naast in de tabel namen ook gebruikt in de ‘options’ en ‘usermeta’ tabellen. Jan Egbert tipte me daarom over de volgende SQL query:

UPDATE wp_usermeta SET meta_key = REPLACE(meta_key, 'wp_', 'nieuweprefix_') WHERE meta_key LIKE 'wp\_%';

Via een aantal andere websites kwam ik er achter dat ook de ‘options’ tabel de WordPress database prefix wordt gebruikt. Daarom zal waarschijnlijk ook de volgende query uitgevoerd moeten worden:

UPDATE wp_options SET option_name = REPLACE(option_name, 'wp_', 'nieuweprefix_') WHERE option_name LIKE 'wp\_%';

Bovenstaande queries gaat echter fout zodra de WordPress database prefix terug komt in de optie naam of de user meta key.

umeta_id user_id meta_key meta_value
1 1 wp_pronamic_wp_version 3.5

Zal na het uitvoeren van de query gewijzigd worden naar:

umeta_id user_id meta_key meta_value
1 1 nieuweprefix_pronamic_nieuweprefix_version 3.5

De “Change DB Prefix” plugin lijkt uitgerust zijn met de juiste queries:

http://plugins.trac.wordpress.org/browser/db-prefix-change/tags/1.1/db_prefix.php#L83

Meer informatie:

Categorieën
PHP WordPress

WordPress update naar 3.5 fatal error

Bij de WordPress update van 3.4.2 naar WordPress 3.5 liepen we bij een aantal websites tegen de volgende foutmelding aan:

HTTP-fout 500 (Internal Server Error): Er is een onverwachte voorwaarde gevonden toen de server het verzoek wilde uitvoeren.

Via de Apache fouten logboek zagen we de volgende foutmelding voorbij komen:

Website 1

[Fri Jan 18 09:14:18.400710 2013] [:error] [pid 17051] [client *.*.*.*:*] PHP Warning:  Missing argument 1 for get_post(), called in /public_html/wp-includes/link-template.php on line 1125 and defined in /public_html/wp-includes/post.php on line 380

[Fri Jan 18 09:17:25.937590 2013] [:error] [pid 17268] [client *.*.*.*:*] PHP Warning:  Division by zero in /public_html/wp-includes/functions.php on line 3237

[Fri Jan 18 09:17:26.019925 2013] [:error] [pid 17144] [client *.*.*.*:*] PHP Fatal error:  Call to undefined function get_current_blog_id() in /public_html/wp-includes/user.php on line 671, referer: http://domainname.tld/wp-admin/update-core.php?action=do-core-upgrade

Website 2

[Fri Jan 18 09:44:52.166372 2013] [:error] [pid 18936] [client *.*.*.*:*] PHP Warning:  Division by zero in /public_html/wp-includes/functions.php on line 3237

[Fri Jan 18 09:44:52.190437 2013] [:error] [pid 18936] [client *.*.*.*:*] PHP Fatal error:  Call to a member function register_handler() on a non-object in /public_html/wp-includes/media.php on line 944

Waardoor deze problemen werden veroorzaakt was een groot raadsel. Ook na een handmatige update van WordPress was het probleem niet opgelost. Uiteindelijk kwamen we tot de ontdekking dat er een caching techniek (XCache) actief was op de hosting omgeving.

Hierdoor werd na de WordPress 3.5 update op de hosting omgeving nog steeds gebruik gemaakt van PHP bestanden/functies uit WordPress 3.4.2. Uiteindelijk hebben we het probleem kunnen oplossen door tijdelijke XCache uit te schakelen.

Het uitschakelen van XCache kan met behulp van de volgende regels in het .htaccess bestand:

php_flag xcache.cacher Off
php_flag xcache.size 0
php_flag xcache.stat Off

Mocht je zelf ook een keer tegen onverklaarbare foutmeldingen aanlopen na een WordPress update dan is het wellicht goed om eens na te gaan welke caching technieken actief zijn.

Categorieën
PHP WordPress

WordPress menu limiet

Binnen WordPress kunnen menu’s eenvoudig aangemaakt en beheert worden. Bij grotere menu’s kunnen er echter problemen ontstaan. Menu’s worden soms niet meer goed opgeslagen of het aantal menu items is beperkt. Binnen het WordPress forum zijn hier verschillende topics over te vinden:

Dit probleem wordt veroorzaakt door de Suhosin module van PHP. Deze module beschermt servers tegen onveilig gebruik van PHP. Dit doet Suhosin onder andere door verschillende beperkingen te activeren.

Eén van de beperking is het aantal ‘post’ en ‘request’ variabelen. WordPress werkt met deze variabelen om menu’s op te slaan. Een minder handige constructie omdat je tegen limieten van bijvoorbeeld Suhosin kunt aanlopen.

Gelukkig kunnen de limieten in veel gevallen verhoogd worden. Vaak moet dit uitgevoerd worden door de hosting partij. Als je echter zelf een server beheert dan kun je dit ook eenvoudig zelf doen. Ik wil graag dat deze limieten per directory in een .htacces bestand geconfigureerd kunnen worden.

Hiervoor heb ik de volgende wijziging doorgevoerd in het “suhosin.ini” configuratie bestand:

nano /etc/php5/apache2/conf.d/suhosin.ini

Vervolgens heb ik de volgende regel gewijzigd van:

suhosin.perdir = "0"

naar:

suhosin.perdir = "pr"

De ‘p’ en ‘r’ karakters geven aan dat ‘post’ en de ‘request’ configuratie instellingen per map zijn in te stellen. Dit onderdeel van Suhosin is niet goed gedocumenteerd, maar in de broncode van de Suhosin bibliotheek is de werking hiervan eenvoudig te raadplegen.

Vervolgens kunnen we het volgende opnemen in het .htaccess bestand om groter menu’s te kunnen beheren binnen WordPress:

# BEGIN PHP
<IfModule mod_php5.c>
	php_value suhosin.post.max_vars 2048
	php_value suhosin.request.max_vars 2048
</IfModule>
# END PHP

Meer informatie:

Categorieën
WordPress

Wijzig WordPress network site domeinaam

Om een WordPress netwerk site domeinnaam te wijzigen kunnen de volgende stappen genomen worden:

  1. Maak een backup van de database.
  2. Pas de volgende query aan en voer deze uit:
    UPDATE wp_2_options SET option_value = REPLACE(option_value, 'huidige-domeinnaam.nl', 'nieuwe-domeinnaam.nl') WHERE option_value NOT LIKE '%:{%';
    UPDATE wp_2_posts SET post_content = REPLACE(post_content, 'huidige-domeinnaam.nl', 'nieuwe-domeinnaam.nl');
    UPDATE wp_2_posts SET guid = REPLACE(guid, 'huidige-domeinnaam.nl', 'nieuwe-domeinnaam.nl');
    UPDATE wp_2_postmeta SET meta_value = REPLACE(meta_value, 'huidige-domeinnaam.nl', 'nieuwe-domeinnaam.nl') WHERE meta_value NOT LIKE '%:{%';
    UPDATE wp_2_links SET link_image = REPLACE(link_image, 'huidige-domeinnaam.nl', 'nieuwe-domeinnaam.nl');

    Wijzig ‘wp_2’ naar de prefix van de network site, ‘huidge-domeinnaam.nl’ naar de huidige domeinnaam en ‘nieuwe-domeinnaam.nl’ naar de nieuwe domeinnaam.

  3. Pas de volgende rewrite regels aan en voeg deze toe aan het .htaccess bestand:
    <IfModule mod_rewrite.c>
    	RewriteEngine On
    	RewriteCond %{HTTP_HOST} ^(www\.)?huidige-domeinnaam\.nl
    	RewriteRule (.*)$ http://nieuwe-domeinnaam.nl/$1 [R=301,L]
    </IfModule>

    Wijzig ‘huidge-domeinnaam.nl’ naar de huidige domeinnaam en ‘nieuwe-domeinnaam.nl’ naar de nieuwe domeinnaam.

  4. Geef de adreswijziging door aan Google via de Google Webmaster Tools(Configuratie » Adreswijziging).

Voor meer informatie over adreswijziging van WordPress network websites, zie ook: