WordPress for the Win! - Zendcon

WordPress for the Win! - Zendcon

Presented on October 21st 2015 at Zendcon, Las Vegas, Nevada, USA.
http://www.zendcon.com/
---------------------------------------------------------------
WordPress nowadays powers more than 20% of all websites and with its extensive plugin infrastructure, is a serious contender on the CMS market. The learning curve for PHP developers to work with WP is very shallow compared to, for instance, Drupal or Typo3.
In this talk, aimed at experienced PHP developers, I will introduce you to essential WordPress concepts and functionality which will allow you to start rapid development using WordPress.
Learn how to develop for WordPress like a pro and take WordPress to the next level.
---------------------------------------------------------------

If you download the slides, the links should be clickable. Unfortunately they don't seem to be in the online deck, so here's a list of relevant & interesting links in semi-random order:

The Basics:
------------------------------
https://codex.wordpress.org/
https://developer.wordpress.org/reference/
http://adambrown.info/p/wp_hooks
https://codex.wordpress.org/Plugin_API
https://codex.wordpress.org/Plugin_API/Action_Reference
https://codex.wordpress.org/Plugin_API/Filter_Reference
https://codex.wordpress.org/The_Loop

WordPress in Your language:
------------------------------
https://make.wordpress.org/polyglots/handbook/tools/glotpress-translate-wordpress-org/
https://translate.wordpress.org/

wp-config.php Tips & Tricks
------------------------------
https://codex.wordpress.org/Editing_wp-config.php

WP Cron
------------------------------
https://developer.wordpress.org/plugins/cron/
https://wordpress.org/plugins/wp-cron-control/

Theming your Site
------------------------------
https://wordpress.org/themes
https://codex.wordpress.org/Child_Themes
http://wphierarchy.com/
https://make.wordpress.org/themes/

Functions.php
------------------------------
https://codex.wordpress.org/Functions_File_Explained
https://codex.wordpress.org/Function_Reference/add_theme_support
https://codex.wordpress.org/Function_Reference/register_nav_menu
https://codex.wordpress.org/Function_Reference/register_sidebar
https://codex.wordpress.org/Theme_Customization_API

Extending WordPress
------------------------------
http://wordpress.org/plugins/
https://codex.wordpress.org/Must_Use_Plugins

Create a Plugin
------------------------------
https://make.wordpress.org/plugins/
https://codex.wordpress.org/Writing_a_Plugin
https://codex.wordpress.org/Shortcode_API
https://codex.wordpress.org/Embeds
https://codex.wordpress.org/Function_Reference/register_post_type
https://codex.wordpress.org/Function_Reference/register_taxonomy
https://codex.wordpress.org/Settings_API
https://codex.wordpress.org/Widgets_API
https://codex.wordpress.org/Function_Reference/wp_enqueue_style
https://codex.wordpress.org/Function_Reference/wp_enqueue_script
https://codex.wordpress.org/Function_Reference/wp_localize_script
https://developer.wordpress.org/plugins/the-basics/activation-deactivation-hooks/
https://developer.wordpress.org/plugins/the-basics/uninstall-methods/

Doing Things the WordPress Way
------------------------------
https://codex.wordpress.org/WordPress_APIs
http://codex.wordpress.org/Function_Reference

Developing & Debugging
------------------------------
https://wordpress.org/plugins/search.php?q=debug+bar
https://wordpress.org/plugins/developer/
https://wordpress.org/plugins/piglatin/
https://wordpress.org/plugins/user-switching/
https://wordpress.org/plugins/log-deprecated-notices/
https://wordpress.org/plugins/whats-running/
https://wordpress.org/plugins/demo-data-creator/
https://wordpress.org/plugins/theme-check/
https://wordpress.org/plugins/rtl-tester/

https://make.wordpress.org/core/handbook/best-practices/coding-standards/
https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/
https://github.com/Varying-Vagrant-Vagrants/VVV
http://wp-cli.org/
http://wpcligui.com/
https://generatewp.com/
http://wpgear.org/
http://wpackagist.org/
http://tgmpluginactivation.com/

Closing
------------------------------
http://twitter.com/jrf_nl
http://profiles.wordpress.org/jrf

Bonus (re: question from the audience)
------------------------------
Moving WP - DB search & replace tool:
https://interconnectit.com/products/search-and-replace-for-wordpress-databases/

2776198ea9584b6c0d4b494293b8d635?s=128

Juliette Reinders Folmer

October 21, 2015
Tweet

Transcript

  1. WordPress For The Win! Juliette Reinders Folmer / @jrf_nl

  2. #zendcon

  3. #zendcon Who Am I? Self-employed, Independent Consultant Creator PHPCheatsheets phpcheatsheets.com

    Frequent Contributor to Open Source Projects
  4. #zendcon

  5. #zendcon  Themes  Plugins  SEO  Ease of

    use  Scalability  Support community  Regular updates  Learning curve  Setup costs  Maintenance costs  Hacker target
  6. #zendcon

  7. #zendcon Anatomy of WordPress

  8. #zendcon Page footer Admin Bar Page content (loop) Page header

    (Invisible) HTML <head> Sidebar containing widgets (Main) menu
  9. #zendcon Admin Bar (Invisible) HTML <head> Admin footer Admin Menu

    1. Post types 2. Custom- izations 3. Extras Admin page (with dashboard widgets)
  10. #zendcon Anatomy of WordPress Functionality  Core  Plugins 

    Themes  Languages  Js Libraries Content  Post Types  Taxonomies  Widgets  Users  Meta data/custom fields  Options  Shortcodes  OEmbeds
  11. #zendcon Hooks

  12. #zendcon Hooks See:  WordPress Codex & Developer Reference 

    Hooks database: http://adambrown.info/p/wp_hooks  Debug Bar – Action & filter hooks plugin
  13. #zendcon Hooking into WP apply_filter( 'hook_name', 'function_name', $priority = 10,

    $accepted_args = 1 ); 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 );
  14. #zendcon Action Hooks Front-end muplugins _loaded plugins _loaded setup _theme

    set_current _user after_setup _theme init wp_loaded parse _request posts _selection wp wp_head the_post wp_meta wp_footer admin_bar_ menu
  15. #zendcon Action Hooks Back-end muplugins _loaded plugins _loaded setup _theme

    set_current _user after_setup _theme init wp_loaded admin _menu admin_init current _screen load- {page} posts_select ion wp admin_head admin_bar _menu admin _notices the_post admin _footer
  16. #zendcon Action Hooks Back-end muplugins _loaded plugins _loaded setup _theme

    set_current _user after_setup _theme init wp_loaded admin _menu admin_init current _screen load- {page} posts_select ion wp admin_head admin_bar _menu admin _notices the_post admin _footer
  17. #zendcon The Loop

  18. #zendcon The Loop <?php if ( have_posts() ) : while

    ( have_posts() ) : the_post(); // // Post Content here // the_title() // the_content() // the_permalink() // ... endwhile; endif;
  19. #zendcon WordPress in Practice

  20. WordPress in Your Language

  21. #zendcon Localized  ~60 languages + ~30 > 50% 

    GlotPress translate.wordpress.org
  22. wp-config.php Tips & Tricks

  23. #zendcon

  24. #zendcon Manage Saved Data <?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', 30 ); // days define( 'MEDIA_TRASH', true );
  25. #zendcon Performance <?php /* 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 );
  26. #zendcon Multisite <?php /* Set up WordPress as Multi-site */

    define( 'WP_ALLOW_MULTISITE', true ); define( 'NOBLOGREDIRECT', 'http://mywp.com' ); /* After setup - will be provided by WP */ define( 'MULTISITE', true ); define( 'SUBDOMAIN_INSTALL', true ); define( 'DOMAIN_CURRENT_SITE', 'mywp.com' ); define( 'PATH_CURRENT_SITE', '/' ); define( 'SITE_ID_CURRENT_SITE', 1 ); define( 'BLOG_ID_CURRENT_SITE', 1 );
  27. #zendcon Custom User Tables <?php /* Overrule the WP User

    tables */ define( 'CUSTOM_USER_TABLE', $table_prefix . 'my_users' ); define( 'CUSTOM_USER_META_TABLE', $table_prefix . 'my_usermeta' );
  28. #zendcon SSL <?php /* Force secure logins and admin sessions

    */ define( 'FORCE_SSL_LOGIN', true ); define( 'FORCE_SSL_ADMIN', true );
  29. #zendcon PHP Memory Limit <?php /* Try to increase PHP

    Memory */ define( 'WP_MEMORY_LIMIT', '128M' ); /* Potentially increase it even more in the admin area */ define( 'WP_MAX_MEMORY_LIMIT', '256M' );
  30. #zendcon No File Editing <?php /* Disable Plugin and Theme

    Update and Installation and/or plugin/theme editor */ define( 'DISALLOW_FILE_EDIT', true ); define( 'DISALLOW_FILE_MODS', true );
  31. #zendcon Limit External URL Access <?php /* Block WP from

    making external calls */ define( 'WP_HTTP_BLOCK_EXTERNAL', true ); /* Limit allowed external hosts */ define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,*.github.com' );
  32. #zendcon Custom Directory Paths [1] <?php /* Overrule some directory

    and url paths. Mind: no traling slashes! */ define( 'WP_CONTENT_DIR', dirname( __FILE__ ) . '/blog/wp-content' ); define( 'WP_CONTENT_URL', 'http://mywp.com/blog/wp-content' ); define( 'UPLOADS', 'blog/wp-content/uploads' ); // Relative to ABSPATH
  33. #zendcon Custom Directory Paths [2] <?php /* Overrule some directory

    and url paths. Mind: no traling slashes! */ define( 'WP_PLUGIN_DIR', dirname( __FILE__ ) . '/blog/wp-content/plugins' ); define( 'WP_PLUGIN_URL', 'http://mywp.com/blog/wp-content/plugins' ); define( 'WPMU_PLUGIN_DIR', dirname( __FILE__ ) . '/blog/wp-content/mu-plugins' ); define( 'WPMU_PLUGIN_URL', 'http://mywp.com/blog/wp-content/mu-plugins');
  34. #zendcon Adjust Auto-Updating <?php /* Disable the auto-updater (WP 3.7+)

    */ define( 'AUTOMATIC_UPDATER_DISABLED', true ); /* Use true/false to change the default behavior */ define( 'WP_AUTO_UPDATE_CORE', 'minor' ); /* Prevent the table upgrade function being run in favor of manually running it */ define( 'DO_NOT_UPGRADE_GLOBAL_TABLES', true );
  35. #zendcon

  36. #zendcon FTP Credentials <?php /* FTP settings */ define( 'FTP_HOST',

    'hostname:port' ); define( 'FTP_USER', 'username' ); define( 'FTP_PASS', 'password' ); define( 'FTP_SSL', true );
  37. #zendcon Debugging <?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 non-minified versions of all scripts, css, disables compression and concatenation */ define( 'SCRIPT_DEBUG', true);
  38. #zendcon Basic Query Debugging <?php /* Remember the DB queries

    run for the current page. */ define( 'SAVEQUERIES', true );
  39. WP Cron

  40. #zendcon WP Cron

  41. #zendcon Adjust WP-Cron <?php /* Prevent Cron running too often

    (plugins) */ define( 'WP_CRON_LOCK_TIMEOUT', 60 ); // seconds /* Run wp-cron with a redirect */ define('ALTERNATE_WP_CRON', true);
  42. #zendcon Disable WP-Cron <?php /* Disable WP-cron in favor of

    real cron */ define( 'DISABLE_WP_CRON', true );
  43. #zendcon

  44. #zendcon Real Cron with Cron Control */5 * * *

    * /usr/local/bin/php -q /path/to/wp/wp- content/plugins/wp-cron-control/wp-cron- control.php http://mywp.com 38a37a2d5b94bc02ce0472a238d493df wget -q 'http://mywp.com/wp- cron.php?doing_wp_cron&38a37a2d5b94bc02ce0472a238 d493df'
  45. Theming Your Site

  46. #zendcon

  47. #zendcon

  48. Child Themes

  49. #zendcon Creating a Child Theme

  50. #zendcon Child Theme – style.css /* Theme Name: Twenty Fifteen

    Child Theme URI: http://localhost/ Template: twentyfifteen Author: Advies en zo Author URI: http://adviesenzo.nl/ Description: My Child theme Text Domain: twentyfifteen-child Version: 1.0.0 */
  51. #zendcon Template Hierarchy Source: http://wphierarchy.com/

  52. #zendcon Example singular.php <?php get_header(); ?> <div id="primary" class="content-area"> <?php

    while ( have_posts() ) : the_post(); if ( is_singular( array( 'employee' ) ) ) { get_template_part( 'template-parts/content', 'employee' ); } else { get_template_part( 'template-parts/content', 'singular' ); } endwhile; ?> </div><!-- #primary --> <?php get_footer(); ?>
  53. Functions.php

  54. #zendcon Typical Theme Setup Functions // Hook 'after_setup_theme' add_theme_support( 'post-formats',

    $formats ); add_theme_support( 'post-thumbnails', $post_types ); add_theme_support( 'custom-background', $defaults ); add_theme_support( 'custom-header', $defaults ); add_theme_support( 'automatic-feed-links' ); // RSS add_theme_support( 'html5', $locations ); add_theme_support( 'title-tag' ); // WP 4.1+ // Hook 'init' register_nav_menus(); // Hook 'widget_init' register_sidebars();
  55. #zendcon Theme Customizer class MyTheme_Customizer { public static function register(

    $customizer ) { $customizer->add_section( 'my_section', $args ); $customizer->add_setting( 'my_setting', $args ); $customizer->add_control( $id, $args ); } public static function header_output() { // Customizer CSS } } add_action( 'customize_register', array( 'MyTheme_Customizer', 'register' ) ); add_action( 'wp_head', array( 'MyTheme_Customizer', 'header_output' ) );
  56. #zendcon Theme Customizer

  57. #zendcon functions.php function add_qr_code( $content ) { $url = 'http://api.qrserver.com/v1/create-

    qr-code/?size=100x100&data=' . urlencode( get_the_permalink() ); $esc_alt = the_title_attribute( array( 'before' => 'QR Code for', 'echo' => false ) ); return '<div class="qr-code"> <img src="' . esc_url( $url ) . '“ alt="' . $esc_alt . '"/> </div>' . $content; } add_filter( 'the_content', 'add_qr_code' );
  58. #zendcon

  59. #zendcon

  60. #zendcon functions.php /* Change admin page footer Branding */ function

    my_admin_footer_text( $left ) { $left = '<img src="' . esc_url( get_stylesheet_directory_uri() . '/images/AEZ_logobw- 32x32.png' ) . '" width="32" height="32" align="left" />' . esc_html__( 'Webdevelopment, design and consultancy:', 'text-domain' ) . '<a href="http://adviesenzo.nl/">Advies en zo</a>'; return $left; } add_filter( 'admin_footer_text', my_admin_footer_text' );
  61. Extending WordPress

  62. #zendcon

  63. #zendcon

  64. #zendcon

  65. #zendcon Must-use Plugins

  66. #zendcon Loading Order wp-config.php Must-use plugins Plugins • [MS] Network-activated

    plugins • Site-activated plugins Theme • Child-theme functions.php • Parent-theme functions.php
  67. Create a Plugin

  68. #zendcon 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 */
  69. #zendcon What Every Plugin Needs  Hook your functionality onto

    actions and filters  Loading your localization files  Do something  Load CSS  Load JS  Add admin page or add to another admin page  Help information  Activation/ Upgrade routines  Uninstall routines  ...
  70. #zendcon Add a shortcode function display_call_to_action( $atts ) { $atts

    = shortcode_atts( array( 'user' => 'office', // Default ), $atts, 'calltoaction' ); $user = get_user_by( 'login', $atts['user'] ); $html = ''; if( $user ) { $html = '<!-- Here goes the actual box html -->'; } return $html; } add_shortcode( 'calltoaction', 'display_call_to_action' );
  71. #zendcon

  72. #zendcon

  73. #zendcon Add Oembed Provider // Register Speakerdeck as an oembed

    provider. function add_speakerdeck_oembed() { wp_oembed_add_provider( // URL format '`http[s]?://(www\.)?speakerdeck\.com/[^/]*/.*`i', // Endpoint 'https://speakerdeck.com/oembed.json', true // Is format a regex ? ); } add_action( 'init', 'add_speakerdeck_oembed' );
  74. #zendcon

  75. #zendcon

  76. #zendcon Add Custom Content Types & Taxonomies register_post_type( $post_type_name, //

    Post type name. Max of 20 chars. Uppercase and spaces not allowed. $args // Arguments for post type. ); register_taxonomy( $taxonomy_name, // Taxonomy internal name. Max 32 chars. Uppercase and spaces not allowed. array( $post_type_name ), // Post types to register this taxonomy for. $args // Arguments for taxonomy. );
  77. #zendcon

  78. #zendcon

  79. #zendcon

  80. #zendcon

  81. #zendcon 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 );
  82. #zendcon

  83. #zendcon 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" );' ) );
  84. #zendcon

  85. #zendcon

  86. #zendcon 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() );
  87. #zendcon (De-)Activation, Upgrade, Uninstall  (De-)Activation:  Upgrading -> save

    plugin version nr & compare  Uninstall -> uninstall.php file /* Set up the (de-)activation actions */ register_activation_hook( __FILE__, array( 'Plugin_Class', 'activate' ) ); register_deactivation_hook( __FILE__, array( 'Plugin_Class', 'deactivate' ) );
  88. Doing Things the WordPress Way

  89. #zendcon 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 REST API * Rewrite API Settings API Shortcode API Theme modification API Theme customization API Transients API Widgets API XML-RPC WordPress API * Expected in WP 4.4
  90. #zendcon Use WP Functions PHP  mysqli_...()  file_put_contents() 

    json_encode()  mail()  unserialize()  htmlspecialchars()  add/stripslashes()  strtotime() / date()  http_build_query()  $_SERVER['HTTPS'] ... WP  $wpdb->....()  $wp_filesystem->put_contents()  wp_json_encode()  wp_mail()  maybe_unserialize()  esc_html()  wp_unslash()  mysql2date() / current_time()  add_query_arg()  is_ssl() ... (I mean it!)
  91. Developing & Debugging

  92. #zendcon Useful Plugins Debug Bar + Extensions Developer Pig Latin

    User Switching Log Deprecated Notices What’s Running Demo Data Theme Check RTL Tester
  93. #zendcon Tools

  94. #zendcon Helpful Infrastructure WordPress Coding Standards CS WP Unit Testing

    Framework Varying Vagrant Vagrants WP CLI Generate WP WP Gear WPackagist vs TGMPA
  95. Thank You! Slides: http://speakerdeck.com/jrf Feedback: https://joind.in/15565 Contact me: @jrf_nl jrf

  96. #zendcon Photo Credits  WordPress - mkhmarketing (crayons) http://www.flickr.com/photos/mkhmarketing/8469030267/ 

    Bridge - Glenn Euloth http://www.flickr.com/photos/eulothg/4956082108/  WordPress - Jenn Vargas http://www.flickr.com/photos/foreverdigital/2768397344/  Billie Holiday – William P. Gottlieb http://lcweb2.loc.gov/diglib/ihas/loc.natlib.gottlieb.04251/default.html  Anatomy - Eva di Martino http://www.pureblacklove.com  Hooks - Raul Lieberwirth http://www.flickr.com/photos/lanier67/185311136/  Loop - Gabe Kinsman http://www.flickr.com/photos/auguris/5286612308/  WordPress - Saad Irfan (core, plugins, themes) http://www.flickr.com/photos/saadirfan/5722057280/