Laying the Proper
Foundation for Plugin &
Theme Development
WORDCAMP LOUISVILLE 2012
Tammy Hart
Designer, front-end developer, and
programmer... I make all the things

Unabashed WordPress addict

Design Engineer at 10up, a premium
WordPress Engineering provider
BUILDING BLOCKS

Setting a Standard
Structure
Theme and plugins can quickly grow   /theme-name
unwieldy. Be prepared with an easy   --/css
to understand and simple to use      --/fonts
directory structure.
                                     --/images
                                     --/includes
                                     --/js
                                     index.php
                                     functions.php
                                     style.css
Commenting
/**
  * Returns an unordered list of recent posts
  * @param int $numposts Default is 3, can be any integer.
  * @param null $author restrict the return to an author
  * @param null $tag restrict the return to a tag.
  * @param string|array $post_type Default is 'post', define the posts type(s) to return
  *
  * @return string HTML unordered list
  */
function tcnmy_recent_posts( $numposts = 3, $author = null, $tag = null, $post_type = 'post' ) {
       $posts = new WP_Query( array(
             'post_type' => $post_type,
             'no_found_posts' => true,
             'posts_per_page' => intval( $numposts ),
             'author' => $author,
             'tag' => $tag
       ) );
...
}
Nomenclature
Avoid naming conflicts by   // used by core
using unique namespaces.    function add_meta_box() { ... }
                            // too common
                            function add_a_meta_box() { ... }
                            // just right!
                            function themename_add_post_meta_box() { ... }


                            // class names use Title Case
Follow WordPress core       class WP_Query { ... }
standards for class         class WP_Rewrite { ... }
naming.                     class Theme_Name_Do_Stuff { ... }
Constants
Save important, static strings in a constant by defining them.



// Set the path constants
define( 'BB_PATH', trailingslashit( dirname( $this->bbconfig ) ) );
define( 'BACKPRESS_PATH' , BB_PATH . 'bb-includes/backpress/' );
define( 'BB_INC', 'bb-includes/' );

// use them
require_once ( BB_PATH . BB_INC . 'class.bb-query.php' );
ENQUEUEUEUEUEUE ... UE

Javascript & Stylesheets
Why Enqueue?
Can't you just call them in the header.php of a theme or add them there with
actions in a plugin?


NO!

Using enqueue functions makes it easier to
manage scripts, stylesheets, their dependants,
and where they show up.
Enqueue Scripts
wp_enqueue_script(
    $handle, // name of the script
    $src, //where to find it
    $deps, // what it depends on to work
    $ver, // version number of the script
    $in_footer // whether to load it in the footer or not
);

// remove an enqueued script
wp_dequeue_script( $handle );
Enqueue Styles
wp_enqueue_style(
    $handle, // name
    $src, //where to find it
    $deps, // what it depends on to work
    $ver, // version number of the script
    $in_footer // whether to load it in the footer or not
);

// remove an enqueued style
wp_dequeue_style( $handle );
Registering
wp_deregister_script( $handle );

wp_register_script(
    $handle, // name of the script
    $src, //where to find it
    $deps, // what it depends on to work
    $ver, // version number of the script
    $in_footer // whether to load it in the footer or not
);

// now you can just...
wp_enqueue_script( $handle );
// or use it in $deps
Put Them in Their Place
ADMIN                                   FRONT END
add_action( 'admin_enqueue_scripts' ,   add_action( 'wp_enqueue_scripts' ,
'themename_admin_enqueue' );            'themename_wp_enqueue' );

function themename_admin_enqueue() {    function themename_wp_enqueue() {
     wp_register_script( ... );              wp_register_script( ... );
     wp_register_style( ... );               wp_register_style( ... );
     wp_enqueue_script( ... );               wp_enqueue_script( ... );
     wp_enqueue_style( ... );                wp_enqueue_style( ... );

     if ( get_post_type() == 'page' )        if ( get_post_type() == 'page' )
          wp_enqueue_script( ... );               wp_enqueue_script( ... );
}                                       }


More Info: http://bit.ly/enqueue
Plugin Example
// Styles and Scripts
add_action( 'admin_enqueue_scripts' , 'recipress_admin_enqueue' );

function recipress_admin_enqueue() {
     wp_enqueue_script( 'recipress_back' , RECIPRESS_URL . 'js/back.js' , array( 'jquery',
'jquery-ui-sortable' ) );
     wp_enqueue_style( 'recipress_back' , RECIPRESS_URL . 'css/back.css' );
}

add_action( 'wp_enqueue_scripts' , 'recipress_wp_enqueue' );

function recipress_wp_enqueue() {
     wp_enqueue_style( 'recipress_front' , RECIPRESS_URL . 'css/front.css' );
}
KEEP IT CLEAN

Using Separate Code Files
Why Include?
Can't you just dump all your code into functions.php of a theme or the main
plugin file?


Yes, but...

Large amounts of code are easier to read and
edit if they are separated into their own files.
Include
// files for themes
include( get_template_directory_uri() . '/includes/some_function.php'
);

// in a plugin
include( CONSTANT_BASE . '/includes/some_function.php' );
Include, Require, _once
// Puts the contents of the file directly where it is called
include()

// Only lets the script call the file once
include_once()

// Same as include() but will stop the script if error occurs
require()

// Same as include_once() with the rules of require()
require_once()
Plugin Example
// Load plugin files
include_once( RECIPRESS_DIR   .   'php/functions.php' );
include_once( RECIPRESS_DIR   .   'php/options.php' );
include_once( RECIPRESS_DIR   .   'php/meta_box.php' );
include_once( RECIPRESS_DIR   .   'php/taxonomies.php' );
include_once( RECIPRESS_DIR   .   'php/output.php' );
include_once( RECIPRESS_DIR   .   'php/widgets.php' );
REMEMBER ALL THE THINGS!

Miscellaneous Memos
Theme/Plugin Header
Theme: style.css              Plugin: plugin_file.php

/*                            /*
Theme Name: 10up.com          Plugin Name: ReciPress
Author: 10up                  Plugin URI: http://recipress.com
Author URI: http://10up.com   Version: 1.8
*/                            */
Readme.txt
Used automatically in the WordPress.org repository for things like:
    ●   Stable Tag
    ●   Description
    ●   Installation
    ●   FAQ
    ●   Screenshots
    ●   Changelog
    ●   Update Notice
    ●   Arbitrary Sections

Check your readme: http://wordpress.org/extend/plugins/about/validator
Localization
// text strings
__( 'String of Text' , 'text-domain' );

// Echoing text
_e( 'String of Text' , 'text-domain' );

// Explaining text
_x( 'String of Text' , 'A string of text' , 'text-domain' );

// Load the text domain
add_action( 'init', 'plugin_text_domain' );
function plugin_text_domain() {
    load_plugin_textdomain( 'text-domain' , false, DEFINED_BASE .
'/lang/' );
}
Controls
class WP_Hotfix_Controller {
     function init() {
          add_action( 'init', 'wp_hotfix_init' );
          register_activation_hook( __FILE__, array( __CLASS__, 'activate' ) );
          register_deactivation_hook( __FILE__, array( __CLASS__, 'deactivate' ) );
     }
     function activate() {
          add_option( 'hotfix_version' , '1' );
          register_uninstall_hook( __FILE__, array( __CLASS__, 'uninstall' ) );
     }
     function deactivate() {
          delete_option( 'hotfix_version' );
     }
     function uninstall() {
          self::deactivate(); // The same, for now
     }
}
THANK YOU!

Questions?
@tammyhart

10up.com
@10up

Laying the proper foundation for plugin and theme development

  • 1.
    Laying the Proper Foundationfor Plugin & Theme Development WORDCAMP LOUISVILLE 2012
  • 2.
    Tammy Hart Designer, front-enddeveloper, and programmer... I make all the things Unabashed WordPress addict Design Engineer at 10up, a premium WordPress Engineering provider
  • 3.
  • 4.
    Structure Theme and pluginscan quickly grow /theme-name unwieldy. Be prepared with an easy --/css to understand and simple to use --/fonts directory structure. --/images --/includes --/js index.php functions.php style.css
  • 5.
    Commenting /** *Returns an unordered list of recent posts * @param int $numposts Default is 3, can be any integer. * @param null $author restrict the return to an author * @param null $tag restrict the return to a tag. * @param string|array $post_type Default is 'post', define the posts type(s) to return * * @return string HTML unordered list */ function tcnmy_recent_posts( $numposts = 3, $author = null, $tag = null, $post_type = 'post' ) { $posts = new WP_Query( array( 'post_type' => $post_type, 'no_found_posts' => true, 'posts_per_page' => intval( $numposts ), 'author' => $author, 'tag' => $tag ) ); ... }
  • 6.
    Nomenclature Avoid naming conflictsby // used by core using unique namespaces. function add_meta_box() { ... } // too common function add_a_meta_box() { ... } // just right! function themename_add_post_meta_box() { ... } // class names use Title Case Follow WordPress core class WP_Query { ... } standards for class class WP_Rewrite { ... } naming. class Theme_Name_Do_Stuff { ... }
  • 7.
    Constants Save important, staticstrings in a constant by defining them. // Set the path constants define( 'BB_PATH', trailingslashit( dirname( $this->bbconfig ) ) ); define( 'BACKPRESS_PATH' , BB_PATH . 'bb-includes/backpress/' ); define( 'BB_INC', 'bb-includes/' ); // use them require_once ( BB_PATH . BB_INC . 'class.bb-query.php' );
  • 8.
  • 9.
    Why Enqueue? Can't youjust call them in the header.php of a theme or add them there with actions in a plugin? NO! Using enqueue functions makes it easier to manage scripts, stylesheets, their dependants, and where they show up.
  • 10.
    Enqueue Scripts wp_enqueue_script( $handle, // name of the script $src, //where to find it $deps, // what it depends on to work $ver, // version number of the script $in_footer // whether to load it in the footer or not ); // remove an enqueued script wp_dequeue_script( $handle );
  • 11.
    Enqueue Styles wp_enqueue_style( $handle, // name $src, //where to find it $deps, // what it depends on to work $ver, // version number of the script $in_footer // whether to load it in the footer or not ); // remove an enqueued style wp_dequeue_style( $handle );
  • 12.
    Registering wp_deregister_script( $handle ); wp_register_script( $handle, // name of the script $src, //where to find it $deps, // what it depends on to work $ver, // version number of the script $in_footer // whether to load it in the footer or not ); // now you can just... wp_enqueue_script( $handle ); // or use it in $deps
  • 13.
    Put Them inTheir Place ADMIN FRONT END add_action( 'admin_enqueue_scripts' , add_action( 'wp_enqueue_scripts' , 'themename_admin_enqueue' ); 'themename_wp_enqueue' ); function themename_admin_enqueue() { function themename_wp_enqueue() { wp_register_script( ... ); wp_register_script( ... ); wp_register_style( ... ); wp_register_style( ... ); wp_enqueue_script( ... ); wp_enqueue_script( ... ); wp_enqueue_style( ... ); wp_enqueue_style( ... ); if ( get_post_type() == 'page' ) if ( get_post_type() == 'page' ) wp_enqueue_script( ... ); wp_enqueue_script( ... ); } } More Info: http://bit.ly/enqueue
  • 14.
    Plugin Example // Stylesand Scripts add_action( 'admin_enqueue_scripts' , 'recipress_admin_enqueue' ); function recipress_admin_enqueue() { wp_enqueue_script( 'recipress_back' , RECIPRESS_URL . 'js/back.js' , array( 'jquery', 'jquery-ui-sortable' ) ); wp_enqueue_style( 'recipress_back' , RECIPRESS_URL . 'css/back.css' ); } add_action( 'wp_enqueue_scripts' , 'recipress_wp_enqueue' ); function recipress_wp_enqueue() { wp_enqueue_style( 'recipress_front' , RECIPRESS_URL . 'css/front.css' ); }
  • 15.
    KEEP IT CLEAN UsingSeparate Code Files
  • 16.
    Why Include? Can't youjust dump all your code into functions.php of a theme or the main plugin file? Yes, but... Large amounts of code are easier to read and edit if they are separated into their own files.
  • 17.
    Include // files forthemes include( get_template_directory_uri() . '/includes/some_function.php' ); // in a plugin include( CONSTANT_BASE . '/includes/some_function.php' );
  • 18.
    Include, Require, _once //Puts the contents of the file directly where it is called include() // Only lets the script call the file once include_once() // Same as include() but will stop the script if error occurs require() // Same as include_once() with the rules of require() require_once()
  • 19.
    Plugin Example // Loadplugin files include_once( RECIPRESS_DIR . 'php/functions.php' ); include_once( RECIPRESS_DIR . 'php/options.php' ); include_once( RECIPRESS_DIR . 'php/meta_box.php' ); include_once( RECIPRESS_DIR . 'php/taxonomies.php' ); include_once( RECIPRESS_DIR . 'php/output.php' ); include_once( RECIPRESS_DIR . 'php/widgets.php' );
  • 20.
    REMEMBER ALL THETHINGS! Miscellaneous Memos
  • 21.
    Theme/Plugin Header Theme: style.css Plugin: plugin_file.php /* /* Theme Name: 10up.com Plugin Name: ReciPress Author: 10up Plugin URI: http://recipress.com Author URI: http://10up.com Version: 1.8 */ */
  • 22.
    Readme.txt Used automatically inthe WordPress.org repository for things like: ● Stable Tag ● Description ● Installation ● FAQ ● Screenshots ● Changelog ● Update Notice ● Arbitrary Sections Check your readme: http://wordpress.org/extend/plugins/about/validator
  • 23.
    Localization // text strings __('String of Text' , 'text-domain' ); // Echoing text _e( 'String of Text' , 'text-domain' ); // Explaining text _x( 'String of Text' , 'A string of text' , 'text-domain' ); // Load the text domain add_action( 'init', 'plugin_text_domain' ); function plugin_text_domain() { load_plugin_textdomain( 'text-domain' , false, DEFINED_BASE . '/lang/' ); }
  • 24.
    Controls class WP_Hotfix_Controller { function init() { add_action( 'init', 'wp_hotfix_init' ); register_activation_hook( __FILE__, array( __CLASS__, 'activate' ) ); register_deactivation_hook( __FILE__, array( __CLASS__, 'deactivate' ) ); } function activate() { add_option( 'hotfix_version' , '1' ); register_uninstall_hook( __FILE__, array( __CLASS__, 'uninstall' ) ); } function deactivate() { delete_option( 'hotfix_version' ); } function uninstall() { self::deactivate(); // The same, for now } }
  • 25.