How to create a WordPress plugin that allows admins to add new custom post types

The following was created from a single short prompt given to Google.com/ai (which is the title of this post). AI is moving rapidly, and although the creation of WordPress Plugins like this is nothing new, for the average user out there with zero knowledge of programming it is an absolutely revelation.

The price of software will fall off a cliff in the not too far future (the cost of software is shifting rapidly from hiring developers to server farms).

The one that will not change so rapidly is the domain expert and visionaries. From a career perspective, that is where anyone thinking of entering the software industry should be headed.

And from a marketing point of view, it is simply this: “Know your market” – which means – know their needs and come up with a solution better than anything currently available.

Create The Perfect Business Quentin Pain signature image

PS. The above was written by me without the use of an AI. No AI can replace any one of us, but it can be disastrous for our jobs unless we’re prepared.

ACF | Registering a Custom Post Type

Creating a WordPress plugin that allows admins to add new custom types involves developing an admin interface to collect information and then dynamically registering the custom post types based on the saved settings. This process combines back-end PHP for registering the post types and front-end code (HTML, CSS, and JavaScript) for the user interface.

Step 1: Create the plugin file structure

Start by creating a new directory in your wp-content/plugins folder. For this example, we’ll name it dynamic-cpt. Inside this folder, create the main plugin file, dynamic-cpt.php.

dynamic-cpt/
├── dynamic-cpt.php
├── admin/
│   ├── css/
│   │   └── admin-styles.css
│   └── js/
│       └── admin-scripts.js

Step 2: Set up the main plugin file (dynamic-cpt.php)

The main file defines the plugin, handles activation/deactivation, and includes the code for the admin pages and custom post type registration.

php

<?php
/**
 * Plugin Name:       Dynamic Custom Post Types
 * Plugin URI:        https://example.com/dynamic-cpt
 * Description:       Allows admins to create new custom post types from the dashboard.
 * Version:           1.0.0
 * Author:            Your Name
 * Author URI:        https://example.com
 * License:           GPL-2.0+
 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain:       dynamic-cpt
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Function to run on plugin activation.
function ddcpt_activate_plugin() {
    // Check if the required function exists.
    if ( ! function_exists( 'register_post_type' ) ) {
        deactivate_plugins( plugin_basename( __FILE__ ) );
        wp_die( 'This plugin requires a compatible version of WordPress.' );
    }
}
register_activation_hook( __FILE__, 'ddcpt_activate_plugin' );

// Include necessary files.
require_once plugin_dir_path( __FILE__ ) . 'admin/admin-menu.php';
require_once plugin_dir_path( __FILE__ ) . 'admin/register-cpt.php';

// Action to register CPTs when WordPress initializes.
add_action( 'init', 'ddcpt_register_custom_post_types' );

// Action to add plugin admin menu.
add_action( 'admin_menu', 'ddcpt_add_admin_menu' );

// Action to save settings.
add_action( 'admin_post_ddcpt_save_settings', 'ddcpt_handle_form_submission' );
?>

Use code with caution.

Step 3: Create the admin menu and settings page (admin/admin-menu.php)

This file handles the admin menu and the HTML for the form where admins will enter the details for their custom post types.

php

<?php
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function ddcpt_add_admin_menu() {
    add_menu_page(
        'Dynamic CPT Settings',
        'Dynamic CPT',
        'manage_options',
        'dynamic-cpt',
        'ddcpt_settings_page_html',
        'dashicons-admin-post',
        6
    );
}

function ddcpt_settings_page_html() {
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
            <input type="hidden" name="action" value="ddcpt_save_settings">
            <?php wp_nonce_field( 'ddcpt_save_settings_nonce' ); ?>
            <table class="form-table">
                <tr>
                    <th scope="row"><label for="ddcpt_singular_name">Singular Name</label></th>
                    <td><input name="ddcpt_singular_name" type="text" id="ddcpt_singular_name" class="regular-text"></td>
                </tr>
                <tr>
                    <th scope="row"><label for="ddcpt_plural_name">Plural Name</label></th>
                    <td><input name="ddcpt_plural_name" type="text" id="ddcpt_plural_name" class="regular-text"></td>
                </tr>
                <tr>
                    <th scope="row"><label for="ddcpt_menu_icon">Menu Icon</label></th>
                    <td><input name="ddcpt_menu_icon" type="text" id="ddcpt_menu_icon" class="regular-text" placeholder="e.g., dashicons-awards"></td>
                </tr>
                <tr>
                    <th scope="row">Supports</th>
                    <td>
                        <fieldset>
                            <label><input type="checkbox" name="ddcpt_supports[]" value="title" checked> Title</label><br>
                            <label><input type="checkbox" name="ddcpt_supports[]" value="editor" checked> Editor</label><br>
                            <label><input type="checkbox" name="ddcpt_supports[]" value="thumbnail"> Thumbnail</label><br>
                            <label><input type="checkbox" name="ddcpt_supports[]" value="excerpt"> Excerpt</label>
                        </fieldset>
                    </td>
                </tr>
            </table>
            <?php submit_button( 'Create Custom Post Type' ); ?>
        </form>
    </div>
    <?php
}

// Handle form submission and save settings.
function ddcpt_handle_form_submission() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    check_admin_referer( 'ddcpt_save_settings_nonce' );

    $singular_name = sanitize_text_field( $_POST['ddcpt_singular_name'] );
    $plural_name = sanitize_text_field( $_POST['ddcpt_plural_name'] );
    $menu_icon = sanitize_text_field( $_POST['ddcpt_menu_icon'] );
    $supports = isset( $_POST['ddcpt_supports'] ) ? array_map( 'sanitize_text_field', $_POST['ddcpt_supports'] ) : array();

    if ( ! empty( $singular_name ) && ! empty( $plural_name ) ) {
        $slug = sanitize_title( $singular_name );

        $new_cpt = array(
            'singular_name' => $singular_name,
            'plural_name'   => $plural_name,
            'slug'          => $slug,
            'menu_icon'     => $menu_icon,
            'supports'      => $supports,
        );

        $existing_cpts = get_option( 'ddcpt_custom_types', array() );
        $existing_cpts[$slug] = $new_cpt;

        update_option( 'ddcpt_custom_types', $existing_cpts );

        // Flush rewrite rules to ensure the new CPT is accessible.
        flush_rewrite_rules();
    }

    wp_safe_redirect( add_query_arg( 'settings-updated', 'true', admin_url( 'admin.php?page=dynamic-cpt' ) ) );
    exit;
}

Use code with caution.

Step 4: Register custom post types dynamically (admin/register-cpt.php)

This file contains the logic to retrieve the custom post types stored in the database and register them with WordPress.

php

<?php
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function ddcpt_register_custom_post_types() {
    $custom_types = get_option( 'ddcpt_custom_types', array() );

    foreach ( $custom_types as $slug => $cpt ) {
        $labels = array(
            'name'          => _x( $cpt['plural_name'], 'Post Type General Name', 'dynamic-cpt' ),
            'singular_name' => _x( $cpt['singular_name'], 'Post Type Singular Name', 'dynamic-cpt' ),
            'menu_name'     => __( $cpt['plural_name'], 'dynamic-cpt' ),
            'all_items'     => __( 'All ' . $cpt['plural_name'], 'dynamic-cpt' ),
            'add_new'       => __( 'Add New ' . $cpt['singular_name'], 'dynamic-cpt' ),
            'add_new_item'  => __( 'Add New ' . $cpt['singular_name'], 'dynamic-cpt' ),
            'edit_item'     => __( 'Edit ' . $cpt['singular_name'], 'dynamic-cpt' ),
            'new_item'      => __( 'New ' . $cpt['singular_name'], 'dynamic-cpt' ),
            'view_item'     => __( 'View ' . $cpt['singular_name'], 'dynamic-cpt' ),
        );

        $args = array(
            'labels'      => $labels,
            'public'      => true,
            'has_archive' => true,
            'menu_icon'   => $cpt['menu_icon'],
            'rewrite'     => array( 'slug' => $slug ),
            'supports'    => $cpt['supports'],
            'show_in_rest' => true, // Important for Gutenberg editor support.
        );

        register_post_type( $slug, $args );
    }
}

Use code with caution.

Step 5: Enqueue admin styles and scripts (optional)

For a cleaner and more professional admin interface, you can add CSS and JavaScript.

admin/css/admin-styles.css:

css

/* Add custom CSS for your admin page if desired */
.ddcpt-notice {
    padding: 1rem;
    background-color: #d1e7dd;
    border-color: #badbcc;
    color: #0f5132;
    border: 1px solid transparent;
    border-radius: .25rem;
    margin-bottom: 1rem;
}

Use code with caution.

admin/js/admin-scripts.js:
This file can be left empty for now, but is ready for future functionality.

Update dynamic-cpt.php to include the assets:

php

// Add this to your main plugin file.
function ddcpt_enqueue_admin_assets() {
    wp_enqueue_style( 'ddcpt-admin-styles', plugin_dir_url( __FILE__ ) . 'admin/css/admin-styles.css' );
    wp_enqueue_script( 'ddcpt-admin-scripts', plugin_dir_url( __FILE__ ) . 'admin/js/admin-scripts.js', array( 'jquery' ), '1.0', true );
}
add_action( 'admin_enqueue_scripts', 'ddcpt_enqueue_admin_assets' );

Use code with caution.

How to use the plugin

  1. Install and activate: Place the entire dynamic-cpt folder into your wp-content/plugins directory and activate it from the WordPress dashboard.
  2. Add a custom post type: Navigate to the new “Dynamic CPT” menu item in your dashboard.
  3. Fill out the form: Enter the singular and plural names for your custom post type, select the features it should support, and choose a menu icon.
  4. Save: Click the “Create Custom Post Type” button. The new custom type will appear in your admin menu.
  5. Create content: You can now create new posts for your custom type just like regular posts or pages.

AI responses may include mistakes