{"slug":"wordpress-custom-post-types","title":"WordPress Custom Post Types and Taxonomies","tags":["development","custom-post-types","taxonomies","rest-api"],"agent_summary":"Register custom post types and taxonomies in functions.php with Gutenberg and REST API support.","trigger_phrases":["custom post type wordpress","register_post_type","wordpress taxonomy","cpt wordpress","wordpress content types"],"runnable":true,"markdown":"\nRegister custom post types (CPTs) and taxonomies in `functions.php` or a dedicated plugin file. Never in theme files if the content needs to persist across theme changes.\n\n## Register a Custom Post Type\n\n```php\nfunction register_custom_post_types() {\n    register_post_type('portfolio', [\n        'labels' => [\n            'name'               => __('Portfolio', 'my-theme'),\n            'singular_name'      => __('Project', 'my-theme'),\n            'add_new_item'       => __('Add New Project', 'my-theme'),\n            'edit_item'          => __('Edit Project', 'my-theme'),\n            'view_item'          => __('View Project', 'my-theme'),\n            'search_items'       => __('Search Portfolio', 'my-theme'),\n            'not_found'          => __('No projects found', 'my-theme'),\n        ],\n        'public'       => true,\n        'has_archive'  => true,\n        'menu_icon'    => 'dashicons-portfolio',\n        'supports'     => ['title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'],\n        'rewrite'      => ['slug' => 'portfolio', 'with_front' => false],\n        'show_in_rest' => true, // Required for Gutenberg support\n        'menu_position' => 5,\n    ]);\n}\nadd_action('init', 'register_custom_post_types');\n```\n\n## Register a Custom Taxonomy\n\n```php\nfunction register_custom_taxonomies() {\n    register_taxonomy('project_type', ['portfolio'], [\n        'labels' => [\n            'name'              => __('Project Types', 'my-theme'),\n            'singular_name'     => __('Project Type', 'my-theme'),\n            'search_items'      => __('Search Project Types', 'my-theme'),\n            'all_items'         => __('All Project Types', 'my-theme'),\n            'edit_item'         => __('Edit Project Type', 'my-theme'),\n            'update_item'       => __('Update Project Type', 'my-theme'),\n            'add_new_item'      => __('Add New Project Type', 'my-theme'),\n        ],\n        'hierarchical'  => true,  // true = category-like, false = tag-like\n        'public'        => true,\n        'show_in_rest'  => true,\n        'rewrite'       => ['slug' => 'project-type'],\n    ]);\n}\nadd_action('init', 'register_custom_taxonomies');\n```\n\n## Flush Rewrite Rules\n\nAfter registering new CPTs, flush rewrite rules once:\n\n```php\n// In activation hook of a plugin\nregister_activation_hook(__FILE__, function() {\n    register_custom_post_types();\n    flush_rewrite_rules();\n});\n```\n\nOr navigate to Settings > Permalinks and click Save in WordPress admin.\n\n## Query CPT Posts\n\n```php\n$projects = new WP_Query([\n    'post_type'      => 'portfolio',\n    'posts_per_page' => 12,\n    'tax_query'      => [\n        [\n            'taxonomy' => 'project_type',\n            'field'    => 'slug',\n            'terms'    => 'web-design',\n        ],\n    ],\n    'orderby' => 'date',\n    'order'   => 'DESC',\n]);\n```\n\n## Common Dashicons for Menu Icons\n\n`dashicons-portfolio`, `dashicons-testimonial`, `dashicons-location-alt`, `dashicons-star-filled`, `dashicons-hammer`, `dashicons-admin-tools`\n","html":"<p>Register custom post types (CPTs) and taxonomies in <code>functions.php</code> or a dedicated plugin file. Never in theme files if the content needs to persist across theme changes.</p>\n<h2>Register a Custom Post Type</h2>\n<pre><code class=\"language-php\">function register_custom_post_types() {\n    register_post_type('portfolio', [\n        'labels' => [\n            'name'               => __('Portfolio', 'my-theme'),\n            'singular_name'      => __('Project', 'my-theme'),\n            'add_new_item'       => __('Add New Project', 'my-theme'),\n            'edit_item'          => __('Edit Project', 'my-theme'),\n            'view_item'          => __('View Project', 'my-theme'),\n            'search_items'       => __('Search Portfolio', 'my-theme'),\n            'not_found'          => __('No projects found', 'my-theme'),\n        ],\n        'public'       => true,\n        'has_archive'  => true,\n        'menu_icon'    => 'dashicons-portfolio',\n        'supports'     => ['title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'],\n        'rewrite'      => ['slug' => 'portfolio', 'with_front' => false],\n        'show_in_rest' => true, // Required for Gutenberg support\n        'menu_position' => 5,\n    ]);\n}\nadd_action('init', 'register_custom_post_types');\n</code></pre>\n<h2>Register a Custom Taxonomy</h2>\n<pre><code class=\"language-php\">function register_custom_taxonomies() {\n    register_taxonomy('project_type', ['portfolio'], [\n        'labels' => [\n            'name'              => __('Project Types', 'my-theme'),\n            'singular_name'     => __('Project Type', 'my-theme'),\n            'search_items'      => __('Search Project Types', 'my-theme'),\n            'all_items'         => __('All Project Types', 'my-theme'),\n            'edit_item'         => __('Edit Project Type', 'my-theme'),\n            'update_item'       => __('Update Project Type', 'my-theme'),\n            'add_new_item'      => __('Add New Project Type', 'my-theme'),\n        ],\n        'hierarchical'  => true,  // true = category-like, false = tag-like\n        'public'        => true,\n        'show_in_rest'  => true,\n        'rewrite'       => ['slug' => 'project-type'],\n    ]);\n}\nadd_action('init', 'register_custom_taxonomies');\n</code></pre>\n<h2>Flush Rewrite Rules</h2>\n<p>After registering new CPTs, flush rewrite rules once:</p>\n<pre><code class=\"language-php\">// In activation hook of a plugin\nregister_activation_hook(__FILE__, function() {\n    register_custom_post_types();\n    flush_rewrite_rules();\n});\n</code></pre>\n<p>Or navigate to Settings > Permalinks and click Save in WordPress admin.</p>\n<h2>Query CPT Posts</h2>\n<pre><code class=\"language-php\">$projects = new WP_Query([\n    'post_type'      => 'portfolio',\n    'posts_per_page' => 12,\n    'tax_query'      => [\n        [\n            'taxonomy' => 'project_type',\n            'field'    => 'slug',\n            'terms'    => 'web-design',\n        ],\n    ],\n    'orderby' => 'date',\n    'order'   => 'DESC',\n]);\n</code></pre>\n<h2>Common Dashicons for Menu Icons</h2>\n<p><code>dashicons-portfolio</code>, <code>dashicons-testimonial</code>, <code>dashicons-location-alt</code>, <code>dashicons-star-filled</code>, <code>dashicons-hammer</code>, <code>dashicons-admin-tools</code></p>\n"}