SlideShare a Scribd company logo
1 of 69
Mastering WordPress
Custom Post Types
By Mike Schinkel – @mikeschinkel
For WordCamp Atlanta Feb 2012
Slides Available Now

 On SpeakerDeck (PDF):

 On SlideShare(PPTX):

 The Code (either one):
416style
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
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
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)
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
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!
What Today’s Post Type?



Example Today:
“PressedComics”
Inspiration for our example:
    Small World Comics
Fire up PhpStorm!
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");
Add a functions.php file

 /wp-content/themes/mikes_theme/functions.php

   <?php
   /*
    * functions.php for mikes_theme
    *
    */
Part 1


     Add a
Custom Post Type
Called "Comics"
Register Post Type
<?php
/*
 * functions.php for mikes_theme
 *
 */

register_post_type( 'comic' );
Must Use "init" Hook
<?php

add_action( 'init', 'mikes_theme_init' );
function mikes_theme_init() {
register_post_type( 'comic' );
}
Must Make "public"

                                      But!
function mikes_theme_init() {
register_post_type( 'comic', array(
    'public' => true,
  ));
}
Must Give "label"

                                      Now!
function mikes_theme_init() {
register_post_type( 'comic', array(
    'public' => true,
    'label' => 'Comics',
  ));
}
Y URL NO LOAD COMIC?!?
Refresh Permalinks
Like Candy from a Baby!
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:
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!
THE COMIC POST LIST
  IN THE ADMIN:
THE COMIC
POST EDIT SCREEN:
Part 2


    Add a
Custom Form
(a "Metabox")
     and
Custom Fields
The "ComicInformation"
 Custom Fields Metabox
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
}
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;
}
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)
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>
Part 3


     Create a
Theme Template File
      for a
 Custom Post Type
Simple Example Theme
Template for Custom Post Type
/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(); ?>
Part 4


Add Admin Columns
     for your
 Custom Post Type
Admin Columns for
the "Comics" Custom Post Type
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;
}
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;
  }
}
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;
}
Part 5


    Adding a
Custom Taxonomy
  to a Post Type
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
     ),
  ));
Part 6


    Configure
 Post Edit Screens
(including Posts and Pages)
'supports'
=>array('title','excerpt','thumbnail')g
               ets this:
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'
       ),
    ));
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
Part 7


Parent Post Field in a
Post Editor Metabox
 (useful for non-same post types)
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;
}
Part 8


 Querying
Custom Post
    Types
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;
}
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;
}
Part 9


Hierarchical URLs for
 Custom Post Types
Hierarchical URLs:
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.
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',
  ...
));
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;
}
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;
}
To get our "Episodes" Page:
/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(); ?>
Part 10


Custom Post Type Filters
   in Admin Post List
Filtering our "Episodes:"
Or Not:
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.
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;
}
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'] ) );
  }
}
Takeaway


You can do practically anything
  you put your mind to with
WordPress' CPTs and a little PHP!
But Wait!


There's More…
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…
Thank You

 To Contact Me:
  Twitter: @mikeschinkel
  http://about.me/mikeschinkel

More Related Content

What's hot

First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentNuvole
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoMohamed Mosaad
 
Shortcodes In-Depth
Shortcodes In-DepthShortcodes In-Depth
Shortcodes In-DepthMicah Wood
 
UIAutomation + Mechanic.js
UIAutomation + Mechanic.jsUIAutomation + Mechanic.js
UIAutomation + Mechanic.jsjaykz52
 
Working with WooCommerce Custom Fields
Working with WooCommerce Custom FieldsWorking with WooCommerce Custom Fields
Working with WooCommerce Custom FieldsAnthony Hortin
 
WordCamp Bristol 2019 - WordPress custom theme building
WordCamp Bristol 2019 - WordPress custom theme buildingWordCamp Bristol 2019 - WordPress custom theme building
WordCamp Bristol 2019 - WordPress custom theme buildingJonny Allbut
 
Drupal Development (Part 2)
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)Jeff Eaton
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Drupal Step-by-Step: How We Built Our Training Site, Part 1
Drupal Step-by-Step: How We Built Our Training Site, Part 1Drupal Step-by-Step: How We Built Our Training Site, Part 1
Drupal Step-by-Step: How We Built Our Training Site, Part 1Acquia
 
Transparent Object Persistence with FLOW3
Transparent Object Persistence with FLOW3Transparent Object Persistence with FLOW3
Transparent Object Persistence with FLOW3Karsten Dambekalns
 
날로 먹는 Django admin 활용
날로 먹는 Django admin 활용날로 먹는 Django admin 활용
날로 먹는 Django admin 활용KyeongMook "Kay" Cha
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3giwoolee
 
Editing the Visual Editor (WordPress)
Editing the Visual Editor (WordPress)Editing the Visual Editor (WordPress)
Editing the Visual Editor (WordPress)Jake Goldman
 
RESTful APIs: Promises & lies
RESTful APIs: Promises & liesRESTful APIs: Promises & lies
RESTful APIs: Promises & liesTareque Hossain
 
Magento 2 | Declarative schema
Magento 2 | Declarative schemaMagento 2 | Declarative schema
Magento 2 | Declarative schemaKiel Pykett
 

What's hot (20)

Amp Up Your Admin
Amp Up Your AdminAmp Up Your Admin
Amp Up Your Admin
 
The Customizer
The CustomizerThe Customizer
The Customizer
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven Development
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup Cairo
 
Shortcodes In-Depth
Shortcodes In-DepthShortcodes In-Depth
Shortcodes In-Depth
 
UIAutomation + Mechanic.js
UIAutomation + Mechanic.jsUIAutomation + Mechanic.js
UIAutomation + Mechanic.js
 
Working with WooCommerce Custom Fields
Working with WooCommerce Custom FieldsWorking with WooCommerce Custom Fields
Working with WooCommerce Custom Fields
 
WordCamp Bristol 2019 - WordPress custom theme building
WordCamp Bristol 2019 - WordPress custom theme buildingWordCamp Bristol 2019 - WordPress custom theme building
WordCamp Bristol 2019 - WordPress custom theme building
 
Drupal Development (Part 2)
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Enecomp 2009
Enecomp 2009Enecomp 2009
Enecomp 2009
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Drupal Step-by-Step: How We Built Our Training Site, Part 1
Drupal Step-by-Step: How We Built Our Training Site, Part 1Drupal Step-by-Step: How We Built Our Training Site, Part 1
Drupal Step-by-Step: How We Built Our Training Site, Part 1
 
Transparent Object Persistence with FLOW3
Transparent Object Persistence with FLOW3Transparent Object Persistence with FLOW3
Transparent Object Persistence with FLOW3
 
날로 먹는 Django admin 활용
날로 먹는 Django admin 활용날로 먹는 Django admin 활용
날로 먹는 Django admin 활용
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
 
Editing the Visual Editor (WordPress)
Editing the Visual Editor (WordPress)Editing the Visual Editor (WordPress)
Editing the Visual Editor (WordPress)
 
RESTful APIs: Promises & lies
RESTful APIs: Promises & liesRESTful APIs: Promises & lies
RESTful APIs: Promises & lies
 
Magento 2 | Declarative schema
Magento 2 | Declarative schemaMagento 2 | Declarative schema
Magento 2 | Declarative schema
 

Viewers also liked

WordCamp Atlanta 2010 Advanced SEo for Wordpress
WordCamp Atlanta 2010 Advanced SEo for WordpressWordCamp Atlanta 2010 Advanced SEo for Wordpress
WordCamp Atlanta 2010 Advanced SEo for WordpressTopher Kohan
 
Startup Atlanta: 2017 Guide To The Ecosystem
Startup Atlanta: 2017 Guide To The EcosystemStartup Atlanta: 2017 Guide To The Ecosystem
Startup Atlanta: 2017 Guide To The EcosystemAdam Harrell
 
Sneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaul
Sneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaulSneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaul
Sneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaulAnthony D. Paul
 
Get Your Website Done
Get Your Website DoneGet Your Website Done
Get Your Website DoneJill Anderson
 
Wordpress security best practices - WordCamp Waukesha 2017
Wordpress security best practices - WordCamp Waukesha 2017Wordpress security best practices - WordCamp Waukesha 2017
Wordpress security best practices - WordCamp Waukesha 2017vdrover
 
Showing ROI: How to Create a Content Marketing Report
Showing ROI: How to Create a Content Marketing ReportShowing ROI: How to Create a Content Marketing Report
Showing ROI: How to Create a Content Marketing ReportIlia Markov
 
WordCamp ATL 2017 - Beginner Session - Plugins
WordCamp ATL 2017 - Beginner Session - PluginsWordCamp ATL 2017 - Beginner Session - Plugins
WordCamp ATL 2017 - Beginner Session - PluginsMickey Mellen
 
Typography: The Backbone of Your Website
Typography: The Backbone of Your WebsiteTypography: The Backbone of Your Website
Typography: The Backbone of Your WebsiteAlison Chandler
 

Viewers also liked (8)

WordCamp Atlanta 2010 Advanced SEo for Wordpress
WordCamp Atlanta 2010 Advanced SEo for WordpressWordCamp Atlanta 2010 Advanced SEo for Wordpress
WordCamp Atlanta 2010 Advanced SEo for Wordpress
 
Startup Atlanta: 2017 Guide To The Ecosystem
Startup Atlanta: 2017 Guide To The EcosystemStartup Atlanta: 2017 Guide To The Ecosystem
Startup Atlanta: 2017 Guide To The Ecosystem
 
Sneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaul
Sneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaulSneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaul
Sneaking in Good UX Without a UX Budget - WordCamp Lancaster 2017 - anthonydpaul
 
Get Your Website Done
Get Your Website DoneGet Your Website Done
Get Your Website Done
 
Wordpress security best practices - WordCamp Waukesha 2017
Wordpress security best practices - WordCamp Waukesha 2017Wordpress security best practices - WordCamp Waukesha 2017
Wordpress security best practices - WordCamp Waukesha 2017
 
Showing ROI: How to Create a Content Marketing Report
Showing ROI: How to Create a Content Marketing ReportShowing ROI: How to Create a Content Marketing Report
Showing ROI: How to Create a Content Marketing Report
 
WordCamp ATL 2017 - Beginner Session - Plugins
WordCamp ATL 2017 - Beginner Session - PluginsWordCamp ATL 2017 - Beginner Session - Plugins
WordCamp ATL 2017 - Beginner Session - Plugins
 
Typography: The Backbone of Your Website
Typography: The Backbone of Your WebsiteTypography: The Backbone of Your Website
Typography: The Backbone of Your Website
 

Similar to Mastering Custom Post Types - WordCamp Atlanta 2012

Wordpress multiple loops
Wordpress multiple loopsWordpress multiple loops
Wordpress multiple loopsRoman Rus
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helperslicejack
 
Custom content types &amp; custom taxonomies in wordpress
Custom content types &amp; custom taxonomies in wordpressCustom content types &amp; custom taxonomies in wordpress
Custom content types &amp; custom taxonomies in wordpressstimasoft
 
Building a Portfolio With Custom Post Types
Building a Portfolio With Custom Post TypesBuilding a Portfolio With Custom Post Types
Building a Portfolio With Custom Post TypesAlex Blackie
 
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...allilevine
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018Adam Tomat
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说Ting Lv
 
WordCamp Denver 2012 - Custom Meta Boxes
WordCamp Denver 2012 - Custom Meta BoxesWordCamp Denver 2012 - Custom Meta Boxes
WordCamp Denver 2012 - Custom Meta BoxesJeremy Green
 
Creatively creating custom post types! word sesh2
Creatively creating custom post types!  word sesh2Creatively creating custom post types!  word sesh2
Creatively creating custom post types! word sesh2techvoltz
 
Laying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme developmentLaying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme developmentTammy Hart
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011Alessandro Nadalin
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stackPaul Bearne
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)Beau Lebens
 
Mongoid in the real world
Mongoid in the real worldMongoid in the real world
Mongoid in the real worldKevin Faustino
 
WordPress Theme Workshop: Sidebars
WordPress Theme Workshop: SidebarsWordPress Theme Workshop: Sidebars
WordPress Theme Workshop: SidebarsDavid Bisset
 
The Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryThe Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryChris Olbekson
 
Rails GUI Development with Ext JS
Rails GUI Development with Ext JSRails GUI Development with Ext JS
Rails GUI Development with Ext JSMartin Rehfeld
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011Maurizio Pelizzone
 
Programmers, communicate your intentions
Programmers, communicate your intentionsProgrammers, communicate your intentions
Programmers, communicate your intentionsYael Zaritsky Perez
 

Similar to Mastering Custom Post Types - WordCamp Atlanta 2012 (20)

Wordpress multiple loops
Wordpress multiple loopsWordpress multiple loops
Wordpress multiple loops
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helper
 
Custom content types &amp; custom taxonomies in wordpress
Custom content types &amp; custom taxonomies in wordpressCustom content types &amp; custom taxonomies in wordpress
Custom content types &amp; custom taxonomies in wordpress
 
Building a Portfolio With Custom Post Types
Building a Portfolio With Custom Post TypesBuilding a Portfolio With Custom Post Types
Building a Portfolio With Custom Post Types
 
CMS content
CMS contentCMS content
CMS content
 
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 
WordCamp Denver 2012 - Custom Meta Boxes
WordCamp Denver 2012 - Custom Meta BoxesWordCamp Denver 2012 - Custom Meta Boxes
WordCamp Denver 2012 - Custom Meta Boxes
 
Creatively creating custom post types! word sesh2
Creatively creating custom post types!  word sesh2Creatively creating custom post types!  word sesh2
Creatively creating custom post types! word sesh2
 
Laying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme developmentLaying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme development
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stack
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)
 
Mongoid in the real world
Mongoid in the real worldMongoid in the real world
Mongoid in the real world
 
WordPress Theme Workshop: Sidebars
WordPress Theme Workshop: SidebarsWordPress Theme Workshop: Sidebars
WordPress Theme Workshop: Sidebars
 
The Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the QueryThe Query the Whole Query and Nothing but the Query
The Query the Whole Query and Nothing but the Query
 
Rails GUI Development with Ext JS
Rails GUI Development with Ext JSRails GUI Development with Ext JS
Rails GUI Development with Ext JS
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011
 
Programmers, communicate your intentions
Programmers, communicate your intentionsProgrammers, communicate your intentions
Programmers, communicate your intentions
 

Recently uploaded

Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsHyundai Motor Group
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetHyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetEnjoy Anytime
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 

Recently uploaded (20)

Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetHyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 

Mastering Custom Post Types - WordCamp Atlanta 2012

  • 1. Mastering WordPress Custom Post Types By Mike Schinkel – @mikeschinkel For WordCamp Atlanta Feb 2012
  • 2. Slides Available Now  On SpeakerDeck (PDF):  On SlideShare(PPTX):  The Code (either one):
  • 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. 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.
  • 7. 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)
  • 8. 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
  • 9. 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!
  • 10. What Today’s Post Type? Example Today: “PressedComics”
  • 11. Inspiration for our example: Small World Comics
  • 13. 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");
  • 14. Add a functions.php file  /wp-content/themes/mikes_theme/functions.php <?php /* * functions.php for mikes_theme * */
  • 15. Part 1 Add a Custom Post Type Called "Comics"
  • 16. Register Post Type <?php /* * functions.php for mikes_theme * */ register_post_type( 'comic' );
  • 17. Must Use "init" Hook <?php add_action( 'init', 'mikes_theme_init' ); function mikes_theme_init() { register_post_type( 'comic' ); }
  • 18. Must Make "public" But! function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, )); }
  • 19. Must Give "label" Now! function mikes_theme_init() { register_post_type( 'comic', array( 'public' => true, 'label' => 'Comics', )); }
  • 20. Y URL NO LOAD COMIC?!?
  • 22. Like Candy from a Baby!
  • 23. 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:
  • 24. 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!
  • 25. THE COMIC POST LIST IN THE ADMIN:
  • 27. Part 2 Add a Custom Form (a "Metabox") and Custom Fields
  • 29. 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 }
  • 30. 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; }
  • 31. 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)
  • 32. 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>
  • 33. Part 3 Create a Theme Template File for a Custom Post Type
  • 34. Simple Example Theme Template for Custom Post Type
  • 35. /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(); ?>
  • 36. Part 4 Add Admin Columns for your Custom Post Type
  • 37. Admin Columns for the "Comics" Custom Post Type
  • 38. 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; }
  • 39. 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; } }
  • 40. 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; }
  • 41. Part 5 Adding a Custom Taxonomy to a Post Type
  • 42. 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 ), ));
  • 43. Part 6 Configure Post Edit Screens (including Posts and Pages)
  • 45. 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' ), ));
  • 46. 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
  • 47. Part 7 Parent Post Field in a Post Editor Metabox (useful for non-same post types)
  • 48. 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; }
  • 50. 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; }
  • 51. 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; }
  • 52. Part 9 Hierarchical URLs for Custom Post Types
  • 54. 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.
  • 55. 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', ... ));
  • 56. 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; }
  • 57. 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; }
  • 58. To get our "Episodes" Page:
  • 59. /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(); ?>
  • 60. Part 10 Custom Post Type Filters in Admin Post List
  • 63. 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.
  • 64. 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; }
  • 65. 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'] ) ); } }
  • 66. Takeaway You can do practically anything you put your mind to with WordPress' CPTs and a little PHP!
  • 68. 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…
  • 69. Thank You  To Contact Me:  Twitter: @mikeschinkel  http://about.me/mikeschinkel