latest version

Post Types Extensions

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.

  • Portfolio extension (post type ct-portfolio)
  • Team Members extension (ct-team)
  • FAQ extension (ct-faq)
  • Testimonials extension (ct-testimonials)
  • Shop Locator extension (ct-shop-locator)

Important

All of these extensions need to be activated in wp-admin Unyson settings menu in order to work.

Structure

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

Features

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.

Views

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.

Static

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.

Extension 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 );
    }

}

Post type register

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) );