When creating a custom post type in a theme, it is neat to put it in an extension. There are many already developed extensions containing custom post types, ie.
ct-portfolio
)ct-team
)ct-faq
)ct-testimonials
)ct-shop-locator
)Important
All of these extensions need to be activated in wp-admin Unyson settings menu in order to work.
All above extensions are similar in structure which follows guidelines: Extensions, for example here’s a structure of Testimonials extension:
ct-testimonials/
├─class-fw-extension-ct-testimonials.php
├─manifest.php
├─options.php
├─posts.php
├─shortcodes/
├─ct-testimonials-slider/
├─class-fw-shortcode-ct-testimonials-slider.php
├─config.php
├─options.php
├─static.php
├─view/
│ ├─view.php
├─static/
├─js/
├─init.js
Activating any of those extensions adds custom post type features in wp-admin menu to add new posts and taxonomies. Most
of them also add shortcodes (in the example ct-testimonials-slider
) which render their own view.
If needed, you can create single or archive custom post type view as documented in Custom Post Types. In the extension above, there are no views except for the shortcode view.
As you can see in the structure, there is init.js
file inside shortcodes
directory. It could be placed inside
ct-testimonials/static/
directly, then it would be enqueued always when the extension is active. The way it is however,
it is only enqueued when the shortcode is rendered as it is not needed on other pages. This is done automatically by the
shortcode class.
The extension class is basically a controller for post metaboxes, post data being sent to the view, as well as basic post type settings, as name, slug, taxonomy etc.
<?php if ( ! defined( 'FW' ) ) {
die( 'Forbidden' );
}
class FW_Extension_CT_Testimonials extends FW_Extension {
private $post_type = 'ct-testimonials';
/**
* @var string
*/
private $testimonials_slug = 'testimonials';
/**
* @var string
*/
private $testimonials_thumbnail = 'thumbnail';
/**
* @internal
*/
public function _init() {
if ( is_admin() ) {
$this->admin_filters();
}
}
/**
* Return the testimonials custom post type
* @return string
*/
public function get_post_type() {
return $this->post_type;
}
/**
* Return the testimonials custom post slug
* @return string
*/
public function get_testimonials_slug() {
return $this->testimonials_slug;
}
public function get_testimonial_thumbnail() {
return $this->testimonials_thumbnail;
}
/**
* Return the testimonials data
*
* @param array $args
*
* @return array
*/
public function get_posts_data( $args = array() ) {
$collector = array();
$queryArgs = array(
'post_type' => $this->get_post_type(),
'numberposts' => - 1,
);
$queryArgs = array_merge( $queryArgs, $args );
$posts = get_posts( $queryArgs );
foreach ( $posts as $post ) {
setup_postdata( $post );
array_push( $collector, (object) array(
'desc' => get_the_content( $post->ID ),
'thumbnail' => get_the_post_thumbnail( $post->ID ),
'thumbnail_id' => get_post_thumbnail_id( $post->ID ),
'thumbnail_url' => get_the_post_thumbnail_url( $post->ID ),
'meta_options' => (object) fw_get_db_post_option( $post->ID )
) );
}
wp_reset_postdata();
return $collector;
}
/**
* @internal
*
* @param array $options
* @param string $post_type
*
* @return array
*/
public function _filter_admin_add_testimonial_options( $options, $post_type ) {
if ( $post_type !== $this->get_post_type() ) {
return $options;
}
$fields = array(
'author' => array(
'label' => __( 'Name', 'ct_theme' ),
'type' => 'text',
'value' => 'John Doe',
),
'position' => array(
'label' => __( 'Company', 'ct_theme' ),
'type' => 'text',
'value' => 'Company inc.',
),
);
$tabs = array(
'demo' => array(
'title' => __( 'Author', 'ct_theme' ),
'type' => 'tab',
'options' => array(
$fields
),
),
);
if ( empty( $options ) ) {
$options = $tabs;
} else {
$currentOptions = current( $options );
$currentKey = key( $currentOptions['options'] );
array_unshift( $options[ $currentKey ]['options'], $tabs );
}
return $options;
}
private function admin_filters() {
add_filter( 'fw_post_options', array( $this, '_filter_admin_add_testimonial_options' ), 10, 2 );
}
}
In posts.php
the post type and taxonomies registration takes place. Keep this file as generic as you can to easily
copy from one project to another.
<?php if ( ! defined( 'FW' ) ) {
die( 'Forbidden' );
}
register_post_type( fw()->extensions->get( 'ct-testimonials' )->get_post_type(), array(
'labels' => array(
'name' => __( 'Testimonials', 'ct_theme' ),
'singular_name' => __( 'Testimonial', 'ct_theme' ),
'menu_name' => __( 'Testimonials', 'ct_theme' ),
'add_new' => __( 'Add New', 'ct_theme' ),
'add_new_item' => __( 'Add New Testimonial', 'ct_theme' ),
'new_item' => __( 'New Testimonial', 'ct_theme' ),
'edit_item' => __( 'Edit Testimonial', 'ct_theme' ),
'view_item' => __( 'View Testimonial', 'ct_theme' ),
'all_items' => __( 'Testimonials', 'ct_theme' ),
'search_items' => __( 'Search Testimonials', 'ct_theme' ),
'parent_item_colon' => '',
'not_found' => __( 'No Testimonials found', 'ct_theme' ),
'not_found_in_trash' => __( 'No Testimonials found in Trash', 'ct_theme' ),
),
'singular_label' => __( 'testimonial', 'ct_theme' ),
'public' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 4,
'menu_icon' => 'dashicons-format-quote',
'capability_type' => 'post',
'hierarchical' => false,
'supports' => array( 'title', 'editor', 'thumbnail' ),
'has_archive' => false,
'rewrite' => array( 'slug' => 'testimonials' ),
'query_var' => false,
'can_export' => true,
'show_in_nav_menus' => true,
'taxonomies' => array( 'post_tag', 'category' )
) );
//Register taxonomy
register_taxonomy( 'testimonial_category', array('testimonials'), array('labels' => array(
'name' => _x('Testimonial Categories', 'taxonomy general name', 'ct_theme'),
'singular_name' => _x('Testimonial Category', 'taxonomy singular name', 'ct_theme'),
'search_items' => __('Search Categories', 'ct_theme'),
'popular_items' => __('Popular Categories', 'ct_theme'),
'all_items' => __('All Categories', 'ct_theme'),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __('Edit Testimonial Category', 'ct_theme'),
'update_item' => __('Update Testimonial Category', 'ct_theme'),
'add_new_item' => __('Add New Testimonial Category', 'ct_theme'),
'new_item_name' => __('New Testimonial Category Name', 'ct_theme'),
'separate_items_with_commas' => __('Separate Testimonial category with commas', 'ct_theme'),
'add_or_remove_items' => __('Add or remove Testimonial category', 'ct_theme'),
'choose_from_most_used' => __('Choose from the most used Testimonial category', 'ct_theme'),
'menu_name' => __('Categories', 'ct_theme')
),
'hierarchical' => true,
'public' => false,
'show_in_nav_menus' => false,
'show_ui' => true,
'show_tagcloud' => false,
'query_var' => 'testimonial_category',
'rewrite' => false) );