WordPress

Development

The Loop

Action Hooks

Enqueue Files

// wp-content/themes/{my_theme}/functions.php

function add_theme_scripts() {
    wp_enqueue_style('slider', get_template_directory_uri() . '/css/slider.css', array(), '1.1', 'all');
    wp_enqueue_script('script', get_template_directory_uri() . '/js/script.js', array('jquery'), 1.1, true);
}
add_action('wp_enqueue_scripts', 'add_theme_scripts');

Enqueue CSS Files

wp_enqueue_style($handle, $src, $deps, $ver, $media);

Parameter Required Description
handle Yes The name of the stylesheet. Should be unique.
src Yes The URL for the file.
deps No Refers to whether or not this stylesheet is dependent on another stylesheet. If this param is set, this stylesheet will not be loaded unless its dependent stylesheet is loaded first.
ver No An arbitrary version number.
media No Specify which type of media to load this stylesheet in, such as ‘all’, ‘screen’, ‘print’ or ‘handheld.’

Enqueue JS Files

wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);

Parameter Required Description
handle Yes The name of the script. Should be unique.
src Yes Full URL of the script, or path of the script relative to the WordPress root directory.
deps No An array of registered script handles this script depends on.
ver No String specifying script version number, if it has one, which is added to the URL as a query string for cache busting purposes. If version is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added.
in_footer No Whether to enqueue the script before instead of in the . Default ‘false’.

Prevent WP Auto Updates

# Disable all automatic WP updates.
define('AUTOMATIC_UPDATER_DISABLED', true);

# Disable automatic WordPress plugin updates:
add_filter( 'auto_update_plugin', '__return_false' );

# Disable automatic WordPress theme updates:
add_filter( 'auto_update_theme', '__return_false' );

add_filter( 'automatic_updater_disabled', '__return_true' );
add_filter( 'auto_update_plugin', '__return_false' );
add_filter( 'auto_update_theme', '__return_false' );
add_filter( 'auto_update_translation', '__return_false' );

AJAX

Debugging

Debug Mode

  • WordPress debugging mode displays PHP notices during development.
  • It is strongly recommended that plugin and theme developers use WP_DEBUG in their development environments.
  • Debugging in WordPress (codex.wordpress.org)
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);

Themes

  • A Theme defines the presentation or theming layer of the WordPress application.
  • Many themes can be installed but only one can be active at a time. Themes are activated from within the WordPress admin panel.
  • All files for each installed theme reside in their own directory in /wp-content/themes/.
  • WordPress includes a default theme. Examine the files in the default theme for working examples.
  • A theme must have at least the stylesheet file style.css and the index.php file present in it’s theme directory to be available in the admin panel.

style.css

/wp-content/themes/{my_theme}/style.css

/*
Theme Name: WattsWork
Theme URI: https://github.com/daniel-watts/dev.wattswork.wordpress.theme
Author: Daniel Watts
Author URI: http://wattswork.com/
Description: A responsive WordPress theme designed for the "dev.wattswork.com" website. Open for public use.
Version: 1.3
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Tags: wattswork, minimal
Text Domain: wattswork
*/

index.php

/wp-content/themes/{my_theme}/index.php

  • The index.php file is the default template file for every front-end request, and is required for the theme to work.
  • All other template files fall-back to the index file.
  • Template logic and file includes for the theme should take place the index file.
/**
 * The main WattsWork Theme WP template file.
 *
 * @package WordPress
 * @subpackage WattsWork
 */

functions.php

/wp-content/themes/{my_theme}/functions.php

  • The functions.php file is the default fall-back file for every request and is where template logic and file includes for the theme should take place.
/**
 * The WattsWork Theme WP functions file.
 *
 * @package WordPress
 * @subpackage WattsWork
 */

Theme Features

  • Theme Features are functionality that may be optionally added to a theme.
  • Themes must register each individual Theme Feature. Registration functions should be called in the theme’s functions.php file.
  • Adding Theme Features usually means getting an editable field in the admin page for the post, and some template methods to print output to your theme.
Feature Registered with Description
Post Thumbnails add_theme_support('post-thumbnails') An image that is chosen as the representative image for Posts, Pages or Custom Post Types. The display of this image is up to the theme.
Sidebars register_sidebar($args) A vertical column provided by a theme for displaying information other than the main content of the web page. Sidebars usually contain widgets that an administrator of the site can customize.
Navigation Menus register_nav_menus() Add customizable navigation menus to a theme. Using menus requires adding display code to theme files.
Theme Markup add_theme_support('html5', $args) Allows themes to explicitly choose to apply HTML5 markup for search forms, comment forms, comment lists, gallery and caption. The second parameter accepts one or more values indicating which HTML5 features to support and is a required parameter for forward compatibility reasons.
Title Tag add_theme_support('title-tag') Allows themes to use future-proofed title tags in the HTML <head> tag.
Custom Headers add_theme_support('custom-header') A custom header is an image that is chosen as the representative image in the theme top header section.
Editor Style add_editor_style() Allows links to a custom stylesheet file in the TinyMCE editor within the post edit screen.
Automatic Feed Links add_theme_support('automatic-feed-links') Adds RSS feed links to HTML <head> tag.
Content Width $content_width = 600; Set the maximum allowed width for any content in the theme, like oEmbeds and images added to posts.
Custom Backgrounds add_theme_support('custom-background') Provides for customization of the background color and image.
Post Formats add_theme_support('post-formats', array('{format name}')) An admin can change how each post looks by choosing a Post Format from a radio-button list in the Publish meta box when saving a post. Options are aside, gallery, link, image, quote, status, video, audio, chat
Theme Logo add_theme_support('custom-logo') Allows themes to add custom logos.
Selective Refresh Support for Widgets add_theme_support('customize-selective-refresh-widgets') Users of the Customizer can selectively refresh a preview mechanism without refreshing the entire preview window.

Sidebars

// /wp-content/themes/{my_theme}/functions.php

function wattsworkmorgue_register_main_sidebar() {
    register_sidebar( array(
        'name' => __('Main Sidebar', 'wattsworkmorgue'),
        'id' => 'main-sidebar',
        'description' => __('Widgets in this area will be shown on all posts and pages.', 'wattsworkmorgue'),
        'before_widget' => '<li id="%1$s" class="widget %2$s">',
        'after_widget'  => '</li>',
        'before_title'  => '<h2 class="widgettitle">',
        'after_title'   => '</h2>',
    ));
}
add_action('widgets_init', 'wattsworkmorgue_register_main_sidebar');

Post Thumbnail

  • Post Thumbnail, also called the Featured Image, is an image that is chosen as the representative image for a Post, Page or Custom Post Type.
  • The Post Thumbnails feature can be enabled by calling the add_theme_support('post-thumbnails') function from the theme functions.php file.
  • At least one default thumbnail size must be defined, but any number of additional sizes can also be defined.
  • NOTE The Post Thumbnail is associated to the post in the database in the wp_postmeta table. The associated thumb ID is stored as the meta_value value with a meta_key called _thumbnail_id.
  • Post Thumbnails (codex.wordpress.org)
// /wp-content/themes/{my_theme}/functions.php

/**
 * Adds Post Thumbnail support to the theme.
 */
if (function_exists('add_theme_support')) { 
    add_theme_support('post-thumbnails');
    set_post_thumbnail_size(200, 9999); // Set the default thumb size to 200px wide with unlimited height.
    add_image_size('small-admin-thumb', 100, 100, true); // Set an additional thumb size of 50px wide by 50px tall and cropped.
}
// /wp-content/themes/{my_theme}/functions.php

/**
 * Adds a thumbnail column to an admin posts list.
 */
function add_admin_thumbnail_column($post_columns){
    $post_columns['featured_thumb'] = __('Featured Image');
    return $post_columns;
}

// Add a thumbnail column to the `posts` and `pages` admin post lists.
add_filter('manage_posts_columns', 'add_admin_thumbnail_column', 2);
add_filter('manage_pages_columns', 'add_admin_thumbnail_column', 2);

/**
 * Prints the thumbnail column content.
 */
function admin_thumbnail_column_content($column_name, $post_id){
    if ($column_name == 'featured_thumb' && function_exists('the_post_thumbnail')) {
        echo the_post_thumbnail('small-admin-thumb');
    }
}

// Get the content for the thumbnail column in `posts` and `pages` admin post lists.
add_action('manage_posts_custom_column', 'admin_thumbnail_column_content', 5, 2);
add_action('manage_pages_custom_column', 'admin_thumbnail_column_content', 5, 2);

Templates

Template Hierarchy

Template Files

  • Template files are PHP files used to render web pages for a WordPress theme.
  • Template files can contain a mixture of HTML, WP Template Tags, and PHP code.
  • Template files can include other template files using WP Template Tags.
    When a piece of a page is included into a template file, such as including the header.php file, the include is called a Template Partial. Template Partials can be embedded in multiple template files, simplifying theme creation.
Filename Description
index.php The main template file. It is required in all themes.
style.css The main stylesheet. It is required in all themes and contains the information header for your theme.
rtl.css The right-to-left stylesheet is included automatically if the website language’s text direction is right-to-left.
comments.php The comments template.
front-page.php The front page template is always used as the site front page if it exists, regardless of what settings on Admin > Settings > Reading.
home.php The home page template is the front page by default. If you do not set WordPress to use a static front page, this template is used to show latest posts.
header.php The header template file usually contains your site’s document type, meta information, links to stylesheets and scripts, and other data.
singular.php The singular template is used for posts when single.php is not found, or for pages when page.php are not found. If singular.php is not found, index.php is used.
single.php The single post template is used when a visitor requests a single post.
single-{post-type}.php The single post template used when a visitor requests a single post from a custom post type. For example, |single-book.php would be used for displaying single posts from a custom post type named book. The index.php is used if a specific |query template for the custom post type is not present.
archive-{post-type}.php The archive post type template is used when visitors request a custom post type archive. For example, |archive-books.php would be used for displaying an archive of posts from the custom post type named books. The archive.php template file is used if the archive-{post-type}.php is not present.
page.php The page template is used when visitors request individual pages, which are a built-in template.
page-{slug}.php The page slug template is used when visitors request a specific page, for example one with the “about” slug (page-about.php).
category.php The category template is used when visitors request posts by category.
tag.php The tag template is used when visitors request posts by tag.
taxonomy.php The taxonomy term template is used when a visitor requests a term in a custom taxonomy.
author.php The author page template is used whenever a visitor loads an author page.
date.php The date/time template is used when posts are requested by date or time.
archive.php The archive template is used when visitors request posts by category, author, or date. Note: this template will be overridden if more specific templates are present like category.php, author.php, and date.php.
search.php The search results template is used to display a visitor’s search results.
attachment.php The attachment template is used when viewing a single attachment like an image, pdf, or other media file.
image.php The image attachment template is a more specific version of attachment.php and is used when viewing a single image attachment. If not present, WordPress will use attachment.php instead.
404.php The 404 template is used when WordPress cannot find a post, page, or other content that matches the visitor’s request.

Template Tags

WP function File included Default include if file not found
get_header() header-{name}.php wp-includes/theme-compat/header.php
get_footer() footer-{name}.php wp-includes/theme-compat/footer.php
get_sidebar() sidebar-{name}.php wp-includes/theme-compat/sidebar.php
get_search_form() searchform.php WP auto-generated
comments_template() comments.php wp-includes/theme-compat/comments.php
get_template_part() {name}.php Returns nothing

Post Tags

WP function Use
the_content() Displays the post content HTML.
get_the_content() Returns the raw post content.
An important difference from the_content() is that get_the_content() does not pass the content through the ‘the_content’ filter. This means that get_the_content() will not auto-embed videos or expand shortcodes, among other things.

Conditional Tags

WP function Returns true if:
is_404() The request returns an “HTTP 404: Not Found” error.
is_admin() The request is for the admin Dashboard or the administration panel.
is_archive() The request is for any type of archive page. An archive can be a Category, Tag, Author, Date, Custom Post Type or Custom Taxonomy based pages.
is_attachment() An attachment. An image or other file uploaded through the post editor’s upload utility. Attachments can be displayed on their own ‘page’ or template.
is_author() An author archive page.
is_category() A category archive page.
is_date() A year, month, or day
is_day() A day
is_feed() A syndication feed
is_front_page() When the front of the site should be displayed, whether it is posts or a Page. Returns true when the main blog page is being displayed and the ‘Settings > Reading ->Front page displays’ is set to “Your latest posts”, or when ‘Settings > Reading ->Front page displays’ is set to “A static page” and the “Front Page” value is the current Page being displayed.
is_home() The request is for the blog homepage. When the main blog home page should be displayed. This is the page which shows the time based blog content of your site, so if you’ve set a static Page for the Front Page (see below), then this will only be true on the Page which you set as the “Posts page” in Administration > Settings > Reading.
is_month() A month
is_network_admin() The request is for a network admin screen (wp-admin/network).
is_page() The request is for an existing single page.
is_post_type_archive() The request is for an archive page of a given post type(s).
is_search() The request is for the search result page.
is_single() A single post. Works for any post type, except attachments and pages.
is_sticky() The current post is a Sticky Post meaning the “Stick this post to the front page” check box has been checked for the post.
is_tag() The request is for a Tag archive page.
is_tax() The request is for a custom taxonomy archive page.
is_time() An hour, minute, or second
is_year() A year

Routing with Conditional Tags

  • When developing an extendable theme it’s best to stick to the Template Hierarchy.
  • If the theme is not extendable, the Template Hierarchy can be bypassed with a custom theme router in the index.php file which is more organized and centralized.
  • The WordPress function get_template_part() can be used to include template files from custom sub-directories making it easier to organize the theme files.
    An example of theme routing using conditional tags in the index.php file.
  • NOTE: When you use is_home() and is_front_page(), you have to use them in the right order to avoid bugs and to test every user configuration.
// wp-content/themes/{my_theme}/index.php

// Route the request to it's template file.
    if (is_front_page() && is_home()) { get_template_part('partials/default_home'); }
elseif (is_front_page()) { get_template_part('partials/static_home'); }
elseif (is_home())       { get_template_part('partials/blog_page_home'); }
elseif (is_single())     { get_template_part('partials/single'); }
elseif (is_search())     { get_template_part('partials/search'); }
  else                   { get_template_part('partials/404'); } // By default everything is a 404 page.
// wp-content/themes/{my_theme}/partials/index.php

<?php get_template_part('partials/doc_head'); ?>
<h1>404 Page Not Found</h1>
<p>Sorry but there is nothing here.</p>
<?php get_template_part('partials/doc_foot'); ?>

Page Titles

# Default value.
$page_title = 'Untitled';

if (is_404()) {
    $page_title = '404 Page Not Found';
} elseif (is_search()) {
    if (get_search_query() == ''){
        $page_title = 'Search Results for Everything';
    } else {
        $page_title = 'Search Results for: "' . get_search_query() . '"';
    }
} elseif (is_home()) {
    $page_title = get_bloginfo('name');
} elseif (is_single() || is_page()) {
    $page_title = get_the_title();
} elseif (is_category()) {
    $page_title = single_cat_title("", false);
} elseif (is_tag()) {
    $page_title = single_tag_title("", false);
} elseif (is_day() ) {
    $page_title = 'Daily Archive ' . get_the_date();
} elseif (is_month()) {
    $page_title = 'Monthly Archive ' . get_the_date('F Y');
} elseif (is_year()) {
    $page_title = 'Yearly Archive ' . get_the_date('Y');
}

Sidebars

Call register_sidebar() for each sidebar you want to create.

# Define the 'main-sidebar'.
add_action( 'widgets_init', 'my_register_sidebars' );
function my_register_sidebars(){

    register_sidebar(
        array(
            'id' => 'main-sidebar',
            'name' => __( 'Main Sidebar' ),
            'description' => __( 'Widgets in this area will be shown on all posts and pages.' ),
            'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            'after_widget' => '</aside>',
            'before_title' => '<h3>',
            'after_title' => '</h3>'
        )
    );

    /* Repeat register_sidebar() code here for each additional sidebar. */
}

Posts

Post types are the different ways a page can be built in WordPress. The most common post type is called the ‘post’, it builds an HTML page with lists of post types. For instance, most WordPress blogs have a homepage which lists the most recent posts, this page has the Post post type.

Post Types

There are five post types available by default in the WordPress:

Type slug
Post post
Page page
Attachement attachment
Revision revision
Post nav_menu_item
Navigation menu post

Additional post-types can be added

Post-Type Features

The add_post_type_support() function enables you to add support for various WordPress features to WordPress post-types. For example, by default the Page post type does not support excerpts, but by using add_post_type_support() you can add support.

add_post_type_support( $pageType,  $featureName );

Custom Admin Fields

Input fields on WordPress add/edit admin screens are called custom fields. Custom field data is called metadata.

Custom fields are displayed inside meta boxes, containers which can be placed on WP add/edit admin screens. When a post is updated, all custom field data is sent along with the post data to be processed server-side.

 

More Resources

Metadata

Custom field values stored in the database are called metadata. Metadata are key-value pairs of data that are attached to WordPress object types (posts, comments, users, terms, etc). Each object type instance is stored respectively as a row in it’s own database table wp_posts, wp_comments, wp_users, etc. Metadata for object types are also stored respectively in their own tables wp_postmeta, wp_commentmeta, wp_usermeta, etc. The only object type in WordPress which does not have metadata is the link.

Metadata tables all have a meta_key and meta_value column as well as a {obj type}_id column to key the metadata entry to the parent post, and an auto-incrementing id column.

Read and Write

The get_post_meta() and update_post_meta() WP functions are used to read and write metadata to the database. Both functions take the parent post ID, the key, and the value as parameters.

NOTE: WordPress has some peculiar behavior around metadata keys. Multiple metadata keys for a post can have the same name.

get_post_meta()

Documentation: developer.wordpress.org

Param Type Req Notes
$post_id int required The Post ID.
$key string optional The name of the meta key to retrieve. By default, returns data for all keys associated to the post. Meta keys are case-sensitive.
Default value: ”
$single bool optional Whether to return a single value.
Default value: false
returns mixed Will be an array of meta key-value pairs if $single is false. Will be the value of the meta data field if $single is true.

Add a Meta Box

To create custom fields a meta box must first be created by calling the add_meta_box() function and defining the post type(s) it should belong to.

The following code can be added to the functions.php file of a theme to create a Settings meta box which will display on the add/edit screens for the post post-type:

/**
 * Add the new `settings` meta box to the 'post' post-type.
 */
function prefix_add_settings_meta_box()
{
    add_meta_box(
        'prefix_post_settings_meta_box', // $id Unique ID of the meta box.
        'Settings', // $title Title of the meta box.
        'prefix_display_post_settings_fields', // $callback Name of the function which displays the meta box fields.
        'post', // $screen Post-type this meta box is assigned-to.
        'normal', // $context
        'high' // $priority
    );
}
add_action('add_meta_boxes', 'prefix_add_settings_meta_box');

// Display the `settings` meta box content.
function prefix_display_post_settings_fields($post, $args)
{
    echo 'Hello!';
}

add_meta_box()

Documentation: developer.wordpress.org

Param Type Req Notes
$id string yes The unique ID for the meta box. (used in the ‘id’ attribute for the meta box).
$title string yes The display title of the meta box. This value can/should be internationalized.
$callback callable yes Name of the function which defines the meta box content. The function should echo its output.
$screen string/array no The post-type ID(s) of the page(s) where the meta box will be displayed. This value can be a single post-type ID, page (screen) ID, WP_Screen object, or an array of IDs.
Default value: null
$context string no Defines the section of the page where the meta box should be placed (normal, advanced, or side). Other contexts vary from screen to screen. Comments screen contexts include ‘normal’ and ‘side’. Menus meta boxes (accordion sections) all use the ‘side’ context.
Default value: ‘advanced’
$priority string no Specifies the order within the section where the meta box will be placed (high, core, default, or low).
Default value: ‘default’
$callback_args array no An array of arguments ($args) that can be passed to the callback function.
Default value: null

Add Fields

The name of a callback function is passed to the add_meta_box() method. The callback function prints the HTML content of the meta box.

/**
 * Prints the `settings` meta box content.
 *
 * @param object $post The current WP post object. Basically the values
 *                     of the `wp_posts` DB table row for the post.
 * @param array  $args Info about the parent meta box as well as any
 *                     callback args passed to the WP `add_meta_box`
 *                     function.
 *
 * @return void
 */
function prefix_display_post_settings_fields($post, $args)
{
    // Get field data from the DB.
    $meta = get_post_meta($post->ID, 'prefix_post_settings_fields', true);

    // Begin the HTML output.
    $html = array();
    
    // Create a hidden nonce field for added security.
    $html[] = '<input type="hidden" name="post_settings_meta_box_nonce" value="' . wp_create_nonce(basename(__FILE__)) . '">';
    
    // Create the label and input field for the `prefix_first_name` field.
    $html[] = '<label for="prefix_post_settings_fields[first_name]">First Name</label>';
    $html[] = '<input type="text" name="prefix_post_settings_fields[first_name]" id="prefix_post_settings_fields[first_name]" class="regular-text" value="' . $this->meta_key($meta, 'first_name') . '">';
    
    // Create the label and input field for the `prefix_last_name` field.
    $html[] = '<label for="prefix_post_settings_fields[last_name]">Last Name</label>';
    $html[] = '<input type="text" name="prefix_post_settings_fields[last_name]" id="prefix_post_settings_fields[last_name]" class="regular-text" value="' . $this->meta_key($meta, 'last_name') . '">';
    
    echo '<pre>';
    print_r($meta);
    echo '</pre>';
    
    // Print the HTML to the screen.
    return print implode("\n", $html);
}

Database

Using the WPDB Class

The wpdb class can be used to execute SQL query statements which return PHP objects
In order to work with the class you have to declare it as a global variable.

global $wpdb;

For OOP I’ve found it best to declare the wpdb object in a custom database class constructor and assign the class to a class property for ease of reuse.

public $wpdb;

public function __construct()
{
    global $wpdb;
    $this->wpdb = $wpdb;
}

Table Names

It is possible to assign prefixes to WordPress database table names. This is done when the WP app is installed. In order to properly work with the WPDB, make sure to append the prefix property from the wpdb object to all table names.

$table_name = $wpdb->prefix . 'posts';
$sql_query = "SELECT * FROM $table_name LIMIT 10";

WP also has built-in table names for working with default tables: $wpdb->posts, $wpdb->postmeta, and $wpdb->users.

Custom Queries

// Use the WP `wpdb` class to access the database.
global $wpdb;

// Query all the attachement posts with no parent post.
$query = "
    SELECT *
      FROM $wpdb->posts
     WHERE $wpdb->posts.post_type = 'attachment'
       AND $wpdb->posts.post_parent = '0'
";

// Get the query results.
$query_results = $wpdb->get_results($query);

// If rows exist, loop through them.
if (count($query_results) > 0) {
    foreach ($query_results as $index => $result_row) {
        echo $result_row . "\n";
    }
}

Query Helper Methods

WP has built-in helper methods for working with basic database queries: $wpdb->insert(), $wpdb->update(), and $wpdb->get_row().

Using an External Database

To connect to an external database, create a new instance of the wpdb class.

// Connect to an external database.
$extdb = new \wpdb($username, $password, $db_name, $db_host);

// test the new DB object.
if (is_object($extdb) && !isset($extdb->error)) {
    // DB object is good.
}
 

More WP DB Resources


Images

http://codex.wordpress.org/Function_Reference/add_image_size

Notes

  • Using the ‘false’ setting will fail to produce a new image in the upload directory if one of the image dimensions of the uploaded image are equal to the new image size.
  • If a registered image size is removed from functions.php, then any image uploaded before that point and then deleted from the media library afterwards, does not have those auto-generated sizes deleted too. Only image sizes that exist in functions.php are deleted.

Comments

WordPress Codex: comments_template()

comments_template() loads a comment template. Used primarily in single Post and Page displays, but will work outside of single displays if $withcomments is set to “1”.

Reference Links