wordpress development paradigms, idiosyncrasies and other big words

Post on 27-Jan-2015

117 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

For seasoned developers approaching WordPress customization or development for the first time the biggest challenge is often not learning the API and method calls: it's grasping the idiosyncrasies of the WordPress framework. In this 45-minute presentation aimed at web coders who are interested in diving into WordPress customization and development, you will learn the key idioms that will accelerate your learning curve and help you approach the framework from a best practices perspective: template hierarchies, themes and child themes, taxonomies, filters and action hooks, execution order and other need-to-know concepts will be presented as well as tips on what the most active online developer communities are and the best places to go for quick (free) help and advice.

TRANSCRIPT

WordPress Development Paradigms, Idiosyncrasies

and Other Big Words

Tom Auger, Zeitguys inc.

WordCamp Montreal, 2011

Introduction

• About me:– Developer of standalone RIAs and large-scale

server-side systems– Siebel integrator and database admin– Perl, PHP, JavaScript, ActionScript 3, SQL,

Python, Java, etc.

– Very much a “DIY Guy”

Surprising Learning Curve

• Lots of files!

• Confusing themes!

• Arcane symbols!– sprintf(__('Something %s', 'domain'), 'weird');

• Hooks everywhere!– add_action('init', 'obscure_func');– $var = apply_filters('obscure_filter');

• Oh my!

The biggest challenge...

• was learning what the topics were that I needed to learn about:– themes, templates, template parts and child themes– database access and the WP_Query in all its

instances– action and filter hooks– WordPress object types: posts, taxonomies and meta

data– i18n (l10n) – where to get reliable, high-level information and help

Meh.

• Let's just go skunkworks.

• I'm a seasoned dev after all...

DIY Approach = Low Level

• Direct database access

• In-place editing of plugin files

• Forking theme files

• In-place (gasp) editing of core files

• Brute force JavaScript injection

• Rolling your own sanitization and security measures

The Bad News

• Unsustainable, fragile to updates

• Non-scalable and highly one-off

• Big security gaps

• Missing out on built-in value-add intelligence

• Re-inventing the wheel

Example: Adding <p> to content

• The starting code:

$posts = get_posts(array(

'post_type' => 'my-custom-type'

));

foreach($posts as $post){

echo '<div>';

echo $post->post_content;

echo '<div>';

}

Option 1: Manually Wrap

• Wait... what about multiple paragraphs? or enclosing block tags?

$posts = get_posts(array(

'post_type' => 'my-custom-type'

));

foreach($posts as $post){

echo '<div>';

echo '<p>'.$post->post_content.'</p>;

echo '<div>';

}

Option 1b: RegEx

• Wheel, meet Tom. Tom, meet Wheel.

$blockElements = implode("|", array('ADDRESS','BLOCKQUOTE','CENTER','DIR','DIV','DL', etc...);

$added_p = preg_replace(

'/(?:\s*<('.$blockElements.')(?:\s+[^>]+\s*)*>\s*(.+?)\s*<\/\1>(?:\r|\n|$)*)|(?:\s*(.+?)\s*(?:\r|\n|$|(?=<(?:'.$blockElements.')>))+)/is','<p$1>$2$3<\/p\1>\n', $post->post_content);

But wait... doesn't WP already do this?

• wpautop(), defined in formatting.php handles all the logic and edge cases

foreach($posts as $post){

echo '<div>';

echo wpautop($post->post_content);

echo '<div>';

}

So what about the_content()?

• Let's exploit those globals and template tags

foreach($posts as $post){

setup_postdata($post);

echo '<div>';

the_content();

echo '<div>';

}

wp_reset_postdata();

So how does the_content() do it?

• IDE – site-wide search (or use phpxref or WPSeek)

• In post-template.php:

function the_content($more_link_text = null, $stripteaser = 0) {$content = get_the_content($more_link_text, $stripteaser);$content = apply_filters('the_content', $content);$content = str_replace(']]>', ']]&gt;', $content);echo $content;

}

Keep following the White Rabbit

• Search for "the_content" within default-filters.php• It runs the following functions:

– capital_P_dangit– wptexturize– convert_smilies– convert_chars– wpautop– shortcode_unautop– prepend_attachment

• That's a lot of value add!

I want all that other good stuff, too!

• Leverage all those the_content methods

foreach($posts as $post){

echo '<div>';

echo apply_filters(

'the_content',

$page->post_content);

echo '<div>';

}

The lesson thus far

• TMTOWTDI, but not all ways are equal

• Use the method that:– is the most abstracted (high level)– requires the least amount of additional code– encapsulates the most value-added

intelligence

“Whenever you're going to write a code block that seems to be quite generic and common, check first if there's a WP function that can do it for you.” – Ozh Richard, de facto WP Plugin expert

Big Words

• Paradigm: a model or pattern that defines a way of thinking or working with a tool

• Idiosyncrasy: an unusual, distinctive and recognizable trait or pattern

• Idiom: a form of expression, natural to a language or context

WordPress Paradigms and Patterns

• Plugins

• Templates

• Hooks

• Post Types and Taxonomies

WordPress Idioms

• The Loop and the Query

• Template tags (and get_)

WordPress Idiosyncrasies

• $wpdb

• wp_enqueue_script()

• No TIME!! (part deux?)– wp_kses(), esc_attr()– body_class(), post_class(), comment_class()

Paradigm: Plugins

• Often confused with Widgets• Nothing more than a distributableway to

inject code at the start of the loading / execution cycle

• Not to be confused with pluggable functions

<?php /*Plugin Name: Name Of The Plugin*/?>

Paradigm:Themes and Templates

Themes

• Control visual look-and-feel of a site

• Require at minimum only index.php and style.css

• But wait, there's more, with functions.php:– Widgets– Admin options– Changes to core behaviour

Child Themes

• Best way to customize a theme for a specific client application

• Clever overloading scheme

• Leverage existing intelligence

%> wp-content/themes/my-child-theme/style.css/*Theme Name: Twenty Ten Child ThemeTemplate: twentyten*/

@import url('../twentyten/style.css');

Template Files

• PHP files, loaded contextually based on Query string

• Overloaded using a strict Template Hierarchy

• Follows conditional hierarchy

Template Parts

• Breaks down template hierarchy to custom level of granularity

• Code reuse design pattern• Allows multiple templates to share

sections

• Eg: events-by-date.php, events-by-category.php, all-events.php

• Note: local vars lose scope (uses "get")include(locate_template('template-part'));

get_template_part('template', 'part');

Page Templates

• Templates that can be admin-applied to Pages (not posts)

<?php/*Template Name: 3 Column*/?>

Post Formats

• Standardized contributor-assignable taxonomy for posts

• Meant to be consistent across all blogs

• aside, chat, gallery, link, image, quote, status, video, audio

<?php get_template_part( 'format', get_post_format());?>

Paradigm:Hooks, Actions and Filters

“WordPress action hooks are a means of providing a way for other developers to insert their own code in specific locations within your code, in order to change or expand the functionality of your code.” – Nathan Rice

http://www.nathanrice.net/blog/an-introduction-to-wordpress-action-hooks/

Hooks

• Spiritually related to GoF's Template Method Design Pattern

• Alternative extension method to subclassing

• Developers create hooks wherever they think other devs may wish to extend their code

• Documented under PluginAPI, but you will encounter them sooner than that

Actions vs. Filters

• Actions inject code into a workflow

• Filters take a variable, modify it and return the same type

// set up action hookdo_action('hook-name');

// set up filter hook$variable = apply_filters('filter-name',

$variable);

Leveraging Action Hooks

• Use an action hook to do something at a specific point in the execution cycle

• Multiple sources can register for a single action hook

add_action('init', 'stuff_to_do_at_init');

General Execution Order

• muplugins_loaded• plugins_loaded• sanitize_comment_cookies• setup_theme• load_textdomain• after_setup_theme• auth_cookie_malformed• set_current_user• init• widgets_init• register_sidebar• wp_register_sidebar_widget• wp_loaded• parse_request*• send_headers*• parse_query*• pre_get_posts*• posts_selection• wp*

• template_redirect• get_header• wp_head• wp_enqueue_scripts• wp_print_styles• wp_print_scripts• get_template_part_loop• loop_start*• the_post*• loop_end*• get_sidebar• dynamic_sidebar• get_search_form• wp_meta• get_footer• twentyten_credits• wp_footer• wp_print_footer_scripts• shutdown

http://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_a_Typical_Request

Action examples

add_action('init', 'register_my_custom_post');

add_action('init', 'register_my_custom_taxonomy');

add_action('widgets_init', 'register_my_widget');

add_action('wp_enqueue_scripts', 'add_my_js_libs');

add_action('save_post', 'save_my_custom_meta');

Leveraging Filter Hooks

• Use a filter hook to modify output or an internal variable

add_filter('the_content', 'change_content');

function change_content($content){$content = 'All your base are belong to us!!!';return $content;

}

Priority and Parameters

• add_filter can take two additional arguments: $priority and $num_args

add_filter('contextual_help', 'my_help', 10, 3);

function my_help($text, $screen_id, $screen){if ($screen_id == 'edit-my_custom_post_type'){

$text = '<p>You are on your own pal</p>';}return $text;

}

Filter Examples

add_filter( 'excerpt_more', 'custom_more' );

add_filter( 'excerpt_length', 'my_length', 999 );function my_length($length){

return 6; // six is average, right?}

Existing Filters and Actions

• WordPress already registers filters and actions

• Find them in wp-includes/default-filters.php

• remove_filter($tag, $function, $priority)

• remove_action() is an alias

So How Do I Find Them?

• Partial lists in the codex:– codex.wordpress.org/Plugin_API/Filter_Reference

– codex.wordpress.org/Plugin_API/Action_Reference • Use a good IDE like Eclipse/PHP, Aptana,

NetBeans, PHPStorm etc... and search for:– do_action(), and do_action_ref_array()– apply_filters(), and apply_filters_ref_array()

• http://adambrown.info/p/wp_hooks

Good Citizenship

• Add your own action and filter hooks wherever it may be appropriate:– things a dev may wish to override but you

don't want to expose to an Admin user– default values (max/min limits etc)– logical spots for extension

• Example: zg-event-query (filter)

• For the love of Pete, document it!

Idiom:The Loop and The Query

Getting Your Content: "The Loop"

• One "The Loop" per page

• Sets globals (eg: $post)

• Drives all template tags (eg: the_content())

• Driven by "the query": the request string

• Affects conditional tags

• Can be supplanted by query_posts()

Secondary Loops

• Used in widgets and sidebars, sub-content and related content

• Must be careful not to clobber globals and affect the main Loop

• Leverage get_posts() or get_pages() for inobtrusive secondary loops

• Or get dirty with WP_Query class• Either way, be sure to read Codex WP_Query

Suspicious Stuff

• Leverage template tags in secondary loops by:– using the_post() method on WP_Query

instance– or setup_postdata() on a $post object

$the_query = new WP_Query( $args );while ( $the_query->have_posts() ){ $the_query->the_post();

the_title();}wp_reset_postdata();

Template Tags and get_

• Template tags– Used exclusively within The Loop– Always echo their results– Rarely (?) take arguments (always working on

the global $post object)

• get_– Most template tags have a get_ equivalent– Does not echo result– Usually takes the ID of a post as argument

Template Tag vs. get_

• Use Template Tag when:– you're in The Loop!

• Use get_ when:– you want the value, not the echo– you're not in The Loop– you are in the loop but want a related item

(eg: attachment)

Idiosyncrasy:$wpdb

wpdb Class

• Instantiated once and globalized in $wpdb

• Provides API to low-level DB calls– $wpdb->query()– $wpdb->get_results()– $wpdb->get_var()

Example: Events

• Custom post type "event"

• Categorized by taxonomy "event-type"

• Event start_date stored in meta

• Let's select: all 'speaking' events with a start date of '2011-07-09'

Pure SQLselect * from wp_postsjoin wp_term_relationships

on ID = object_idjoin wp_term_taxonomy

on wp_term_taxonomy.term_taxonomy_id =wp_term_relationships.term_taxonomy_idand taxonomy = 'event-type'

join wp_termson wp_term_taxonomy.term_id =wp_terms.term_idand wp_terms.slug = 'speaking'

join wp_postmetaon wp_postmeta.post_id = IDand meta_key = 'event-date'and meta_value = '2011-07-09'

wherepost_type = 'event'and post_status = 'published'

More Properer SQLselect * from wp_posts as Pjoin wp_term_relationships TR_EVENT

on P.ID = TR_EVENT.object_idjoin wp_term_taxonomy TT_EVENT

on TT_EVENT.term_taxonomy_id =TR_EVENT.term_taxonomy_id

TT_EVENT.taxonomy = 'event-type'join wp_terms T_EVENT

on TT_EVENT.term_id = T_EVENT.term_idand T_EVENT.slug = 'speaking'

join wp_postmeta M_DATEon M_DATE.post_id = P.IDand M_DATE.meta_key = 'event-date'and M_DATE.meta_value = '2011-07-09'

whereP.post_type = 'event'and P.post_status = 'published'

Don't Use Table Names!select * from {$wpdb->posts} Pjoin {$wpdb->term_relationships} TR_EVENT

on P.ID = TR_EVENT.object_idjoin {$wpdb->term_taxonomy} TT_EVENT

on TT_EVENT.term_taxonomy_id =TR_EVENT.term_taxonomy_id

TT_EVENT.taxonomy = 'event-type'join {$wpdb->terms} T_EVENT

on TT_EVENT.term_id =T_EVENT.term_idand T_EVENT.slug = 'speaking'

join {$wpdb->postmeta} M_DATEon M_DATE.post_id = P.IDand M_DATE.meta_key = 'event-date'and M_DATE.meta_value = '2011-07-09'

whereP.post_type = 'event'and P.post_status = 'published'

More Saferer Query$wpdb->prepare("select * from {$wpdb->posts} Pjoin {$wpdb->term_relationships} TR_EVENT

on P.ID = TR_EVENT.object_idjoin {$wpdb->term_taxonomy} TT_EVENT

on TT_EVENT.term_taxonomy_id =TR_EVENT.term_taxonomy_id

TT_EVENT.taxonomy = 'event-type'join {$wpdb->terms} T_EVENT

on TT_EVENT.term_id =T_EVENT.term_idand T_EVENT.slug = %s

join {$wpdb->postmeta} M_DATEon M_DATE.post_id = P.IDand M_DATE.meta_key = 'event-date'and M_DATE.meta_value = %s

whereP.post_type = 'event'and P.post_status = 'published'",

'speaking', '2011-07-09');

But, Whenever We Can...

get_posts(array('post_type' => 'event','tax_query' => array(array(

'taxonomy' => 'event-type','field' => 'slug''terms' => 'speaking'

)),'meta_query' => array(array(

'key' => 'event-date','value' => $todays_date

))));

Use Built-Ins Whenever You Can

• Take advantage of cacheing and optimization

• Future-proof code

• Chances are, there's a function or method to do what you want– Look in Codex under WP_Query– Look in source under query.php, post.php,

category.php, taxonomy.php

Idiosyncrasy:wp_enqueue_script

We Love jQuery

• (Don't)– Jump into header.php– Add <script src="my-jquery-min.js"></script>

• (Don't)– add_action('wp_head', 'add_my_jquery');

Enqueue = The Canadian Way, eh?

• DO

add_action('wp_enqueue_scripts', 'add_my_scripts');function add_my_scripts(){

wp_enqueue_scripts('jquery-ui-core',get_stylesheet_directory_uri() .

'/script',array('jquery'),'1.8.14',false // in-header

);}

add_action('admin_enqueue_scripts', 'add_admin_scripts'); // careful here...

No One Likes Conflict

• jQuery runs in "no-conflict" mode...

jQuery(document).ready(function($) { $('#mydiv').css({color:'red', border:'2px solid red'});});

(function($) {var test = "hello, world!";function testMe(){

alert(test);}$(document).ready(testMe);

})(jQuery);

Resources and Forums

• Documentation:– Codex (of course)– Google: "wordpress add_action"– Adam Brown– WPSeek, phpxref– Your own IDE

• Help:– wordpress.org/support (yeah, not really...)– www.experts-exchange.com

• http://www.experts-exchange.com/Web_Development/Blogs/WordPress/

– wordpress.stackexchange.com

Thanks!

www.tomauger.com

www.zeitguys.com

@TomAuger

Other Stuff for more time

Paradigm:Post Types and Taxonomies

Posts

• Posts are the atomic element for all WordPress content – "actual" posts– pages– comments– attachments– drafts and revisions– custom post types

Taxonomies

• Taxonomies are the relational device that group posts together.– categories, – tags, – nav menus– post formats?– custom taxonomies

• Groupings that are shared by different items

What About Meta?

• Use meta for discrete, non-grouping data, unique to the content item (eg: price)

• Sortables (eg: year)

• Groups that are not meaningfully shared (eg: Otto's TV show seasons across different shows)

Custom Post vs. Custom Tax

• Use Custom Post for content that:– should not appear in your feed– represents a distinct type of "content"– is always associated with a set of metadata– may require a customized input form– needs a separate capability / access– needs its own private taxonomy

• Examples: products, events, albums

Custom Post vs. Custom Tax

• Use a custom taxonomy when:– You want additional ways to group items

together– You want a way to filter out a set of items– You want a new metabox

• Eg: colour, software posts, manufacturers

top related