WordPress development paradigms, idiosyncrasies and other big words


Published on

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.

Published in: Technology, Business
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

WordPress development paradigms, idiosyncrasies and other big words

  1. 1. WordPress Development Paradigms, Idiosyncrasies and Other Big Words Tom Auger, Zeitguys inc. WordCamp Montreal, 2011
  2. 2. Introduction <ul><li>About me: </li></ul><ul><ul><li>Developer of standalone RIAs and large-scale server-side systems </li></ul></ul><ul><ul><li>Siebel integrator and database admin </li></ul></ul><ul><ul><li>Perl, PHP, JavaScript, ActionScript 3, SQL, Python, Java, etc. </li></ul></ul><ul><ul><li>Very much a “DIY Guy” </li></ul></ul>
  3. 3. Surprising Learning Curve <ul><li>Lots of files! </li></ul><ul><li>Confusing themes! </li></ul><ul><li>Arcane symbols! </li></ul><ul><ul><li>sprintf(__('Something %s', 'domain'), 'weird'); </li></ul></ul><ul><li>Hooks everywhere! </li></ul><ul><ul><li>add_action('init', 'obscure_func'); </li></ul></ul><ul><ul><li>$var = apply_filters('obscure_filter'); </li></ul></ul><ul><li>Oh my! </li></ul>
  4. 4. The biggest challenge... <ul><li>was learning what the topics were that I needed to learn about: </li></ul><ul><ul><li>themes, templates, template parts and child themes </li></ul></ul><ul><ul><li>database access and the WP_Query in all its instances </li></ul></ul><ul><ul><li>action and filter hooks </li></ul></ul><ul><ul><li>WordPress object types: posts, taxonomies and meta data </li></ul></ul><ul><ul><li>i18n (l10n) </li></ul></ul><ul><ul><li>where to get reliable, high-level information and help </li></ul></ul>
  5. 5. Meh. <ul><li>Let's just go skunkworks. </li></ul><ul><li>I'm a seasoned dev after all... </li></ul>
  6. 6. DIY Approach = Low Level <ul><li>Direct database access </li></ul><ul><li>In-place editing of plugin files </li></ul><ul><li>Forking theme files </li></ul><ul><li>In-place (gasp) editing of core files </li></ul><ul><li>Brute force JavaScript injection </li></ul><ul><li>Rolling your own sanitization and security measures </li></ul>
  7. 7. The Bad News <ul><li>Unsustainable, fragile to updates </li></ul><ul><li>Non-scalable and highly one-off </li></ul><ul><li>Big security gaps </li></ul><ul><li>Missing out on built-in value-add intelligence </li></ul><ul><li>Re-inventing the wheel </li></ul>
  8. 8. Example: Adding <p> to content <ul><li>The starting code: </li></ul>$posts = get_posts(array( 'post_type' => 'my-custom-type' )); foreach($posts as $post){ echo '<div>'; echo $post->post_content; echo '<div>'; }
  9. 9. Option 1: Manually Wrap <ul><li>Wait... what about multiple paragraphs? or enclosing block tags? </li></ul>$posts = get_posts(array( 'post_type' => 'my-custom-type' )); foreach($posts as $post){ echo '<div>'; echo '<p>'.$post->post_content.'</p>; echo '<div>'; }
  10. 10. Option 1b: RegEx <ul><li>Wheel, meet Tom. Tom, meet Wheel. </li></ul>$blockElements = implode(&quot;|&quot;, 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</p1>n', $post->post_content);
  11. 11. But wait... doesn't WP already do this? <ul><li>wpautop(), defined in formatting.php handles all the logic and edge cases </li></ul>foreach($posts as $post){ echo '<div>'; echo wpautop($post->post_content); echo '<div>'; }
  12. 12. So what about the_content()? <ul><li>Let's exploit those globals and template tags </li></ul>foreach($posts as $post){ setup_postdata($post); echo '<div>'; the_content(); echo '<div>'; } wp_reset_postdata();
  13. 13. So how does the_content() do it? <ul><li>IDE – site-wide search (or use phpxref or WPSeek) </li></ul><ul><li>In post-template.php: </li></ul>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; }
  14. 14. Keep following the White Rabbit <ul><li>Search for &quot;the_content&quot; within default-filters.php </li></ul><ul><li>It runs the following functions: </li></ul><ul><ul><li>capital_P_dangit </li></ul></ul><ul><ul><li>wptexturize </li></ul></ul><ul><ul><li>convert_smilies </li></ul></ul><ul><ul><li>convert_chars </li></ul></ul><ul><ul><li>wpautop </li></ul></ul><ul><ul><li>shortcode_unautop </li></ul></ul><ul><ul><li>prepend_attachment </li></ul></ul><ul><li>That's a lot of value add! </li></ul>
  15. 15. I want all that other good stuff, too! <ul><li>Leverage all those the_content methods </li></ul>foreach($posts as $post){ echo '<div>'; echo apply_filters( 'the_content', $page->post_content ); echo '<div>'; }
  16. 16. The lesson thus far <ul><li>TMTOWTDI, but not all ways are equal </li></ul><ul><li>Use the method that: </li></ul><ul><ul><li>is the most abstracted (high level) </li></ul></ul><ul><ul><li>requires the least amount of additional code </li></ul></ul><ul><ul><li>encapsulates the most value-added intelligence </li></ul></ul>
  17. 17. <ul><li>“ 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 </li></ul>
  18. 18. Big Words <ul><li>Paradigm: a model or pattern that defines a way of thinking or working with a tool </li></ul><ul><li>Idiosyncrasy: an unusual, distinctive and recognizable trait or pattern </li></ul><ul><li>Idiom: a form of expression, natural to a language or context </li></ul>
  19. 19. WordPress Paradigms and Patterns <ul><li>Plugins </li></ul><ul><li>Templates </li></ul><ul><li>Hooks </li></ul><ul><li>Post Types and Taxonomies </li></ul>
  20. 20. WordPress Idioms <ul><li>The Loop and the Query </li></ul><ul><li>Template tags (and get_) </li></ul>
  21. 21. WordPress Idiosyncrasies <ul><li>$wpdb </li></ul><ul><li>wp_enqueue_script() </li></ul><ul><li>No TIME!! (part deux?) </li></ul><ul><ul><li>wp_kses(), esc_attr() </li></ul></ul><ul><ul><li>body_class(), post_class(), comment_class() </li></ul></ul>
  22. 22. Paradigm: Plugins <ul><li>Often confused with Widgets </li></ul><ul><li>Nothing more than a distributableway to inject code at the start of the loading / execution cycle </li></ul><ul><li>Not to be confused with pluggable functions </li></ul><?php /* Plugin Name: Name Of The Plugin */ ?>
  23. 23. Paradigm: Themes and Templates
  24. 24. Themes <ul><li>Control visual look-and-feel of a site </li></ul><ul><li>Require at minimum only index.php and style.css </li></ul><ul><li>But wait, there's more, with functions.php: </li></ul><ul><ul><li>Widgets </li></ul></ul><ul><ul><li>Admin options </li></ul></ul><ul><ul><li>Changes to core behaviour </li></ul></ul>
  25. 25. Child Themes <ul><li>Best way to customize a theme for a specific client application </li></ul><ul><li>Clever overloading scheme </li></ul><ul><li>Leverage existing intelligence </li></ul>%> wp-content/themes/my-child-theme/style.css /* Theme Name: Twenty Ten Child Theme Template: twentyten */ @import url('../twentyten/style.css');
  26. 26. Template Files <ul><li>PHP files, loaded contextually based on Query string </li></ul><ul><li>Overloaded using a strict Template Hierarchy </li></ul><ul><li>Follows conditional hierarchy </li></ul>
  27. 28. Template Parts <ul><li>Breaks down template hierarchy to custom level of granularity </li></ul><ul><li>Code reuse design pattern </li></ul><ul><li>Allows multiple templates to share sections </li></ul><ul><li>Eg: events-by-date.php, events-by-category.php, all-events.php </li></ul><ul><li>Note: local vars lose scope (uses &quot;get&quot;) </li></ul>include(locate_template('template-part')); get_template_part('template', 'part');
  28. 29. Page Templates <ul><li>Templates that can be admin-applied to Pages (not posts) </li></ul><?php /* Template Name: 3 Column */ ?>
  29. 30. Post Formats <ul><li>Standardized contributor-assignable taxonomy for posts </li></ul><ul><li>Meant to be consistent across all blogs </li></ul><ul><li>aside, chat, gallery, link, image, quote, status, video, audio </li></ul><?php get_template_part( 'format', get_post_format()); ?>
  30. 31. Paradigm: Hooks, Actions and Filters
  31. 32. <ul><li>“ 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 </li></ul><ul><li>http://www.nathanrice.net/blog/an-introduction-to-wordpress-action-hooks/ </li></ul>
  32. 33. Hooks <ul><li>Spiritually related to GoF's Template Method Design Pattern </li></ul><ul><li>Alternative extension method to subclassing </li></ul><ul><li>Developers create hooks wherever they think other devs may wish to extend their code </li></ul><ul><li>Documented under PluginAPI, but you will encounter them sooner than that </li></ul>
  33. 34. Actions vs. Filters <ul><li>Actions inject code into a workflow </li></ul><ul><li>Filters take a variable, modify it and return the same type </li></ul>// set up action hook do_action('hook-name'); // set up filter hook $variable = apply_filters('filter-name', $variable);
  34. 35. Leveraging Action Hooks <ul><li>Use an action hook to do something at a specific point in the execution cycle </li></ul><ul><li>Multiple sources can register for a single action hook </li></ul>add_action('init', 'stuff_to_do_at_init');
  35. 36. General Execution Order <ul><li>muplugins_loaded </li></ul><ul><li>plugins_loaded </li></ul><ul><li>sanitize_comment_cookies </li></ul><ul><li>setup_theme </li></ul><ul><li>load_textdomain </li></ul><ul><li>after_setup_theme </li></ul><ul><li>auth_cookie_malformed </li></ul><ul><li>set_current_user </li></ul><ul><li>init </li></ul><ul><li>widgets_init </li></ul><ul><li>register_sidebar </li></ul><ul><li>wp_register_sidebar_widget </li></ul><ul><li>wp_loaded </li></ul><ul><li>parse_request* </li></ul><ul><li>send_headers* </li></ul><ul><li>parse_query* </li></ul><ul><li>pre_get_posts* </li></ul><ul><li>posts_selection </li></ul><ul><li>wp* </li></ul><ul><li>template_redirect </li></ul><ul><li>get_header </li></ul><ul><li>wp_head </li></ul><ul><li>wp_enqueue_scripts </li></ul><ul><li>wp_print_styles </li></ul><ul><li>wp_print_scripts </li></ul><ul><li>get_template_part_loop </li></ul><ul><li>loop_start* </li></ul><ul><li>the_post* </li></ul><ul><li>loop_end* </li></ul><ul><li>get_sidebar </li></ul><ul><li>dynamic_sidebar </li></ul><ul><li>get_search_form </li></ul><ul><li>wp_meta </li></ul><ul><li>get_footer </li></ul><ul><li>twentyten_credits </li></ul><ul><li>wp_footer </li></ul><ul><li>wp_print_footer_scripts </li></ul><ul><li>shutdown </li></ul>http://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_a_Typical_Request
  36. 37. 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');
  37. 38. Leveraging Filter Hooks <ul><li>Use a filter hook to modify output or an internal variable </li></ul>add_filter('the_content', 'change_content'); function change_content($content){ $content = 'All your base are belong to us!!!'; return $content; }
  38. 39. Priority and Parameters <ul><li>add_filter can take two additional arguments: $priority and $num_args </li></ul>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; }
  39. 40. 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? }
  40. 41. Existing Filters and Actions <ul><li>WordPress already registers filters and actions </li></ul><ul><li>Find them in wp-includes/default-filters.php </li></ul><ul><li>remove_filter($tag, $function, $priority) </li></ul><ul><li>remove_action() is an alias </li></ul>
  41. 42. So How Do I Find Them? <ul><li>Partial lists in the codex: </li></ul><ul><ul><li>codex.wordpress.org/Plugin_API/Filter_Reference </li></ul></ul><ul><ul><li>codex.wordpress.org/Plugin_API/Action_Reference </li></ul></ul><ul><li>Use a good IDE like Eclipse/PHP, Aptana, NetBeans, PHPStorm etc... and search for: </li></ul><ul><ul><li>do_action(), and do_action_ref_array() </li></ul></ul><ul><ul><li>apply_filters(), and apply_filters_ref_array() </li></ul></ul><ul><li>http://adambrown.info/p/wp_hooks </li></ul>
  42. 43. Good Citizenship <ul><li>Add your own action and filter hooks wherever it may be appropriate: </li></ul><ul><ul><li>things a dev may wish to override but you don't want to expose to an Admin user </li></ul></ul><ul><ul><li>default values (max/min limits etc) </li></ul></ul><ul><ul><li>logical spots for extension </li></ul></ul><ul><li>Example: zg-event-query (filter) </li></ul><ul><li>For the love of Pete, document it! </li></ul>
  43. 44. Idiom: The Loop and The Query
  44. 45. Getting Your Content: &quot;The Loop&quot; <ul><li>One &quot;The Loop&quot; per page </li></ul><ul><li>Sets globals (eg: $post) </li></ul><ul><li>Drives all template tags (eg: the_content()) </li></ul><ul><li>Driven by &quot;the query&quot;: the request string </li></ul><ul><li>Affects conditional tags </li></ul><ul><li>Can be supplanted by query_posts() </li></ul>
  45. 46. Secondary Loops <ul><li>Used in widgets and sidebars, sub-content and related content </li></ul><ul><li>Must be careful not to clobber globals and affect the main Loop </li></ul><ul><li>Leverage get_posts() or get_pages() for inobtrusive secondary loops </li></ul><ul><li>Or get dirty with WP_Query class </li></ul><ul><li>Either way, be sure to read Codex WP_Query </li></ul>
  46. 47. Suspicious Stuff <ul><li>Leverage template tags in secondary loops by: </li></ul><ul><ul><li>using the_post() method on WP_Query instance </li></ul></ul><ul><ul><li>or setup_postdata() on a $post object </li></ul></ul>$the_query = new WP_Query( $args ); while ( $the_query->have_posts() ){ $the_query->the_post(); the_title(); } wp_reset_postdata();
  47. 48. Template Tags and get_ <ul><li>Template tags </li></ul><ul><ul><li>Used exclusively within The Loop </li></ul></ul><ul><ul><li>Always echo their results </li></ul></ul><ul><ul><li>Rarely (?) take arguments (always working on the global $post object) </li></ul></ul><ul><li>get_ </li></ul><ul><ul><li>Most template tags have a get_ equivalent </li></ul></ul><ul><ul><li>Does not echo result </li></ul></ul><ul><ul><li>Usually takes the ID of a post as argument </li></ul></ul>
  48. 49. Template Tag vs. get_ <ul><li>Use Template Tag when: </li></ul><ul><ul><li>you're in The Loop! </li></ul></ul><ul><li>Use get_ when: </li></ul><ul><ul><li>you want the value, not the echo </li></ul></ul><ul><ul><li>you're not in The Loop </li></ul></ul><ul><ul><li>you are in the loop but want a related item (eg: attachment) </li></ul></ul>
  49. 50. Idiosyncrasy: $wpdb
  50. 51. wpdb Class <ul><li>Instantiated once and globalized in $wpdb </li></ul><ul><li>Provides API to low-level DB calls </li></ul><ul><ul><li>$wpdb->query() </li></ul></ul><ul><ul><li>$wpdb->get_results() </li></ul></ul><ul><ul><li>$wpdb->get_var() </li></ul></ul>
  51. 52. Example: Events <ul><li>Custom post type &quot;event&quot; </li></ul><ul><li>Categorized by taxonomy &quot;event-type&quot; </li></ul><ul><li>Event start_date stored in meta </li></ul><ul><li>Let's select: all 'speaking' events with a start date of '2011-07-09' </li></ul>
  52. 53. Pure SQL select * from wp_posts join wp_term_relationships on ID = object_id join wp_term_taxonomy on wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id and taxonomy = 'event-type' join wp_terms on wp_term_taxonomy.term_id = wp_terms.term_id and wp_terms.slug = 'speaking' join wp_postmeta on wp_postmeta.post_id = ID and meta_key = 'event-date' and meta_value = '2011-07-09' where post_type = 'event' and post_status = 'published'
  53. 54. More Properer SQL select * from wp_posts as P join wp_term_relationships TR_EVENT on P .ID = TR_EVENT .object_id join 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_id and T_EVENT .slug = 'speaking' join wp_postmeta M_DATE on M_DATE .post_id = P.ID and M_DATE .meta_key = 'event-date' and M_DATE .meta_value = '2011-07-09' where P .post_type = 'event' and P .post_status = 'published'
  54. 55. Don't Use Table Names! select * from {$wpdb->posts} P join {$wpdb->term_relationships} TR_EVENT on P.ID = TR_EVENT.object_id join {$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_id and T_EVENT.slug = 'speaking' join {$wpdb->postmeta} M_DATE on M_DATE.post_id = P.ID and M_DATE.meta_key = 'event-date' and M_DATE.meta_value = '2011-07-09' where P.post_type = 'event' and P.post_status = 'published'
  55. 56. More Saferer Query $wpdb->prepare (&quot;select * from {$wpdb->posts} P join {$wpdb->term_relationships} TR_EVENT on P.ID = TR_EVENT.object_id join {$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_id and T_EVENT.slug = %s join {$wpdb->postmeta} M_DATE on M_DATE.post_id = P.ID and M_DATE.meta_key = 'event-date' and M_DATE.meta_value = %s where P.post_type = 'event' and P.post_status = 'published'&quot;, 'speaking', '2011-07-09' );
  56. 57. 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 )) ));
  57. 58. Use Built-Ins Whenever You Can <ul><li>Take advantage of cacheing and optimization </li></ul><ul><li>Future-proof code </li></ul><ul><li>Chances are, there's a function or method to do what you want </li></ul><ul><ul><li>Look in Codex under WP_Query </li></ul></ul><ul><ul><li>Look in source under query.php, post.php, category.php, taxonomy.php </li></ul></ul>
  58. 59. Idiosyncrasy: wp_enqueue_script
  59. 60. We Love jQuery <ul><li>(Don't) </li></ul><ul><ul><li>Jump into header.php </li></ul></ul><ul><ul><li>Add <script src=&quot;my-jquery-min.js&quot;></script> </li></ul></ul><ul><li>(Don't) </li></ul><ul><ul><li>add_action('wp_head', 'add_my_jquery'); </li></ul></ul>
  60. 61. Enqueue = The Canadian Way, eh? <ul><li>DO </li></ul><ul><li>add_action('wp_enqueue_scripts', 'add_my_scripts'); </li></ul><ul><ul><li>function add_my_scripts(){ </li></ul></ul><ul><ul><li>wp_enqueue_scripts('jquery-ui-core', </li></ul></ul><ul><ul><li>get_stylesheet_directory_uri() . '/script', </li></ul></ul><ul><ul><li>array('jquery'), </li></ul></ul><ul><ul><li>'1.8.14', </li></ul></ul><ul><ul><li>false // in-header </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>add_action('admin_enqueue_scripts', 'add_admin_scripts'); // careful here... </li></ul></ul>
  61. 62. No One Likes Conflict <ul><li>jQuery runs in &quot;no-conflict&quot; mode... </li></ul>jQuery(document).ready(function($) { $('#mydiv').css({color:'red', border:'2px solid red'}); }); (function($) { var test = &quot;hello, world!&quot;; function testMe(){ alert(test); } $(document).ready(testMe); })(jQuery);
  62. 63. Resources and Forums <ul><li>Documentation: </li></ul><ul><ul><li>Codex (of course) </li></ul></ul><ul><ul><li>Google: &quot;wordpress add_action&quot; </li></ul></ul><ul><ul><li>Adam Brown </li></ul></ul><ul><ul><li>WPSeek, phpxref </li></ul></ul><ul><ul><li>Your own IDE </li></ul></ul><ul><li>Help: </li></ul><ul><ul><li>wordpress.org/support (yeah, not really...) </li></ul></ul><ul><ul><li>www.experts-exchange.com </li></ul></ul><ul><ul><ul><li>http://www.experts-exchange.com/Web_Development/Blogs/WordPress / </li></ul></ul></ul><ul><ul><li>wordpress.stackexchange.com </li></ul></ul>
  63. 64. Thanks! www.tomauger.com www.zeitguys.com @TomAuger
  64. 65. Other Stuff for more time
  65. 66. Paradigm: Post Types and Taxonomies
  66. 67. Posts <ul><li>Posts are the atomic element for all WordPress content </li></ul><ul><ul><li>&quot;actual&quot; posts </li></ul></ul><ul><ul><li>pages </li></ul></ul><ul><ul><li>comments </li></ul></ul><ul><ul><li>attachments </li></ul></ul><ul><ul><li>drafts and revisions </li></ul></ul><ul><ul><li>custom post types </li></ul></ul>
  67. 68. Taxonomies <ul><li>Taxonomies are the relational device that group posts together. </li></ul><ul><ul><li>categories, </li></ul></ul><ul><ul><li>tags, </li></ul></ul><ul><ul><li>nav menus </li></ul></ul><ul><ul><li>post formats? </li></ul></ul><ul><ul><li>custom taxonomies </li></ul></ul><ul><li>Groupings that are shared by different items </li></ul>
  68. 69. What About Meta? <ul><li>Use meta for discrete, non-grouping data, unique to the content item (eg: price) </li></ul><ul><li>Sortables (eg: year) </li></ul><ul><li>Groups that are not meaningfully shared (eg: Otto's TV show seasons across different shows) </li></ul>
  69. 70. Custom Post vs. Custom Tax <ul><li>Use Custom Post for content that: </li></ul><ul><ul><li>should not appear in your feed </li></ul></ul><ul><ul><li>represents a distinct type of &quot;content&quot; </li></ul></ul><ul><ul><li>is always associated with a set of metadata </li></ul></ul><ul><ul><li>may require a customized input form </li></ul></ul><ul><ul><li>needs a separate capability / access </li></ul></ul><ul><ul><li>needs its own private taxonomy </li></ul></ul><ul><li>Examples: products, events, albums </li></ul>
  70. 71. Custom Post vs. Custom Tax <ul><li>Use a custom taxonomy when: </li></ul><ul><ul><li>You want additional ways to group items together </li></ul></ul><ul><ul><li>You want a way to filter out a set of items </li></ul></ul><ul><ul><li>You want a new metabox </li></ul></ul><ul><li>Eg: colour, software posts, manufacturers </li></ul>