Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WordPress for the Win!

WordPress for the Win!

Presented on February 7th 2015 at the SunshinePHP Unconference, Miami, Florida and February 10th 2015 at the JAXWeb/JAXPHP usergroup at Jacksonville, Florida.
With the release of WP3, WordPress has become a serious contender on the CMS market. The WordPress plugin system allows you to add functionality to WordPress in a snap and turn it into much more than 'just a blogging platform'.
Learn how to develop for WordPress like a pro and take WordPress to the next level.


Juliette Reinders Folmer

February 07, 2015


  1. WordPress for the Win! Juliette Reinders Folmer

  2. Who am I? Self- employed independent consultant 15+ years in

    IT and web development Contributor to LimeSurvey, phpBB, WordPress, AdoDB and more
  3. None
  4. None
  5. Anatomy of WordPress

  6. Page footer Admin Bar Page content (loop) Page header (Invisible)

    HTML <head> Sidebar containing widgets (Main) menu
  7. Admin Bar (Invisible) HTML <head> Admin footer Admin Menu 1.

    Post types 2. Custom- izations 3. Extras Admin page (with dashboard widgets)
  8. Anatomy of WordPress Core Plugins Themes Languages Js Libraries Content

    via: Post Types Taxonomies Sidebars Widgets Users Enhanced with Meta data / Custom fields
  9. Hooks

  10. Hooks Actions – do something Filters – filter someting and

    return the result See: WordPress Codex Hooks database: http://adambrown.info/p/wp_hooks Debug Bar - Action& filter hooks plugin
  11. The Loop

  12. The Loop <?php if ( have_posts() ) { while (

    have_posts() ) { the_post(); // // Post Content here // } // end while } // end if ?>
  13. WordPress in practice

  14. wp-config.php Tips & Tricks

  15. None
  16. wp-config.php /* Change how WP deals with post revisions, trash

    and auto-saves */ define( 'WP_POST_REVISIONS', 20 ); define( 'AUTOSAVE_INTERVAL', 60 ); // seconds define( 'EMPTY_TRASH_DAYS', 7 ); // days (30) define( 'MEDIA_TRASH', true ); /* Enable Compression en concatenation and cache */ define( 'COMPRESS_CSS', true ); define( 'COMPRESS_SCRIPTS', true ); define( 'CONCATENATE_SCRIPTS', true ); define( 'ENFORCE_GZIP', true ); define( 'WP_CACHE', true ); /* Set up WordPress as Multi-site */ define( 'WP_ALLOW_MULTISITE', true );
  17. wp-config.php /* Force secure logins and admin sessions */ define(

    'FORCE_SSL_LOGIN', true ); define( 'FORCE_SSL_ADMIN', true ); /* Disable Plugin and Theme Update and Installation and/or plugin/theme editor */ define( 'DISALLOW_FILE_EDIT', true ); define( 'DISALLOW_FILE_MODS', true ); /* Disable the new WP 3.7+ auto-updater */ define( 'AUTOMATIC_UPDATER_DISABLED', true ); /* FTP settings */ define( 'FTP_HOST', 'hostname:port' ); define( 'FTP_USER', 'username' ); define( 'FTP_PASS', 'password' );
  18. wp-config.php /* Enable debugging */ define( 'WP_DEBUG', true); define( 'WP_DEBUG_DISPLAY‘,

    true); /* Error logging to wp-content/debug.log */ define( 'WP_DEBUG_LOG', true); /* Load the development (non-minified) versions of all scripts, css, disables compression and concatenation */ define( 'SCRIPT_DEBUG', true); /* Try to increase PHP Memory */ define( 'WP_MEMORY_LIMIT', '128M' );
  19. WordPress in your language

  20. None
  21. Make WP speak your language define( 'WPLANG', 'de_DE' );

  22. Theming your site

  23. None
  24. None
  25. Child themes

  26. Creating a child theme

  27. Child theme – style.css /* Theme Name: Twenty Twelve Child

    Theme URI: http://localhost/ Template: twentytwelve Author: Advies en zo Author URI: http://adviesenzo.nl/ Description: My Child theme Text Domain: twentytwelve Version: 1.0.0 */ @import url("../twentytwelve/style.css"); /* =Theme customization starts here */
  28. Functions.php

  29. Hooking into WP add_action( 'hook_name', 'function_name', $priority = 10, $accepted_args

    = 1 ); add_action( 'hook_name', array( $this, 'method_name' ), $priority = 10, $accepted_args = 1 ); add_action( 'hook_name', array( __CLASS__, 'static_method_name' ), $priority = 10, $accepted_args = 1 ); apply_filter( 'hook_name', 'function_name', $priority = 10, $accepted_args = 1 );
  30. functions.php function favicon_link() { echo '<link rel="shortcut icon" type="image/x-icon" href="http://localhost/wp/favicon.ico"

    />'; echo '<link rel="icon" type="image/ico" href="http://localhost/wp/favicon.ico" />'; } add_action('wp_head', 'favicon_link'); add_action('admin_head', 'favicon_link'); function hide_profile_fields( $contactmethods ) { unset( $contactmethods['aim'] ); unset( $contactmethods['jabber'] ); unset( $contactmethods['yim'] ); return $contactmethods; } add_filter( 'user_contactmethods', 'hide_profile_fields' );
  31. None
  32. functions.php /* Change admin page footer – Branding */ function

    my_admin_footer_text( $left ) { $left = '<img src="' . get_stylesheet_directory_uri() . '/images/AEZ_logobw-32x32.png" width="32" height="32" alt="Advies en zo logo" align="left“ style="margin-top: 0px; margin-right: 5px;" /> Webdevelopment, design and consultancy: <a href="http://adviesenzo.nl/" title="Advies en zo"> Advies en zo </a>'; return $left; } add_filter( 'admin_footer_text', ‘my_admin_footer_text' );
  33. Extending WordPress

  34. None
  35. None
  36. None
  37. Must-use plugins

  38. Create a plugin

  39. Starting a plugin <?php /* Plugin Name: Demo Quotes Plugin

    Plugin URI: https://github.com/jrfnl/wp-plugin-best- practices-demo Description: Demo plugin - Best Practices Tutorial Version: 1.0 Author: Juliette Reinders Folmer Author URI: http://adviesenzo.nl/ Text Domain: demo-quotes-plugin Domain Path: /languages/ License: GPL v3 */
  40. What every plugin needs Hook your functionality onto actions and

    filters Loading your localization files Load CSS Load JS Do something Add admin page or add to another admin page Help information Activation/ Upgrade routines Uninstall routines ...
  41. Add custom content types & taxonomies register_post_type( $post_type_name, // Post

    type name. Max of 20 characters. Uppercase and spaces not allowed. $args // Arguments for post type. ); register_taxonomy( $taxonomy_name, // Taxonomy internal name. Max 32 characters. Uppercase and spaces not allowed. array( $post_type_name, ), // Post types to register this taxonomy for $args // Arguments for taxonomy. );
  42. None
  43. None
  44. Add a settings page register_setting( $option_group, $option_name, $sanitize_callback ); get/update/delete_option(

    $option_name ); add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $page_slug, $call_back ); add_settings_section( $section_id, $title, $callback, $page_slug ); add_settings_field( $id, $title, $callback, $page_slug, $section_id, $args ); settings_fields( $option_group ) do_settings_sections( $page_slug ); do_settings_fields( $page_slug, $section_id );
  45. None
  46. Add a widget class My_Widget extends WP_Widget { // widget

    actual processes public function __construct() {} // outputs the content of the widget public function widget( $args, $instance ) {} // outputs the options form on admin public function form( $instance ) {} // processes widget options to be saved public function update( $new_instance, $old_instance ) {} } add_action('widgets_init', create_function( '', 'return register_widget( "My_Widget" );' ) );
  47. None
  48. None
  49. (De-)Activation, upgrade, uninstall (De-)Activation: Can’t be added from within a

    class Can use methods within a class Upgrading: No upgrade hook Save plugin version nr to option & compare /* Set up the (de-)activation actions */ register_activation_hook( __FILE__, array( ‘Plugin_Class', 'activate' ) ); register_deactivation_hook( __FILE__, array( ' Plugin_Class ', 'deactivate' ) ); • Uninstall via uninstall.php file
  50. Enqueue scripts & styles wp_register_style( 'handle', plugins_url( 'css/style' . $suffix

    . '.css', __FILE__ ), array(), VERSION, 'all' ); wp_enqueue_style( 'handle' ); wp_register_script( 'handle', plugins_url( 'js/file' . $suffix . '.js', __FILE__ ), array( 'jquery', 'wp-ajax-response' ), VERSION, true // load in footer ); wp_enqueue_script( 'handle' ); wp_localize_script( 'handle', 'i18n_js_objectname', array() );
  51. Best Practices

  52. Be Unique

  53. Be Unique PHP: Classes Functions global vars (global) constants WP:

    shortcodes option(s) / meta fields nonces settings pages custom post types hooks Filenames HTML/CSS: classes, ids Javascript: I18n object functions Multi-lingual I18n text domain Choose your plugin name carefully & implement consistently
  54. Don’t reinvent the wheel

  55. Don’t reinvent the wheel Dashboard Widgets API Database API HTTP

    API File Header API Filesystem API Heartbeat API Metadata API Options API Plugin API Quicktags API Rewrite API Settings API Shortcode API Theme modification API Theme customization API Transients API Widgets API XML-RPC WordPress API
  56. Avoid conflict

  57. Avoid conflict function_exists() class_exists() Jquery no conflicts mode Use bundled

  58. Libraries shipped with WP common /wp-admin/js/common.js sack /wp-includes/js/tw-sack.js quicktags /wp-includes/js/quicktags.js

    colorpicker /wp-includes/js/colorpicker.js editor /wp-admin/js/editor.js wp-fullscreen /wp-admin/js/wp-fullscreen.js prototype /wp-includes/js/prototype.js wp-ajax-response /wp-includes/js/wp-ajax-response.js wp-pointer /wp-includes/js/wp-pointer.js autosave /wp-includes/js/autosave.js wp-lists /wp-includes/js/wp-lists.js scriptaculous-root /wp-includes/js/scriptaculous/wp- scriptaculous.js scriptaculous-builder /wp-includes/js/scriptaculous/builder.js scriptaculous-dragdrop /wp-includes/js/scriptaculous/dragdrop.js scriptaculous-effects /wp-includes/js/scriptaculous/effects.js scriptaculous-slider /wp-includes/js/scriptaculous/slider.js scriptaculous-sound /wp-includes/js/scriptaculous/sound.js scriptaculous-controls /wp-includes/js/scriptaculous/controls.js scriptaculous scriptaculous-dragdrop, scriptaculous- slider, scriptaculous-controls, scriptaculous-root cropper /wp-includes/js/crop/cropper.js thickbox /wp-includes/js/thickbox/thickbox.js jcrop /wp-includes/js/jcrop/jquery.Jcrop.js swfobject /wp-includes/js/swfobject.js plupload /wp-includes/js/plupload/plupload.js plupload-html5 wp-includes/js/plupload/plupload.html5.js plupload-flash /wp- includes/js/plupload/plupload.flash.js" plupload-silverlight /wp- includes/js/plupload/plupload.silverlight.js plupload-html4 /wp- includes/js/plupload/plupload.html4.js plupload-full plupload, plupload-html5, plupload-flash, plupload-silverlight, plupload-html4 plupload-handlers /wp-includes/js/plupload/handlers.js swfupload /wp-includes/js/swfupload/swfupload.js swfupload-swfobject /wp- includes/js/swfupload/plugins/swfupload.swfobject.js swfupload-queue /wp- includes/js/swfupload/plugins/swfupload.queue.js jquery /wp-includes/js/jquery/jquery.js (v1.7.2 as of WP 3.3, v1.8.3 as of WP 3.5) jquery-ui-core /wp- includes/js/jquery/ui/jquery.ui.core.min.js jquery-effects-core /wp- includes/js/jquery/ui/jquery.effects.core.min.js jquery-effects-blind /wp- includes/js/jquery/ui/jquery.effects.blind.min.js jquery-effects-bounce /wp- includes/js/jquery/ui/jquery.effects.bounce.min.js jquery-effects-clip /wp- includes/js/jquery/ui/jquery.effects.clip.min.js jquery-effects-drop /wp- includes/js/jquery/ui/jquery.effects.drop.min.js jquery-effects-explode /wp- includes/js/jquery/ui/jquery.effects.explode.min.js jquery-effects-fade /wp- includes/js/jquery/ui/jquery.effects.fade.min.js jquery-effects-fold /wp- includes/js/jquery/ui/jquery.effects.fold.min.js jquery-effects-highlight /wp- includes/js/jquery/ui/jquery.effects.highlight.min.js jquery-effects-pulsate /wp- includes/js/jquery/ui/jquery.effects.pulsate.min.js jquery-effects-scale /wp- includes/js/jquery/ui/jquery.effects.scale.min.js jquery-effects-shake /wp- includes/js/jquery/ui/jquery.effects.shake.min.js jquery-effects-slide /wp- includes/js/jquery/ui/jquery.effects.slide.min.js jquery-effects-transfer /wp- includes/js/jquery/ui/jquery.effects.transfer.min.js jquery-ui-accordion /wp- includes/js/jquery/ui/jquery.ui.accordion.min.js jquery-ui-autocomplete /wp- includes/js/jquery/ui/jquery.ui.autocomplete.min.js jquery-ui-button /wp- includes/js/jquery/ui/jquery.ui.button.min.js jquery-ui-datepicker /wp- includes/js/jquery/ui/jquery.ui.datepicker.min.js jquery-ui-dialog /wp- includes/js/jquery/ui/jquery.ui.dialog.min.js jquery-ui-draggable /wp- includes/js/jquery/ui/jquery.ui.draggable.min.js jquery-ui-droppable /wp- includes/js/jquery/ui/jquery.ui.droppable.min.js jquery-ui-mouse /wp- includes/js/jquery/ui/jquery.ui.mouse.min.js
  59. Be lazy, stay lean

  60. Be lazy, be lean Use the available is_...() functions Conditional

    loading of include files Conditional loading of css / js both on admin as well as frontend! Minify js and css New in WP3.6: has_shortcode()
  61. Be safe

  62. Be safe Check early & check often Validation all input

    sanitize_text_field(), sanitize_title(), sanitize_meta() etc Escape all output esc_html(), esc_attr(), esc_url(), esc_textarea(), esc_js() etc Use wp_nonce
  63. Be wordly

  64. Be worldly GetText UTF-8 Impact on data validation load_plugin_textdomain('my_plugin', false,

    dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); sprintf( __( 'Post updated. <a href="%s">View post</a>', 'my_plugin' ), esc_url( get_permalink( $post_ID ) ) ), esc_html__( 'Custom field updated.', 'my_plugin' );
  65. Let others hook in

  66. Let others hook in Offer your own action hooks Offer

    your own filter hooks do_action( 'my_unique_action_hook', $var_to_pass ); $filtered_var = apply_filters( 'my_unique_filter_hook', $var_to_pass ); Document using the @api tag
  67. Make it beautiful

  68. Pay your dues

  69. Pay your dues Keep the WP requirements in mind Document

    your code Use the coding standards WordPress coding standards: http://make.wordpress.org/core/handbook/coding- standards/php/ CodeSniffs available: https://github.com/WordPress-Coding-Standards/WordPress- Coding-Standards
  70. Don’t get discouraged WP_DEBUG constants Enable error logging! wp_config.php: @ini_set()

    set_error_handling() to a backtrace function Debug bar to the rescue JS console logging + plugin set_transient() Beware: Lots of templates which do not comply to the WP standards!
  71. Get involved

  72. Help someone who’s struggling

  73. Find an abandoned project

  74. Have fun!

  75. One last thing.... I need your help! http://survey.diversitymatters.it/2015 5 minutes

    to answer + spread the word === You're AWESOME !!!
  76. Credits Anatomy - Eva di Martino http://www.pureblacklove.com Bridge - Glenn

    Euloth http://www.flickr.com/photos/eulothg/4956082108/ Conflict - Asaf Antman http://www.flickr.com/photos/asafantman/5134136997/ Help - Green Kozi http://www.flickr.com/photos/themacinator/3445776069/ Hooks - Raul Lieberwirth http://www.flickr.com/photos/lanier67/185311136/ Hooks – Macroman (red background) http://www.flickr.com/photos/macroman/34644959/ Alone – Jon http://www.flickr.com/photos/jb-london/3594171841/ Fun - Justin Beckley http://www.flickr.com/photos/justinbeckleyphotography/8452437969/ Lazy - Kevin Cauchi http://www.flickr.com/photos/kpcauchi/5376768095/ Loop - Gabe Kinsman http://www.flickr.com/photos/auguris/5286612308/ Security – kismihok http://www.flickr.com/photos/kismihok/9686252463/
  77. Credits Unique - Luca Volpi (leafs) http://www.flickr.com/photos/luca_volpi/2974346674/ Unique - David

    Sprinks (birds) http://www.flickr.com/photos/davidspinks/4211976336/ Wheel - Pauline Mak http://www.flickr.com/photos/__my__photos/5025541044/ WordPress - mkhmarketing (crayons) http://www.flickr.com/photos/mkhmarketing/8469030267/ WordPress - Tom Woodward (revolution) http://www.flickr.com/photos/bionicteaching/3048825267/ WordPress - Saad Irfan (core, plugins, themes) http://www.flickr.com/photos/saadirfan/5722057280/ CMS Landscape - Philippe Martin http://www.flickr.com/photos/lafabriquedeblogs/5997969999/ World - Kenneth Lu http://www.flickr.com/photos/toasty/1540997910/ Bike - Pauline Mak http://www.flickr.com/photos/__my__photos/6399028713/ Daisies - Steve Wall http://www.flickr.com/photos/stevewall/4780035332/
  78. Keep in touch! (I’m self-employed, you can hire me ;-)

    ) Juliette Reinders Folmer Email: juliette@adviesenzo.nl Web: http://www.adviesenzo.nl/ LinkedIn: http://nl.linkedin.com/in/julietterf Twitter: http://twitter.com/jrf_nl GitHub: http://github.com/jrfnl/ WordPress: http://profiles.wordpress.org/jrf Please rate this talk on ... ? Endorsements and recommendations on LinkedIn are much appreciated too!