Practical example 01

Create new posts
with a front-end form

Display an atshift Fields field group as an input form for signed-in users, then create a new post in a specified WordPress post type.

01

What this example does

  • Displays a field group created in the CFS settings on the front end.
  • Allows a signed-in user to create a draft in a specified post type.
  • Supports tabs, accordions, conditional groups, and loop fields in the same form.
API used in this example

CFS()->form() provides the fields, nonce, form session, validation, and save process.

02

Prepare a field group

  1. Open Settings → atshift Fields and create a field group.
  2. Add the fields you need and configure required fields and row limits.
  3. Open the field group editor and find its numeric ID in the post=123 part of the URL.

Replace 123 in the examples below with the ID of your field group.

03

Reject signed-out submissions

Add this to the theme's functions.php or a site-specific plugin. New posts use the post type's create_posts capability.

functions.php

PHP / Permissions
<?php
add_filter(
  'cfs_form_can_save',
  function ( $can_save, $post_id, $post_data ) {
    if ( ! is_user_logged_in() ) {
      return false;
    }

    $post_type = sanitize_key( $post_data['post_type'] ?? 'post' );
    $object    = get_post_type_object( $post_type );

    return $object
      && current_user_can( $object->cap->create_posts );
  },
  10,
  5
);
This filter rejects direct, modified form submissions too. A nonce protects against CSRF, but it does not replace authentication or authorization.
04

Load the form CSS and JavaScript

This example uses a page with the slug front-form. Register the form assets on wp_enqueue_scripts so they are available before wp_head() runs.

functions.php

PHP / Assets
<?php
add_action( 'wp_enqueue_scripts', function () {
  if ( is_page( 'front-form' ) && is_user_logged_in() ) {
    CFS()->form->load_assets();
  }
} );
05

Render the form in a page template

This page template creates a new draft in the member_entry custom post type.

The page is only the location of the form

The values are not saved to the page using this template. Set post_type to post to create a standard post, or use a custom post type name to save there.

page-front-form.php

PHP / Template
<?php
/* Template Name: CFS Front-end Form */

if ( ! is_user_logged_in() ) {
  auth_redirect();
}

$post_type = 'member_entry'; // Custom post type used as the destination.

get_header();
?>

<main class="front-form">
  <h1>Create entry</h1>

  <?php
  echo CFS()->form( array(
    'post_id'              => false, // false creates a new post.
    'field_groups'         => array( 123 ), // Field group ID.
    'post_type'            => $post_type, // Destination post type.
    'post_status'          => 'draft', // Save new posts as drafts.
    'post_title'           => 'Title',
    'submit_label'         => 'Save',
    'confirmation_url'     => home_url( '/front-form/?saved=1' ),
  ) );
  ?>
</main>

<?php get_footer(); ?>
Need to edit existing posts?

The separate editing existing posts example explains how to use post_id.

06

Safeguards for public forms

A form intentionally available to signed-out visitors needs additional controls.

  • Fix the destination: Define the post type, post status, and field group IDs on the server.
  • Limit submissions: Apply IP or session rate limits and consider CAPTCHA and WAF controls.
  • Limit payload size: Restrict text length, array size, loop rows, and total request size.
  • Validate by field type: Validate email, URL, and numeric values, and allow only necessary HTML.
  • Validate referenced IDs: Confirm that related posts, users, terms, and attachments are selectable.
  • Restrict files: Limit MIME types, extensions, file size, and upload capabilities.
  • Escape output: Use functions such as esc_html(), esc_url(), and wp_kses_post() for the output context.
Recommended default

If public access is not required, rejecting signed-out submissions on the server is the strongest starting point.

07

Test before deployment

  • A signed-out visitor is redirected to the login screen.
  • Only users with the required capability can create new posts.
  • Tabs, conditional groups, and loop fields render and save correctly.
  • The saved post type and post status match the intended configuration.
  • Saved values are escaped correctly wherever they are displayed.