How Not to Build a WordPress Plugin Will Norris < http://willnorris.com />
Upgradability Performance Security Extensibility
Unique Function Names
Function Name Prefix wcpdx_activate() wcpdx_deactivate() wcpdx_uninstall()
Class class WordCampPDX { function activate() function deactivate() function uninstall() }
Never Assume File Location
Traditional Directory Layout example.com/ wordpress/ wp-config.php wp-content/ plugins/ themes/
Non-Traditional Layout (since WP 2.6) example.com/ wordpress/ wp-config.php wordpress-content/ plugins/ themes/
Plugin URL ur doin it wrong: <img src=”<?php bloginfo(‘wpurl’) ?>/wp-content/plugins/wcpdx/logo.png” ?> dats bedder: <img src=”<?php echo WP_PLUGIN_URL ?>/wcpdx/logo.png ?>”/> you haz it: <img src=”<?php echo plugins_url(‘logo.png’, __FILE__) ?>” />
Plugin URL plugins_url() supports WPMU plugin directory auto detects SSL supports renamed plugin directory calls ‘plugins_url’ filter
Friends of plugins_url() site_url() admin_url() includes_url() content_url() no home_url() (why not?)
Including Files ur doin it wrong: include ‘../../wp-content/...’ dats bedder: include ABSPATH . ‘wp-content/...’ you haz it: include WP_CONTENT_DIR . ‘/...’
Find the Right Hook Load as late as possible, but no later
Admin Hooks ur doin it wrong: add_action(‘admin_init’, ‘wcpdx_admin_init’) add_action(‘admin_head’, ‘wcpdx_admin_head’) you haz it: $hookname = add_options_page( ... ) add_action(“admin_load-$hookname”, ‘wcpdx_admin_init’) add_action(“admin_head-$hookname”, ‘wcpdx_admin_head’)
Styles and Scripts ur doin it wrong: <script rel=”<?php echo plugins_url(‘wcpdx.js’, __FILE__) ?>”></script> you haz it: wp_enqueue_script(‘wcpdx’, plugins_url(‘wcpdx.js’, __FILE__)) wp_enqueue_style(‘wcpdx’, plugins_url(‘wcpdx.css’, __FILE__))
Styles and Scripts wp_register_* and wp_enqueue_* support dependencies push scripts to footer caching support based on version (one day) server side concatenation
Add your own hooks A strategically placed hook covers a multitude of sins.
Custom Hooks Can do everything core WP hooks do: event notification (actions) massage data (the_content) replace values (stylesheet) extend functionality (http_api_curl) replace functionality
Custom Hooks do_action(‘my-action’) do_action(‘my-action’, $a, $b) do_action_ref_array(‘my-action’, array($wcpdx)) apply_filters(‘my-filter’, $wcpdx) apply_filters(‘my-filter’, $wcpdx, $a, $b)
Custom Tables
Designed for Flexibility WordPress database supports custom options arbitrary metadata for posts, users, and comments (2.9) custom taxonomies custom post types
Custom Post Types Used by WordPress core for posts pages revisions attachments
If it walks like a duck... author date and time title content comments categories and tags permalink order hierarchy (additional arbitrary metadata)
Admin Settings Pages
Admin Settings Pages Don’t waste time processing manually register_setting( ‘wcpdx’, ‘my-option’ ) http://codex.wordpress.org/Settings_API http://codex.wordpress.org/Creating_Options_Pages# Register_Settings
Admin Settings Pages Do you really need a dedicated page? Add options to any built-in settings page add_settings_field( ... )
Direct Plugin Files
Direct Plugin File Calls Direct HTTP request to plugin file ajax.php: echo ‘<script type=”text/javascript”> jQuery.get(“‘ . plugins_url(‘ajax.php’, __FILE__) . ‘”); // do something with AJAX data </script>’;
Direct Plugin File Calls If ajax.php includes anything similar to: require_once(‘../../../wp-load.php’); ur doin it wrong
WordPress Requests Permalink URL: http://example.com/2009/01/hello-world becomes: http://example.com/index.php? year=2009& monthnum=01& name=hello-world
Custom WP Request Instead of making an AJAX call to: http://example.com/wp-content/plugins/wcpdx/ajax.php we want a URL like: http://example.com/index.php?wcpdx=ajax-handler
Custom WP Requests function wcpdx_parse_request($wp) { // only process requests with &quot;wcpdx=ajax-handler&quot; if (array_key_exists('wcpdx', $wp->query_vars) && $wp->query_vars['wcpdx'] == 'ajax-handler') { // process the request. } } add_action('parse_request', 'wcpdx_parse_request'); function wcpdx_query_vars($vars) { $vars[] = 'wcpdx'; return $vars; } add_filter('query_vars', 'wcpdx_query_vars');

How Not to Build a WordPress Plugin

  • 1.
    How Not toBuild a WordPress Plugin Will Norris < http://willnorris.com />
  • 2.
  • 3.
  • 4.
    Function Name Prefixwcpdx_activate() wcpdx_deactivate() wcpdx_uninstall()
  • 5.
    Class class WordCampPDX{ function activate() function deactivate() function uninstall() }
  • 6.
  • 7.
    Traditional Directory Layoutexample.com/ wordpress/ wp-config.php wp-content/ plugins/ themes/
  • 8.
    Non-Traditional Layout (sinceWP 2.6) example.com/ wordpress/ wp-config.php wordpress-content/ plugins/ themes/
  • 9.
    Plugin URL urdoin it wrong: <img src=”<?php bloginfo(‘wpurl’) ?>/wp-content/plugins/wcpdx/logo.png” ?> dats bedder: <img src=”<?php echo WP_PLUGIN_URL ?>/wcpdx/logo.png ?>”/> you haz it: <img src=”<?php echo plugins_url(‘logo.png’, __FILE__) ?>” />
  • 10.
    Plugin URL plugins_url()supports WPMU plugin directory auto detects SSL supports renamed plugin directory calls ‘plugins_url’ filter
  • 11.
    Friends of plugins_url()site_url() admin_url() includes_url() content_url() no home_url() (why not?)
  • 12.
    Including Files urdoin it wrong: include ‘../../wp-content/...’ dats bedder: include ABSPATH . ‘wp-content/...’ you haz it: include WP_CONTENT_DIR . ‘/...’
  • 13.
    Find the RightHook Load as late as possible, but no later
  • 14.
    Admin Hooks urdoin it wrong: add_action(‘admin_init’, ‘wcpdx_admin_init’) add_action(‘admin_head’, ‘wcpdx_admin_head’) you haz it: $hookname = add_options_page( ... ) add_action(“admin_load-$hookname”, ‘wcpdx_admin_init’) add_action(“admin_head-$hookname”, ‘wcpdx_admin_head’)
  • 15.
    Styles and Scriptsur doin it wrong: <script rel=”<?php echo plugins_url(‘wcpdx.js’, __FILE__) ?>”></script> you haz it: wp_enqueue_script(‘wcpdx’, plugins_url(‘wcpdx.js’, __FILE__)) wp_enqueue_style(‘wcpdx’, plugins_url(‘wcpdx.css’, __FILE__))
  • 16.
    Styles and Scriptswp_register_* and wp_enqueue_* support dependencies push scripts to footer caching support based on version (one day) server side concatenation
  • 17.
    Add your ownhooks A strategically placed hook covers a multitude of sins.
  • 18.
    Custom Hooks Cando everything core WP hooks do: event notification (actions) massage data (the_content) replace values (stylesheet) extend functionality (http_api_curl) replace functionality
  • 19.
    Custom Hooks do_action(‘my-action’)do_action(‘my-action’, $a, $b) do_action_ref_array(‘my-action’, array($wcpdx)) apply_filters(‘my-filter’, $wcpdx) apply_filters(‘my-filter’, $wcpdx, $a, $b)
  • 20.
  • 21.
    Designed for FlexibilityWordPress database supports custom options arbitrary metadata for posts, users, and comments (2.9) custom taxonomies custom post types
  • 22.
    Custom Post TypesUsed by WordPress core for posts pages revisions attachments
  • 23.
    If it walkslike a duck... author date and time title content comments categories and tags permalink order hierarchy (additional arbitrary metadata)
  • 24.
  • 25.
    Admin Settings PagesDon’t waste time processing manually register_setting( ‘wcpdx’, ‘my-option’ ) http://codex.wordpress.org/Settings_API http://codex.wordpress.org/Creating_Options_Pages# Register_Settings
  • 26.
    Admin Settings PagesDo you really need a dedicated page? Add options to any built-in settings page add_settings_field( ... )
  • 27.
  • 28.
    Direct Plugin FileCalls Direct HTTP request to plugin file ajax.php: echo ‘<script type=”text/javascript”> jQuery.get(“‘ . plugins_url(‘ajax.php’, __FILE__) . ‘”); // do something with AJAX data </script>’;
  • 29.
    Direct Plugin FileCalls If ajax.php includes anything similar to: require_once(‘../../../wp-load.php’); ur doin it wrong
  • 30.
    WordPress Requests PermalinkURL: http://example.com/2009/01/hello-world becomes: http://example.com/index.php? year=2009& monthnum=01& name=hello-world
  • 31.
    Custom WP RequestInstead of making an AJAX call to: http://example.com/wp-content/plugins/wcpdx/ajax.php we want a URL like: http://example.com/index.php?wcpdx=ajax-handler
  • 32.
    Custom WP Requestsfunction wcpdx_parse_request($wp) { // only process requests with &quot;wcpdx=ajax-handler&quot; if (array_key_exists('wcpdx', $wp->query_vars) && $wp->query_vars['wcpdx'] == 'ajax-handler') { // process the request. } } add_action('parse_request', 'wcpdx_parse_request'); function wcpdx_query_vars($vars) { $vars[] = 'wcpdx'; return $vars; } add_filter('query_vars', 'wcpdx_query_vars');