Function — Add custom post types as plugins - martindubenet/Wordpress GitHub Wiki

NOTES:1. Adding the labels 'thisTheme' makes it compatible with the multi-lingual plugin WPML.2. You need to set your permanlinks to /%category%/%postname%/ in other to access the posts generated from those custom types.

Custom Post Types (CTPs)

It is a best practice to set Custom Post Types within a dedicated Plugin instead on the theme's functions.php file. Since CPTs are related to database contentsRefer to this tutorial: « WordPress Functionality Plugins » from Css-Tricks to learn how.

You can find online custom Post Type generator such as cpt-generator.propernoun.co that will save you a lot of time.

Render a CPT as a template file

We have two options here depending on the design requirements:

  1. Either a « Template Part »,
  2. Or an entire « Template File ».

Template Parts

/template-parts/content-register_post_type().php

Rely on parts if only the main content area differs from the default post type. If, like a « default (blog) post type » your CPTs contents are :

  1. Relative to a time line,
  2. Same navigation logic of «Previous post» and «Next post» navigation.
  3. Same page header (<h1>) has your blog post,

This partial logic is embeded in Wordpress template hierchy. A native get_template_part() function is available.

Template Files

The singular post template used when a visitor requests a single post from a custom post type. For example, /singular-book.php would be used for displaying single posts from a custom post type named book. The /index.php used if a specific query template for the custom post type is not present.

Simply duplicate & rename the singular.php to your registered post-type value :

/singular-register_post_type().php

Render a list of your CPTs

WP_Query is a class used in WordPress theming that accepts a variety of parameters to request and fetch posts around those parameters. Use it lo loop within your CPTs and display it in a page.

Gutenberg editor

In the code snippet above, you need to set 'show_in_rest' => true to enable the new Gutenberg editor in custom post-type.

Custom Fields Metabox

NOTES: After using it on a project I strongly recommand to rely on the plugin Advanced Custom Fields (ACF).

  1. From your theme or plugin :In the code snippet where you declare the custom post type, set within the $args array key support the 'custom_fields' as a value. If more then one values seperate them with comas (ex: 'other_value', 'custom_fields').
  2. From the dashboard :Follow this tutorial: https://kaspars.net/blog/custom-fields-metabox-gutenberg

Translation for multilangue support

slug translation via Permalinks

Translating the array( 'slug' ) of the rewrite parameter does not support the usual gettext translation properly. It just does not translate it at all. Therefor Christopher Davis shared a workaround on his github, «cpt-permalinks.php».

1st Step:

I download his «Custom-Post-Type Base» plugin file in my theme/plugin, then I include the file within my /functions.php file, previous to my own CPT function:

// load `function wpse30021_cpt_base`
include_once(inc/cpt-permalinks.php);

2nd Step

Within my CPT function, I copy/paste this parameter line within in the $args array:

'rewrite' => array( 'slug' => get_option( 'wpse30021_cpt_base' ) ),`

 

CPT Models

plugin name theme template Structured data schema
posttype-jobpost /single-jobpost.php Google job posting
posttype-portfolio /single-portfolio.php CreativeWork
posttype-wine /single-wines.php Winery and Product

Jobpost CPT

// Register Custom Post Type for Job Post.
function customTheme_jobPostType_init() {
	$labels = array(
		'name'               => _x( 'Jobs', 'post type general name', 'thisTheme' ),
		'singular_name'      => _x( 'Job', 'post type singular name', 'thisTheme' ),
		'menu_name'          => __( 'Job posts', 'admin menu', 'thisTheme' ),
		'add_new_item'       => __( 'Add New Job Post', 'thisTheme' ),
		'new_item'           => __( 'New Job Post', 'thisTheme' ),
		'edit_item'          => __( 'Edit Job Post', 'thisTheme' ),
		'view_item'          => __( 'View Job Post', 'thisTheme' ),
		'all_items'          => __( 'All Job Posts', 'thisTheme' ),
		'search_items'       => __( 'Search Job Posts', 'thisTheme' ),
		'parent_item_colon'  => __( 'Parent Job Posts:', 'thisTheme' ),
		'not_found'          => __( 'No job posts found.', 'thisTheme' ),
		'not_found_in_trash' => __( 'No job posts found in Trash.', 'thisTheme' )
	);

	$args = array(
		'capability_type'    => 'post',
		'can_export'         => true,
		'description'        => __( 'Description.', 'thisTheme' ),
		'has_archive'        => false,
		'hierarchical'       => false,
		'labels'             => $labels,
		'menu_position'      => 5, // positionned below `posts` in the side Admin Menu
		'menu_icon'          => 'dashicons-id', // developer.wordpress.org/resource/dashicons/#id
		'public'             => true,
		'publicly_queryable' => true,
		'query_var'          => true,
		//'rewrite'            => array( 'slug' => 'job-post' ), // url rewriting for SEO
		'show_in_menu'       => true,
		'show_in_rest'       => true, // true enables gutenberg editor
		'show_ui'            => true,
		'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'custom_fields', 'excerpt', 'comments' ),
                'taxonomies'         => array('post_tag', 'category')
	);

	register_post_type( 'jobpost', $args );
}
add_action( 'init', 'customTheme_jobPostType_init' );

💼 Portfolio CPT

/* Register Custom Post Type for Portfolio */
function cw_post_type() {

    register_post_type( 'portfolio',
        array(
            'labels' => array(
                'name'          => __( 'Portfolio' ),
                'singular_name' => __( 'Portfolio' )
            ),
            'has_archive'    => true,
            'public'         => true,
            //'rewrite'        => array('slug' => 'portfolio'),
            'show_in_rest'   => true,
            'supports'       => array('editor', 'thumbnail', 'custom_fields', 'excerpt')
            'taxonomies'     => array('post_tag', 'category')
        )
    );
}
add_action( 'init', 'cw_post_type' );

🍷 Wines

// Register Custom Post Type for Wine Bottles
function custom_wine_post_type() {
    $labels = array(
        'name'                  => _x('Wines', 'Post Type General Name', 'posttype wine'),
        'singular_name'         => _x('Wine', 'Post Type Singular Name', 'posttype wine'),
        'add_new'               => __('Add New', 'posttype wine'),
        'add_new_item'          => __('Add A New Wine', 'posttype wine'),
        'all_items'             => __('All Wines', 'posttype wine'),
        'archives'              => __('Wine Archives', 'posttype wine'),
        'edit_item'             => __('Edit Item', 'posttype wine'),
        'featured_image'        => __('Product Image', 'posttype wine'),
        'filter_items_list'     => __('Filter Wines List', 'posttype wine'),
        'insert_into_item'      => __('Post Types', 'posttype wine'),
        'items_list'            => __('Wines List', 'posttype wine'),
        'items_list_navigation' => __('Wines List Navigation', 'posttype wine'),
        'menu_name'             => __('Wine Bottles', 'posttype wine'),
        'name_admin_bar'        => __('Add New', 'posttype wine'),
        'new_item'              => __('New Wine', 'posttype wine'),
        'not_found'             => __('No Wine Found', 'posttype wine'),
        'not_found_in_trash'    => __('Not Found In Trash', 'posttype wine'),
        'parent_item_colon'     => __('Parent Item', 'posttype wine'),
        'remove_featured_image' => __('Remove Product Image', 'posttype wine'),
        'search_items'          => __('Search A Wine', 'posttype wine'),
        'set_featured_image'    => __('Set Product Image', 'posttype wine'),
        'update_item'           => __('Update Item', 'posttype wine'),
        'uploaded_to_this_item' => __('Uploaded To This Product', 'posttype wine'),
        'use_featured_image'    => __('Use As Product Image', 'posttype wine'),
        'view_item'             => __('View Wine', 'posttype wine'),
    );
    $args = array(
        'capability_type'       => 'page',
        'can_export'            => true,
        'description'           => __('Wine product page', 'posttype wine'),
        'exclude_from_search'   => false,
        'label'                 => __('Post Type', 'posttype wine'),
        'labels'                => $labels,
        'has_archive'           => true,
        'hierarchical'          => false,
        'menu_position'         => 5,
        'publicly_queryable'    => true,
        'public'                => true,
        'show_in_admin_bar'     => true,
        'show_in_menu'          => true,
        'show_in_nav_menus'     => true,
	'show_in_rest'          => true, // true enables gutenberg editor
        'show_ui'               => true,
        'supports'              => array('editor', 'title', 'trackbacks', 'content', 'revisions', 'excerpt', 'custom_fields', 'author', 'post_attributes', 'featured_image', 'post_formats', 'comments'),
        'taxonomies'            => array('post_tag', 'category')
    );
    register_post_type('wines', $args);
}
add_action('init', 'custom_wine_post_type', 0);