WordPress for the Win! - PHPWorld

WordPress for the Win! - PHPWorld

Presented on November 18th 2015 at PHPWorld, Washington, D.C., USA.
https://world.phparch.com/
---------------------------------------------------------------
WordPress nowadays powers more than 20% of all websites, and with its extensive plugin infrastructure, it is a serious contender in 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, which is intended for 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

November 18, 2015
Tweet

Transcript

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

  2. #phpworld

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

    Frequent Contributor to Open Source Projects
  4. #phpworld

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

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

  7. #phpworld Anatomy of WordPress

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

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

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

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

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

    Hooks database: http://adambrown.info/p/wp_hooks  Debug Bar – Action & filter hooks plugin
  13. #phpworld 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. #phpworld 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. #phpworld 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 _selection wp admin _head admin_bar _menu admin _notices the_post admin _footer
  16. #phpworld 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 _selection wp admin _head admin_bar _menu admin _notices the_post admin _footer
  17. #phpworld The Loop

  18. #phpworld The Loop if ( have_posts() ) : while (

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

  20. WordPress in Your Language

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

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

  23. #phpworld

  24. #phpworld Manage Saved Data /* 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. #phpworld Performance /* Enable Compression, concatenation and cache */ define(

    'COMPRESS_CSS', true ); define( 'COMPRESS_SCRIPTS', true ); define( 'CONCATENATE_SCRIPTS', true ); define( 'ENFORCE_GZIP', true ); define( 'WP_CACHE', true );
  26. #phpworld Multisite /* 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. #phpworld Custom User Tables /* Overrule the WP User tables

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

    define( 'FORCE_SSL_LOGIN', true ); define( 'FORCE_SSL_ADMIN', true );
  29. #phpworld PHP Memory Limit /* 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. #phpworld No File Editing /* Disable Plugin and Theme Update

    and Installation and/or plugin/theme editor */ define( 'DISALLOW_FILE_EDIT', true ); define( 'DISALLOW_FILE_MODS', true );
  31. #phpworld Limit External URL Access /* 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. #phpworld Custom Directory Paths [1] /* 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. #phpworld Custom Directory Paths [2] /* 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. #phpworld Adjust Auto-Updating /* 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. #phpworld

  36. #phpworld FTP Credentials /* FTP settings */ define( 'FTP_HOST', 'hostname:port'

    ); define( 'FTP_USER', 'username' ); define( 'FTP_PASS', 'password' ); define( 'FTP_SSL', true );
  37. #phpworld Debugging /* 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. #phpworld Basic Query Debugging /* Remember the DB queries run

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

  40. #phpworld WP Cron

  41. #phpworld Adjust WP-Cron /* 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. #phpworld Disable WP-Cron /* Disable WP-cron in favor of real

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

  44. #phpworld 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 &38a37a2d5b94bc02ce0472a238d493df'
  45. Theming Your Site

  46. #phpworld

  47. #phpworld

  48. Child Themes

  49. #phpworld Creating a Child Theme

  50. #phpworld 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. #phpworld Template Hierarchy Source: http://wphierarchy.com/

  52. #phpworld 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. #phpworld 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+
  55. #phpworld Typical Theme Setup Functions // Hook 'init' register_nav_menus(); //

    Hook 'widget_init' register_sidebars();
  56. #phpworld 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' ) );
  57. #phpworld Theme Customizer

  58. #phpworld 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' );
  59. #phpworld

  60. #phpworld

  61. #phpworld 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' );
  62. Extending WordPress

  63. #phpworld

  64. #phpworld

  65. #phpworld

  66. #phpworld Must-use Plugins

  67. #phpworld 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
  68. Create a Plugin

  69. #phpworld 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 */
  70. #phpworld 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  ...
  71. #phpworld 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' );
  72. #phpworld

  73. #phpworld

  74. #phpworld 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' );
  75. #phpworld

  76. #phpworld

  77. #phpworld 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. );
  78. #phpworld

  79. #phpworld

  80. #phpworld

  81. #phpworld

  82. #phpworld 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 );
  83. #phpworld

  84. #phpworld 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" );' ) );
  85. #phpworld

  86. #phpworld

  87. #phpworld 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() );
  88. #phpworld (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' ) );
  89. Doing Things the WordPress Way

  90. #phpworld 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
  91. #phpworld 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!)
  92. Developing & Debugging

  93. #phpworld Useful Plugins Debug Bar + Extensions Developer Pig Latin

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

  95. #phpworld Helpful Infrastructure WordPress Coding Standards CS WP Unit Testing

    Framework Varying Vagrant Vagrants WP CLI Generate WP WP Gear WPackagist vs TGMPA
  96. #phpworld 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/
  97. #phpworld

  98. Thank You! Slides: http://speakerdeck.com/jrf Feedback: https://joind.in/14755 Contact me: @jrf_nl jrf