WordPress Custom Type with Custom Post Field

Last days I’ve been developing a very simple custom post type for WordPress.

The aim was to allow the user to create an event, which in this case consists of:

  1. title
  2. description
  3. date

Title and description are already provided by the wordpress built-in post type, that means we just need to teach wordpress how to manage date.

In order to keep the code clean all the Custom Type’s code is inside a class Event which is inside a folder ‘custom_types’ whithin the theme’s folder.

/theme/custom_types/Event.php

class Event
 {
}

Then we add the class methods to WP on the functions.php after including the class itself:

    require(“custom_types/Event.php”);

First of all WP needs to know about our Post Type so that it has to be registered

 public static function create()
 {
 register_post_type('event',
 array
 (
 'description' => __('Events'),
 'labels' => array
 (
 'name'                    => __('Events'),
 'singular_name'            => __('Event'),
 'add_new'                => __('Add New'),
 'add_new_item'            => __('Add New Event'),
 'edit_item'                => __('Edit Event'),
 'new_item'                => __('New Event'),
 'view_item'                => __('View Event'),
 'search_items'            => __('Search Events'),
 'not_found'                => __('No events found'),
 'not_found_in_trash'    => __('No events found in Trash'),
 'parent_item_colon'        => ''
 ),
 'supports' => array('title', 'editor'),
 'public' => true,
 'capability_type' => 'post',
 'show_ui' => true,
 'publicly_queryable' => true,
 'hierarchical' => false,
 'menu_position' => null,
 'query_var' => true,
 'taxonomies' => array('post_tag', 'category'),
 'has_archive' => true,
 'rewrite' => array('slug' => 'events')
 )
 );
 }

we add this method to WP on the functions.php file via:

    //add custom post type to WP
add_action(‘init’, ‘Event::create’, 0);

Making the long story short register_post_type says to WordPress:

‘hey you, here is my custom type and it has the following features’

the meaning of all these features is well explained on the official documentation.

Now i’s time to add our columns

 

public static function columns($columns)
 {
 return array
 (
 'title'            => __('Title'),
 'event_date'    => __('Event Date'),
 'author'        => __('Author'),
 'tags'            => __('Tags')
 );
 }

 

Add to WP:

    //custom columns
add_filter(‘manage_edit-event_columns’ , ‘Event::columns’);

N.B. -event is the name of our custom post type

Here we are defining which columns will be used on the listing table of our custom type, the parameter $custom contains the default post columns, we could decide to unset some of them and add ours or (as shown above) just return an array with the columns we want.

As you can see we return 3 ‘built-in’ columns (title,author,tags) + our custom column (event_date).

WordPress also need to know what to output for each custom columns:

 

public static function backend_view($column)
 {
 global $post;
switch($column)
 {
 case 'event_date' :
 {
 echo(Event::get_date($post));
 break;
 }
 }
 }

Add to WP:

    //backend visualization
add_action(‘manage_posts_custom_column’, ‘Event::backend_view’);

here we say: ‘whenever you are rendering something about column event_date, print the Event’s date, we will se later on what’s inside Event::get_date($post), remember Event is the class containing our Custom Post type definition.

At this stage we are ready to find out a new menu point on the admin backend called ‘Events’, the table listing all the events (no one until now) and the page to edit/insert a new Event.

What? there is no ‘event date’ field on the edit page?
Yes, we need to specify a custom post field in order to be able to add this feature to our Events.

Adding the possibility of Managing custom columns

The previous steps don’t provide the feature on inserting/editing our custom column, to fix that point we need to introduce a custom post field:


public static function editor()
 {
 add_meta_box('event_date_box', __('Event Date'), 'Event::date_edit', 'event', 'normal', 'low');
 }
public static function date_edit()
 {
 global $post;
 $start = Event::get_date($post);
 echo("<label for='start_date'>Data:</label><input type='text' name='event_date' class='event_date' value='{$start}' />");
 }
public static function date_insert()
 {
 global $post;
if(!preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/([0-9]{4})$/", $_POST['event_date'], $pieces))
 return;
 else
 update_post_meta($post->ID, 'event_date', mktime(0,0,0,$pieces[2],$pieces[1],$pieces[3]));
 }
public static function date_delete()
 {
 global $post;
 delete_post_meta($post->ID, 'event_date');
 }

 

add to WP:

    //add custom fields to the editor
add_action(‘add_meta_boxes’, ‘Event::editor’);
//manage event_date
add_action(‘save_post’, ‘Event::date_insert’);
add_action(‘delete_post’, ‘Event::date_delete’);

add_meta_box add a new box on the post editing page, the third parameter is the one which specify which function will render the box.

As you can see Event::date_edit outputs an input field which our users will insert the date.

We need to define also what WP should do with the user input once the post is saved/deleted.

In the first case we store the input on the database by means of date_insert (actually here we check the date format and if it is valid we turn it into timestamp befora storing).

update_post_meta add/update a custom post field with name ‘event_date’ at the event we are saving.

The custom value is retrieved from the database and shown on he input if the alue itself exists, the methon by which we search for the value is the previously seen ‘Event::get_date’:

 

private static function get_date($post)
 {
 $data = get_post_custom_values('event_date', $post->ID);
 if(count($data))
 return date('d/m/Y',array_shift($data));
 else
 '';
 }

 

Here we search for the custom value on the db, if it exists we turn in back to a human-readable date otherwise just return an empty string.

In case we delete and event we teach wordpress how to delete the custom field ‘event_date’ by means of delete_post_meta.

Now we are done, our brand new Event Custom Type it’s on-line and users has the possibility of inserting the event date.

Anyway we could make the input a little bit more user-friendy with help of jquery…

Adding jQuery to our event date input

we need to include jquery and jqueryUI to the admin:

 

public static function add_js()
 {
 wp_enqueue_script('jqueryui', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js');
 wp_enqueue_script('jquery_i18n', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/i18n/jquery-ui-i18n.min.js');
 wp_enqueue_script('admin', WP_CONTENT_URL . '/themes/theme/js/admin.js', array('jquery','jqueryui','jquery_i18n'));
 }

 

jquery is already present on WordPress, thet’s why we pick just jqueryUI and all it’s translations from the Google CDN. Then we load our javascript (which is located on the js folder of our theme) setting as dependencies jquery, jqueryUI and its translations.

The same way we load the css styleshit:

 

public function add_css()
 {
 wp_enqueue_style('jqueryui', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/flick/jquery-ui.css');
 }

 

Add to WP:

    //add javascript support
add_action(‘admin_print_scripts’, ‘Event::add_js’);
//add css style
add_action(‘admin_print_styles’, ‘Event::add_css’);

This way we make WP load all the scripts we need.

Finally we can write the few lines we need to properly add a calendar to our Event Date Input:

 

jQuery(document).ready(function()
 {
 jQuery('input.event_date').datepicker({dateFormat: 'dd/mm/yy'});
 jQuery('input.event_date').datepicker('option',jQuery.datepicker.regional["it"]);
 //close if opened on page load
 jQuery('#ui-datepicker-div:visible').hide();
 });

 

Here we go, now our custom post type admin interface in ready!

Complete Code

Event.php


<?php
class Event
 {
 public static function create()
 {
 register_post_type('event',
 array
 (
 'description' => __('Events'),
 'labels' => array
 (
 'name'                    => __('Events'),
 'singular_name'            => __('Event'),
 'add_new'                => __('Add New'),
 'add_new_item'            => __('Add New Event'),
 'edit_item'                => __('Edit Event'),
 'new_item'                => __('New Event'),
 'view_item'                => __('View Event'),
 'search_items'            => __('Search Events'),
 'not_found'                => __('No events found'),
 'not_found_in_trash'    => __('No events found in Trash'),
 'parent_item_colon'        => ''
 ),
 'supports' => array('title', 'editor'),
 'public' => true,
 'capability_type' => 'post',
 'show_ui' => true,
 'publicly_queryable' => true,
 'hierarchical' => false,
 'menu_position' => null,
 'query_var' => true,
 'taxonomies' => array('post_tag', 'category'),
 'has_archive' => true,
 'rewrite' => array('slug' => 'events')
 )
 );
 }
public static function columns($columns)
 {
 return array
 (
 'title'            => __('Title'),
 'event_date'    => __('Event Date'),
 'author'        => __('Author'),
 'tags'            => __('Tags')
 );
 }
public static function backend_view($column)
 {
 global $post;
switch($column)
 {
 case 'event_date' :
 {
 echo(Event::get_date($post));
 break;
 }
 }
 }
public static function editor()
 {
 add_meta_box('event_date_box', __('Event Date'), 'Event::date_edit', 'event', 'normal', 'low');
 }
public static function date_edit()
 {
 global $post;
 $start = Event::get_date($post);
 echo("<label for='start_date'>Data:</label><input type='text' name='event_date' class='event_date' value='{$start}' />");
 }
public static function date_insert()
 {
 global $post;
if(!preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/([0-9]{4})$/", $_POST['event_date'], $pieces))
 return;
 else
 update_post_meta($post->ID, 'event_date', mktime(0,0,0,$pieces[2],$pieces[1],$pieces[3]));
 }
public static function date_delete()
 {
 global $post;
 delete_post_meta($post->ID, 'event_date');
 }
public static function add_js()
 {
 wp_enqueue_script('jqueryui', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js');
 wp_enqueue_script('jquery_i18n', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/i18n/jquery-ui-i18n.min.js');
 wp_enqueue_script('admin', WP_CONTENT_URL . '/themes/theme/js/admin.js', array('jquery','jqueryui','jquery_i18n'));
 }
public function add_css()
 {
 wp_enqueue_style('jqueryui', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/flick/jquery-ui.css');
 }
private static function get_date($post)
 {
 $data = get_post_custom_values('event_date', $post->ID);
 if(count($data))
 return date('d/m/Y',array_shift($data));
 else
 '';
 }
 }

 

functions.php


/*
 * CUSTOM POST TYPE: EVENTS
 */
 require("custom_types/Event.php");
 //add custom post type to WP
 add_action('init', 'Event::create', 0);
 //custom columns
 add_filter('manage_edit-event_columns' , 'Event::columns');
 //backend visualization
 add_action('manage_posts_custom_column', 'Event::backend_view');
 //add custom fields to the editor
 add_action('add_meta_boxes', 'Event::editor');
 //manage event_date
 add_action('save_post', 'Event::date_insert');
 add_action('delete_post', 'Event::date_delete');
 //add javascript support
 add_action('admin_print_scripts', 'Event::add_js');
 //add css style
 add_action('admin_print_styles', 'Event::add_css');

 

admin.js

 

jQuery(document).ready(function()
 {
 /*
 * datepicker
 */
 jQuery('input.event_date').datepicker({dateFormat: 'dd/mm/yy'});
 jQuery('input.event_date').datepicker('option',jQuery.datepicker.regional["it"]);
 //close if opened on page load
 jQuery('#ui-datepicker-div:visible').hide();
 });

 

Leave a Reply

Your email address will not be published. Required fields are marked *