Many themes or plugins create custom post types (like 'Website', 'Product') and their associated taxonomies (like 'Website Category'). Sometimes, you need to allow front-end users to submit posts to these custom taxonomies, not just the default 'Post' type. This article explains how to implement this feature using pure code.
Core Implementation Principle
WordPress provides the powerful wp_insert_post() function to create posts of any type. The key is correctly setting its parameters, especially post_type and tax_input.
Key Code Example
The following code handles form submission, creates a pending custom post, and associates it with a specified term. Place it in your theme's functions.php or a custom plugin.
function handle_cpt_submission() {
// 1. Security: verify nonce
if ( ! isset( $_POST['submit_nonce'] ) || ! wp_verify_nonce( $_POST['submit_nonce'], 'cpt_submit_action' ) ) {
wp_die( 'Security check failed.' );
}
// 2. Sanitize and validate data
$post_title = sanitize_text_field( $_POST['post_title'] ?? '' );
$post_content = wp_kses_post( $_POST['post_content'] ?? '' );
$term_id = absint( $_POST['term_id'] ?? 0 );
if ( empty( $post_title ) || empty( $post_content ) || $term_id <= 0 ) {
wp_die( 'Please fill all required fields.' );
}
// 3. Assemble post data
$new_post = array(
'post_type' => 'your_cpt', // Replace with your CPT name
'post_title' => $post_title,
'post_content' => $post_content,
'post_status' => 'pending', // Set to 'pending' for moderation
'tax_input' => array(
'your_taxonomy' => array( $term_id ), // Replace with your taxonomy name
),
);
// 4. Insert post
$post_id = wp_insert_post( $new_post, true );
// 5. Handle result
if ( is_wp_error( $post_id ) ) {
wp_die( 'Submission failed: ' . $post_id->get_error_message() );
} else {
wp_safe_redirect( home_url( '/thank-you/' ) );
exit;
}
}
add_action( 'admin_post_nopriv_cpt_submit', 'handle_cpt_submission' );
add_action( 'admin_post_cpt_submit', 'handle_cpt_submission' );
Front-End Form Essentials
Create a form whose action points to admin-post.php with a hidden action parameter matching the hook above.
<form method='post' action='<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>'>
<?php wp_nonce_field( 'cpt_submit_action', 'submit_nonce' ); ?>
<input type='hidden' name='action' value='cpt_submit'>
<label for='post_title'>Title:</label>
<input type='text' id='post_title' name='post_title' required>
<label for='post_content'>Content:</label>
<textarea id='post_content' name='post_content' required></textarea>
<label for='term_id'>Select Category:</label>
<?php
wp_dropdown_categories( array(
'taxonomy' => 'your_taxonomy', // Replace
'name' => 'term_id',
'show_option_none' => 'Select',
'required' => true,
'value_field' => 'term_id',
) );
?>
<input type='submit' value='Submit'>
</form>
Important Notes & Security
- Permission Control: The
admin_post_*hooks are a standard, secure way to handle front-end forms. - Data Validation: Always sanitize user input with functions like
sanitize_text_field(),wp_kses_post(), andabsint()to prevent XSS and SQL injection. - Nonce Verification:
wp_nonce_field()andwp_verify_nonce()prevent CSRF attacks. - Replace Names: Change
your_cptandyour_taxonomyto your actual registered post type and taxonomy names. - Status Management: Setting
post_statustopendingallows admin moderation before publishing.
Following these steps, you can build a secure, reliable front-end submission system for custom post types and taxonomies.