How to make future request forums on WordPress and Greenshift

Today, we will discuss how to create a future request forum on a WordPress site without using any future request forum plugins. This will also demonstrate how flexible your site can be on Greenshift if you know what you’re doing. We will also share all the templates so you can do this easily.

First of all, I want to mention that I will use some code snippets. You can put them in a child theme or in the code snippet plugin, but I prefer to use a simple, clean, custom plugin. This way, it doesn’t conflict with the theme, and you can put just PHP code in it without using styles.

You can download clean plugin from tutorial.

The first thing that you need is to register a custom post type and taxonomy. We will use post type “request”. You can use plugin CPT UI or ACF, ACPT or any other plugins but I will use just code for my clean plugin

function register_request_post_type() {
    $labels = array(
        'name'                  => _x( 'Requests', 'Post Type General Name', 'greenshift-code-snippet-plugin' ),
        'singular_name'         => _x( 'Request', 'Post Type Singular Name', 'greenshift-code-snippet-plugin' ),
        'menu_name'             => __( 'Requests', 'greenshift-code-snippet-plugin' ),
        'all_items'             => __( 'All Requests', 'greenshift-code-snippet-plugin' ),
        'add_new_item'          => __( 'Add New Request', 'greenshift-code-snippet-plugin' ),
        'add_new'               => __( 'Add New', 'greenshift-code-snippet-plugin' ),
        'new_item'              => __( 'New Request', 'greenshift-code-snippet-plugin' ),
        'edit_item'             => __( 'Edit Request', 'greenshift-code-snippet-plugin' ),
        'update_item'           => __( 'Update Request', 'greenshift-code-snippet-plugin' ),
        'view_item'             => __( 'View Request', 'greenshift-code-snippet-plugin' ),
        'view_items'            => __( 'View Requests', 'greenshift-code-snippet-plugin' ),
        'search_items'          => __( 'Search Requests', 'greenshift-code-snippet-plugin' ),
    $args = array(
        'label'                 => __( 'Request', 'greenshift-code-snippet-plugin' ),
        'description'           => __( 'Request Custom Post Type', 'greenshift-code-snippet-plugin' ),
        'labels'                => $labels,
        'supports'              => array( 'title', 'editor', 'thumbnail', 'custom-fields', 'author', 'excerpt', 'comments' ),
        'taxonomies'            => array( 'request_tag' ),
        'hierarchical'          => false,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 5,
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => true,
        'can_export'            => true,
        'has_archive'           => true,
        'exclude_from_search'   => false,
        'publicly_queryable'    => true,
        'capability_type'       => 'post',
        'show_in_rest' => true,
    register_post_type( 'request', $args );
add_action( 'init', 'register_request_post_type' );

// Register Custom Taxonomy "Request Tag"
function register_request_tag_taxonomy() {
    $labels = array(
        'name'                       => _x( 'Request Tags', 'Taxonomy General Name', 'greenshift-code-snippet-plugin' ),
        'singular_name'              => _x( 'Request Tag', 'Taxonomy Singular Name', 'greenshift-code-snippet-plugin' ),
        'menu_name'                  => __( 'Request Tags', 'greenshift-code-snippet-plugin' ),
        'all_items'                  => __( 'All Request Tags', 'greenshift-code-snippet-plugin' ),
        'parent_item'                => __( 'Parent Request Tag', 'greenshift-code-snippet-plugin' ),
        'parent_item_colon'          => __( 'Parent Request Tag:', 'greenshift-code-snippet-plugin' ),
        'new_item_name'              => __( 'New Request Tag Name', 'greenshift-code-snippet-plugin' ),
        'add_new_item'               => __( 'Add New Request Tag', 'greenshift-code-snippet-plugin' ),
        'edit_item'                  => __( 'Edit Request Tag', 'greenshift-code-snippet-plugin' ),
        'update_item'                => __( 'Update Request Tag', 'greenshift-code-snippet-plugin' ),
        'view_item'                  => __( 'View Request Tag', 'greenshift-code-snippet-plugin' ),
        'separate_items_with_commas' => __( 'Separate Request Tags with commas', 'greenshift-code-snippet-plugin' ),
        'add_or_remove_items'        => __( 'Add or remove Request Tags', 'greenshift-code-snippet-plugin' ),
        'choose_from_most_used'      => __( 'Choose from the most used Request Tags', 'greenshift-code-snippet-plugin' ),
        'popular_items'              => __( 'Popular Request Tags', 'greenshift-code-snippet-plugin' ),
        'search_items'               => __( 'Search Request Tags', 'greenshift-code-snippet-plugin' ),
        'not_found'                  => __( 'Not Found', 'greenshift-code-snippet-plugin' ),
        'no_terms'                   => __( 'No Request Tags', 'greenshift-code-snippet-plugin' ),
        'items_list'                 => __( 'Request Tags list', 'greenshift-code-snippet-plugin' ),
        'items_list_navigation'      => __( 'Request Tags list navigation', 'greenshift-code-snippet-plugin' ),
    $args = array(
        'labels'                     => $labels,
        'hierarchical'               => false,
        'public'                     => true,
        'show_ui'                    => true,
        'show_admin_column'          => true,
        'show_in_nav_menus'          => true,
        'show_tagcloud'              => true,
        'show_in_rest' => true,
    register_taxonomy( 'request_tag', array( 'request' ), $args );
add_action( 'init', 'register_request_tag_taxonomy');

By this code, I registered request post type and request_tag that I can use to mark requests (I will use new, in progress, live, declined, etc) tags.

Now, I need to build two pages – one will be for archive of Request posts and one will be Single Request Item

If you use Greenshift theme, you can create custom templates for custom post types when you visit Appearance – Site Editor – Templates. Then click on Plus icon

Site editor can take up to 30 seconds to load all template parts, so, if you don’t see the option to create Single Request and Archive templates, just wait a bit, it should appear if you created the post type properly

If you don’t use an FSE theme, ask the author of your theme how to make templates for post types. If your theme doesn’t support this, you can use the Query add-on of Greenshift and the Template Replacement feature.

Request Forum Templates

Now you need to make custom templates. For archives, I will use Query builder block + thumbs/hot counter block for voting + dynamic fields. Also I need to add some kind of filters so users can filter most commented and most voted items. I will use Filter panel.

In the right area, I will also add Form with Form Element Block. You can use any other blocks, but if you want to investigate how it’s done on our site, we provide these templates in our Library of FSE Templates. You can find it in Templates – Custom templates section

Submit form

We need to make also special submit form. Again, you can use any frontend plugin but in my case, I just need to add option for users to create title and simple description so I will create custom form with Form Elements and I will do form submit processing via custom code

// Register Form processor for Requests
add_action( 'admin_post_submit_feature_form', 'submit_feature_form_handler' );
add_action( 'admin_post_nopriv_submit_feature_form', 'submit_feature_form_handler' );
function submit_feature_form_handler() {
    // Check if the user is authorized to submit the form
    //if ( ! current_user_can( 'publish_posts' ) ) {
        //wp_die( 'Unauthorized user' );
        wp_die( 'Unauthorized user' );

    // Retrieve form data
    $title = !empty($_POST['title']) ? sanitize_text_field( $_POST['title'] ) : '';
    $content = !empty($_POST['content']) ? wp_kses_post( $_POST['content'] ) : '';

    // Create a new post of type "features"
    $post_id = wp_insert_post( array(
        'post_title'    => $title,
        'post_content'  => wp_slash($content),
        'post_status'   => 'publish',
        'post_type' => 'request',
    ) );

    // Redirect the user after submission
    if ( $post_id ) {
        wp_set_object_terms($post_id, 'new', 'request_tag', false);
        wp_redirect( get_the_permalink($post_id) );
    } else {
        echo 'Unexpected error';

Here are a few important things in the code. Pay attention to this line: “admin_post_submit_feature_form” — this is the name of the hook for “admin_post_” The second part of the hook name is the key that we must use in our form. So, logic is next. The form triggers the action “submit_feature_form,” and this code will guarantee that WordPress runs the code for this action. To make this happen, we need to use as the action of your form.

Don’t forget to put your link of your site in this field if you use the template

Now, inside the form, create an Input field with the type hidden and action “submit_feature_form”.

and also create fields that you want to send in form

So, whole process is next. Form is sending request to file that responsible for admin actions /wp-admin/admin-post.php. In form you send name of action submit_feature_form. Now, as form handler you can use admin_post hooks of wordpress.

More about admin_post action

It’s important to mention that I don’t use any kind of capability checking in form. Code is commented here

//if ( ! current_user_can( 'publish_posts' ) ) {
        //wp_die( 'Unauthorized user' );

This is because My form is using Visibility options from Greenshift to check if user is logged in and if it’s premium user. If not – I show him Login form

But depending on your membership conditions, I strongly recommend removing// from the code to uncomment it so only specific roles of users can submit request items on your site

Also, it’s important to sanitize all user input. I do this in the next lines

$title = !empty($_POST['title']) ? sanitize_text_field( $_POST['title'] ) : '';
$content = !empty($_POST['content']) ? wp_kses_post( $_POST['content'] ) : '';

Also, I add the specific tag “new” to all newly submitted items. Later, if I want to change the status of an item, I simply change it in the admin area when I edit the post.

Also, I can add comments to the post, or I can add the editor’s information in the post. I use Info box block for this.

Also, I make custom styling for each tag. If you check Meta getter block that is responsible for showing tags, you can see the next custom code

I use IDs of tags that exist on my site. You need to create them in Requests – request tags, then check your tag IDs and change the code to match your IDs.

Single Item for Request

So, the last step is to make a single item for Requests. I do this in Site Editor – Templates – Add new template. It’s the same as for archives, just select to create single request item. We also added template. You can download it from Gist Just copy text and insert in your template.