Successfully reported this slideshow.

Mastering Custom Post Types - WordCamp Atlanta 2012

10

Share

Upcoming SlideShare
Quality code by design
Quality code by design
Loading in …3
×
1 of 69
1 of 69

Mastering Custom Post Types - WordCamp Atlanta 2012

10

Share

Download to read offline

Description

Presentation of WordCamp Atlanta 2012 - Covers a collection of PHP-based techniques for using Custom Post Types to get the most out of WordPress.

Transcript

  1. 1. Mastering WordPress Custom Post Types By Mike Schinkel – @mikeschinkel For WordCamp Atlanta Feb 2012
  2. 2. Slides Available Now  On SpeakerDeck (PDF):  On SlideShare(PPTX):  The Code (either one):
  3. 3. 416style
  4. 4. Who Am I?  Conflicted: ½ Entrepreneur, ½ Web Developer  Founder &Prez of NewClarity in Atlanta – We:  Build Plugins for Distribution via WordPress.org  Extend WordPress for Vertical Market CMS Active Teacher  350+ Answers on SE’s WordPress Answers  Former Meetup Organizer & Presenter  Former Developer Trainer
  5. 5. What do I know?  Tends to develop deep expertise in narrow areas.  2010-2012 – WordPress + PHP + MySQL + jQuery  2007-2009 – Drupal + PHP + MySQL  1995-2006 – ASP + VBScript + MS SQL Server  1993-1994 – Visual Basic + Access Database  1987-1993 – Clipper for DOS  1985-1986 – dBase II & dBase III  1983-1984 – Turbo Pascal
  6. 6. My Primary Toolset Mostly commercial because they are worth it.  PhpStorm ($99) + Zend Debugger (free)  Navicat for MySQL ($79)  VirtualHostX ($40)  Transmit for FTP ($34)/FileZilla (free)  HTTPScoop ($15)  Apache+PHP (on Mac OS X), MySQL (free)
  7. 7. What We’ll Cover Today Everything will be in PHP 1. Define a Custom Post Type in PHP 2. Custom Form ("MetaBox") + Custom Fields 3. Theme Template for Custom Post Type 4. Custom Columns in Admin Post List 5. Custom Taxonomies for any Post Type
  8. 8. Today (cont’d) 6. Configure Edit Screens for Posts and Pages 7. Parent Post Field in a Post Editor Metabox 8. Querying Custom Post Types 9. Hierarchical URLs for Custom Post Types 10. Custom Post Type Filters in Admin Post List  Recognize and Bypass the Various Gotchas!
  9. 9. What Today’s Post Type? Example Today: “PressedComics”
  10. 10. Inspiration for our example: Small World Comics
  11. 11. Fire up PhpStorm!
  12. 12. Create a Child Theme  /wp-content/themes/mikes_theme/styles.css /* Theme Name: Mike's Theme Description: Child Theme of Twenty Eleven Template: twentyeleven */ @import url("../twentyeleven/style.css");
  13. 13. Add a functions.php file  /wp-content/themes/mikes_theme/functions.php <?php /* * functions.php for mikes_theme * */
  14. 14. Part 1 Add a Custom Post Type Called "Comics"
  15. 15. Register Post Type <?php /* * functions.php for mikes_theme * */ register_post_type( 'comic' );
  16. 16. Must Use "init" Hook <?php add_action( 'init', 'mikes_theme_init' ); function mikes_theme_init() { register_post_type( 'comic' ); }
  17. 17. Must Make "public" But! function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, )); }
  18. 18. Must Give "label" Now! function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', )); }
  19. 19. Y URL NO LOAD COMIC?!?
  20. 20. Refresh Permalinks
  21. 21. Like Candy from a Baby!
  22. 22. Need "with_front" to omit /blog/ from URL: function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', 'rewrite' => array( 'with_front' => false, ), Better, but )); } quite right:
  23. 23. Need "slug" to make URL start with /comics/(pural): function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', 'rewrite' => array( 'with_front' => false, 'slug' => 'comics', ), )); } Perfecto!
  24. 24. THE COMIC POST LIST IN THE ADMIN:
  25. 25. THE COMIC POST EDIT SCREEN:
  26. 26. Part 2 Add a Custom Form (a "Metabox") and Custom Fields
  27. 27. The "ComicInformation" Custom Fields Metabox
  28. 28. Add a Custom Metabox: add_action('add_meta_boxes','mikes_theme_add_meta_boxes'); function mikes_theme_add_meta_boxes( $post_type ) { if ( 'comic' == $post_type ) add_meta_box( 'comic_info_box', // $id 'Comic Information', // $title 'mikes_theme_comic_meta_box', // $callback 'comic', // $page, 'normal', // $context, 'high' ); // $priority }
  29. 29. Add a Custom Metabox Callback Function function mikes_theme_comic_meta_box( $post ) { $cartoonist = ''; $since= ''; $website = ''; $html =<<<HTML <table> <tr> <th><label for="cartoonist">Cartoonist:</label></th> <td><input type="text" name="cartoonist" value="{$cartoonist}" size="25" /></td> </tr> <tr> <th><label for="since">Since:</label></th> <td><input type="text" name="since" value="{$since}" size="15" /></td> </tr> <tr> <th><label for="website">Website:</label></th> <td><input type="text" name="website" value="{$website}" size="25" /></td> </tr> </table> HTML; echo $html; }
  30. 30. Update Custom Fields: add_action( 'save_post', 'mikes_theme_save_post'); function mikes_theme_save_post( $post_id ) { if ( 'comic' == $post_type ) { update_post_meta($post_id,'_cartoonist',$_POST['cartoonist']); update_post_meta($post_id,'_since',$_POST['since']); update_post_meta($post_id,'_website',$_POST['website']); } } Note the leading underscores on the post meta 'key' names (2nd parameter)
  31. 31. Load Custom Fields: function mikes_theme_comic_meta_box( $post ) { $cartoonist = get_post_meta( $post->ID, '_cartoonist', true ); $since = get_post_meta( $post->ID, '_since', true ); $website = get_post_meta( $post->ID, '_website', true ); $html =<<<HTML <table>
  32. 32. Part 3 Create a Theme Template File for a Custom Post Type
  33. 33. Simple Example Theme Template for Custom Post Type
  34. 34. /wp- content/themes/your_theme/singl e-comic.php: <?php //Template for displaying single Comic Post Type. get_header(); if ( have_posts() ): the_post(); ?> <div id="content"> <div id="post-<?phpthe_ID(); ?>" <?phppost_class(); ?>> <h1 class="entry-title"><?phpthe_title(); ?></h1> Cartoonist: <?php echo get_post_meta( $post->ID, '_cartoonist', true); ?> <br/> Since: <?php echo get_post_meta( $post->ID, '_since', true ); ?> <br/> Website: <?php echo get_post_meta( $post->ID, '_website', true ); ?> <br/><br/> <?phpthe_content(); ?> </div> </div> <?phpendif; get_footer(); ?>
  35. 35. Part 4 Add Admin Columns for your Custom Post Type
  36. 36. Admin Columns for the "Comics" Custom Post Type
  37. 37. Use hook "manage_edit-{$post_type}_columns" add_filter( 'manage_edit-comic_columns', 'mikes_theme_manage_edit_comic_columns' ); function mikes_theme_manage_edit_comic_columns( $columns ) { $columns['cartoonist'] = 'Cartoonist'; $columns['website'] = 'Website'; return $columns; }
  38. 38. Use hook "manage_{$post_type}_posts_custom_columns" add_filter( 'manage_comic_posts_custom_column', 'mikes_theme_manage_comic_posts_custom_column', 10, 2 ); function mikes_theme_manage_comic_posts_custom_column( $column_name, $post_id ) { switch ( $column_name ) { case 'cartoonist': echo get_post_meta( $post_id, "_cartoonist", true ); break; case 'website': $website = get_post_meta( $post_id, "_website", true ); $domain = trim( str_replace( 'http://', '', $website ), '/' ); echo "<a href="{$website}">{$domain}</a>"; break; } }
  39. 39. Better Admin Columns for the "Comics" Custom Post Type function mikes_theme_manage_edit_comic_columns( $columns ) { $new_columns = array(); foreach( $columns as $key => $value ) { if ( 'date' == $key ) { $new_columns['cartoonist'] = 'Cartoonist'; $new_columns['website'] = 'Website'; } $new_columns[$key] = $value; } return $new_columns; }
  40. 40. Part 5 Adding a Custom Taxonomy to a Post Type
  41. 41. An "Art Style" Taxonomy for the Comics Post Type function mikes_theme_init() { ... ... register_taxonomy( 'art-style', 'comic', array( 'hierarchical' => true, 'label' => 'Art Styles', 'rewrite' => array( 'slug' => 'art-styles', 'with_front' => false ), ));
  42. 42. Part 6 Configure Post Edit Screens (including Posts and Pages)
  43. 43. 'supports' =>array('title','excerpt','thumbnail')g ets this:
  44. 44. Configure an "Episodes" Post Type Specify what it "supports" function mikes_theme_init() { ... ... register_post_type( 'episode', array( 'label' => 'Episodes', 'public' => true, 'rewrite' => array( 'slug' =>'episodes', 'with_front' => false ), 'supports' => array( 'title', 'thumbnail', 'excerpt' ), ));
  45. 45. Options for "supports"  'title' – Includes permalink  'editor' – WYSIWYG+HTML content  'author'  'thumbnail' – Featured, theme must support post-thumbnails  'excerpt'  'trackbacks'  'custom-fields'  'comments – Will add comment count balloon on edit screen  'revisions' – Will store revisions  'page-attributes' – Menu order, Parent if hierarchical=true  'post-formats' – Add post formats
  46. 46. Part 7 Parent Post Field in a Post Editor Metabox (useful for non-same post types)
  47. 47. Create a Metabox to Associate an Episode with a Comic: 'parent_id' is key function mikes_theme_add_meta_boxes($post_type) { ... if ( 'episode' == $post_type ) add_meta_box( 'episode_info_box', 'Episode Info', 'mikes_theme_episode_meta_box', 'episode','side','low' ); } function mikes_theme_episode_meta_box( $post ) { $html =<<<HTML <table><tr> <th><label for="parent_id">Comic:</label></th> <td><input type="text" name="parent_id" value="{$post->post_parent}" /></td> </tr></table> HTML; echo $html; }
  48. 48. Part 8 Querying Custom Post Types
  49. 49. Use the "Comic" Drop Down within the hook 'mikes_theme_episode_meta_box' function mikes_theme_episode_meta_box( $post ) { $select_html = mikes_theme_comic_dropdown( $post->post_parent ); $html =<<<HTML <table> <tr> <th><label for="parent_id">Comic:</label></th> <td>{$select_html}</td> </tr> </table> HTML; echo $html; }
  50. 50. Use WP_Query() to create a "Comic" Drop Down for "Episode" Parent Selection function mikes_theme_comic_dropdown( $selected_id ) { $query = new WP_Query( 'post_type=comic&posts_per_page=-1' ); $comics = array(); foreach( $query->posts as $comic ) { $title = get_the_title( $comic->ID ); $selected = $comic->ID == intval( $selected_id ) ? ' selected' : ''; $comics[ $comic->ID ] = <<<HTML <option value="{$comic->ID}"{$selected}>{$title}</option> HTML; } $comics = implode( '', $comics ); $html =<<<HTML <select name="parent_id"> <option value="0">None selected</option> {$comics} </select> HTML; return $html; }
  51. 51. Part 9 Hierarchical URLs for Custom Post Types
  52. 52. Hierarchical URLs:
  53. 53. Enable /comics/{$comic}/{$episode}/ such as/comics/small-world/xmas-2012/ 1. Call add_rewrite_rule()in 'init'hook. 2. Add 'query_var'arguments to 'comic' and 'episode' post types named 'comic_qv' and 'episode_qv', respectively. 3. Add 'post_type_link' hook. 4. Add 'request'hook.
  54. 54. Call add_rewrite_rule() in 'init' hook. And add 'query_var' arguments add_rewrite_rule( '^comics/([^/]*)/([^/]*)/?', 'index.php?post_type=episode&comic_qv=$matches[1]&episode_qv=$matches[2]', 'top' ); register_post_type( 'comic', array( ... 'query_var' => 'comic_qv', ... )); register_post_type( 'episode', array( ... 'query_var' => 'episode_qv', ... ));
  55. 55. Add 'post_type_link'hook. add_action( 'post_type_link', 'mikes_theme_post_type_link', 10, 4 ); function mikes_theme_post_type_link( $link, $post, $leavename, $sample ) { if ( 'episode' == $post->post_type ) { $parent = get_post( $post->post_parent ); $comic_slug = isset( $parent->post_name ) ? $parent->post_name ' : '%comic%'; $episode_slug = $sample ? '%postname%' : $post->post_name; $link = preg_replace( '#^(https?://[^/]+/).*$#', "$1comics/{$comic_slug}/{$episode_slug}/", $link ); } return $link; }
  56. 56. Add 'request'hook. add_action( 'request', 'mikes_theme_request' ); function mikes_theme_request( $query_vars ) { global $wp; if ( ! is_admin() && isset( $query_vars['post_type'] ) && 'episode' == $query_vars['post_type'] ) { $comic = get_page_by_path( $query_vars['comic_qv'], OBJECT, 'comic' ); $episode_query = new WP_Query( array( 'name' => $query_vars['episode_qv'], 'post_type' => 'episode', 'fields' => 'ids', 'post_parent' => $comic->ID, 'posts_per_page' => 1, 'suppress_filters' => true, )); if ( 0 == count( $episode_query->posts ) ) { $query_vars = array( 'error' => '404' ); } } return $query_vars; }
  57. 57. To get our "Episodes" Page:
  58. 58. /wp- content/themes/your_theme/singl e-episode.php: <?php get_header(); if ( have_posts() ): the_post(); ?> <div id="content"> <div id="post-<?phpthe_ID(); ?>" <?phppost_class(); ?>> <?phpedit_post_link( 'Edit', '<div class="edit-link">', '</div>' ); ?> <?phpprevious_post_link( '%link', '&lt;&lt;&lt;Previous' ); ?> &nbsp;&nbsp;&nbsp; <?phpnext_post_link( '%link', 'Next&gt&gt&gt;' ); ?> <h2 class="entry-parent">Comic: <?php echo get_the_title( $post->post_parent ); ?></h2> <h1 class="entry-title"><?phpthe_title(); ?></h1> <?phpthe_content(); ?> <?php if ( has_post_thumbnail( $post->ID ) ) $image_html = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' ); ?> <imgsrc="<?php echo $image_html[0]; ?>"> </div> </div> <?phpendif; get_footer(); ?>
  59. 59. Part 10 Custom Post Type Filters in Admin Post List
  60. 60. Filtering our "Episodes:"
  61. 61. Or Not:
  62. 62. Enable /comics/{$comic}/{$episode}/ such as/comics/small-world/xmas-2012/ 1. Make mikes_theme_comic_dropdown() reusable. 2. Add 'restrict_manage_posts' hook. 3. Add 'pre_get_posts'hook.
  63. 63. Make mikes_theme_comic_dropdown() reusable function mikes_theme_comic_dropdown( $selected_id, $name = 'parent_id' ) { $query = new WP_Query( 'post_type=comic&posts_per_page=-1' ); $comics = array(); foreach( $query->posts as $comic ) { $title = get_the_title( $comic->ID ); $selected = $comic->ID == intval( $selected_id ) ? ' selected' : ''; $comics[ $comic->ID ] = <<<HTML <option value="{$comic->ID}"{$selected}>{$title}</option> HTML; } $comics = implode( '', $comics ); $html =<<<HTML <select name="{$name}"> <option value="0">None selected</option> {$comics} </select> HTML; return $html; }
  64. 64. Add 'restrict_manage_posts' hook. And add 'pre_get_posts'hook. add_action( 'restrict_manage_posts', 'mikes_theme_restrict_manage_posts' ); function mikes_theme_restrict_manage_posts() { $comic_id = empty( $_GET['comic_id'] ) ? 0 : $_GET['comic_id']; echo 'Comic: ' . mikes_theme_comic_dropdown( $comic_id, 'comic_id' ); } add_filter('pre_get_posts','mikes_theme_pre_get_posts'); function mikes_theme_pre_get_posts( $query ) { global $pagenow, $typenow, $wp_the_query; if ( 'edit.php' == $pagenow&& 'episode' == $typenow&& $query === $wp_the_query&& ! empty( $_GET['comic_id'] ) ) { $query->set( 'post_parent', intval( $_GET['comic_id'] ) ); } }
  65. 65. Takeaway You can do practically anything you put your mind to with WordPress' CPTs and a little PHP!
  66. 66. But Wait! There's More…
  67. 67. Look for “Sunrise”  A Platform Extension for WordPress  Targeting needs of Professional Site Builders  To be GPL and freely distributed  Designed to be Modular  Goal: To Have Community of Module Contributors  Timeline:  Pre-Alpha now  Closed Beta – Q1 2012  Open Beta – Q2 2012  Release – Hmm…
  68. 68. Thank You  To Contact Me:  Twitter: @mikeschinkel  http://about.me/mikeschinkel

Description

Presentation of WordCamp Atlanta 2012 - Covers a collection of PHP-based techniques for using Custom Post Types to get the most out of WordPress.

Transcript

  1. 1. Mastering WordPress Custom Post Types By Mike Schinkel – @mikeschinkel For WordCamp Atlanta Feb 2012
  2. 2. Slides Available Now  On SpeakerDeck (PDF):  On SlideShare(PPTX):  The Code (either one):
  3. 3. 416style
  4. 4. Who Am I?  Conflicted: ½ Entrepreneur, ½ Web Developer  Founder &Prez of NewClarity in Atlanta – We:  Build Plugins for Distribution via WordPress.org  Extend WordPress for Vertical Market CMS Active Teacher  350+ Answers on SE’s WordPress Answers  Former Meetup Organizer & Presenter  Former Developer Trainer
  5. 5. What do I know?  Tends to develop deep expertise in narrow areas.  2010-2012 – WordPress + PHP + MySQL + jQuery  2007-2009 – Drupal + PHP + MySQL  1995-2006 – ASP + VBScript + MS SQL Server  1993-1994 – Visual Basic + Access Database  1987-1993 – Clipper for DOS  1985-1986 – dBase II & dBase III  1983-1984 – Turbo Pascal
  6. 6. My Primary Toolset Mostly commercial because they are worth it.  PhpStorm ($99) + Zend Debugger (free)  Navicat for MySQL ($79)  VirtualHostX ($40)  Transmit for FTP ($34)/FileZilla (free)  HTTPScoop ($15)  Apache+PHP (on Mac OS X), MySQL (free)
  7. 7. What We’ll Cover Today Everything will be in PHP 1. Define a Custom Post Type in PHP 2. Custom Form ("MetaBox") + Custom Fields 3. Theme Template for Custom Post Type 4. Custom Columns in Admin Post List 5. Custom Taxonomies for any Post Type
  8. 8. Today (cont’d) 6. Configure Edit Screens for Posts and Pages 7. Parent Post Field in a Post Editor Metabox 8. Querying Custom Post Types 9. Hierarchical URLs for Custom Post Types 10. Custom Post Type Filters in Admin Post List  Recognize and Bypass the Various Gotchas!
  9. 9. What Today’s Post Type? Example Today: “PressedComics”
  10. 10. Inspiration for our example: Small World Comics
  11. 11. Fire up PhpStorm!
  12. 12. Create a Child Theme  /wp-content/themes/mikes_theme/styles.css /* Theme Name: Mike's Theme Description: Child Theme of Twenty Eleven Template: twentyeleven */ @import url("../twentyeleven/style.css");
  13. 13. Add a functions.php file  /wp-content/themes/mikes_theme/functions.php <?php /* * functions.php for mikes_theme * */
  14. 14. Part 1 Add a Custom Post Type Called "Comics"
  15. 15. Register Post Type <?php /* * functions.php for mikes_theme * */ register_post_type( 'comic' );
  16. 16. Must Use "init" Hook <?php add_action( 'init', 'mikes_theme_init' ); function mikes_theme_init() { register_post_type( 'comic' ); }
  17. 17. Must Make "public" But! function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, )); }
  18. 18. Must Give "label" Now! function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', )); }
  19. 19. Y URL NO LOAD COMIC?!?
  20. 20. Refresh Permalinks
  21. 21. Like Candy from a Baby!
  22. 22. Need "with_front" to omit /blog/ from URL: function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', 'rewrite' => array( 'with_front' => false, ), Better, but )); } quite right:
  23. 23. Need "slug" to make URL start with /comics/(pural): function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', 'rewrite' => array( 'with_front' => false, 'slug' => 'comics', ), )); } Perfecto!
  24. 24. THE COMIC POST LIST IN THE ADMIN:
  25. 25. THE COMIC POST EDIT SCREEN:
  26. 26. Part 2 Add a Custom Form (a "Metabox") and Custom Fields
  27. 27. The "ComicInformation" Custom Fields Metabox
  28. 28. Add a Custom Metabox: add_action('add_meta_boxes','mikes_theme_add_meta_boxes'); function mikes_theme_add_meta_boxes( $post_type ) { if ( 'comic' == $post_type ) add_meta_box( 'comic_info_box', // $id 'Comic Information', // $title 'mikes_theme_comic_meta_box', // $callback 'comic', // $page, 'normal', // $context, 'high' ); // $priority }
  29. 29. Add a Custom Metabox Callback Function function mikes_theme_comic_meta_box( $post ) { $cartoonist = ''; $since= ''; $website = ''; $html =<<<HTML <table> <tr> <th><label for="cartoonist">Cartoonist:</label></th> <td><input type="text" name="cartoonist" value="{$cartoonist}" size="25" /></td> </tr> <tr> <th><label for="since">Since:</label></th> <td><input type="text" name="since" value="{$since}" size="15" /></td> </tr> <tr> <th><label for="website">Website:</label></th> <td><input type="text" name="website" value="{$website}" size="25" /></td> </tr> </table> HTML; echo $html; }
  30. 30. Update Custom Fields: add_action( 'save_post', 'mikes_theme_save_post'); function mikes_theme_save_post( $post_id ) { if ( 'comic' == $post_type ) { update_post_meta($post_id,'_cartoonist',$_POST['cartoonist']); update_post_meta($post_id,'_since',$_POST['since']); update_post_meta($post_id,'_website',$_POST['website']); } } Note the leading underscores on the post meta 'key' names (2nd parameter)
  31. 31. Load Custom Fields: function mikes_theme_comic_meta_box( $post ) { $cartoonist = get_post_meta( $post->ID, '_cartoonist', true ); $since = get_post_meta( $post->ID, '_since', true ); $website = get_post_meta( $post->ID, '_website', true ); $html =<<<HTML <table>
  32. 32. Part 3 Create a Theme Template File for a Custom Post Type
  33. 33. Simple Example Theme Template for Custom Post Type
  34. 34. /wp- content/themes/your_theme/singl e-comic.php: <?php //Template for displaying single Comic Post Type. get_header(); if ( have_posts() ): the_post(); ?> <div id="content"> <div id="post-<?phpthe_ID(); ?>" <?phppost_class(); ?>> <h1 class="entry-title"><?phpthe_title(); ?></h1> Cartoonist: <?php echo get_post_meta( $post->ID, '_cartoonist', true); ?> <br/> Since: <?php echo get_post_meta( $post->ID, '_since', true ); ?> <br/> Website: <?php echo get_post_meta( $post->ID, '_website', true ); ?> <br/><br/> <?phpthe_content(); ?> </div> </div> <?phpendif; get_footer(); ?>
  35. 35. Part 4 Add Admin Columns for your Custom Post Type
  36. 36. Admin Columns for the "Comics" Custom Post Type
  37. 37. Use hook "manage_edit-{$post_type}_columns" add_filter( 'manage_edit-comic_columns', 'mikes_theme_manage_edit_comic_columns' ); function mikes_theme_manage_edit_comic_columns( $columns ) { $columns['cartoonist'] = 'Cartoonist'; $columns['website'] = 'Website'; return $columns; }
  38. 38. Use hook "manage_{$post_type}_posts_custom_columns" add_filter( 'manage_comic_posts_custom_column', 'mikes_theme_manage_comic_posts_custom_column', 10, 2 ); function mikes_theme_manage_comic_posts_custom_column( $column_name, $post_id ) { switch ( $column_name ) { case 'cartoonist': echo get_post_meta( $post_id, "_cartoonist", true ); break; case 'website': $website = get_post_meta( $post_id, "_website", true ); $domain = trim( str_replace( 'http://', '', $website ), '/' ); echo "<a href="{$website}">{$domain}</a>"; break; } }
  39. 39. Better Admin Columns for the "Comics" Custom Post Type function mikes_theme_manage_edit_comic_columns( $columns ) { $new_columns = array(); foreach( $columns as $key => $value ) { if ( 'date' == $key ) { $new_columns['cartoonist'] = 'Cartoonist'; $new_columns['website'] = 'Website'; } $new_columns[$key] = $value; } return $new_columns; }
  40. 40. Part 5 Adding a Custom Taxonomy to a Post Type
  41. 41. An "Art Style" Taxonomy for the Comics Post Type function mikes_theme_init() { ... ... register_taxonomy( 'art-style', 'comic', array( 'hierarchical' => true, 'label' => 'Art Styles', 'rewrite' => array( 'slug' => 'art-styles', 'with_front' => false ), ));
  42. 42. Part 6 Configure Post Edit Screens (including Posts and Pages)
  43. 43. 'supports' =>array('title','excerpt','thumbnail')g ets this:
  44. 44. Configure an "Episodes" Post Type Specify what it "supports" function mikes_theme_init() { ... ... register_post_type( 'episode', array( 'label' => 'Episodes', 'public' => true, 'rewrite' => array( 'slug' =>'episodes', 'with_front' => false ), 'supports' => array( 'title', 'thumbnail', 'excerpt' ), ));
  45. 45. Options for "supports"  'title' – Includes permalink  'editor' – WYSIWYG+HTML content  'author'  'thumbnail' – Featured, theme must support post-thumbnails  'excerpt'  'trackbacks'  'custom-fields'  'comments – Will add comment count balloon on edit screen  'revisions' – Will store revisions  'page-attributes' – Menu order, Parent if hierarchical=true  'post-formats' – Add post formats
  46. 46. Part 7 Parent Post Field in a Post Editor Metabox (useful for non-same post types)
  47. 47. Create a Metabox to Associate an Episode with a Comic: 'parent_id' is key function mikes_theme_add_meta_boxes($post_type) { ... if ( 'episode' == $post_type ) add_meta_box( 'episode_info_box', 'Episode Info', 'mikes_theme_episode_meta_box', 'episode','side','low' ); } function mikes_theme_episode_meta_box( $post ) { $html =<<<HTML <table><tr> <th><label for="parent_id">Comic:</label></th> <td><input type="text" name="parent_id" value="{$post->post_parent}" /></td> </tr></table> HTML; echo $html; }
  48. 48. Part 8 Querying Custom Post Types
  49. 49. Use the "Comic" Drop Down within the hook 'mikes_theme_episode_meta_box' function mikes_theme_episode_meta_box( $post ) { $select_html = mikes_theme_comic_dropdown( $post->post_parent ); $html =<<<HTML <table> <tr> <th><label for="parent_id">Comic:</label></th> <td>{$select_html}</td> </tr> </table> HTML; echo $html; }
  50. 50. Use WP_Query() to create a "Comic" Drop Down for "Episode" Parent Selection function mikes_theme_comic_dropdown( $selected_id ) { $query = new WP_Query( 'post_type=comic&posts_per_page=-1' ); $comics = array(); foreach( $query->posts as $comic ) { $title = get_the_title( $comic->ID ); $selected = $comic->ID == intval( $selected_id ) ? ' selected' : ''; $comics[ $comic->ID ] = <<<HTML <option value="{$comic->ID}"{$selected}>{$title}</option> HTML; } $comics = implode( '', $comics ); $html =<<<HTML <select name="parent_id"> <option value="0">None selected</option> {$comics} </select> HTML; return $html; }
  51. 51. Part 9 Hierarchical URLs for Custom Post Types
  52. 52. Hierarchical URLs:
  53. 53. Enable /comics/{$comic}/{$episode}/ such as/comics/small-world/xmas-2012/ 1. Call add_rewrite_rule()in 'init'hook. 2. Add 'query_var'arguments to 'comic' and 'episode' post types named 'comic_qv' and 'episode_qv', respectively. 3. Add 'post_type_link' hook. 4. Add 'request'hook.
  54. 54. Call add_rewrite_rule() in 'init' hook. And add 'query_var' arguments add_rewrite_rule( '^comics/([^/]*)/([^/]*)/?', 'index.php?post_type=episode&comic_qv=$matches[1]&episode_qv=$matches[2]', 'top' ); register_post_type( 'comic', array( ... 'query_var' => 'comic_qv', ... )); register_post_type( 'episode', array( ... 'query_var' => 'episode_qv', ... ));
  55. 55. Add 'post_type_link'hook. add_action( 'post_type_link', 'mikes_theme_post_type_link', 10, 4 ); function mikes_theme_post_type_link( $link, $post, $leavename, $sample ) { if ( 'episode' == $post->post_type ) { $parent = get_post( $post->post_parent ); $comic_slug = isset( $parent->post_name ) ? $parent->post_name ' : '%comic%'; $episode_slug = $sample ? '%postname%' : $post->post_name; $link = preg_replace( '#^(https?://[^/]+/).*$#', "$1comics/{$comic_slug}/{$episode_slug}/", $link ); } return $link; }
  56. 56. Add 'request'hook. add_action( 'request', 'mikes_theme_request' ); function mikes_theme_request( $query_vars ) { global $wp; if ( ! is_admin() && isset( $query_vars['post_type'] ) && 'episode' == $query_vars['post_type'] ) { $comic = get_page_by_path( $query_vars['comic_qv'], OBJECT, 'comic' ); $episode_query = new WP_Query( array( 'name' => $query_vars['episode_qv'], 'post_type' => 'episode', 'fields' => 'ids', 'post_parent' => $comic->ID, 'posts_per_page' => 1, 'suppress_filters' => true, )); if ( 0 == count( $episode_query->posts ) ) { $query_vars = array( 'error' => '404' ); } } return $query_vars; }
  57. 57. To get our "Episodes" Page:
  58. 58. /wp- content/themes/your_theme/singl e-episode.php: <?php get_header(); if ( have_posts() ): the_post(); ?> <div id="content"> <div id="post-<?phpthe_ID(); ?>" <?phppost_class(); ?>> <?phpedit_post_link( 'Edit', '<div class="edit-link">', '</div>' ); ?> <?phpprevious_post_link( '%link', '&lt;&lt;&lt;Previous' ); ?> &nbsp;&nbsp;&nbsp; <?phpnext_post_link( '%link', 'Next&gt&gt&gt;' ); ?> <h2 class="entry-parent">Comic: <?php echo get_the_title( $post->post_parent ); ?></h2> <h1 class="entry-title"><?phpthe_title(); ?></h1> <?phpthe_content(); ?> <?php if ( has_post_thumbnail( $post->ID ) ) $image_html = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' ); ?> <imgsrc="<?php echo $image_html[0]; ?>"> </div> </div> <?phpendif; get_footer(); ?>
  59. 59. Part 10 Custom Post Type Filters in Admin Post List
  60. 60. Filtering our "Episodes:"
  61. 61. Or Not:
  62. 62. Enable /comics/{$comic}/{$episode}/ such as/comics/small-world/xmas-2012/ 1. Make mikes_theme_comic_dropdown() reusable. 2. Add 'restrict_manage_posts' hook. 3. Add 'pre_get_posts'hook.
  63. 63. Make mikes_theme_comic_dropdown() reusable function mikes_theme_comic_dropdown( $selected_id, $name = 'parent_id' ) { $query = new WP_Query( 'post_type=comic&posts_per_page=-1' ); $comics = array(); foreach( $query->posts as $comic ) { $title = get_the_title( $comic->ID ); $selected = $comic->ID == intval( $selected_id ) ? ' selected' : ''; $comics[ $comic->ID ] = <<<HTML <option value="{$comic->ID}"{$selected}>{$title}</option> HTML; } $comics = implode( '', $comics ); $html =<<<HTML <select name="{$name}"> <option value="0">None selected</option> {$comics} </select> HTML; return $html; }
  64. 64. Add 'restrict_manage_posts' hook. And add 'pre_get_posts'hook. add_action( 'restrict_manage_posts', 'mikes_theme_restrict_manage_posts' ); function mikes_theme_restrict_manage_posts() { $comic_id = empty( $_GET['comic_id'] ) ? 0 : $_GET['comic_id']; echo 'Comic: ' . mikes_theme_comic_dropdown( $comic_id, 'comic_id' ); } add_filter('pre_get_posts','mikes_theme_pre_get_posts'); function mikes_theme_pre_get_posts( $query ) { global $pagenow, $typenow, $wp_the_query; if ( 'edit.php' == $pagenow&& 'episode' == $typenow&& $query === $wp_the_query&& ! empty( $_GET['comic_id'] ) ) { $query->set( 'post_parent', intval( $_GET['comic_id'] ) ); } }
  65. 65. Takeaway You can do practically anything you put your mind to with WordPress' CPTs and a little PHP!
  66. 66. But Wait! There's More…
  67. 67. Look for “Sunrise”  A Platform Extension for WordPress  Targeting needs of Professional Site Builders  To be GPL and freely distributed  Designed to be Modular  Goal: To Have Community of Module Contributors  Timeline:  Pre-Alpha now  Closed Beta – Q1 2012  Open Beta – Q2 2012  Release – Hmm…
  68. 68. Thank You  To Contact Me:  Twitter: @mikeschinkel  http://about.me/mikeschinkel

More Related Content

Related Books

Free with a 30 day trial from Scribd

See all

×