render_login_message(); } ob_start(); ?>
render_dashboard_header(); ?> render_dashboard_tabs(); ?> render_dashboard_content(); ?>

display_name ) ); ?>

' . esc_html__( 'Post deleted successfully!', 'airy-frontend-forms' ) . '
'; } ?>
get_posts_count() ); ?> get_drafts_count() ); ?>
render_drafts_tab(); } else { $this->render_posts_tab(); } } /** * Render posts tab */ private function render_posts_tab() { $posts = $this->get_user_posts(); ?>
render_posts_filters(); ?>

render_submit_button(); ?>
render_posts_table( $posts ); ?>
render_pagination(); ?>
get_user_drafts(); ?>

render_submit_button(); ?>
render_drafts_list( $drafts ); ?>
(get_posts_count() ); ?>) (get_posts_count( 'publish' ) ); ?>) (get_posts_count( 'pending' ) ); ?>) (get_posts_count( 'draft' ) ); ?>)
get_post_type_counts(); if ( count( $post_type_counts ) > 1 ) : ?>
$pt_data ) : ?> ()
render_submit_button(); ?>
post_title ); ?> post_type ); if ( $post_type_obj ) { echo ' ' . esc_html( $post_type_obj->labels->singular_name ) . ''; } // Check for rejection. global $wpdb; $rejections_table = $wpdb->prefix . 'affcf_rejections'; // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name from $wpdb->prefix, plugin-controlled $rejection = $wpdb->get_row( $wpdb->prepare( "SELECT rejection_reason, rejected_at, rejected_by FROM {$rejections_table} WHERE post_id = %d ORDER BY rejected_at DESC LIMIT 1", $post->ID ) ); // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter if ( $rejection && 'draft' === $post->post_status ) : ?>
⚠️
rejection_reason ) : ?> rejection_reason ); ?>
rejected_at ), time() ) ); ?>
post_status ) : ?>
render_status_badge( $post->post_status ) ); ?> post_date ) ) ); ?> render_post_actions( $post ) ); ?>
draft_data, true ); $form_repo = new AFFCF_Form_Repository(); $form = $form_repo->get_by_id( $draft->form_id ); ?>

form_name ); ?>
last_saved ), time() ) ) ); ?>
render_draft_actions( $draft, $form ) ); ?>
array( 'label' => __( 'Published', 'airy-frontend-forms' ), 'class' => 'success', ), 'pending' => array( 'label' => __( 'Pending Review', 'airy-frontend-forms' ), 'class' => 'warning', ), 'draft' => array( 'label' => __( 'Draft', 'airy-frontend-forms' ), 'class' => 'info', ), 'trash' => array( 'label' => __( 'Trashed', 'airy-frontend-forms' ), 'class' => 'danger', ), ); $badge = $badges[ $status ] ?? array( 'label' => ucfirst( $status ), 'class' => 'default', ); return sprintf( '%s', esc_attr( $badge['class'] ), esc_html( $badge['label'] ) ); } /** * Render post actions * * @param object $post Post object. * @return string HTML. */ private function render_post_actions( $post ) { $actions = array(); // Get edit page. $pages = get_option( 'affcf_default_pages', array() ); $edit_page_id = ! empty( $pages['custom_edit_page_id'] ) ? $pages['custom_edit_page_id'] : ( $pages['edit_page_id'] ?? 0 ); // Edit link - Show for ALL statuses (pending, draft, AND published). // When editing a published post, it will go back to pending for re-review. if ( $edit_page_id ) { $edit_url = add_query_arg( 'post_id', $post->ID, get_permalink( $edit_page_id ) ); $actions[] = sprintf( '%s', esc_url( $edit_url ), __( 'Edit', 'airy-frontend-forms' ) ); } // View link - Only for published posts. if ( 'publish' === $post->post_status ) { $actions[] = sprintf( '%s', esc_url( get_permalink( $post->ID ) ), __( 'View', 'airy-frontend-forms' ) ); } // Delete link - For pending/draft only (can't delete published posts from frontend). if ( in_array( $post->post_status, array( 'pending', 'draft' ), true ) ) { $delete_url = wp_nonce_url( add_query_arg( array( 'action' => 'affcf_delete_post', 'post_id' => $post->ID, ), admin_url( 'admin-post.php' ) ), 'affcf_delete_post_' . $post->ID ); $actions[] = sprintf( '%s', esc_url( $delete_url ), esc_js( __( 'Are you sure you want to delete this post?', 'airy-frontend-forms' ) ), __( 'Delete', 'airy-frontend-forms' ) ); } return implode( ' | ', $actions ); } /** * Render draft actions * * @param object $draft Draft object. * @param object $form Form object (used for future extensibility). * @return string HTML. */ private function render_draft_actions( $draft, $form ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- $form kept for future extensibility. $actions = array(); // Get submit page. $pages = get_option( 'affcf_default_pages', array() ); $submit_page_id = ! empty( $pages['custom_submit_page_id'] ) ? $pages['custom_submit_page_id'] : ( $pages['submit_page_id'] ?? 0 ); if ( $submit_page_id ) { $continue_url = add_query_arg( 'draft_id', $draft->id, get_permalink( $submit_page_id ) ); $actions[] = sprintf( '%s', esc_url( $continue_url ), __( 'Continue Editing', 'airy-frontend-forms' ) ); } // Delete button. $actions[] = sprintf( '', $draft->id, __( 'Delete', 'airy-frontend-forms' ) ); return implode( ' ', $actions ); } /** * Render submit button */ private function render_submit_button() { $pages = get_option( 'affcf_default_pages', array() ); $submit_page_id = ! empty( $pages['custom_submit_page_id'] ) ? $pages['custom_submit_page_id'] : ( $pages['submit_page_id'] ?? 0 ); if ( $submit_page_id ) { printf( '%s', esc_url( get_permalink( $submit_page_id ) ), esc_html__( 'Submit New Post', 'airy-frontend-forms' ) ); } } /** * Render pagination */ private function render_pagination() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for pagination display only $paged = isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $total_posts = $this->get_posts_count(); $per_page = 20; $total_pages = ceil( $total_posts / $per_page ); if ( $total_pages <= 1 ) { return; } ?>
1 ) : ?> « »
get_form_post_types(); if ( 'all' !== $post_type_filter && in_array( $post_type_filter, $all_post_types, true ) ) { $query_post_types = array( $post_type_filter ); } else { $query_post_types = $all_post_types; } $args = array( 'author' => get_current_user_id(), 'post_type' => $query_post_types, 'posts_per_page' => 20, 'paged' => $paged, 'orderby' => 'date', 'order' => 'DESC', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required to filter posts created by this plugin array( 'key' => '_affcf_form_id', 'compare' => 'EXISTS', ), ), ); if ( 'all' !== $status ) { $args['post_status'] = $status; } else { $args['post_status'] = array( 'publish', 'pending', 'draft' ); } $query = new WP_Query( $args ); return $query->posts; } /** * Get all post types used in forms * * @return array Post types. */ private function get_form_post_types() { // Get all forms. $form_repo = new AFFCF_Form_Repository(); $forms = $form_repo->get_all( array( 'status' => 'all' ) ); // Collect unique post types. $post_types = array(); foreach ( $forms as $form ) { if ( ! empty( $form->post_type ) && ! in_array( $form->post_type, $post_types, true ) ) { $post_types[] = $form->post_type; } } // If no forms or no post types found, default to 'post'. if ( empty( $post_types ) ) { $post_types = array( 'post' ); } return $post_types; } /** * Get user's drafts * * @return array Drafts. */ private function get_user_drafts() { $auto_save = AFFCF_Auto_Save::get_instance(); return $auto_save->get_user_drafts( get_current_user_id() ); } /** * Get posts count * * @param string $status Post status. * @return int Count. */ private function get_posts_count( $status = '' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for post type filtering $post_type_filter = isset( $_GET['affcf_type'] ) ? sanitize_text_field( wp_unslash( $_GET['affcf_type'] ) ) : 'all'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended // Determine post types for the query. $all_post_types = $this->get_form_post_types(); if ( 'all' !== $post_type_filter && in_array( $post_type_filter, $all_post_types, true ) ) { $query_post_types = array( $post_type_filter ); } else { $query_post_types = $all_post_types; } $args = array( 'author' => get_current_user_id(), 'post_type' => $query_post_types, 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required to count posts created by this plugin array( 'key' => '_affcf_form_id', 'compare' => 'EXISTS', ), ), ); if ( $status ) { $args['post_status'] = $status; } else { $args['post_status'] = array( 'publish', 'pending', 'draft' ); } $query = new WP_Query( $args ); return $query->found_posts; } /** * Get post counts grouped by post type for the current user. * * @return array Associative array of post_type => array( 'label' => string, 'count' => int ). */ private function get_post_type_counts() { $all_post_types = $this->get_form_post_types(); $args = array( 'author' => get_current_user_id(), 'post_type' => $all_post_types, 'post_status' => array( 'publish', 'pending', 'draft' ), 'posts_per_page' => -1, 'fields' => 'ids', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required to count posts per post type created by this plugin array( 'key' => '_affcf_form_id', 'compare' => 'EXISTS', ), ), ); $query = new WP_Query( $args ); $counts = array(); if ( ! empty( $query->posts ) ) { foreach ( $query->posts as $post_id ) { $pt = get_post_type( $post_id ); if ( ! isset( $counts[ $pt ] ) ) { $pt_obj = get_post_type_object( $pt ); $counts[ $pt ] = array( 'label' => $pt_obj ? $pt_obj->labels->singular_name : $pt, 'count' => 0, ); } ++$counts[ $pt ]['count']; } } return $counts; } /** * Get drafts count * * @return int Count. */ private function get_drafts_count() { $drafts = $this->get_user_drafts(); return count( $drafts ); } }