39
Yannick Lefebvre (@ylefebvre) Wordpress Plugin Developer Plugin Development Demystified

Wordpress Plugin Development Demystified

Embed Size (px)

DESCRIPTION

For many WordPress users, even seasoned PHP developers, creating new plugins for WordPress seems like a daunting task. After talking about specific best practices in plugin development last year, this presentation will take a step back to show attendees how simple creating plugins for WordPress from the ground up can be by looking at the architecture of a WordPress plugin, from the basic concepts of registering actions and filters to more advanced concepts such as the creation of admin pages and registering shortcodes.

Citation preview

Page 1: Wordpress Plugin Development Demystified

Yannick Lefebvre (@ylefebvre)Wordpress Plugin Developer

Plugin Development Demystified

Page 2: Wordpress Plugin Development Demystified

Plugin Development Demystified

Topics● Introduction● Plugins Overview● File Structure● Actions and Filter Hooks● Activation, Deactivation

and Removal● Administration Pages

● Meta Boxes● Shortcodes● Publishing your plugin● Recommended

Readings● Questions

Page 3: Wordpress Plugin Development Demystified

Introduction

● Migrated from Blogger to Wordpress in April 2004● Released first plugin in March 2005 (Link Library)● Released 7 Plugins to date

● http://profiles.wordpress.org/users/jackdewey/

Page 4: Wordpress Plugin Development Demystified

Plugins Overview

● Allows developers to extend default Wordpress capabilities

● Open plugin architecture present since very first versions

● Plugin API constantly refined and expanded● Plugin code size and complexity vary widely from

one to another● Functionality stays in place when theme is changed● Can be installed directly from Wordpress admin or

through a manual upload and activation process

Page 5: Wordpress Plugin Development Demystified

Basic Plugin File Structure

● Made from one or more php code file(s)● Can optionally contain other file types (e.g. images,

text files, translation files, etc...)● Located directly in the wp-content\plugins directory

or in a sub-directory within the plugins folder● Entry point is a .php file that contains a specific

plugin header at its top

Page 6: Wordpress Plugin Development Demystified

Plugin File Header

<?php/*Plugin Name: My New Google Analytics PluginPlugin URI: http://yannickcorner.nayanna.bizDescription: New revolutionary GA PluginVersion: 1.0Author: Yannick LefebvreAuthor URI: http://yannickcorner.nayanna.bizLicense: GPL2*/?>

<?php/*Plugin Name: My New Google Analytics PluginPlugin URI: http://yannickcorner.nayanna.bizDescription: New revolutionary GA PluginVersion: 1.0Author: Yannick LefebvreAuthor URI: http://yannickcorner.nayanna.bizLicense: GPL2*/?>

● This information registers the plugin with Wordpress● Most of this data is visible to users in the Plugins

admin section

Page 7: Wordpress Plugin Development Demystified

First plugin sighting

Page 8: Wordpress Plugin Development Demystified

Plugin Evaluation Rules

● Function declared in plugin can be called from theme template file or other plugins

● Function names must be different from Wordpress core functions and other plugins

● Entire content is evaluated each time site is rendered

● A single error will usually bring down the entire site

● Using a local development environment is much safer than developing on live site

Page 9: Wordpress Plugin Development Demystified

Plugin Evaluation Error

Page 10: Wordpress Plugin Development Demystified

Actions and Filter Hooks

● The power of plugins comes from their ability to register custom functions to be called at specific points during the execution of Wordpress

● This process is called hooking● Two types of hooks

● Action hooks allow for code to be executed at a specific point during the page processing loop

● Filter hooks are called during Wordpress data processing to allow plugins to modify, increase or reduce data before it is displayed

Page 11: Wordpress Plugin Development Demystified

Assigning an action hook

add_action ( 'hook_name', 'your_function_name', [priority], [accepted_args] );

Exampleadd_action('wp_head', 'newga_header');

add_action ( 'hook_name', 'your_function_name', [priority], [accepted_args] );

Exampleadd_action('wp_head', 'newga_header');

● Most hook names can be found in Wordpress Codex. Includes description of arguments and hook purpose.

● More complete list is available on third-party sites, but these lack additional information

● A third source is the Wordpress code itself

function wp_head() {do_action('wp_head');

}

function wp_head() {do_action('wp_head');

}

Page 12: Wordpress Plugin Development Demystified

Full action hook implementation

add_action('wp_head', 'newga_header');

function newga_header() { ?><script type="text/javascript">var gaJsHost = (("https:" == document.location.protocol) ?

"https://ssl." : "http://www.");document.write(unescape("%3Cscript src='" + gaJsHost + "google-

analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));</script><script type="text/javascript">try{var pageTracker = _gat._getTracker("UA-xxxxxx-x");pageTracker._trackPageview();} catch(err) {}</script>

<? }

add_action('wp_head', 'newga_header');

function newga_header() { ?><script type="text/javascript">var gaJsHost = (("https:" == document.location.protocol) ?

"https://ssl." : "http://www.");document.write(unescape("%3Cscript src='" + gaJsHost + "google-

analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));</script><script type="text/javascript">try{var pageTracker = _gat._getTracker("UA-xxxxxx-x");pageTracker._trackPageview();} catch(err) {}</script>

<? }

● Prints script code in page header when wp_head() is called in theme template

Page 13: Wordpress Plugin Development Demystified

Typical Action Hooks for WP Page

Page 14: Wordpress Plugin Development Demystified

Assigning a filter hook

add_filter($tag, $function_to_add, [$priority], [$accepted_args]);

Exampleadd_filter( 'the_content', 'newga_content_filter');

add_filter($tag, $function_to_add, [$priority], [$accepted_args]);

Exampleadd_filter( 'the_content', 'newga_content_filter');

● Filters hooks receive data arguments that they can modify within their processing function and must return data, modified or intact

● In WP core, filter function are called with one or more data parameters. The number of parameters needs to be used for accepted_args value

function the_content($more_link_text = null, $stripteaser = 0) {$content = get_the_content($more_link_text, $stripteaser);$content = apply_filters('the_content', $content);$content = str_replace(']]>', ']]&gt;', $content);echo $content;

}

function the_content($more_link_text = null, $stripteaser = 0) {$content = get_the_content($more_link_text, $stripteaser);$content = apply_filters('the_content', $content);$content = str_replace(']]>', ']]&gt;', $content);echo $content;

}

Page 15: Wordpress Plugin Development Demystified

Full filter hook implementation

add_filter( 'the_content', 'newga_content_filter');

function newga_content_filter($the_content) {

// Search through contents for links and add google analytics code after hrefs

// <a href="http://www.example.com" onClick="recordOutboundLink(this, 'Outbound Links', 'example.com');return false;">

return $the_content;

}

add_filter( 'the_content', 'newga_content_filter');

function newga_content_filter($the_content) {

// Search through contents for links and add google analytics code after hrefs

// <a href="http://www.example.com" onClick="recordOutboundLink(this, 'Outbound Links', 'example.com');return false;">

return $the_content;

}

● The result of this code would be extra tags and details around links in post and page content

Page 16: Wordpress Plugin Development Demystified

Database Read Filters

Page 17: Wordpress Plugin Development Demystified

Storing plugin data

● Most plugins have options for user configuration● There are multiple ways to store custom plugin data

● Wordpress Options: get_option / set_option, single options or arrays

● Custom tables in SQL schema● Config files in plugin directory

Page 18: Wordpress Plugin Development Demystified

Storing plugin data using Wordpress Options

● update_option( $option_name, $newvalue );● Creates option if it does not exist. Updates if it does.● Accepts single variable or array as value

● get_option( $show, $default );● Show is name of option● Default is optional value to be returned if option does not exist

● Initial option value is usually created in plugin activation function

Page 19: Wordpress Plugin Development Demystified

Activation / Deactivation

● First step in many plugins is to register functions that will be called on activation and deactivation

register_activation_hook(__FILE__, 'my_new_plugin_activate');

register_deactivation_hook(__FILE__, 'my_new_plugin_deactivate');

register_activation_hook(__FILE__, 'my_new_plugin_activate');

register_deactivation_hook(__FILE__, 'my_new_plugin_deactivate');

● The deactivation function should NOT be used to delete user data as deactivation might be temporary

Page 20: Wordpress Plugin Development Demystified

Activation Example

register_activation_hook(__FILE__, 'my_new_plugin_activate');

function my_new_plugin_activate() {if (get_option('NewGA_Options') === false){

$options['gauser'] = '';update_option('NewGA_Options', $options);

}}

register_activation_hook(__FILE__, 'my_new_plugin_activate');

function my_new_plugin_activate() {if (get_option('NewGA_Options') === false){

$options['gauser'] = '';update_option('NewGA_Options', $options);

}}

● This code first checks if the options already exists and creates new default values if they don't.

Page 21: Wordpress Plugin Development Demystified

Uninstallation Code

● Uninstallation code should remove all traces of the plugin

register_uninstall_hook(__FILE__, 'my_new_plugin_uninstall');register_uninstall_hook(__FILE__, 'my_new_plugin_uninstall');

● Can also be implemented as straight PHP file called uninstall.php in plugin directory that will execute when uninstalled

Page 22: Wordpress Plugin Development Demystified

Administrative Pages

● Admin page allows users to configure plugin options● Register function to get called when the admin

menu is built

add_action('admin_menu', 'my_new_plugin_admin_menu');

function my_new_plugin_admin_menu() {

global $pagehooktop;$pagehooktop = add_menu_page( 'New GA

General Options', 'New GA', 'manage_options', 'new-ga', 'my_new_plugin_show_admin', plugins_url( '/icons/NewGA16.png' , __FILE__ ));

}

add_action('admin_menu', 'my_new_plugin_admin_menu');

function my_new_plugin_admin_menu() {

global $pagehooktop;$pagehooktop = add_menu_page( 'New GA

General Options', 'New GA', 'manage_options', 'new-ga', 'my_new_plugin_show_admin', plugins_url( '/icons/NewGA16.png' , __FILE__ ));

}

Page 23: Wordpress Plugin Development Demystified

Administrative Pages

● Implement admin page rendering function

function my_new_plugin_show_admin() { $options = get_option('NewGA_Options');?><h1>New Google Analytics Plugin</h1>

<form name="newgaform" method="post" action="">

GA User ID: <input type="text" name="gauser" value="<?php echo $options['gauser']; ?>"/><br />

<input type="submit" value="Submit" /></form>

<?php }

function my_new_plugin_show_admin() { $options = get_option('NewGA_Options');?><h1>New Google Analytics Plugin</h1>

<form name="newgaform" method="post" action="">

GA User ID: <input type="text" name="gauser" value="<?php echo $options['gauser']; ?>"/><br />

<input type="submit" value="Submit" /></form>

<?php }

Page 24: Wordpress Plugin Development Demystified

Administrative Pages

● Process Post Data

function my_new_plugin_show_admin() {

if (isset($_POST['gauser'])){

$options['gauser'] = $_POST['gauser'];update_option('NewGA_Options', $options);

}$options = get_option('NewGA_Options');?><h1>New Google Analytics Plugin</h1>

<form name="newgaform" method="post" action="">

GA User ID: <input type="text" name="gauser" value="<?php echo $options['gauser']; ?>"/><br />

<input type="submit" value="Submit" /></form>

<?php }

function my_new_plugin_show_admin() {

if (isset($_POST['gauser'])){

$options['gauser'] = $_POST['gauser'];update_option('NewGA_Options', $options);

}$options = get_option('NewGA_Options');?><h1>New Google Analytics Plugin</h1>

<form name="newgaform" method="post" action="">

GA User ID: <input type="text" name="gauser" value="<?php echo $options['gauser']; ?>"/><br />

<input type="submit" value="Submit" /></form>

<?php }

Page 25: Wordpress Plugin Development Demystified

Administrative Pages

● Add Security

function my_new_plugin_show_admin() {

if (isset($_POST['gauser'])){

check_admin_referer('newga');$options['gauser'] = $_POST['gauser'];update_option('NewGA_Options', $options);

}

$options = get_option('NewGA_Options');?><h1>New Google Analytics Plugin</h1>

<form name="newgaform" method="post" action=""><?php wp_nonce_field('newga'); ?>GA User ID: <input type="text" name="gauser" value="<?php

echo $options['gauser']; ?>"/><br /><input type="submit" value="Submit" /></form>

<?php }

function my_new_plugin_show_admin() {

if (isset($_POST['gauser'])){

check_admin_referer('newga');$options['gauser'] = $_POST['gauser'];update_option('NewGA_Options', $options);

}

$options = get_option('NewGA_Options');?><h1>New Google Analytics Plugin</h1>

<form name="newgaform" method="post" action=""><?php wp_nonce_field('newga'); ?>GA User ID: <input type="text" name="gauser" value="<?php

echo $options['gauser']; ?>"/><br /><input type="submit" value="Submit" /></form>

<?php }

Page 26: Wordpress Plugin Development Demystified

Updated Header Code

function newga_header() {$options = get_option('NewGA_Options');?>

<script type="text/javascript">var gaJsHost = (("https:" == document.location.protocol) ?

"https://ssl." : "http://www.");document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));

</script><script type="text/javascript">try{var pageTracker = _gat._getTracker("<?php echo $options['gauser']; ?

>");pageTracker._trackPageview();} catch(err) {}</script>

<?php}

function newga_header() {$options = get_option('NewGA_Options');?>

<script type="text/javascript">var gaJsHost = (("https:" == document.location.protocol) ?

"https://ssl." : "http://www.");document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));

</script><script type="text/javascript">try{var pageTracker = _gat._getTracker("<?php echo $options['gauser']; ?

>");pageTracker._trackPageview();} catch(err) {}</script>

<?php}

● Use option data in header code

Page 27: Wordpress Plugin Development Demystified

Meta Boxes

● Meta Boxes are the 'containers' that group together data fields in the default Wordpress admin sections

● Plugins can use meta boxes in their own admin sections or to add custom sections to other parts of Wordpress (e.g. Posts Editor, Links Editor, etc...)

Page 28: Wordpress Plugin Development Demystified

Meta Boxes

function my_new_plugin_admin_menu() {

global $pagehooktop;$pagehooktop = add_menu_page( 'New GA General Options', "New

GA", 'manage_options', 'new-ga', 'my_new_plugin_show_admin', plugins_url( '/icons/NewGA16.png' , __FILE__ ));

add_meta_box('newga_general_meta_box', 'General Settings', 'my_new_plugin_meta_box', $pagehooktop, 'normal', 'high');

wp_enqueue_script('postbox');}

function my_new_plugin_admin_menu() {

global $pagehooktop;$pagehooktop = add_menu_page( 'New GA General Options', "New

GA", 'manage_options', 'new-ga', 'my_new_plugin_show_admin', plugins_url( '/icons/NewGA16.png' , __FILE__ ));

add_meta_box('newga_general_meta_box', 'General Settings', 'my_new_plugin_meta_box', $pagehooktop, 'normal', 'high');

wp_enqueue_script('postbox');}

Page 29: Wordpress Plugin Development Demystified

Meta Boxes Implementation

<form name="newgaform" method="post" action=""><?php wp_nonce_field('newga'); ?>GA User ID: <input type="text" name="gauser" value="<?php echo

$options['gauser']; ?>"/><br /><input type="submit" value="Submit" /></form>

<form name="newgaform" method="post" action=""><?php wp_nonce_field('newga'); ?>GA User ID: <input type="text" name="gauser" value="<?php echo

$options['gauser']; ?>"/><br /><input type="submit" value="Submit" /></form>

● The original simple form code does get more complex when using meta boxes to include all of the right styles

● Original form code:

● New form code on following page...

Page 30: Wordpress Plugin Development Demystified

Meta Boxes Implementation

<form name="newgaform" method="post" action=""><?php wp_nonce_field('newga'); ?><div id="poststuff" class="metabox-holder" style='width: 95%'>

<div id="post-body"><div id="post-body-content">

<?php if ($_GET['page'] == 'new-ga'){

global $pagehooktop;do_meta_boxes($pagehooktop, 'normal', $data);

}?>

</div></div><br class="clear"/>

</div></form><script type="text/javascript">

//<![CDATA[jQuery(document).ready( function($) {

// close postboxes that should be closed$('.if-js-closed').removeClass('if-js-closed').addClass('closed');// postboxes setuppostboxes.add_postbox_toggles('<?php

if ($_GET['page'] == 'new-ga'){

global $pagehooktop;echo $pagehooktop;

}?>');

});//]]>

</script>

<form name="newgaform" method="post" action=""><?php wp_nonce_field('newga'); ?><div id="poststuff" class="metabox-holder" style='width: 95%'>

<div id="post-body"><div id="post-body-content">

<?php if ($_GET['page'] == 'new-ga'){

global $pagehooktop;do_meta_boxes($pagehooktop, 'normal', $data);

}?>

</div></div><br class="clear"/>

</div></form><script type="text/javascript">

//<![CDATA[jQuery(document).ready( function($) {

// close postboxes that should be closed$('.if-js-closed').removeClass('if-js-closed').addClass('closed');// postboxes setuppostboxes.add_postbox_toggles('<?php

if ($_GET['page'] == 'new-ga'){

global $pagehooktop;echo $pagehooktop;

}?>');

});//]]>

</script>Okay, maybe this one is still a bit mystifying :)Okay, maybe this one is still a bit mystifying :)

Page 31: Wordpress Plugin Development Demystified

Meta Boxes Implementation

function my_new_plugin_meta_box() { ?>GA User ID: <input type="text" name="gauser" value="<?php

echo $options['gauser']; ?>"/><br /><input type="submit" value="Submit" />

<?php }

function my_new_plugin_meta_box() { ?>GA User ID: <input type="text" name="gauser" value="<?php

echo $options['gauser']; ?>"/><br /><input type="submit" value="Submit" />

<?php }

● Code to render contents of Meta Box

Page 32: Wordpress Plugin Development Demystified

Adding meta boxes to existing editors

add_meta_box ('linklibrary_meta_box', 'Link Library - Additional Link Parameters', 'll_link_edit_extra', 'link', 'normal', 'high');

add_meta_box ('linklibrary_meta_box', 'Link Library - Additional Link Parameters', 'll_link_edit_extra', 'link', 'normal', 'high');

Page 33: Wordpress Plugin Development Demystified

Saving meta box data added to existing editors

add_action('add_link', 'add_link_field');add_action('edit_link', 'add_link_field');add_action('delete_link', 'delete_link_field');

function add_link_field($link_id) {// Save extra link fields// Can be saved to Wordpress options or custom MySQL tables// $link_id parameter is ID of new or existing link

}

Function delete_link_field($link_id) {// Delete custom link data from custom MySQL tables// or Wordpress options

}

add_action('add_link', 'add_link_field');add_action('edit_link', 'add_link_field');add_action('delete_link', 'delete_link_field');

function add_link_field($link_id) {// Save extra link fields// Can be saved to Wordpress options or custom MySQL tables// $link_id parameter is ID of new or existing link

}

Function delete_link_field($link_id) {// Delete custom link data from custom MySQL tables// or Wordpress options

}

● Action hooks are used to register custom functions to save additional meta box data

Page 34: Wordpress Plugin Development Demystified

Adding a shortcode

● Simple codes used in a post or page to insert content

● [gallery]● [gallery id="123" size="medium"]

● Can also be used to output special code before and after content

● [style1]My text block[/style1]● These are often introduced by themes● Dangerous to use since they will become regular text if you

change to a new theme without these codes

● Consider creating a simple shortcode plugin if you repeatedly insert similar code on site

Page 35: Wordpress Plugin Development Demystified

Shortcode Implementation

● Since shortcodes are found anywhere within posts / pages, they must return their output instead of displaying it directly

add_shortcode('youtubevid', 'youtubevid_func');

function youtubevid_func($atts) { extract(shortcode_atts(array( 'id' ), $atts));

$output = '<iframe width="560" height="349" src="http://www.youtube.com/embed/' . $id . '" frameborder="0" allowfullscreen></iframe>';

return $output;}

add_shortcode('youtubevid', 'youtubevid_func');

function youtubevid_func($atts) { extract(shortcode_atts(array( 'id' ), $atts));

$output = '<iframe width="560" height="349" src="http://www.youtube.com/embed/' . $id . '" frameborder="0" allowfullscreen></iframe>';

return $output;}

[youtubevid id='hDV-lgmNQUE'][youtubevid id='hDV-lgmNQUE']

Page 36: Wordpress Plugin Development Demystified

Publishing your plugin on Wordpress.org

● Any Open Source plugin can be published on Wordpress.org with a few very easy steps:1) Register on Wordpress.org

2) Submit a plugin name and description

3) Receive approval within a few days

4) Create a plugin readme following wordpress.org template

5) Publish plugin to Wordpress subversion repository

Page 37: Wordpress Plugin Development Demystified

TortoiseSVN User Interface

Page 38: Wordpress Plugin Development Demystified

Recommended Readings

● Professional Wordpress Plugin Development by Brad Williams, Ozh Richard and Justin Tadlock, published by WROX Press

● Wordpress Codex (codex.wordpress.com)

● PHP.net● StackOverflow.com Programming

Samples● Today's presentation and code samples

available at:● http://yannickcorner.nayanna.biz/wcmtl2011

Page 39: Wordpress Plugin Development Demystified

Questions?

Thank you for attending this talk on Plugin Development Demystified

Contact: [email protected]: @ylefebvre

Blog : http://yannickcorner.nayanna.bizPlugins: http://profiles.wordpress.org/users/jackdewey/