<?php if ( ! defined( 'ABSPATH' ) ) exit;
* This class adds our submission CPT and handles displaying submissions in the wp-admin.
* @subpackage Classes/Submissions
* @copyright Copyright (c) 2014, WPNINJAS
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
// Register our submission custom post type.
add_action( 'init', array( $this, 'register_cpt' ), 5 );
// Populate our field settings var
add_action( 'current_screen', array( $this, 'setup_fields' ) );
// Filter our hidden columns by form ID.
add_action( 'wp', array( $this, 'filter_hidden_columns' ) );
// Add our submenu for the submissions page.
add_action( 'admin_menu', array( $this, 'add_submenu' ), 10 );
// Change our submission columns.
add_filter( 'manage_nf_sub_posts_columns', array( $this, 'change_columns' ) );
// Make our columns sortable.
add_filter( 'manage_edit-nf_sub_sortable_columns', array( $this, 'sortable_columns' ) );
// Actually do the sorting
add_filter( 'request', array( $this, 'sort_columns' ) );
// Add the appropriate data for our custom columns.
add_action( 'manage_posts_custom_column', array( $this, 'custom_columns' ), 10, 2 );
// Add our submission filters.
add_action( 'restrict_manage_posts', array( $this, 'add_filters' ) );
add_filter( 'parse_query', array( $this, 'table_filter' ) );
add_filter( 'posts_clauses', array( $this, 'search' ), 20 );
add_action( 'admin_footer', array( $this, 'jquery_remove_counts' ) );
// Filter our post counts
add_filter( 'wp_count_posts', array( $this, 'count_posts' ), 10, 3 );
// Filter our bulk actions
add_filter( 'bulk_actions-edit-nf_sub', array( $this, 'remove_bulk_edit' ) );
add_action( 'admin_footer-edit.php', array( $this, 'bulk_admin_footer' ) );
// Filter our bulk updated/trashed messages
add_filter( 'bulk_post_updated_messages', array( $this, 'updated_messages_filter' ), 10, 2 );
// Filter singular updated/trashed messages
add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
// Add our metabox for editing field values
add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
// Save our metabox values
add_action( 'save_post', array( $this, 'save_sub' ), 10, 2 );
// Save our hidden columns by form id.
add_action( 'wp_ajax_nf_hide_columns', array( $this, 'hide_columns' ) );
// Load any custom screen options
add_filter( 'screen_settings', array( $this, 'output_screen_options' ), 10, 2 );
// Listen for our exports button.
add_action( 'load-edit.php', array( $this, 'export_listen' ) );
// Filter our submission capabilities
add_filter( 'user_has_cap', array( $this, 'cap_filter' ), 10, 3 );
* Register our submission CPT
public function register_cpt() {
if ( ! isset ( $_REQUEST['form_id'] ) || empty( $_REQUEST['form_id'] ) ) {
$not_found = __( 'Please select a form to view submissions', 'ninja-forms' );
$not_found = __( 'No Submissions Found', 'ninja-forms' );
$name = _x( 'Submissions', 'post type general name', 'ninja-forms' );
if ( ! empty ( $_REQUEST['form_id'] ) ) {
$form_title = Ninja_Forms()->form( absint( $_REQUEST['form_id'] ) )->get_setting( 'form_title' );
$name =$name . ' - ' . $form_title;
'singular_name' => _x( 'Submission', 'post type singular name', 'ninja-forms' ),
'add_new' => _x( 'Add New', 'nf_sub' ),
'add_new_item' => __( 'Add New Submission', 'ninja-forms' ),
'edit_item' => __( 'Edit Submission', 'ninja-forms' ),
'new_item' => __( 'New Submission', 'ninja-forms' ),
'view_item' => __( 'View Submission', 'ninja-forms' ),
'search_items' => __( 'Search Submissions', 'ninja-forms' ),
'not_found' => $not_found,
'not_found_in_trash' => __( 'No Submissions Found In The Trash', 'ninja-forms' ),
'parent_item_colon' => ''
'publicly_queryable' => false,
'_builtin' => false, // It's a custom post type, not built in!
'rewrite' => array( 'slug' => 'nf_sub' ), // Permalinks format
'supports' => array( 'custom-fields' ),
'capability_type' => 'nf_sub',
'publish_posts' => 'nf_sub',
'edit_posts' => 'nf_sub',
'edit_others_posts' => 'nf_sub',
'delete_posts' => 'nf_sub',
'delete_others_posts' => 'nf_sub',
'read_private_posts' => 'nf_sub',
'delete_post' => 'nf_sub',
register_post_type( 'nf_sub',$args );
* Populate our fields var with all the fields. This keeps us from needing to ping the database later.
public function setup_fields() {
global $pagenow, $typenow;
// Bail if we aren't on the edit.php page, we aren't editing our custom post type, or we don't have a form_id set.
if ( ( $pagenow != 'edit.php' && $pagenow != 'post.php' ) || $typenow != 'nf_sub' )
if ( isset ( $_REQUEST['form_id'] ) ) {
$form_id = absint( $_REQUEST['form_id'] );
} else if ( isset ( $_REQUEST['post'] ) ) {
$form_id = Ninja_Forms()->sub( absint( $_REQUEST['post'] ) )->form_id;
$this->form_id = $form_id;
Ninja_Forms()->form( $form_id );
* Add our submissions submenu
public function add_submenu() {
// Add our submissions submenu
$sub_page = add_submenu_page( 'ninja-forms', __( 'Submissions', 'ninja-forms' ), __( 'Submissions', 'ninja-forms' ), apply_filters( 'ninja_forms_admin_submissions_capabilities', 'manage_options' ), 'edit.php?post_type=nf_sub' );
// Enqueue our JS on the edit page.
//add_action( 'load-' . $sub_page, array( $this, 'load_js' ) );
add_action( 'admin_print_styles', array( $this, 'load_js' ) );
add_action( 'admin_print_styles', array( $this, 'load_css' ) );
// Remove the publish box from the submission editing page.
remove_meta_box( 'submitdiv', 'nf_sub', 'side' );
* Enqueue our submissions JS file.
public function load_js() {
global $pagenow, $typenow;
// Bail if we aren't on the edit.php page or we aren't editing our custom post type.
if ( ( $pagenow != 'edit.php' && $pagenow != 'post.php' ) || $typenow != 'nf_sub' )
$form_id = isset ( $_REQUEST['form_id'] ) ? absint( $_REQUEST['form_id'] ) : '';
if ( defined( 'NINJA_FORMS_JS_DEBUG' ) && NINJA_FORMS_JS_DEBUG ) {
$plugin_settings = nf_get_settings();
$date_format = ninja_forms_date_to_datepicker( $plugin_settings['date_format'] );
$datepicker_args = array();
if ( !empty( $date_format ) ) {
$datepicker_args['dateFormat'] = $date_format;
wp_enqueue_script( 'subs-cpt',
NF_PLUGIN_URL . 'assets/js/' . $src .'/subs-cpt' . $suffix . '.js',
array('jquery', 'jquery-ui-datepicker') );
wp_localize_script( 'subs-cpt', 'nf_sub', array( 'form_id' => $form_id, 'datepicker_args' => apply_filters( 'ninja_forms_admin_submissions_datepicker_args', $datepicker_args ) ) );
* Enqueue our submissions CSS file.
public function load_css() {
global $pagenow, $typenow;
// Bail if we aren't on the edit.php page or the post.php page.
if ( ( $pagenow != 'edit.php' && $pagenow != 'post.php' ) || $typenow != 'nf_sub' )
wp_enqueue_style( 'nf-sub', NF_PLUGIN_URL .'assets/css/cpt.css' );
wp_enqueue_style( 'nf-jquery-ui-freshness', NF_PLUGIN_URL .'assets/css/jquery-ui-fresh.min.css' );
* Modify the columns of our submissions table.
public function change_columns( $cols ) {
// Compatibility with old field registration system. Can be removed when the new one is in place.
global $ninja_forms_fields;
'cb' => '<input type="checkbox" />',
'id' => __( '#', 'ninja-forms' ),
// Compatibility with old field registration system. Can be removed when the new one is in place.
if ( isset ( $_GET['form_id'] ) && $_GET['form_id'] != '' ) {
$form_id = absint( $_GET['form_id'] );
if ( is_object( Ninja_Forms()->form( $this->form_id ) ) && is_array ( Ninja_Forms()->form( $this->form_id )->fields ) ) {
foreach ( Ninja_Forms()->form( $this->form_id )->fields as $field ) {
$field_id = $field['id'];
$field_type = $field['type'];
if ( isset ( $ninja_forms_fields[ $field_type ] ) ) {
$reg_field = $ninja_forms_fields[ $field_type ];
$process_field = $reg_field['process_field'];
if ( isset ( $field['data']['admin_label'] ) && ! empty ( $field['data']['admin_label'] ) ) {
$label = $field['data']['admin_label'];
} else if ( isset ( $field['data']['label'] ) ) {
$label = $field['data']['label'];
if ( strlen( $label ) > 140 )
$label = substr( $label, 0, 140 );
if ( isset ( $field['data']['label'] ) && $process_field )
$cols[ 'form_' . $form_id . '_field_' . $field_id ] = $label;
$cols['sub_date'] = __( 'Date', 'ninja-forms' );
return apply_filters( 'nf_sub_table_columns', $cols, $form_id );
* Make our columns sortable
public function sortable_columns() {
// Get a list of all of our fields.
$columns = get_column_headers( 'edit-nf_sub' );
foreach ( $columns as $slug => $c ) {
$tmp_array[ $slug ] = $slug;
* Actually sort our columns
public function sort_columns( $vars ) {
global $pagenow, $typenow;
if( array_key_exists( 'orderby', $vars ) ) {
if( strpos( $vars['orderby'], 'form_' ) !== false ) {
$args = explode( '_', $vars['orderby'] );
if ( isset ( Ninja_Forms()->form( $this->form_id )->fields[ $field_id ]['data']['num_sort'] ) && Ninja_Forms()->form( $this->form_id )->fields[ $field_id ]['data']['num_sort'] == 1 ) {
$orderby = 'meta_value_num';
$vars['orderby'] = $orderby;
$vars['meta_key'] = '_field_' . $field_id;
} else if ( $vars['orderby'] == 'id' ) {
$vars['orderby'] = 'meta_value_num';
$vars['meta_key'] = '_seq_num';
} else if( is_admin() && $typenow == 'nf_sub' && $pagenow == 'edit.php' ) {
$vars['orderby'] = 'meta_value_num';
$vars['meta_key'] = '_seq_num';
* Add our custom column data
public function custom_columns( $column, $sub_id ) {
if ( isset ( $_GET['form_id'] ) ) {
$form_id = absint($_GET['form_id']);
echo apply_filters( 'nf_sub_table_seq_num', Ninja_Forms()->sub( $sub_id )->get_seq_num(), $sub_id, $column );
echo '<div class="locked-info"><span class="locked-avatar"></span> <span class="locked-text"></span></div>';
if ( !isset ( $_GET['post_status'] ) || $_GET['post_status'] == 'all' ) {
echo '<div class="row-actions custom-row-actions">';
do_action( 'nf_sub_table_before_row_actions', $sub_id, $column );
echo '<span class="edit"><a href="post.php?post=' . $sub_id . '&action=edit&ref=' . urlencode( esc_url( add_query_arg( array() ) ) ) . '" title="' . __( 'Edit this item', 'ninja-forms' ) . '">' . __( 'Edit', 'ninja-forms' ) . '</a> | </span>
<span class="edit"><a href="' . esc_url( add_query_arg( array( 'export_single' => $sub_id ) ) ) . '" title="' . __( 'Export this item', 'ninja-forms' ) . '">' . __( 'Export', 'ninja-forms' ) . '</a> | </span>';
$row_actions = apply_filters( 'nf_sub_table_row_actions', array(), $sub_id, $form_id );
if ( ! empty( $row_actions ) ) {
echo implode(" | ", $row_actions);
echo '<span class="trash"><a class="submitdelete" title="' . __( 'Move this item to the Trash', 'ninja-forms' ) . '" href="' . get_delete_post_link( $sub_id ) . '">' . __( 'Trash', 'ninja-forms' ) . '</a> </span>';
do_action( 'nf_sub_table_after_row_actions', $sub_id, $column );
echo '<div class="row-actions custom-row-actions">';
do_action( 'nf_sub_table_before_row_actions_trash', $sub_id, $column );
echo '<span class="untrash"><a title="' . esc_attr( __( 'Restore this item from the Trash', 'ninja-forms' ) ) . '" href="' . wp_nonce_url( sprintf( get_edit_post_link( $sub_id ) . '&action=untrash', $sub_id ) , 'untrash-post_' . $sub_id ) . '">' . __( 'Restore', 'ninja-forms' ) . '</a> | </span>
<span class="delete"><a class="submitdelete" title="' . esc_attr( __( 'Delete this item permanently', 'ninja-forms' ) ) . '" href="' . get_delete_post_link( $sub_id, '', true ) . '">' . __( 'Delete Permanently', 'ninja-forms' ) . '</a></span>';
do_action( 'nf_sub_table_after_row_actions_trash', $sub_id, $column );
} else if ( $column == 'sub_date' ) {
$post = get_post( $sub_id );
if ( '0000-00-00 00:00:00' == $post->post_date ) {
$t_time = $h_time = __( 'Unpublished', 'ninja-forms' );
$t_time = get_the_time( 'Y/m/d g:i:s A' );
$m_time = $post->post_date;
$time = get_post_time( 'G', true, $post );
$time_diff = time() - $time;
if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS )
$h_time = sprintf( __( '%s ago', 'ninja-forms' ), human_time_diff( $time ) );
$h_time = mysql2date( 'Y/m/d', $m_time );
$t_time = apply_filters( 'nf_sub_title_time', $t_time );
$h_time = apply_filters( 'nf_sub_human_time', $h_time );
/** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */
echo '<abbr title="' . $t_time . '">' . $h_time . '</abbr>';
echo apply_filters( 'nf_sub_table_status', __( 'Submitted', 'ninja-forms' ), $sub_id );
} else if ( strpos( $column, '_field_' ) !== false ) {
global $ninja_forms_fields;
$field_id = str_replace( 'form_' . $form_id . '_field_', '', $column );
//if ( apply_filters( 'nf_add_sub_value', Ninja_Forms()->field( $field_id )->type->add_to_sub, $field_id ) ) {
$field = Ninja_Forms()->form( $form_id )->fields[ $field_id ];
$field_type = $field['type'];
if ( isset ( $ninja_forms_fields[ $field_type ] ) ) {
$reg_field = $ninja_forms_fields[ $field_type ];
if ( isset ( $reg_field['sub_table_value'] ) ) {
$edit_value_function = $reg_field['sub_table_value'];
$edit_value_function = 'nf_field_text_sub_table_value';
$user_value = Ninja_Forms()->sub( $sub_id )->get_field( $field_id );
$args['field_id'] = $field_id;
$args['user_value'] = ninja_forms_esc_html_deep( $user_value );
call_user_func_array( $edit_value_function, $args );
* Add our submission filters
public function add_filters() {
// Bail if we aren't in our submission custom post type.
if ( $typenow != 'nf_sub' )
// Add our Form selection dropdown.
$forms = Ninja_Forms()->forms()->get_all();
$form_id = isset( $_GET['form_id'] ) ? absint($_GET['form_id']) : '';
$begin_date = isset ( $_GET['begin_date'] ) ? sanitize_text_field($_GET['begin_date']) : '';
$end_date = isset ( $_GET['end_date'] ) ? sanitize_text_field($_GET['end_date']) : '';
// Add begin date and end date filter fields.
$html = '<div style="float:left;">';
$html .= '<span style="float:left;" class="spinner"></span>';
$html .= '<select name="form_id" id="form_id" class="nf-form-jump">';
$html .= '<option value="">- ' . __( 'Select a form', 'ninja-forms' ) . '</option>';
if ( is_array( $forms ) ) {
foreach ( $forms as $f_id ) {
$form_title = Ninja_Forms()->form( $f_id )->get_setting( 'form_title' );
$html .= '<option value="' . $f_id . '" ' . selected( $form_id, $f_id, false ) . '>' . $form_title . '</option>';