SlideShare a Scribd company logo
WordPress 
Building Potent Websites 
By: Kyle Cearley @ractoon
Who’s this guy? 
+ = 
Corgi illustration http://oliviawhen.blogspot.com/
What we’ll be looking at: 
Part 1: The Appearance 
Creating modern, modular designs that are easy to use and maintain. 
Part 2: Plugins 
Things to be aware of when building plugins. 
Part 3: Tips and Tricks 
WordPress is vast, things happen (or don’t), some fixes for common issues.
Part 1 
The Appearance (Themes)
A WordPress Theme 
Ta-da… 
wp-content 
themes 
my-theme 
index.php 
style.css
Theme Starting Points 
β€’ From scratch 
β€’ Existing theme (child theme) 
β€’ Framework / Boilerplate
Building from an Existing Theme 
β€’ Always create a child theme 
my-theme 
my-theme-child 
functions.php 
style.css (required)
Child Theme Setup 
/* 
Theme Name: My Child Theme 
Template: my-theme 
… 
*/ 
my-theme-child 
style.css functions.php 
<?php 
add_action( 'wp_enqueue_scripts', 
'enqueue_child_theme_styles', 
PHP_INT_MAX ); 
function enqueue_child_theme_styles() { 
wp_enqueue_style( 'parent-style', 
get_template_directory_uri().'/style.css 
' ); 
wp_enqueue_style( 'child-style', 
get_stylesheet_directory_uri() . 
'/style.css', array('parent-style') ); 
}
Theme Frameworks / Boilerplates 
β€’ Bones 
http://themble.com/bones/ 
β€’ Underscores 
http://underscores.me/ 
β€’ FoundationPress 
https://github.com/olefredrik/foundationpress 
β€’ Roots 
http://roots.io/starter-theme/ 
β€’ Genesis 
http://my.studiopress.com/themes/genesis/
Typical Modular Design 
header.php 
Client defined section nav 
Standard content section with animation shortcode 
Tabbed content 
section Content slider 
Standard content section with custom background 
footer.php 
Banner 
Widget with custom background
The Goal 
β€’ An easy to use theme that nestles users in the 
design 
β€’ Don’t make them think too hard 
β€’ Reduce support requests (save yourself time)
Potential Paths to The Goal 
β€’ Shortcodes 
β€’ Custom meta boxes/fields 
https://github.com/WebDevStudios/Custom-Metaboxes-and- 
Fields-for-WordPress 
β€’ Visual Composer 
http://codecanyon.net/item/visual-composer-page-builder-for- 
wordpress/242431 
β€’ Advanced Custom Fields (ACF) PRO 
http://www.advancedcustomfields.com/pro/
Shortcodes 
[button]Button Text[/button] 
[button link="http://www.example.com" popup="yes"] 
Output: 
<a class="button" href="#">Button Text</a> 
<a class="button" href="http://www.example.com" target="_blank">Default Text</a>
Shortcodes 
β€’ Good for small manipulations of content or 
inserting special content 
β€’ Tricky to remember 
β€’ Attributes lack selection/validation
Adding Shortcodes 
functions.php (or separate plugin) 
function button_func( $atts, $content ) { 
$atts = shortcode_atts( 
array( 
'link' => '#', 
'popup' => '' 
), $atts ); 
$html = '<a href="' . $atts['link'] . '"'; 
if ( !empty( $atts['popup'] ) ) $html .= ' target="_blank"'; 
$html .= '>'; 
$html .= do_shortcode( $content ); 
$html .= '</a>'; 
return $html; 
} 
add_shortcode( 'button', 'button_func' );
Shortcode Cleanup 
functions.php (or separate plugin) 
function cleanup_shortcode_fix( $content ) { 
$array = array ( 
'<p>[' => '[', 
']</p>' => ']', 
']<br />' => ']', 
']<br>' => ']' 
); 
$content = strtr( $content, $array ); 
return $content; 
} 
add_filter( 'the_content', 'cleanup_shortcode_fix' ); 
add_filter( 'acf_the_content', 'cleanup_shortcode_fix' ); 
Or (the nuclear option): 
remove_filter( 'the_content', 'wpautop' ); 
remove_filter( 'the_excerpt', 'wpautop' );
Meta Boxes
Custom Meta Boxes / Fields 
β€’ Good variety of field types 
β€’ Extensible 
β€’ Tightly coupled with the theme 
β€’ Need to define each field/group with code
Adding Meta Boxes / Fields 
<?php 
add_filter( 'cmb_meta_boxes', 'cmb_sample_metaboxes' ); 
function cmb_sample_metaboxes( array $meta_boxes ) { 
$prefix = '_cmb_'; 
$meta_boxes['test_metabox'] = array( 
'id' => 'test_metabox', 
'title' => __( 'Test Metabox', 'cmb' ), 
'pages' => array( 'page', ), 
'context' => 'normal', 
'priority' => 'high', 
'show_names' => true, 
'fields' => array( 
array( 
'name' => __( 'Test Text', 'cmb' ), 
'desc' => __( 'field description (optional)', 'cmb' ), 
'id' => $prefix . 'test_text', 
'type' => 'text', 
'show_on_cb' => 'cmb_test_text_show_on_cb' 
), 
... 
) 
); 
} 
functions.php
Displaying Meta Fields 
page.php / post.php 
Uses native WordPress get_post_meta function: 
<?php 
$meta_values = get_post_meta( $post_id, $key, $single ); 
Example: 
<?php 
global $post; 
$text = get_post_meta( $post->ID, '_cmb_test_text', true ); 
echo $text;
Meta Fields Cleanup 
Start meta field keys with _ to hide from custom fields 
To display the Custom Fields metabox activate it in Screen Options: 
Shows:
Visual Composer
Visual Composer 
β€’ Visual page builder with drag/drop interface 
β€’ Pre-configured templates for layouts 
β€’ Over 40 content blocks (element types) 
β€’ Visual query builder 
β€’ Extensible 
β€’ Content stored as post meta in serialized array
Advanced Custom Fields PRO 
β€’ Wide variety of field types 
β€’ Visual field setup and configuration 
β€’ Easy to sync fields between installs 
β€’ Extensible 
β€’ Users given only the controls you define
Using Advanced Custom Fields PRO 
β€’ Repeater 
β€’ Image 
β€’ Gallery 
β€’ Flexible 
Content 
β€’ Relationship 
β€’ Post Object 
β€’ Date Picker 
β€’ Checkbox 
β€’ Select 
β€’ Text 
β€’ True / False 
β€’ File 
β€’ Page Link 
β€’ Wysiwyg Editor 
β€’ Google Map 
β€’ Textarea 
β€’ Color Picker 
β€’ Taxonomy 
β€’ oEmbed
Defining ACF PRO Field Groups
Defining ACF PRO Fields
Populating ACF PRO Fields
Displaying ACF Pro Fields 
page.php / post.php 
<?php the_field( 'my_field_name' ); ?>
(Bones) Theme File Structure 
(Automatically saves your ACF fields) 
my-theme 
acf-json 
library 
css 
scss 
style.css 
style.css 
_base.scss, _481up.scss, _768up.scss…
CSS Preprocessors 
β€’ Prepros (Mac, Windows) 
http://alphapixels.com/prepros/ 
β€’ CodeKit (Mac) 
https://incident57.com/codekit/
Including Stylesheets 
Option 1: 
wp_register_style( $handle, $src, $deps, $ver, $media ); 
wp_enqueue_style( $handle ); 
Option 2: 
wp_enqueue_style( $handle, $src, $deps, $ver, $media ); 
functions.php 
function mytheme_enqueue_styles() { 
$style_file = get_template_directory_uri() . 
'/library/css/style.css'; 
wp_enqueue_style( 'my-styles', $style_file, array(), filemtime( 
$style_file ), 'all' ); 
} 
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_styles' );
Stylesheet Output 
functions.php 
… 
wp_enqueue_style( 'my-styles', $style_file, array(), filemtime( 
$style_file ), 'all' ); 
… 
Output: 
<link rel='stylesheet' id='my-styles-css' 
href='http://mysite.local/wp-content/themes/my-theme/ 
library/css/style.css?ver=1414191171' type='text/css' 
media='all' />
Including Scripts 
Option 1: 
wp_register_script( $handle, $src, $deps, $ver, $in_footer ); 
wp_enqueue_script( $handle ); 
Option 2: 
wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer ); 
functions.php 
function mytheme_enqueue_scripts() { 
$script_file = get_template_directory_uri() . 
'/library/js/scripts.js'; 
wp_enqueue_script( 'my-scripts', $script_file, array( 'jquery' ), 
filemtime( $script_file ), true ); 
} 
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );
Scripts Output 
<script type='text/javascript' src='http://mysite.local/wp-content/ 
themes/my-theme/ 
library/js/min/scripts.js?ver=1413837351'></script> 
… 
wp_enqueue_script( 'my-scripts', $script_file, array( 'jquery' ), 
filemtime( $script_file ), true ); 
… 
functions.php 
Output:
The Power of Enqueue 
β€’ Allows other devs/plugins to modify styles/scripts 
as needed 
β€’ Allows you to tack things on to scripts/styles: 
– Inline styles 
wp_add_inline_style( 'my-styles', $custom_css ); 
– Style data (such as conditional IE wrappers) 
global $wp_styles; 
$wp_styles->add_data( 'my-ie-styles', 'conditional', 'lt IE 
9' ); 
– Localize scripts 
wp_localize_script( 'my-scripts', 'greeting', 'Bonjour!' );
Content Section Types 
β€’ Standard Content 
β€’ Sliders 
β€’ Tabbed content 
β€’ Testimonials 
β€’ Custom post type displays (news, resources, 
etc.) 
β€’ Other sections the design calls for
Flexible Sections for Clients 
β€’ Add, remove, and change order 
β€’ Modify background color/image, headlines, 
description text, etc. 
β€’ Keep clients focused on their content 
– Useful defaults 
– Only show relevant items (conditional toggles) 
– Expect weird content (longer/shorter, 
larger/smaller than mockup) 
– Fill in the gaps for clients
Creating Content Sections 
Each section type is a Flexible Content field set 
up in Advanced Custom Fields
Template Parts 
Allow you to reuse chunks of code, and for child 
themes to replace sections as needed 
<?php get_template_part ( $slug, $name ); ?>
Creating Template Parts 
page.php / post.php 
<?php get_template_part ( 'chunk' ); ?> 
my-theme 
chunk.php (2) 
my-theme-child 
chunk.php (1)
Creating Template Parts 
page.php / post.php 
<?php get_template_part ( 'chunk', 'adunk' ); ?> 
my-theme 
chunk-adunk.php (2) 
chunk.php (4) 
my-theme-child 
chunk-adunk.php (1) 
chunk.php (3)
Template Part for the Content Sections 
Content sections are contained in a template part: 
content-sections.php 
content-sections.php 
my-theme 
The content sections template part is included on desired page/post templates: 
page.php / post.php 
<?php get_template_part ('content-sections' ); ?>
Displaying the Content Sections 
content-sections.php 
<?php 
if ( have_rows( 'sections' ) ): 
$section_id = 1; 
?> 
<?php while ( have_rows('sections') ) : the_row(); ?> 
<?php $layout = get_row_layout(); ?> 
<section id="content-section-<?php echo $section_id; ?>" class="<?php echo $layout; ?>"> 
<?php if ( 'content' == $layout ): // default content section ?> 
<?php the_sub_field( 'content' ); ?> 
<?php endif; ?> 
</section> 
<?php 
$section_id++; 
endwhile; 
endif; 
?>
Customizing Content Sections 
Default 
Custom Background Color 
Custom Background Image
Applying Custom Styles to Sections 
<?php 
if ( have_rows( 'sections' ) ): 
$content_sections_css = ''; 
$section_id = 1; 
while ( have_rows('sections') ) : the_row(); ?> 
$content_sections_css .= "#content-section-{$section_id} {"; 
$background = get_sub_field( 'background' ); 
if ( 'color' == $background ) { 
$background_color = get_sub_field( 'background_color' ); 
$content_sections_css .= "background-color: {$background_color};"; 
} 
$content_sections_css .= "}"; 
$section_id++; 
endwhile; 
wp_add_inline_style( 'my-styles', $content_sections_css ); 
endif; 
Loop through sections 
Content section selector 
Set styles 
Attach inline styles 
functions.php (in wp_enqueue_scripts function)
Custom Section Styles Output 
The enqueued stylesheet from earlier that the inline styles are attached to 
<link rel='stylesheet' id='my-styles-css' 
href='http://mysite.local/wp-content/themes/my-theme/ 
library/css/style.css?ver=1414191171' type='text/css' 
media='all' /> 
<style type='text/css'> 
#content-section-1 { 
background-color: #cc0000; 
} 
</style> 
Inline styles output right after 
the attached stylesheet
Part 1.1 
The Appearance (Widgets)
Widgets 
β€’ Use to display content that should appear on 
multiple posts/pages 
β€’ Can conditionally display widgets with plugins 
such as Display Widgets: 
https://wordpress.org/plugins/display-widgets/ 
β€’ Widget Boilerplate: 
https://github.com/tommcfarlin/WordPress- 
Widget-Boilerplate
<?php 
add_action( 'widgets_init', 'my_register_sidebars' ); 
function my_register_sidebars() { 
register_sidebar( array( 
'id' => 'sidebar', 
'name' => __( 'Sidebar', 'bonestheme' ), 
'description' => __( 'The main sidebar.', 'bonestheme' ), 
'before_widget' => '<div id="%1$s" class="widget %2$s">', 
'after_widget' => '</div>', 
'before_title' => '<h4 class="widgettitle">', 
'after_title' => '</h4>', 
)); 
... 
} 
Creating Widget Areas (Sidebars) 
functions.php
Displaying Widget Areas (Sidebars) 
sidebar.php 
<div id="sidebar" class="sidebar cf" role="complementary"> 
<?php if ( is_active_sidebar( 'sidebar' ) ) : ?> 
<?php dynamic_sidebar( 'sidebar' ); ?> 
<?php endif; ?> 
</div>
Advanced Custom Fields in Widgets 
After creating your widget using the Widget Boilerplate:
public function widget( $args, $instance ) { 
extract( $args ); 
echo $before_widget; 
?> 
<section> 
<?php 
$content = get_field( 'content', 'widget_' . $widget_id ); 
echo do_shortcode( $content ); 
?> 
</section> 
<?php 
echo $after_widget; 
} 
Displaying ACF Fields in Widgets 
Accessed through second argument which is the widget_id prefixed by "widget_"
// widget sections 
$sidebars_widgets = wp_get_sidebars_widgets(); 
$widget_ids = array_merge( $sidebars_widgets['sidebar'] ); 
$widget_sections_css = ''; 
foreach( $widget_ids as $id ) { 
if ( $background_color = get_field( 'background_color', 'widget_' . $id ) ) { 
$widget_sections_css .= " 
#{$id} section { 
background-color: {$background_color}; 
}"; 
} 
} 
if ( !empty( $widget_sections_css ) ) { 
wp_add_inline_style( 'my-styles', $widget_sections_css ); 
} 
Custom Styles for Widget Fields 
functions.php (in wp_enqueue_scripts function)
Part 2 
Plugins
Hooks 
Hooks allow you to modify, extend, and enhance 
WordPress through an API in your themes and 
plugins. 
There are two flavors: 
β€’ Actions 
β€’ Filters
Actions 
Triggered by specific events, typically used for 
executing functions. 
β€’ do_action() 
– Defines a hookable location 
β€’ add_action() 
– Attaches a function to a hook defined with do_action() 
β€’ has_action() 
– Checks if action exists 
β€’ remove_action()
Default WordPress Actions 
β€’ wp_enqueue_scripts 
β€’ register_sidebar 
β€’ dynamic_sidebar 
β€’ wp_head 
β€’ get_header 
β€’ get_footer 
β€’ plugins_loaded 
β€’ And many more… 
http://codex.wordpress.org/Plugin_API/Action_Reference
<?php 
... 
<section id="content-section-<?php echo $section_id; ?>" class="<?php echo $layout; ?>"> 
<?php do_action( 'my_content_section_before', $layout ); ?> 
<?php if ( 'content' == $layout ): // default content section ?> 
<?php the_sub_field( 'content' ); ?> 
<?php endif; ?> 
<?php do_action('my_content_section_after', $layout ); ?> 
</section> 
... 
Custom Action Setup 
content-sections.php
Custom Action Usage 
functions.php 
<?php 
function my_extra_content( $layout ) { 
echo 'This Content Section uses the layout: ' . $layout; 
} 
add_action( 'my_content_section_before', 'my_extra_content' ); 
Output: 
This Content Section uses the layout: content 
{ section content fields displayed here… }
Filters 
Functions that data passes through, typically used 
to manipulate data. 
β€’ apply_filters() 
– Defines a hookable location 
β€’ add_filter() 
– Attaches a filter to a hook defined with apply_filters() 
β€’ has_filter() 
– Checks if filter exists 
β€’ Remove_filter()
Default WordPress Filters 
β€’ the_excerpt 
β€’ the_content 
β€’ the_title 
β€’ wp_list_pages 
β€’ sanitize_title 
β€’ menu_order 
β€’ image_resize_dimensions 
β€’ And many more… 
http://codex.wordpress.org/Plugin_API/Filter_Reference
Custom Filter Setup and Usage 
functions.php (or separate plugin) 
<?php 
$args = array( 
'post_type' => 'locations', 
'region' => 'USA', 
'posts_per_page' => 5 
); 
$locations = new WP_Query( apply_filters( 'my_locations_query', $args ) ); 
Usage: 
<?php 
function my_new_locations_query( $args ) { 
$args['region'] = 'Canada'; 
return $args; 
} 
add_filter( 'my_locations_query', 'my_new_locations_query' );
A WordPress Plugin 
wp-content 
plugins 
my-plugin 
plugin.php 
Ta-da…
Plugin Setup 
plugin.php 
<?php 
/* 
* Plugin Name: My Plugin 
* Plugin URI: http://myplugin.mysite.com 
* Description: It’s my plugin, and I do what I want. 
* Version: 1.0 
* Author: Me 
* Author URI: http://www.mysite.com 
* License: GPL2 
* Text Domain: my-plugin 
*/ 
Plugin Boilerplate: 
https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate
Plugin Using Classes 
plugin.php 
<?php 
/* 
* Plugin Name: My Plugin 
* Plugin URI: http://myplugin.mysite.com 
* Description: It’s my plugin, and I do what I want. 
* Version: 1.0 
* ... 
*/ 
class MyPostType { 
public function __construct() { 
// custom post type 
add_action( 'init', array( $this, 'my_custom_post_type' ) ); 
} 
public function my_custom_post_type() { 
// my custom post type defined here 
} 
} 
$myPostType = new MyPostType();
What theme components should be 
plugins? 
β€’ Shortcodes 
β€’ Custom Post Types 
β€’ Custom Taxonomies 
β€’ Custom Widgets 
Nestle users in the design, don’t trap them.
Part 2.1 
I18n (Internationalization)
I18n (Internationalization) 
Making your themes / plugins translatable 
Standard strings: 
$hello = __( 'Hello there', 'my-text-domain' ); 
_e( 'This is echoed', 'my-text-domain' ); 
Singular / plural strings: 
_n( 'One potato', 'Many potatoes', $count, 'my-text-domain' ); 
Differentiating strings with similar names (setting the context): 
_x( 'Name', 'my context', 'my-text-domain' ); 
_ex( 'Echo name', 'my context', 'my-text-domain' );
I18n with Variables 
Standard strings with a variable: 
$hello = sprintf( __( 'Hello there, %s', 'my-text-domain' ), 
'Bob' ); // store in variable 
printf( __( 'Hello there, %s', 'my-text-domain' ), 'Bob' ); // or 
just output 
Singlular / plural strings with a variable: 
$potato = sprintf( _n('A lonely potato', 'Here are %d potatoes', 
$count, 'my-text-domain' ), $count ); // store in variable 
printf( _n('A lonely potato', 'Here are %d potatoes', $count, 
'my-text-domain' ), $count ); // or just output
Part 2.2 
Security with Nonces
Nonces 
β€’ Protect your themes/plugins against CSRF 
(Cross-Site Request Forgery), multiple/invalid 
submissions 
β€’ A.K.A. CSRF Tokens
Adding Nonces to URLs 
wp_nonce_url( $actionurl, $action, $name ); 
Usage: 
$bare_url = 'http://example.com/wp-admin/ 
post.php?post=123&action=trash'; 
$complete_url = wp_nonce_url( $bare_url, 'trash-post_' . 
$post->ID, '_wpnonce' ); 
http://example.com/wp-admin/ 
post.php?post=123&action=trash&_wpnonce=b192fc4204 
Output:
Adding Nonces to Forms 
wp_nonce_field( $action, $name, $referer, $echo ); 
Usage: 
wp_nonce_field( 'delete-user_' . $user_id, '_wpnonce', 
true, true ); 
<input type="hidden" id="_wpnonce" name="_wpnonce" 
value="796c7766b1"> 
<input type="hidden" name="_wp_http_referer" value="/wp-admin/ 
edit-user.php"> 
Output:
Adding Nonces Anywhere 
wp_create_nonce( $action ); 
Usage: 
wp_create_nonce( 'my-nonce' ); 
Value: 
295a686963
Verifying Nonces 
From Form / URL: 
check_admin_referer( 'delete-user_' . $user_id ); 
From some other context: 
wp_verify_nonce( 'delete-user_' . $user_id ); 
From AJAX: 
check_ajax_referer( 'get-users' );
Part 2.3 
Using AJAX in Plugins
add_action( 'wp_ajax_myfunc', 'prefix_ajax_myfunc' ); 
add_action( 'wp_ajax_nopriv_myfunc', 'prefix_ajax_myfunc' ); 
function prefix_ajax_myfunc() { 
check_ajax_referer( 'my-nonce', 'security' ); 
echo $_POST['foo']; 
die(); 
} 
AJAX: The Setup 
functions.php (or separate plugin)
AJAX: The Nonce 
functions.php (or separate plugin, in wp_enqueue_scripts function) 
<?php 
// Set Your Nonce 
$ajax_nonce = wp_create_nonce( "my-nonce" ); 
wp_localize_script( 'my-scripts', 'ajaxNonce', $ajax_nonce );
AJAX: The Usage 
scripts.js 
jQuery(document).ready(function($) { 
var data = { 
action: 'myfunc', 
security: ajaxNonce, 
foo: 'Hello World!' 
}; 
$.post(ajaxurl, data, function(response) { 
alert("Response: " + response); 
}); 
});
Part 3 
Tips and Tricks
Protecting Email Addresses 
<?php antispambot( $emailaddy, $hex_encoding ) ?> 
Usage: 
<?php echo antispambot( 'test.mctest@mysite.com' ); ?> 
Result: 
&#106;&#111;h&#110;&#46;&#100;&#111;&#101;&#64;mysit&#101;.&#99;&#111;&#109; 
Browser sees: 
test.mctest@mysite.com
Quickstarts for Custom Components 
http://generatewp.com/
Custom ACF Color Picker Swatches 
Customize swatches based on design / theme colors: 
These things
Custom ACF Color Picker Swatches 
functions.php 
function acf_custom_config() { 
global $parent_file; 
if ( 
strpos($parent_file, 'post-new.php') !== FALSE || 
strpos($parent_file, 'edit.php') !== FALSE ) { 
echo " 
<script> 
jQuery(document).ready(function($){ 
if ($('.acf-color_picker').length) { 
$('.acf-color_picker').iris({ 
palettes: ['#f60', '#ffa839', '#3078bf', '#e0ebf5', '#58585a', '#2e3137'], 
change: function(event, ui) { 
$(this).parents('.wp-picker-container').find('.wp-color-result'). 
css('background-color', ui.color.toString()); 
} 
}); 
} 
}); 
</script> 
"; 
} 
} 
add_action( 'in_admin_footer', 'acf_custom_config' );
Make Admin Listings Relevant 
Use the Admin Columns Pro plugin to clean up the post listing pages: 
β€’ Show relevant columns for post types, hide unnecessary columns 
β€’ Allow client to edit items in the listing (inline edits) 
β€’ Display ACF PRO fields as well
Thank You! 
If you ever had any questions or wanted to chat: 
kyle@ractoon.com

More Related Content

PPT
WordPress development paradigms, idiosyncrasies and other big words
PDF
Wordcamp abq cf-cpt
PDF
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
PPTX
Childthemes ottawa-word camp-1919
PPT
Custom Post Types and Meta Fields
PPTX
The Way to Theme Enlightenment 2017
PDF
WordPress Theme Development for Designers
PPTX
jQuery from the very beginning
WordPress development paradigms, idiosyncrasies and other big words
Wordcamp abq cf-cpt
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
Childthemes ottawa-word camp-1919
Custom Post Types and Meta Fields
The Way to Theme Enlightenment 2017
WordPress Theme Development for Designers
jQuery from the very beginning

What's hot (20)

KEY
Geek Moot '09 -- Smarty 101
KEY
jQuery Anti-Patterns for Performance & Compression
PPTX
WordPress theme development from scratch : ICT MeetUp 2013 Nepal
PPTX
Let's write secure Drupal code! - DrupalCamp Oslo, 2018
PPTX
Π‘Π΅Ρ€Π³Π΅ΠΉ Π˜Π²Π°Ρ‰Π΅Π½ΠΊΠΎ - Meet Magento Ukraine - Π¦Π΅Π½Ρ‹ Π² Magento 2
Β 
KEY
Django Admin: Widgetry & Witchery
PPTX
Let's write secure drupal code! - Drupal Camp Pannonia 2019
PPTX
WordPress Theme Development: Part 2
PDF
Drupal 8: Routing & More
Β 
PDF
Working with the django admin
PPTX
Introduction to Plugin Programming, WordCamp Miami 2011
KEY
WordPress Developers Israel Meetup #1
PDF
WordPress Theming 101
PPTX
Let's write secure Drupal code! - Drupal Camp Poland 2019
PPTX
Let's write secure Drupal code! DUG Belgium - 08/08/2019
PDF
Creating GUI Component APIs in Angular and Web Components
PDF
OSDC 2009 Rails Turtorial
PPTX
WordPress Plugin development
ZIP
Learning the basics of the Drupal API
PDF
Dependency Management with RequireJS
Geek Moot '09 -- Smarty 101
jQuery Anti-Patterns for Performance & Compression
WordPress theme development from scratch : ICT MeetUp 2013 Nepal
Let's write secure Drupal code! - DrupalCamp Oslo, 2018
Π‘Π΅Ρ€Π³Π΅ΠΉ Π˜Π²Π°Ρ‰Π΅Π½ΠΊΠΎ - Meet Magento Ukraine - Π¦Π΅Π½Ρ‹ Π² Magento 2
Β 
Django Admin: Widgetry & Witchery
Let's write secure drupal code! - Drupal Camp Pannonia 2019
WordPress Theme Development: Part 2
Drupal 8: Routing & More
Β 
Working with the django admin
Introduction to Plugin Programming, WordCamp Miami 2011
WordPress Developers Israel Meetup #1
WordPress Theming 101
Let's write secure Drupal code! - Drupal Camp Poland 2019
Let's write secure Drupal code! DUG Belgium - 08/08/2019
Creating GUI Component APIs in Angular and Web Components
OSDC 2009 Rails Turtorial
WordPress Plugin development
Learning the basics of the Drupal API
Dependency Management with RequireJS
Ad

Similar to Building Potent WordPress Websites (20)

PPTX
The Way to Theme Enlightenment
PDF
Gail villanueva add muscle to your wordpress site
PDF
Build WordPress themes like a heavyweight - WordCamp Lancaster 2013
PPTX
PSD to WordPress
PDF
Seven deadly theming sins
PDF
How to make a WordPress theme
PPTX
Drupal 7 β€” Circle theme
PPTX
WordPress Structure and Best Practices
PDF
Design Systems, Pattern Libraries & WordPress
PPTX
Writing your own WordPress themes and plugins
PDF
Don't Fear the Custom Theme: How to build a custom WordPress theme with only ...
PPTX
May the core be with you - JandBeyond 2014
KEY
Workshop quality assurance for php projects tek12
PPTX
Flask – Python
PDF
Building a Portfolio With Custom Post Types
PPSX
WordPress Theme Design and Development Workshop - Day 3
PDF
Implement rich snippets in your webshop
PPTX
Use Symfony2 components inside WordPress
PDF
Django workshop : let's make a blog
PDF
WordPress Theme Workshop: Part 3
The Way to Theme Enlightenment
Gail villanueva add muscle to your wordpress site
Build WordPress themes like a heavyweight - WordCamp Lancaster 2013
PSD to WordPress
Seven deadly theming sins
How to make a WordPress theme
Drupal 7 β€” Circle theme
WordPress Structure and Best Practices
Design Systems, Pattern Libraries & WordPress
Writing your own WordPress themes and plugins
Don't Fear the Custom Theme: How to build a custom WordPress theme with only ...
May the core be with you - JandBeyond 2014
Workshop quality assurance for php projects tek12
Flask – Python
Building a Portfolio With Custom Post Types
WordPress Theme Design and Development Workshop - Day 3
Implement rich snippets in your webshop
Use Symfony2 components inside WordPress
Django workshop : let's make a blog
WordPress Theme Workshop: Part 3
Ad

Recently uploaded (20)

PPTX
QR Codes Qr codecodecodecodecocodedecodecode
PPTX
SAP Ariba Sourcing PPT for learning material
PPTX
INTERNET------BASICS-------UPDATED PPT PRESENTATION
PDF
Slides PDF The World Game (s) Eco Economic Epochs.pdf
PPTX
PptxGenJS_Demo_Chart_20250317130215833.pptx
PPTX
522797556-Unit-2-Temperature-measurement-1-1.pptx
PDF
πŸ’° π”πŠπ“πˆ πŠπ„πŒπ„ππ€ππ†π€π πŠπˆππ„π‘πŸ’πƒ π‡π€π‘πˆ 𝐈𝐍𝐈 πŸπŸŽπŸπŸ“ πŸ’°
Β 
PDF
Tenda Login Guide: Access Your Router in 5 Easy Steps
PPTX
Funds Management Learning Material for Beg
PDF
Unit-1 introduction to cyber security discuss about how to secure a system
PDF
Paper PDF World Game (s) Great Redesign.pdf
PDF
Sims 4 Historia para lo sims 4 para jugar
PDF
SASE Traffic Flow - ZTNA Connector-1.pdf
PPT
Design_with_Watersergyerge45hrbgre4top (1).ppt
PPTX
introduction about ICD -10 & ICD-11 ppt.pptx
PPTX
international classification of diseases ICD-10 review PPT.pptx
PDF
Triggering QUIC, presented by Geoff Huston at IETF 123
Β 
PDF
The Internet -By the Numbers, Sri Lanka Edition
Β 
PPTX
CHE NAA, , b,mn,mblblblbljb jb jlb ,j , ,C PPT.pptx
PDF
Automated vs Manual WooCommerce to Shopify Migration_ Pros & Cons.pdf
QR Codes Qr codecodecodecodecocodedecodecode
SAP Ariba Sourcing PPT for learning material
INTERNET------BASICS-------UPDATED PPT PRESENTATION
Slides PDF The World Game (s) Eco Economic Epochs.pdf
PptxGenJS_Demo_Chart_20250317130215833.pptx
522797556-Unit-2-Temperature-measurement-1-1.pptx
πŸ’° π”πŠπ“πˆ πŠπ„πŒπ„ππ€ππ†π€π πŠπˆππ„π‘πŸ’πƒ π‡π€π‘πˆ 𝐈𝐍𝐈 πŸπŸŽπŸπŸ“ πŸ’°
Β 
Tenda Login Guide: Access Your Router in 5 Easy Steps
Funds Management Learning Material for Beg
Unit-1 introduction to cyber security discuss about how to secure a system
Paper PDF World Game (s) Great Redesign.pdf
Sims 4 Historia para lo sims 4 para jugar
SASE Traffic Flow - ZTNA Connector-1.pdf
Design_with_Watersergyerge45hrbgre4top (1).ppt
introduction about ICD -10 & ICD-11 ppt.pptx
international classification of diseases ICD-10 review PPT.pptx
Triggering QUIC, presented by Geoff Huston at IETF 123
Β 
The Internet -By the Numbers, Sri Lanka Edition
Β 
CHE NAA, , b,mn,mblblblbljb jb jlb ,j , ,C PPT.pptx
Automated vs Manual WooCommerce to Shopify Migration_ Pros & Cons.pdf

Building Potent WordPress Websites

  • 1. WordPress Building Potent Websites By: Kyle Cearley @ractoon
  • 2. Who’s this guy? + = Corgi illustration http://oliviawhen.blogspot.com/
  • 3. What we’ll be looking at: Part 1: The Appearance Creating modern, modular designs that are easy to use and maintain. Part 2: Plugins Things to be aware of when building plugins. Part 3: Tips and Tricks WordPress is vast, things happen (or don’t), some fixes for common issues.
  • 4. Part 1 The Appearance (Themes)
  • 5. A WordPress Theme Ta-da… wp-content themes my-theme index.php style.css
  • 6. Theme Starting Points β€’ From scratch β€’ Existing theme (child theme) β€’ Framework / Boilerplate
  • 7. Building from an Existing Theme β€’ Always create a child theme my-theme my-theme-child functions.php style.css (required)
  • 8. Child Theme Setup /* Theme Name: My Child Theme Template: my-theme … */ my-theme-child style.css functions.php <?php add_action( 'wp_enqueue_scripts', 'enqueue_child_theme_styles', PHP_INT_MAX ); function enqueue_child_theme_styles() { wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css ' ); wp_enqueue_style( 'child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style') ); }
  • 9. Theme Frameworks / Boilerplates β€’ Bones http://themble.com/bones/ β€’ Underscores http://underscores.me/ β€’ FoundationPress https://github.com/olefredrik/foundationpress β€’ Roots http://roots.io/starter-theme/ β€’ Genesis http://my.studiopress.com/themes/genesis/
  • 10. Typical Modular Design header.php Client defined section nav Standard content section with animation shortcode Tabbed content section Content slider Standard content section with custom background footer.php Banner Widget with custom background
  • 11. The Goal β€’ An easy to use theme that nestles users in the design β€’ Don’t make them think too hard β€’ Reduce support requests (save yourself time)
  • 12. Potential Paths to The Goal β€’ Shortcodes β€’ Custom meta boxes/fields https://github.com/WebDevStudios/Custom-Metaboxes-and- Fields-for-WordPress β€’ Visual Composer http://codecanyon.net/item/visual-composer-page-builder-for- wordpress/242431 β€’ Advanced Custom Fields (ACF) PRO http://www.advancedcustomfields.com/pro/
  • 13. Shortcodes [button]Button Text[/button] [button link="http://www.example.com" popup="yes"] Output: <a class="button" href="#">Button Text</a> <a class="button" href="http://www.example.com" target="_blank">Default Text</a>
  • 14. Shortcodes β€’ Good for small manipulations of content or inserting special content β€’ Tricky to remember β€’ Attributes lack selection/validation
  • 15. Adding Shortcodes functions.php (or separate plugin) function button_func( $atts, $content ) { $atts = shortcode_atts( array( 'link' => '#', 'popup' => '' ), $atts ); $html = '<a href="' . $atts['link'] . '"'; if ( !empty( $atts['popup'] ) ) $html .= ' target="_blank"'; $html .= '>'; $html .= do_shortcode( $content ); $html .= '</a>'; return $html; } add_shortcode( 'button', 'button_func' );
  • 16. Shortcode Cleanup functions.php (or separate plugin) function cleanup_shortcode_fix( $content ) { $array = array ( '<p>[' => '[', ']</p>' => ']', ']<br />' => ']', ']<br>' => ']' ); $content = strtr( $content, $array ); return $content; } add_filter( 'the_content', 'cleanup_shortcode_fix' ); add_filter( 'acf_the_content', 'cleanup_shortcode_fix' ); Or (the nuclear option): remove_filter( 'the_content', 'wpautop' ); remove_filter( 'the_excerpt', 'wpautop' );
  • 18. Custom Meta Boxes / Fields β€’ Good variety of field types β€’ Extensible β€’ Tightly coupled with the theme β€’ Need to define each field/group with code
  • 19. Adding Meta Boxes / Fields <?php add_filter( 'cmb_meta_boxes', 'cmb_sample_metaboxes' ); function cmb_sample_metaboxes( array $meta_boxes ) { $prefix = '_cmb_'; $meta_boxes['test_metabox'] = array( 'id' => 'test_metabox', 'title' => __( 'Test Metabox', 'cmb' ), 'pages' => array( 'page', ), 'context' => 'normal', 'priority' => 'high', 'show_names' => true, 'fields' => array( array( 'name' => __( 'Test Text', 'cmb' ), 'desc' => __( 'field description (optional)', 'cmb' ), 'id' => $prefix . 'test_text', 'type' => 'text', 'show_on_cb' => 'cmb_test_text_show_on_cb' ), ... ) ); } functions.php
  • 20. Displaying Meta Fields page.php / post.php Uses native WordPress get_post_meta function: <?php $meta_values = get_post_meta( $post_id, $key, $single ); Example: <?php global $post; $text = get_post_meta( $post->ID, '_cmb_test_text', true ); echo $text;
  • 21. Meta Fields Cleanup Start meta field keys with _ to hide from custom fields To display the Custom Fields metabox activate it in Screen Options: Shows:
  • 23. Visual Composer β€’ Visual page builder with drag/drop interface β€’ Pre-configured templates for layouts β€’ Over 40 content blocks (element types) β€’ Visual query builder β€’ Extensible β€’ Content stored as post meta in serialized array
  • 24. Advanced Custom Fields PRO β€’ Wide variety of field types β€’ Visual field setup and configuration β€’ Easy to sync fields between installs β€’ Extensible β€’ Users given only the controls you define
  • 25. Using Advanced Custom Fields PRO β€’ Repeater β€’ Image β€’ Gallery β€’ Flexible Content β€’ Relationship β€’ Post Object β€’ Date Picker β€’ Checkbox β€’ Select β€’ Text β€’ True / False β€’ File β€’ Page Link β€’ Wysiwyg Editor β€’ Google Map β€’ Textarea β€’ Color Picker β€’ Taxonomy β€’ oEmbed
  • 26. Defining ACF PRO Field Groups
  • 29. Displaying ACF Pro Fields page.php / post.php <?php the_field( 'my_field_name' ); ?>
  • 30. (Bones) Theme File Structure (Automatically saves your ACF fields) my-theme acf-json library css scss style.css style.css _base.scss, _481up.scss, _768up.scss…
  • 31. CSS Preprocessors β€’ Prepros (Mac, Windows) http://alphapixels.com/prepros/ β€’ CodeKit (Mac) https://incident57.com/codekit/
  • 32. Including Stylesheets Option 1: wp_register_style( $handle, $src, $deps, $ver, $media ); wp_enqueue_style( $handle ); Option 2: wp_enqueue_style( $handle, $src, $deps, $ver, $media ); functions.php function mytheme_enqueue_styles() { $style_file = get_template_directory_uri() . '/library/css/style.css'; wp_enqueue_style( 'my-styles', $style_file, array(), filemtime( $style_file ), 'all' ); } add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_styles' );
  • 33. Stylesheet Output functions.php … wp_enqueue_style( 'my-styles', $style_file, array(), filemtime( $style_file ), 'all' ); … Output: <link rel='stylesheet' id='my-styles-css' href='http://mysite.local/wp-content/themes/my-theme/ library/css/style.css?ver=1414191171' type='text/css' media='all' />
  • 34. Including Scripts Option 1: wp_register_script( $handle, $src, $deps, $ver, $in_footer ); wp_enqueue_script( $handle ); Option 2: wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer ); functions.php function mytheme_enqueue_scripts() { $script_file = get_template_directory_uri() . '/library/js/scripts.js'; wp_enqueue_script( 'my-scripts', $script_file, array( 'jquery' ), filemtime( $script_file ), true ); } add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );
  • 35. Scripts Output <script type='text/javascript' src='http://mysite.local/wp-content/ themes/my-theme/ library/js/min/scripts.js?ver=1413837351'></script> … wp_enqueue_script( 'my-scripts', $script_file, array( 'jquery' ), filemtime( $script_file ), true ); … functions.php Output:
  • 36. The Power of Enqueue β€’ Allows other devs/plugins to modify styles/scripts as needed β€’ Allows you to tack things on to scripts/styles: – Inline styles wp_add_inline_style( 'my-styles', $custom_css ); – Style data (such as conditional IE wrappers) global $wp_styles; $wp_styles->add_data( 'my-ie-styles', 'conditional', 'lt IE 9' ); – Localize scripts wp_localize_script( 'my-scripts', 'greeting', 'Bonjour!' );
  • 37. Content Section Types β€’ Standard Content β€’ Sliders β€’ Tabbed content β€’ Testimonials β€’ Custom post type displays (news, resources, etc.) β€’ Other sections the design calls for
  • 38. Flexible Sections for Clients β€’ Add, remove, and change order β€’ Modify background color/image, headlines, description text, etc. β€’ Keep clients focused on their content – Useful defaults – Only show relevant items (conditional toggles) – Expect weird content (longer/shorter, larger/smaller than mockup) – Fill in the gaps for clients
  • 39. Creating Content Sections Each section type is a Flexible Content field set up in Advanced Custom Fields
  • 40. Template Parts Allow you to reuse chunks of code, and for child themes to replace sections as needed <?php get_template_part ( $slug, $name ); ?>
  • 41. Creating Template Parts page.php / post.php <?php get_template_part ( 'chunk' ); ?> my-theme chunk.php (2) my-theme-child chunk.php (1)
  • 42. Creating Template Parts page.php / post.php <?php get_template_part ( 'chunk', 'adunk' ); ?> my-theme chunk-adunk.php (2) chunk.php (4) my-theme-child chunk-adunk.php (1) chunk.php (3)
  • 43. Template Part for the Content Sections Content sections are contained in a template part: content-sections.php content-sections.php my-theme The content sections template part is included on desired page/post templates: page.php / post.php <?php get_template_part ('content-sections' ); ?>
  • 44. Displaying the Content Sections content-sections.php <?php if ( have_rows( 'sections' ) ): $section_id = 1; ?> <?php while ( have_rows('sections') ) : the_row(); ?> <?php $layout = get_row_layout(); ?> <section id="content-section-<?php echo $section_id; ?>" class="<?php echo $layout; ?>"> <?php if ( 'content' == $layout ): // default content section ?> <?php the_sub_field( 'content' ); ?> <?php endif; ?> </section> <?php $section_id++; endwhile; endif; ?>
  • 45. Customizing Content Sections Default Custom Background Color Custom Background Image
  • 46. Applying Custom Styles to Sections <?php if ( have_rows( 'sections' ) ): $content_sections_css = ''; $section_id = 1; while ( have_rows('sections') ) : the_row(); ?> $content_sections_css .= "#content-section-{$section_id} {"; $background = get_sub_field( 'background' ); if ( 'color' == $background ) { $background_color = get_sub_field( 'background_color' ); $content_sections_css .= "background-color: {$background_color};"; } $content_sections_css .= "}"; $section_id++; endwhile; wp_add_inline_style( 'my-styles', $content_sections_css ); endif; Loop through sections Content section selector Set styles Attach inline styles functions.php (in wp_enqueue_scripts function)
  • 47. Custom Section Styles Output The enqueued stylesheet from earlier that the inline styles are attached to <link rel='stylesheet' id='my-styles-css' href='http://mysite.local/wp-content/themes/my-theme/ library/css/style.css?ver=1414191171' type='text/css' media='all' /> <style type='text/css'> #content-section-1 { background-color: #cc0000; } </style> Inline styles output right after the attached stylesheet
  • 48. Part 1.1 The Appearance (Widgets)
  • 49. Widgets β€’ Use to display content that should appear on multiple posts/pages β€’ Can conditionally display widgets with plugins such as Display Widgets: https://wordpress.org/plugins/display-widgets/ β€’ Widget Boilerplate: https://github.com/tommcfarlin/WordPress- Widget-Boilerplate
  • 50. <?php add_action( 'widgets_init', 'my_register_sidebars' ); function my_register_sidebars() { register_sidebar( array( 'id' => 'sidebar', 'name' => __( 'Sidebar', 'bonestheme' ), 'description' => __( 'The main sidebar.', 'bonestheme' ), 'before_widget' => '<div id="%1$s" class="widget %2$s">', 'after_widget' => '</div>', 'before_title' => '<h4 class="widgettitle">', 'after_title' => '</h4>', )); ... } Creating Widget Areas (Sidebars) functions.php
  • 51. Displaying Widget Areas (Sidebars) sidebar.php <div id="sidebar" class="sidebar cf" role="complementary"> <?php if ( is_active_sidebar( 'sidebar' ) ) : ?> <?php dynamic_sidebar( 'sidebar' ); ?> <?php endif; ?> </div>
  • 52. Advanced Custom Fields in Widgets After creating your widget using the Widget Boilerplate:
  • 53. public function widget( $args, $instance ) { extract( $args ); echo $before_widget; ?> <section> <?php $content = get_field( 'content', 'widget_' . $widget_id ); echo do_shortcode( $content ); ?> </section> <?php echo $after_widget; } Displaying ACF Fields in Widgets Accessed through second argument which is the widget_id prefixed by "widget_"
  • 54. // widget sections $sidebars_widgets = wp_get_sidebars_widgets(); $widget_ids = array_merge( $sidebars_widgets['sidebar'] ); $widget_sections_css = ''; foreach( $widget_ids as $id ) { if ( $background_color = get_field( 'background_color', 'widget_' . $id ) ) { $widget_sections_css .= " #{$id} section { background-color: {$background_color}; }"; } } if ( !empty( $widget_sections_css ) ) { wp_add_inline_style( 'my-styles', $widget_sections_css ); } Custom Styles for Widget Fields functions.php (in wp_enqueue_scripts function)
  • 56. Hooks Hooks allow you to modify, extend, and enhance WordPress through an API in your themes and plugins. There are two flavors: β€’ Actions β€’ Filters
  • 57. Actions Triggered by specific events, typically used for executing functions. β€’ do_action() – Defines a hookable location β€’ add_action() – Attaches a function to a hook defined with do_action() β€’ has_action() – Checks if action exists β€’ remove_action()
  • 58. Default WordPress Actions β€’ wp_enqueue_scripts β€’ register_sidebar β€’ dynamic_sidebar β€’ wp_head β€’ get_header β€’ get_footer β€’ plugins_loaded β€’ And many more… http://codex.wordpress.org/Plugin_API/Action_Reference
  • 59. <?php ... <section id="content-section-<?php echo $section_id; ?>" class="<?php echo $layout; ?>"> <?php do_action( 'my_content_section_before', $layout ); ?> <?php if ( 'content' == $layout ): // default content section ?> <?php the_sub_field( 'content' ); ?> <?php endif; ?> <?php do_action('my_content_section_after', $layout ); ?> </section> ... Custom Action Setup content-sections.php
  • 60. Custom Action Usage functions.php <?php function my_extra_content( $layout ) { echo 'This Content Section uses the layout: ' . $layout; } add_action( 'my_content_section_before', 'my_extra_content' ); Output: This Content Section uses the layout: content { section content fields displayed here… }
  • 61. Filters Functions that data passes through, typically used to manipulate data. β€’ apply_filters() – Defines a hookable location β€’ add_filter() – Attaches a filter to a hook defined with apply_filters() β€’ has_filter() – Checks if filter exists β€’ Remove_filter()
  • 62. Default WordPress Filters β€’ the_excerpt β€’ the_content β€’ the_title β€’ wp_list_pages β€’ sanitize_title β€’ menu_order β€’ image_resize_dimensions β€’ And many more… http://codex.wordpress.org/Plugin_API/Filter_Reference
  • 63. Custom Filter Setup and Usage functions.php (or separate plugin) <?php $args = array( 'post_type' => 'locations', 'region' => 'USA', 'posts_per_page' => 5 ); $locations = new WP_Query( apply_filters( 'my_locations_query', $args ) ); Usage: <?php function my_new_locations_query( $args ) { $args['region'] = 'Canada'; return $args; } add_filter( 'my_locations_query', 'my_new_locations_query' );
  • 64. A WordPress Plugin wp-content plugins my-plugin plugin.php Ta-da…
  • 65. Plugin Setup plugin.php <?php /* * Plugin Name: My Plugin * Plugin URI: http://myplugin.mysite.com * Description: It’s my plugin, and I do what I want. * Version: 1.0 * Author: Me * Author URI: http://www.mysite.com * License: GPL2 * Text Domain: my-plugin */ Plugin Boilerplate: https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate
  • 66. Plugin Using Classes plugin.php <?php /* * Plugin Name: My Plugin * Plugin URI: http://myplugin.mysite.com * Description: It’s my plugin, and I do what I want. * Version: 1.0 * ... */ class MyPostType { public function __construct() { // custom post type add_action( 'init', array( $this, 'my_custom_post_type' ) ); } public function my_custom_post_type() { // my custom post type defined here } } $myPostType = new MyPostType();
  • 67. What theme components should be plugins? β€’ Shortcodes β€’ Custom Post Types β€’ Custom Taxonomies β€’ Custom Widgets Nestle users in the design, don’t trap them.
  • 68. Part 2.1 I18n (Internationalization)
  • 69. I18n (Internationalization) Making your themes / plugins translatable Standard strings: $hello = __( 'Hello there', 'my-text-domain' ); _e( 'This is echoed', 'my-text-domain' ); Singular / plural strings: _n( 'One potato', 'Many potatoes', $count, 'my-text-domain' ); Differentiating strings with similar names (setting the context): _x( 'Name', 'my context', 'my-text-domain' ); _ex( 'Echo name', 'my context', 'my-text-domain' );
  • 70. I18n with Variables Standard strings with a variable: $hello = sprintf( __( 'Hello there, %s', 'my-text-domain' ), 'Bob' ); // store in variable printf( __( 'Hello there, %s', 'my-text-domain' ), 'Bob' ); // or just output Singlular / plural strings with a variable: $potato = sprintf( _n('A lonely potato', 'Here are %d potatoes', $count, 'my-text-domain' ), $count ); // store in variable printf( _n('A lonely potato', 'Here are %d potatoes', $count, 'my-text-domain' ), $count ); // or just output
  • 71. Part 2.2 Security with Nonces
  • 72. Nonces β€’ Protect your themes/plugins against CSRF (Cross-Site Request Forgery), multiple/invalid submissions β€’ A.K.A. CSRF Tokens
  • 73. Adding Nonces to URLs wp_nonce_url( $actionurl, $action, $name ); Usage: $bare_url = 'http://example.com/wp-admin/ post.php?post=123&action=trash'; $complete_url = wp_nonce_url( $bare_url, 'trash-post_' . $post->ID, '_wpnonce' ); http://example.com/wp-admin/ post.php?post=123&action=trash&_wpnonce=b192fc4204 Output:
  • 74. Adding Nonces to Forms wp_nonce_field( $action, $name, $referer, $echo ); Usage: wp_nonce_field( 'delete-user_' . $user_id, '_wpnonce', true, true ); <input type="hidden" id="_wpnonce" name="_wpnonce" value="796c7766b1"> <input type="hidden" name="_wp_http_referer" value="/wp-admin/ edit-user.php"> Output:
  • 75. Adding Nonces Anywhere wp_create_nonce( $action ); Usage: wp_create_nonce( 'my-nonce' ); Value: 295a686963
  • 76. Verifying Nonces From Form / URL: check_admin_referer( 'delete-user_' . $user_id ); From some other context: wp_verify_nonce( 'delete-user_' . $user_id ); From AJAX: check_ajax_referer( 'get-users' );
  • 77. Part 2.3 Using AJAX in Plugins
  • 78. add_action( 'wp_ajax_myfunc', 'prefix_ajax_myfunc' ); add_action( 'wp_ajax_nopriv_myfunc', 'prefix_ajax_myfunc' ); function prefix_ajax_myfunc() { check_ajax_referer( 'my-nonce', 'security' ); echo $_POST['foo']; die(); } AJAX: The Setup functions.php (or separate plugin)
  • 79. AJAX: The Nonce functions.php (or separate plugin, in wp_enqueue_scripts function) <?php // Set Your Nonce $ajax_nonce = wp_create_nonce( "my-nonce" ); wp_localize_script( 'my-scripts', 'ajaxNonce', $ajax_nonce );
  • 80. AJAX: The Usage scripts.js jQuery(document).ready(function($) { var data = { action: 'myfunc', security: ajaxNonce, foo: 'Hello World!' }; $.post(ajaxurl, data, function(response) { alert("Response: " + response); }); });
  • 81. Part 3 Tips and Tricks
  • 82. Protecting Email Addresses <?php antispambot( $emailaddy, $hex_encoding ) ?> Usage: <?php echo antispambot( 'test.mctest@mysite.com' ); ?> Result: &#106;&#111;h&#110;&#46;&#100;&#111;&#101;&#64;mysit&#101;.&#99;&#111;&#109; Browser sees: test.mctest@mysite.com
  • 83. Quickstarts for Custom Components http://generatewp.com/
  • 84. Custom ACF Color Picker Swatches Customize swatches based on design / theme colors: These things
  • 85. Custom ACF Color Picker Swatches functions.php function acf_custom_config() { global $parent_file; if ( strpos($parent_file, 'post-new.php') !== FALSE || strpos($parent_file, 'edit.php') !== FALSE ) { echo " <script> jQuery(document).ready(function($){ if ($('.acf-color_picker').length) { $('.acf-color_picker').iris({ palettes: ['#f60', '#ffa839', '#3078bf', '#e0ebf5', '#58585a', '#2e3137'], change: function(event, ui) { $(this).parents('.wp-picker-container').find('.wp-color-result'). css('background-color', ui.color.toString()); } }); } }); </script> "; } } add_action( 'in_admin_footer', 'acf_custom_config' );
  • 86. Make Admin Listings Relevant Use the Admin Columns Pro plugin to clean up the post listing pages: β€’ Show relevant columns for post types, hide unnecessary columns β€’ Allow client to edit items in the listing (inline edits) β€’ Display ACF PRO fields as well
  • 87. Thank You! If you ever had any questions or wanted to chat: kyle@ractoon.com

Editor's Notes

  • #3: In 2002 I thought I’d finally found something compact and lightweight that made sense to me. The popularity wasn’t as high as it is now, but that wasn’t a big deal to me. Then in 2007 I started working with WordPress and had similar feelings.
  • #5: Here we go. You signed up for the whole seat this evening, but you’re only going to need the edge.
  • #6: Now you’re probably going to need the rest of your seat. Go ahead and get comfortable, and please ask any questions that come to mind.
  • #7: From scratch you’ve got the theme started already if you follow the previous slide.
  • #9: Typically files in the child theme will override those of the parent, but functions.php is a special case – it does not override. The benefit of using wp_enqueue_style() over @import is that enqueued stylesheets are all referenced from the HTML output to the browser, whereas an @import statement is referenced from the main stylesheet, which is an extra step before the browser knows where to look next.
  • #15: Not well suited for layouts, easy to mistype a tag, forget a closing tag, or lose track especially if a large amount of shortcodes are used.
  • #17: This is due to wpautop(Β $foo,Β $brΒ ) which adds paragraphs for double line breaks, an <br> for single (second argument). Can disable the filter entirely remove_filter( 'the_content', 'wpautop' ); remove_filter( 'the_excerpt', 'wpautop' );
  • #18: Use get_post_meta() function to display the values.
  • #20: What’s up with setting that $prefix? Attempts to ensure the fields are unique, and the underscore hides it from display in the Custom Fields metabox.
  • #25: acf-json folder in themes
  • #31: Duplicate style.css? The default theme style.css is a placeholder to make WordPress happy and list the theme. Bones uses enqueueing to load styles, which allows us to do cool stuff later with inline styles.
  • #32: If you haven’t had the pleasure of working with CSS preprocessors I’d highly recommend it, they are quite choice as Ferris Bueller would say.
  • #33: Register can be used in any hook, enqueue should only be used on wp_enqueue_scripts or admin_enqueue_scripts hook. Filemtime to automatically version stylesheet. get_template_directory_uri() vs. get_stylesheet_directory_uri()
  • #35: Register can be used in any hook, enqueue should only be used on wp_enqueue_scripts or admin_enqueue_scripts hook. Filemtime to automatically version stylesheet. get_template_directory_uri() vs. get_stylesheet_directory_uri()
  • #37: Banner section uses wp_localize_script to define the image since we’re using the backstretch plugin in that section.
  • #39: Example of slideshow, if only one image is set, centering content within containers, sizing images appropriately in containers (using custom WordPress thumbnail sizes), etc. Goldilocks syndrome, they’ll upload things that are too big or small, your job to make them just right.
  • #41: $slug for the generic template, $name for the specialized template
  • #45: Add content sections as needed
  • #56: We covered quite a bit so I’m going to let that marinate for a minute while I get a quick drink. Were there any questions at all?
  • #57: Why bother with hooks? If modifying plugin/core behavior your changes are preserved, don’t have to worry about breaking randomly in the future.
  • #58: Events like publishing a post, changing themes, activating/deactivating plugins
  • #60: Now tags or content can be inserted before and after content section content
  • #61: Now tags or content can be inserted before and after content section content
  • #64: Region is custom taxonomy
  • #66: Common myth – a lot of plugins slows down your site. More a factor of what the plugins do: loading lots of scripts/styles, extra database queries, expensive operations (fulltext searches), remote requests, etc.
  • #67: Use classes to avoid naming collisions, requires some slight tweaks to hooks though. Need to pass and array where the first item references the object, second item is method name within the class.
  • #69: We covered quite a bit so I’m going to let that marinate for a minute while I get a quick drink. Were there any questions at all?
  • #70: You can then run your files through a service such as http://www.icanlocalize.com/tools/php_scanner to create translation files (.po). Then can run through something like Poedit to translate individual strings and compile into .mo files
  • #72: We covered quite a bit so I’m going to let that marinate for a minute while I get a quick drink. Were there any questions at all?
  • #73: If anyone attempts to modify the URL or data with a nonce it fails with a 403 Forbidden response. https://www.getpantheon.com/blog/nonce-upon-time-wordpress
  • #74: $action – nonce action name (optional), $name – nonce name, default β€˜_wpnonce’
  • #78: We covered quite a bit so I’m going to let that marinate for a minute while I get a quick drink. Were there any questions at all?
  • #79: Need _nopriv if it needs to be accessible on the front-end. By adding exit() or die() after returning your desired content prevents the default response from admin-ajax.php - usually zero (0) - being returned as well. Can also use the WP_Ajax_Response class to generate XML responses.
  • #83: Use 0 to only allow decimal encoding (&#123;) and 1 to also allow hex encoding (&x7B;). Default: 0