Wordpress Plugin Development Demystified

36,929 views
36,720 views

Published on

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.

Published in: Technology, Art & Photos

Wordpress Plugin Development Demystified

  1. 1. Plugin Development Demystified Yannick Lefebvre (@ylefebvre) Wordpress Plugin Developer
  2. 2. Plugin Development DemystifiedTopics● Introduction ● Meta Boxes● Plugins Overview ● Shortcodes● File Structure ● Publishing your plugin● Actions and Filter Hooks ● Recommended Readings● Activation, Deactivation and Removal ● Questions● Administration Pages
  3. 3. 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/
  4. 4. 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
  5. 5. 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-contentplugins 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
  6. 6. Plugin File Header<?php<?php/*/*Plugin Name: My New Google Analytics PluginPlugin Name: My New Google Analytics PluginPlugin URI: http://yannickcorner.nayanna.bizPlugin URI: http://yannickcorner.nayanna.bizDescription: New revolutionary GA PluginDescription: New revolutionary GA PluginVersion: 1.0Version: 1.0Author: Yannick LefebvreAuthor: Yannick LefebvreAuthor URI: http://yannickcorner.nayanna.bizAuthor URI: http://yannickcorner.nayanna.bizLicense: GPL2License: GPL2*/*/?>?>● This information registers the plugin with Wordpress● Most of this data is visible to users in the Plugins admin section
  7. 7. First plugin sighting
  8. 8. 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
  9. 9. Plugin Evaluation Error
  10. 10. 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
  11. 11. Assigning an action hookadd_action ( hook_name, your_function_name, [priority],add_action ( hook_name, your_function_name, [priority],[accepted_args] );[accepted_args] );ExampleExampleadd_action(wp_head, newga_header);add_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 itselffunction wp_head() {function wp_head() { do_action(wp_head); do_action(wp_head);}}
  12. 12. Full action hook implementationadd_action(wp_head, newga_header);add_action(wp_head, newga_header);function newga_header() { ?>function newga_header() { ?> <script type="text/javascript"> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? var gaJsHost = (("https:" == document.location.protocol) ?"https://ssl." : "http://www.");"https://ssl." : "http://www."); document.write(unescape("%3Cscript src=" + gaJsHost + "google- document.write(unescape("%3Cscript src=" + gaJsHost + "google-analytics.com/ga.js type=text/javascript%3E%3C/script%3E"));analytics.com/ga.js type=text/javascript%3E%3C/script%3E")); </script> </script> <script type="text/javascript"> <script type="text/javascript"> try{ try{ var pageTracker = _gat._getTracker("UA-xxxxxx-x"); var pageTracker = _gat._getTracker("UA-xxxxxx-x"); pageTracker._trackPageview(); pageTracker._trackPageview(); } catch(err) {} } catch(err) {} </script> </script><? }<? }● Prints script code in page header when wp_head() is called in theme template
  13. 13. Typical Action Hooks for WP Page
  14. 14. Assigning a filter hookadd_filter($tag, $function_to_add, [$priority], [$accepted_args]);add_filter($tag, $function_to_add, [$priority], [$accepted_args]);ExampleExampleadd_filter( the_content, newga_content_filter);add_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 valuefunction the_content($more_link_text = null, $stripteaser = 0) {function the_content($more_link_text = null, $stripteaser = 0) { $content = get_the_content($more_link_text, $stripteaser); $content = get_the_content($more_link_text, $stripteaser); $content = apply_filters(the_content, $content); $content = apply_filters(the_content, $content); $content = str_replace(]]>, ]]&gt;, $content); $content = str_replace(]]>, ]]&gt;, $content); echo $content; echo $content;}}
  15. 15. Full filter hook implementationadd_filter( the_content, newga_content_filter);add_filter( the_content, newga_content_filter);function newga_content_filter($the_content) {function newga_content_filter($the_content) { // Search through contents for links and add google analytics // Search through contents for links and add google analyticscode after hrefscode after hrefs // <a href="http://www.example.com" // <a href="http://www.example.com"onClick="recordOutboundLink(this, Outbound Links,onClick="recordOutboundLink(this, Outbound Links,example.com);return false;">example.com);return false;"> return $the_content; return $the_content; } }● The result of this code would be extra tags and details around links in post and page content
  16. 16. Database Read Filters
  17. 17. 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
  18. 18. 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
  19. 19. Activation / Deactivation● First step in many plugins is to register functions that will be called on activation and deactivationregister_activation_hook(__FILE__, my_new_plugin_activate);register_activation_hook(__FILE__, my_new_plugin_activate);register_deactivation_hook(__FILE__, my_new_plugin_deactivate);register_deactivation_hook(__FILE__, my_new_plugin_deactivate);● The deactivation function should NOT be used to delete user data as deactivation might be temporary
  20. 20. Activation Exampleregister_activation_hook(__FILE__, my_new_plugin_activate);register_activation_hook(__FILE__, my_new_plugin_activate);function my_new_plugin_activate() {function my_new_plugin_activate() { if (get_option(NewGA_Options) === false) if (get_option(NewGA_Options) === false) { { $options[gauser] = ; $options[gauser] = ; update_option(NewGA_Options, $options); update_option(NewGA_Options, $options); } }}}● This code first checks if the options already exists and creates new default values if they dont.
  21. 21. Uninstallation Code● Uninstallation code should remove all traces of the pluginregister_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
  22. 22. Administrative Pages● Admin page allows users to configure plugin options● Register function to get called when the admin menu is builtadd_action(admin_menu,add_action(admin_menu,my_new_plugin_admin_menu);my_new_plugin_admin_menu);function my_new_plugin_admin_menu() {function my_new_plugin_admin_menu() { global $pagehooktop; global $pagehooktop; $pagehooktop = add_menu_page( New GA $pagehooktop = add_menu_page( New GAGeneral Options, New GA, manage_options,General Options, New GA, manage_options,new-ga, my_new_plugin_show_admin, plugins_url(new-ga, my_new_plugin_show_admin, plugins_url(/icons/NewGA16.png , __FILE__ ));/icons/NewGA16.png , __FILE__ )); } }
  23. 23. Administrative Pages● Implement admin page rendering function function my_new_plugin_show_admin() { function my_new_plugin_show_admin() { $options = get_option(NewGA_Options); $options = get_option(NewGA_Options); ?> ?> <h1>New Google Analytics Plugin</h1> <h1>New Google Analytics Plugin</h1> <form name="newgaform" method="post" action=""> <form name="newgaform" method="post" action=""> GA User ID: <input type="text" name="gauser" value="<?php GA User ID: <input type="text" name="gauser" value="<?php echo $options[gauser]; ?>"/><br /> echo $options[gauser]; ?>"/><br /> <input type="submit" value="Submit" /> <input type="submit" value="Submit" /> </form> </form> <?php } <?php }
  24. 24. Administrative Pages● Process Post Data function my_new_plugin_show_admin() { function my_new_plugin_show_admin() { if (isset($_POST[gauser])) if (isset($_POST[gauser])) { { $options[gauser] = $_POST[gauser]; $options[gauser] = $_POST[gauser]; update_option(NewGA_Options, $options); update_option(NewGA_Options, $options); } } $options = get_option(NewGA_Options); $options = get_option(NewGA_Options); ?> ?> <h1>New Google Analytics Plugin</h1> <h1>New Google Analytics Plugin</h1> <form name="newgaform" method="post" action=""> <form name="newgaform" method="post" action=""> GA User ID: <input type="text" name="gauser" value="<?php GA User ID: <input type="text" name="gauser" value="<?php echo $options[gauser]; ?>"/><br /> echo $options[gauser]; ?>"/><br /> <input type="submit" value="Submit" /> <input type="submit" value="Submit" /> </form> </form> <?php } <?php }
  25. 25. Administrative Pages● Add Security function my_new_plugin_show_admin() { function my_new_plugin_show_admin() { if (isset($_POST[gauser])) if (isset($_POST[gauser])) { { check_admin_referer(newga); check_admin_referer(newga); $options[gauser] = $_POST[gauser]; $options[gauser] = $_POST[gauser]; update_option(NewGA_Options, $options); update_option(NewGA_Options, $options); } } $options = get_option(NewGA_Options); $options = get_option(NewGA_Options); ?> ?> <h1>New Google Analytics Plugin</h1> <h1>New Google Analytics Plugin</h1> <form name="newgaform" method="post" action=""> <form name="newgaform" method="post" action=""> <?php wp_nonce_field(newga); ?> <?php wp_nonce_field(newga); ?> GA User ID: <input type="text" name="gauser" value="<?php GA User ID: <input type="text" name="gauser" value="<?php echo $options[gauser]; ?>"/><br /> echo $options[gauser]; ?>"/><br /> <input type="submit" value="Submit" /> <input type="submit" value="Submit" /> </form> </form> <?php } <?php }
  26. 26. Updated Header Code● Use option data in header codefunctionfunction newga_header() { newga_header() {$options$options = get_option(NewGA_Options); = get_option(NewGA_Options);?>?> <script type="text/javascript"> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? var gaJsHost = (("https:" == document.location.protocol) ?"https://ssl." : "http://www.");"https://ssl." : "http://www.");document.write(unescape("%3Cscript src=" + gaJsHost + "google-document.write(unescape("%3Cscript src=" + gaJsHost + "google-analytics.com/ga.js type=text/javascript%3E%3C/script%3E"));analytics.com/ga.js type=text/javascript%3E%3C/script%3E")); </script> </script> <script type="text/javascript"> <script type="text/javascript"> try{ try{ var pageTracker = _gat._getTracker("<?php echo $options[gauser]; ? var pageTracker = _gat._getTracker("<?php echo $options[gauser]; ?>");>"); pageTracker._trackPageview(); pageTracker._trackPageview(); } catch(err) {} } catch(err) {} </script> </script><?php<?php}}
  27. 27. 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...)
  28. 28. Meta Boxesfunction my_new_plugin_admin_menu() {function my_new_plugin_admin_menu() { global $pagehooktop; global $pagehooktop; $pagehooktop = add_menu_page( New GA General Options, "New $pagehooktop = add_menu_page( New GA General Options, "NewGA", manage_options, new-ga, my_new_plugin_show_admin,GA", manage_options, new-ga, my_new_plugin_show_admin,plugins_url( /icons/NewGA16.png , __FILE__ ));plugins_url( /icons/NewGA16.png , __FILE__ )); add_meta_box(newga_general_meta_box, General Settings, add_meta_box(newga_general_meta_box, General Settings,my_new_plugin_meta_box, $pagehooktop, normal, high);my_new_plugin_meta_box, $pagehooktop, normal, high); wp_enqueue_script(postbox); wp_enqueue_script(postbox);}}
  29. 29. Meta Boxes Implementation● The original simple form code does get more complex when using meta boxes to include all of the right styles● Original form code: <form name="newgaform" method="post" action=""> <form name="newgaform" method="post" action=""> <?php wp_nonce_field(newga); ?> <?php wp_nonce_field(newga); ?> GA User ID: <input type="text" name="gauser" value="<?php echo GA User ID: <input type="text" name="gauser" value="<?php echo$options[gauser]; ?>"/><br />$options[gauser]; ?>"/><br /> <input type="submit" value="Submit" /> <input type="submit" value="Submit" /> </form> </form>● New form code on following page...
  30. 30. Meta Boxes Implementation<form name="newgaform" method="post" action=""><form name="newgaform" method="post" action=""> <?php wp_nonce_field(newga); ?> <?php wp_nonce_field(newga); ?> <div id="poststuff" class="metabox-holder" style=width: 95%> <div id="poststuff" class="metabox-holder" style=width: 95%> <div id="post-body"> <div id="post-body"> <div id="post-body-content"> <div id="post-body-content"> <?php <?php if ($_GET[page] == new-ga) if ($_GET[page] == new-ga) { { global $pagehooktop; global $pagehooktop; do_meta_boxes($pagehooktop, normal, $data); do_meta_boxes($pagehooktop, normal, $data); } } ?> ?> </div> </div> </div> </div> <br class="clear"/> <br class="clear"/> </div> </div> </form> </form> <script type="text/javascript"> <script type="text/javascript"> //<![CDATA[ //<![CDATA[ jQuery(document).ready( function($) { jQuery(document).ready( function($) { // close postboxes that should be closed // close postboxes that should be closed $(.if-js-closed).removeClass(if-js-closed).addClass(closed); $(.if-js-closed).removeClass(if-js-closed).addClass(closed); // postboxes setup // postboxes setup postboxes.add_postbox_toggles(<?php postboxes.add_postbox_toggles(<?php if ($_GET[page] == new-ga) if ($_GET[page] == new-ga) { { global $pagehooktop; global $pagehooktop; echo $pagehooktop; echo $pagehooktop; } } ?>); ?>); }); }); //]]> //]]> Okay, maybe this one is still a bit mystifying :) Okay, maybe this one is still a bit mystifying :) </script> </script>
  31. 31. Meta Boxes Implementation● Code to render contents of Meta Box function my_new_plugin_meta_box() { ?> function my_new_plugin_meta_box() { ?> GA User ID: <input type="text" name="gauser" value="<?php GA User ID: <input type="text" name="gauser" value="<?php echo $options[gauser]; ?>"/><br /> echo $options[gauser]; ?>"/><br /> <input type="submit" value="Submit" /> <input type="submit" value="Submit" /> <?php } <?php }
  32. 32. Adding meta boxes to existing editorsadd_meta_box (linklibrary_meta_box, Link Library - Additionaladd_meta_box (linklibrary_meta_box, Link Library - AdditionalLink Parameters, ll_link_edit_extra, link, normal,Link Parameters, ll_link_edit_extra, link, normal,high);high);
  33. 33. Saving meta box data added to existing editors● Action hooks are used to register custom functions to save additional meta box data add_action(add_link, add_link_field); add_action(add_link, add_link_field); add_action(edit_link, add_link_field); add_action(edit_link, add_link_field); add_action(delete_link, delete_link_field); add_action(delete_link, delete_link_field); function add_link_field($link_id) { function add_link_field($link_id) { // Save extra link fields // Save extra link fields // Can be saved to Wordpress options or custom // Can be saved to Wordpress options or custom MySQL tables MySQL tables // $link_id parameter is ID of new or existing // $link_id parameter is ID of new or existing link link } } Function delete_link_field($link_id) { Function delete_link_field($link_id) { // Delete custom link data from custom MySQL tables // Delete custom link data from custom MySQL tables // or Wordpress options // or Wordpress options } }
  34. 34. 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
  35. 35. 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); add_shortcode(youtubevid, youtubevid_func); function youtubevid_func($atts) { function youtubevid_func($atts) { extract(shortcode_atts(array( extract(shortcode_atts(array( id id ), $atts)); ), $atts)); $output = <iframe width="560" height="349" $output = <iframe width="560" height="349" src="http://www.youtube.com/embed/ . $id . " frameborder="0" src="http://www.youtube.com/embed/ . $id . " frameborder="0" allowfullscreen></iframe>; allowfullscreen></iframe>; return $output; return $output; } } [youtubevid id=hDV-lgmNQUE] [youtubevid id=hDV-lgmNQUE]
  36. 36. 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
  37. 37. TortoiseSVN User Interface
  38. 38. 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● Todays presentation and code samples available at: ● http://yannickcorner.nayanna.biz/wcmtl2011
  39. 39. Questions? Thank you for attending this talk on Plugin Development Demystified Contact: ylefebvre@gmail.com Twitter: @ylefebvre Blog : http://yannickcorner.nayanna.bizPlugins: http://profiles.wordpress.org/users/jackdewey/

×