2nd WP MeetUp in Vienna

28.02.2013 @Schraubenfabrik

with Franz Josef Kaiser

Professional Plugin Development

Drop-Ins, MU-Plugins, Plugins, Themes

Use the right tool for the job.

  1. Drop-Ins: Replaces core functionality
  2. MU-Plugins: Single file plugins, that load before plugins. Don't need configuration. Load on all site of a Multisite install.
  3. Plugins: Add functionality.
  4. Themes: Visualizes your content. Add styles, MarkUp and define what to show where. No added functionality.

Don't stuff everything in your themes functions.php file.


Available Drop-Ins

File Type of Plugin Loaded Context
Source Hakre
advanced-cache.php Advanced caching plugin. on WP_CACHE value Single
db.php Custom database class always Single
db-error.php Custom database error message on error Single
install.php Custom install script on install Single
maintenance.php Custom maintenance message on maintenance Single
object-cache.php External object cache always Single
sunrise.php Executed before Multisite is loaded on SUNRISE value Multi
blog-deleted.php Custom blog deleted message on deleted blog Multi
blog-inactive.php Custom blog inactive message on inactive blog Multi
blog-suspended.php Custom blog suspended message on archived or spammed blog Multi

Example Drop-In: db-error.php

Improve upon core. Make it better, faster, more reliable.
Plain PHP files that need no Plugin header comment block.
Drop! them in your wp-content folder, or whatever you named it.

Example ~/wp-content/db-error.php file: Send a 503 header to avoid loosing page rank.

$protocol = $_SERVER["SERVER_PROTOCOL"];
if (
	'HTTP/1.1' != $protocol
	AND 'HTTP/1.0' != $protocol
	$protocol = 'HTTP/1.0';
header( "{$protocol} 503 Service Unavailable", true, 503 );
header( 'Content-Type: text/html; charset=utf-8' );
header( 'Retry-After: 600' );

MU Plugins

When to use a MU Plugin?

Ever found a small snippet that you wanted to throw in your functions.php?
Users, Use a MU Plugin for that!
If you ain't got a mu-plugins folder in your wp-content dir: simply add one. It's safe.

MU Plugin example

Disable the capital_P_dangit filter callback.

# No direct file access without WP core loaded.
defined( 'ABSPATH' ) OR exit;
 * Plugin Name: Disable »capitalPdangit«
 * Description: My content is my content. Don't mess with it.
 * Author:      Franz Josef Kaiser (wecodemore[at]gmail.com)
 * Author URl:  http://unserkaiser.com
 * License:     MIT
add_action( 'muplugins_loaded', 'NO_capital_P_dangit', 5 );
function NO_capital_P_dangit()
	foreach (
		array( 'the_content', 'the_title', 'comment_text' )
		as $filter
		remove_filter( $filter, 'capital_P_dangit' );



Or: What this talk is about.

The "Paranoia" config setup

Errors are for development, not for production. Don't leave it to your users to find out your mistakes. #

define( 'DS',                   DIRECTORY_SEPARATOR );
# ==================================
# PHP errors & log: Drop what you don't need.
@ini_set( 'display_errors',     1 );
@ini_set( 'log_errors',         1 );

# ==================================
define( 'WP_DEBUG',             true );
// file: ~/WP_CONTENT_DIR/debug.log
define( 'WP_DEBUG_LOG',         true );
define( 'WP_DEBUG_DISPLAY',     true );
define( 'SAVEQUERIES',          true );
define( 'DIEONDBERROR',         true );
define( 'ERRORLOGFILE', WP_CONTENT_DIR.DS.'logs'.DS.'mu_error.log' );
# PHP Error log location
@ini_set( 'error_log', WP_CONTENT_DIR.DS.'logs'.DS.'php_error.log' );

Error reporting

Users: Be nice, and ♥ your developer. Provide meaningful error reports - use the paranoia setup if something is not working.


Voted: 1/5 *


Taxes bug! このEasy Digital Downloads のプラグインは、プライス20,000.以上で 税金計算のバグが有ります。 実際にご確認ください。 プライス20,000. 税金5 % 制作者に連絡しても駄目でした。 なので、Rating は、1.

Source: Pippin Williamson "Easy Digital Downloads" Plugin at the wp.org repo.

Be unique!

Throwing things into the global namespace is like driving on the wrong side of the street to see what happens. Safe a day, avoid collisions.

Plugins API basics

Avoid hacking core files. There's an API to do it. The difference between actions and filters.

Action: do_action( 'name', $additional_arguments );
Filter: apply_filters( 'name', $minimum_argument, $additional_arguments );

Time to hook in

MU-Plugins, Plugins and Themes: each group has their own hook.

Hook in once, with a priority lower than 10, so others have a chance to modify them with the default priority of 10.

A basic plugin

Example: The WCM Current Admin Info Plugin. Hooks in at plugins_loaded to load all files.

defined( 'ABSPATH' ) OR exit;
 * Plugin Name:  Current admin screen info
 * Author:       Franz Josef Kaiser (wecodemore[at]gmail.com)
add_action( 'plugins_loaded', array( 'WCM_CSD', 'init' ), 5 );
final class WCM_CSD
	private static $instance;

	public static function init()
		is_null( self::$instance )
			AND self::$instance = new self;
		return self::$instance;

	public function __construct()
		$files = glob(plugin_dir_path(__FILE__).'inc/*.php');
		foreach ( $files as $file )
			require_once $file;

One ♥ for shared host users

Fatal error: Allowed memory size of *** bytes exhausted…

This is what your users get: The white screen of † death!
Happens mostly on the ~/wp-admin/dashboard.php for shared hosts.
Tells us, that a lot of crappy plugins didn't care about where they load themselves.

Contextual and conditional loading


Requests need time, scripts and files use memory.

add_action( 'admin_enqueue_scripts', 'wpm_vie_enqueue' );
function wpm_vie_enqueue( $hook )
	in_array( $hook, array( 'post.php', 'post-new.php' ) )
		AND wp_enqueue_script( 'vienna' );



Sometimes, "Give me an option!" is like…

Plugins should blend in

Digital Footprint

Less is more!

Don't feel bad if you offer no options at all.
Advantages of no options: Less chances to…

Do one job, but do it right.

Data and the Database…

…and translations

…is something for another talk.

Follow the right people

A short (an incomplete) list of developers doing it right.… in alphabetical order.

Thank you! … Questions?

Franz Josef Kaiser

Download the presentation … soon