SlideShare a Scribd company logo
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

Amp Up Your Admin
Amp Up Your AdminAmp Up Your Admin
Amp Up Your Admin
Amanda Giles
 
The Customizer
The CustomizerThe Customizer
The Customizer
Konstantin Obenland
 
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
Nuvole
 
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
Mohamed Mosaad
 
Shortcodes In-Depth
Shortcodes In-DepthShortcodes In-Depth
Shortcodes In-Depth
Micah Wood
 
UIAutomation + Mechanic.js
UIAutomation + Mechanic.jsUIAutomation + Mechanic.js
UIAutomation + Mechanic.js
jaykz52
 
Working with WooCommerce Custom Fields
Working with WooCommerce Custom FieldsWorking with WooCommerce Custom Fields
Working with WooCommerce Custom Fields
Anthony 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 building
Jonny 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 @ Etsy
Nishan Subedi
 
Enecomp 2009
Enecomp 2009Enecomp 2009
Enecomp 2009
Fabio Akita
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
Azim 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 1
Acquia
 
Transparent Object Persistence with FLOW3
Transparent Object Persistence with FLOW3Transparent Object Persistence with FLOW3
Transparent Object Persistence with FLOW3
Karsten 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 #3
giwoolee
 
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 & lies
Tareque Hossain
 
Magento 2 | Declarative schema
Magento 2 | Declarative schemaMagento 2 | Declarative schema
Magento 2 | Declarative schema
Kiel 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 Wordpress
Topher 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 Ecosystem
Adam 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 - anthonydpaul
Anthony D. Paul
 
Get Your Website Done
Get Your Website DoneGet Your Website Done
Get Your Website Done
Jill 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 2017
vdrover
 
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
Ilia Markov
 
WordCamp ATL 2017 - Beginner Session - Plugins
WordCamp ATL 2017 - Beginner Session - PluginsWordCamp ATL 2017 - Beginner Session - Plugins
WordCamp ATL 2017 - Beginner Session - Plugins
Mickey Mellen
 
Typography: The Backbone of Your Website
Typography: The Backbone of Your WebsiteTypography: The Backbone of Your Website
Typography: The Backbone of Your Website
Alison 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 loops
Roman Rus
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helper
slicejack
 
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
stimasoft
 
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
Alex Blackie
 
CMS content
CMS contentCMS content
CMS content
iemail808
 
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 2018
Adam 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 Boxes
Jeremy 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 sesh2
techvoltz
 
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
Tammy 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-2011
Alessandro Nadalin
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stack
Paul 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 world
Kevin Faustino
 
WordPress Theme Workshop: Sidebars
WordPress Theme Workshop: SidebarsWordPress Theme Workshop: Sidebars
WordPress Theme Workshop: Sidebars
David 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 Query
Chris Olbekson
 
Rails GUI Development with Ext JS
Rails GUI Development with Ext JSRails GUI Development with Ext JS
Rails GUI Development with Ext JS
Martin Rehfeld
 
WordPress for developers - phpday 2011
WordPress for developers -  phpday 2011WordPress for developers -  phpday 2011
WordPress for developers - phpday 2011
Maurizio Pelizzone
 
Programmers, communicate your intentions
Programmers, communicate your intentionsProgrammers, communicate your intentions
Programmers, communicate your intentions
Yael 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

5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
DanBrown980551
 
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
DanBrown980551
 
Christine's Product Research Presentation.pptx
Christine's Product Research Presentation.pptxChristine's Product Research Presentation.pptx
Christine's Product Research Presentation.pptx
christinelarrosa
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
DianaGray10
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
Edge AI and Vision Alliance
 
Northern Engraving | Nameplate Manufacturing Process - 2024
Northern Engraving | Nameplate Manufacturing Process - 2024Northern Engraving | Nameplate Manufacturing Process - 2024
Northern Engraving | Nameplate Manufacturing Process - 2024
Northern Engraving
 
High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024
Vadym Kazulkin
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
Neo4j
 
AppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSFAppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSF
Ajin Abraham
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
MichaelKnudsen27
 
Christine's Supplier Sourcing Presentaion.pptx
Christine's Supplier Sourcing Presentaion.pptxChristine's Supplier Sourcing Presentaion.pptx
Christine's Supplier Sourcing Presentaion.pptx
christinelarrosa
 
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
Alex Pruden
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
The Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptxThe Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptx
operationspcvita
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
ssuserfac0301
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
Jakub Marek
 
"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota
Fwdays
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
Pablo Gómez Abajo
 

Recently uploaded (20)

5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
 
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
 
Christine's Product Research Presentation.pptx
Christine's Product Research Presentation.pptxChristine's Product Research Presentation.pptx
Christine's Product Research Presentation.pptx
 
What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
 
Northern Engraving | Nameplate Manufacturing Process - 2024
Northern Engraving | Nameplate Manufacturing Process - 2024Northern Engraving | Nameplate Manufacturing Process - 2024
Northern Engraving | Nameplate Manufacturing Process - 2024
 
High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
 
AppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSFAppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSF
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
 
Christine's Supplier Sourcing Presentaion.pptx
Christine's Supplier Sourcing Presentaion.pptxChristine's Supplier Sourcing Presentaion.pptx
Christine's Supplier Sourcing Presentaion.pptx
 
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
The Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptxThe Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptx
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
 
"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota"Choosing proper type of scaling", Olena Syrota
"Choosing proper type of scaling", Olena Syrota
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
 

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