Tag: Custom Post Types

  • Custom Post Types

    Here’s an example of a custom post type for an “Example” CPT:

    <?php
    
    class CPT_Example
    {
        /**
         * CPT_NAME is the custom post type name. Also used to generate the CPT Label using `ucfirst()`.
         * 
         * @var string
         */
        const CPT_NAME = 'example';
    
        const TAX_NAME_TYPE = 'example-type';
    
        const NONCE_NAME = 'example_meta_box';
    
        public $fields = [
            'example_name',
            'example_company',
        ];
    
        /**
         * Set all the required hooks to register the Staff custom post type and all other required components/features
         * 
         * @return void
         */
        public function init()
        {
            // All the init operations we need to do in one call
            add_action('init', [$this, 'register']);
    
            // Remove the "Archive: " prefix (eg: "Archive: Staff Directory")
            add_filter('get_the_archive_title_prefix', [$this, 'remove_archive_prefix'], 10, 1);
    
            // Add a custom metabox for the example post type
            add_action('add_meta_boxes', [$this, 'add_meta_boxes']);
        }
    
        /**
         * Method to choreograph the registration of the custom post type and all of its required components
         * 
         * @return void
         */
        public function register()
        {
            $this->register_taxonomies();
            $this->register_post_type();
    
            add_action('save_post_' . self::CPT_NAME, [$this, 'save_example_meta']);
        }
    
        /**
         * Registers the Staff custom post type
         * 
         * @return void
         */
        public function register_post_type()
        {
            $uc_label = ucwords(str_replace('-', ' ', self::CPT_NAME));
            $uc_plural = $uc_label . 's';
    
            register_post_type(
                self::CPT_NAME,
                [
                    'labels' => [
                        'name'                => $uc_plural,
                        'singular_name'       => $uc_label,
                        'menu_name'           => $uc_label,
                        'parent_item_colon'   => 'Parent ' . $uc_label,
                        'all_items'           => 'All ' . $uc_plural,
                        'view_item'           => 'View ' . $uc_label,
                        'add_new_item'        => 'Add New ' . $uc_label,
                        'add_new'             => 'Add New',
                        'edit_item'           => 'Edit ' . $uc_label,
                        'update_item'         => 'Update ' . $uc_label,
                        'search_items'        => 'Search ' . $uc_plural,
                        'not_found'           => 'Not Found',
                        'not_found_in_trash'  => 'Not found in Trash',
                    ],
                    'taxonomies'    => [ self::TAX_NAME_TYPE, /* Add more taxonomies here */ ],
                    'show_ui'       => true,
                    'public'        => true,
                    'has_archive'   => true,
                    'rewrite'       => [
                        'slug'          => self::CPT_NAME . 's',
                        'with_front'    => false, // removes the /blog/ prefix in the url
                        'feeds'         => false,
                        'pages'         => true,
                        'ep_mask'       => EP_PAGES
                    ],
                    'menu_icon'     => 'dashicons-businessman',
                    'supports'      => ['title', 'editor', 'thumbnail'],
                    'show_in_rest'  => true,
                    'rest_base'     => self::CPT_NAME
                ]
            );
        }
    
        public function register_taxonomies()
        {
            register_taxonomy(
                self::TAX_NAME_TYPE,
                self::CPT_NAME,
                [
                    'labels' => [
                        'name'              => 'Example Types',
                        'singular_name'     => 'Example Type',
                        'search_items'      => 'Search Example Types',
                        'all_items'         => 'All Example Types',
                        'parent_item'       => 'Parent Example Type',
                        'parent_item_colon' => 'Parent Example Type:',
                        'edit_item'         => 'Edit Example Type',
                        'update_item'       => 'Update Example Type',
                        'add_new_item'      => 'Add New Example Type',
                        'new_item_name'     => 'New Example Type Name',
                        'menu_name'         => 'Example Types',
                    ],
                    'show_ui'           => true,
                    'show_admin_column' => true,
                    'hierarchical'      => true,
                    'show_in_rest'      => true,
                    'rest_base'         => self::TAX_NAME_TYPE . 's'
                ]
            );
        }
    
        /**
         * Remove the "Archives:" prefix from the archive title for the post type
         * 
         * @param string $prefix    The current prefix as given by the filter
         * @return string           The modified prefix
         */ 
        public function remove_archive_prefix($prefix)
        {
            return is_post_type_archive(self::CPT_NAME)
                || is_tax(self::TAX_NAME_TYPE)
                    ? ''
                    : $prefix;
        }
    
        public function add_meta_boxes()
        {
            add_meta_box(
                'example_posting_meta_box',
                'Example Details',
                [$this, 'render_example_meta_box'],
                self::CPT_NAME,
                'normal',
                'high'
            );
        }
    
        public function render_example_meta_box($post)
        {
            // Get existing meta values ('post' here means the object type comes from the posts table)
            $meta = get_metadata( 'post', $post->ID, '', true );
            foreach ( $this->fields as $field ) {
                $$field = $meta[$field][0] ?? '';
            }
    
            // Add the hidden nonce field
            wp_nonce_field( self::NONCE_NAME, self::NONCE_NAME . '_nonce');
    
            include_once EXAMPLE_TEMPLATEDIR . 'metabox.php';
        }
    
        public function save_example_meta($post_id) 
        {
            // Add nonce check, autosave check, and capability check here
            $nonce = $_POST[self::NONCE_NAME . '_nonce'] ?? false;
            if ( !$nonce || !wp_verify_nonce($nonce, self::NONCE_NAME) ) {
                return $post_id;
            }
    
            foreach ( $this->fields as $field ) {
                if (isset($_POST[$field])) {
                    update_post_meta($post_id, $field, $_POST[$field]);
                }
            }
        }
    }