__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

[email protected]: ~ $
<?php

namespace WPForms\Pro\Admin\Entries;

use WPForms\Admin\Notice;
use WPForms\Pro\Admin\Entries\Table\DataObjects\Column;
use WPForms\Pro\Admin\Entries\Table\Facades\Columns;
use WPForms\Pro\Admin\DashboardWidget;
use WPForms\Pro\AntiSpam\SpamEntry;
use WPForms\Pro\Forms\Fields\FileUpload\Field as FileUploadField;
use WPForms_Form_Handler;

/**
 * Display list of all entries for a single form.
 *
 * @since 1.8.6
 */
class Page {

	use FilterSearch;

	/**
	 * Entry trash status.
	 *
	 * @since 1.8.5
	 */
	const TRASH_ENTRY_STATUS = 'trash';

	/**
	 * Store admin alerts.
	 *
	 * @since 1.8.6
	 *
	 * @var array
	 */
	public $alerts = [];

	/**
	 * Abort. Bail on proceeding to process the page.
	 *
	 * @since 1.8.6
	 *
	 * @var bool
	 */
	public $abort = false;

	/**
	 * The human-readable error message.
	 *
	 * @since 1.8.6
	 *
	 * @var string
	 */
	private $abort_message;

	/**
	 * Form ID.
	 *
	 * @since 1.8.6
	 *
	 * @var int
	 */
	public $form_id;

	/**
	 * Form object.
	 *
	 * @since 1.8.6
	 *
	 * @var WPForms_Form_Handler
	 */
	public $form;

	/**
	 * Forms object.
	 *
	 * @since 1.8.6
	 *
	 * @var WPForms_Form_Handler[]
	 */
	public $forms;

	/**
	 * Entries object.
	 *
	 * @since 1.8.6
	 *
	 * @var ListTable
	 */
	public $entries;

	/**
	 * Primary class constructor.
	 *
	 * @since 1.8.6
	 */
	public function __construct() {

		$this->hooks();
	}

	/**
	 * Register hooks.
	 *
	 * @since 1.8.6
	 */
	private function hooks() {

		// Heartbeat doesn't pass $_GET parameters checked by $this->init() condition.
		add_filter( 'heartbeat_received', [ $this, 'heartbeat_new_entries_check' ], 10, 3 );

		// AJAX-callbacks.
		add_action( 'wp_ajax_wpforms_entry_list_process_delete_all', [ $this, 'process_delete' ] );
		add_action( 'wp_ajax_wpforms_entry_list_process_trash_all', [ $this, 'process_trash' ] );
	}

	/**
	 * Determine if the user is viewing the entries list page, if so, party on.
	 *
	 * @since 1.8.6
	 */
	public function init() { // phpcs:disable WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		// Only load if we are actually on the overview page.
		if ( ! wpforms_is_admin_page( 'entries', 'list' ) ) {
			return;
		}

		$form_id = $this->get_filtered_form_id();

		if ( empty( $form_id ) ) {
			wp_safe_redirect( admin_url( 'admin.php?page=wpforms-entries' ) );
			exit;
		}

		if ( ! wpforms_current_user_can( 'view_entries_form_single', $form_id ) ) {
			wp_die( esc_html__( 'You do not have permission to view this form\'s entries.', 'wpforms' ), 403 );
		}

		$form = wpforms()->obj( 'form' )->get( $form_id );

		if ( empty( $form ) || $form->post_status === self::TRASH_ENTRY_STATUS ) {
			$this->abort_message = esc_html__( 'It looks like the form you are trying to access is no longer available.', 'wpforms' );
			$this->abort         = true;
		}

		$this->remove_get_parameters();
		set_screen_options();

		// Load the classes that build the entries' table.
		add_action( 'current_screen', [ $this, 'load_entries_list_table' ], 5 );

		// Processing and setup.
		add_action( 'wpforms_entries_init', [ $this, 'process_filter_dates' ], 7, 1 );
		add_action( 'wpforms_entries_init', [ $this, 'process_filter_search' ], 7, 1 );
		add_action( 'wpforms_entries_init', [ $this, 'process_read' ], 8, 1 );
		add_action( 'wpforms_entries_init', [ $this, 'setup' ], 10, 1 );
		add_action( 'wpforms_entries_init', [ $this, 'register_alerts' ], 20, 1 );

		/**
		 * Fires on init entries list page.
		 *
		 * @since 1.0.0
		 *
		 * @param string $context Current context.
		 */
		do_action( 'wpforms_entries_init', 'list' ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

		// Output.
		add_action( 'wpforms_admin_page', [ $this, 'list_all' ] );
		add_action( 'wpforms_admin_page', [ $this, 'display_abort_message' ] );
		add_action( 'wpforms_admin_page', [ $this, 'field_column_setting' ] );
		add_action( 'wpforms_entry_list_title', [ $this, 'list_form_actions' ], 10, 1 );

		// Enqueues.
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
		add_filter( 'wpforms_admin_strings', [ $this, 'js_strings' ] );

		// Apply filter to search by date on Entries page.
		add_filter( 'wpforms_entry_handler_get_entries_args', [ $this, 'get_filtered_entry_table_args' ] );
	} // phpcs:enable WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

	/**
	 * Remove unnecessary $_GET parameters for shorter URL.
	 *
	 * @since 1.8.6
	 */
	private function remove_get_parameters() {

		$remove_args = [
			'_wp_http_referer',
			'action',
			'action2',
			'_wpnonce',
			'read',
			'unread',
			'spam',
			'unspam',
			'unstarred',
			'starred',
			'deleted',
			'trashed',
			'restored',
		];

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['paged'] ) && (int) $_GET['paged'] < 2 ) {
			$remove_args[] = 'paged';
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
		if ( ! isset( $_GET['search']['term'] ) || wpforms_is_empty_string( $_GET['search']['term'] ) ) {
			$remove_args[] = 'search';
		}

		if ( empty( $this->get_filtered_dates() ) ) {
			$remove_args[] = 'date';
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput
		$_SERVER['REQUEST_URI'] = remove_query_arg( $remove_args, $_SERVER['REQUEST_URI'] );
	}

	/**
	 * Load the PHP classes and initialize an entries table.
	 *
	 * @since 1.8.6
	 */
	public function load_entries_list_table() {

		// Create an `ListTable` instance and process bulk actions.
		$this->entries = new ListTable();

		$this->entries->process_bulk_actions();
	}

	/**
	 * Enqueue assets for the entries pages.
	 *
	 * @since 1.8.6
	 */
	public function enqueues() {

		// JavaScript.
		wp_enqueue_script(
			'wpforms-htmx',
			WPFORMS_PLUGIN_URL . 'assets/lib/htmx.min.js',
			[],
			WPFORMS_VERSION,
			true
		);

		wp_enqueue_script(
			'wpforms-flatpickr',
			WPFORMS_PLUGIN_URL . 'assets/lib/flatpickr/flatpickr.min.js',
			[ 'jquery' ],
			'4.6.9',
			false
		);

		// CSS.
		wp_enqueue_style(
			'wpforms-flatpickr',
			WPFORMS_PLUGIN_URL . 'assets/lib/flatpickr/flatpickr.min.css',
			[],
			'4.6.9'
		);

		$min = wpforms_get_min_suffix();

		wp_enqueue_style(
			'wpforms-admin-list-table-ext',
			WPFORMS_PLUGIN_URL . "assets/css/admin-list-table-ext{$min}.css",
			[ 'wpforms-multiselect-checkboxes' ],
			WPFORMS_VERSION
		);

		wp_enqueue_script(
			'wpforms-admin-list-table-ext',
			WPFORMS_PLUGIN_URL . "assets/js/admin/share/list-table-ext{$min}.js",
			[ 'jquery', 'jquery-ui-sortable', 'underscore', 'wpforms-multiselect-checkboxes', 'wpforms-htmx' ],
			WPFORMS_VERSION,
			true
		);

		wp_enqueue_script(
			'wpforms-admin-entries',
			WPFORMS_PLUGIN_URL . "assets/pro/js/admin/entries/entries{$min}.js",
			[ 'jquery', 'wpforms-flatpickr' ],
			WPFORMS_VERSION,
			true
		);

		/**
		 * Fires on enqueue entries list page assets.
		 *
		 * @since 1.0.0
		 *
		 * @param string $context Current context.
		 */
		do_action( 'wpforms_entries_enqueue', 'list' ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
	}

	/**
	 * Watch for and run complete marking all entries as read.
	 *
	 * @since 1.8.6
	 */
	public function process_read() {

		$form_id = $this->get_filtered_form_id();

		// Check for run switch.
		if ( empty( $_GET['action'] ) || ! $form_id || $_GET['action'] !== 'markread' || empty( $_GET['_wpnonce'] ) ) {
			return;
		}

		// Security check.
		if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'wpforms_entry_list_markread' ) ) {
			return;
		}

		wpforms()->obj( 'entry' )->mark_all_read( $form_id );

		$this->alerts[] = [
			'type'    => 'success',
			'message' => esc_html__( 'All entries marked as read.', 'wpforms' ),
			'dismiss' => true,
		];
	}

	/**
	 * Entry deletion and trigger if needed.
	 *
	 * @since 1.8.6
	 */
	public function process_delete() {

		// Security check.
		if ( ! check_ajax_referer( 'wpforms-admin', 'nonce', false ) ) {
			wp_send_json_error( esc_html__( 'Your session expired. Please reload the builder.', 'wpforms' ) );
		}

		$form_id = $this->get_filtered_form_id();

		// Require data check.
		if ( ! $form_id ) {
			wp_send_json_error( esc_html__( 'Something went wrong while performing this action.', 'wpforms' ) );
		}

		// Permission check.
		if ( ! wpforms_current_user_can( 'delete_entries_form_single', $form_id ) ) {
			wp_send_json_error( esc_html__( 'You do not have permission to perform this action.', 'wpforms' ) );
		}

		// Get the screen first.
		$screen = isset( $_REQUEST['page'] ) ? sanitize_key( $_REQUEST['page'] ) : '';

		// The delete all functionality should only be available on the trash and spam screens.
		// All other places the delete all button will be replaced by trash all button.
		if ( ! in_array( $screen, [ self::TRASH_ENTRY_STATUS, SpamEntry::ENTRY_STATUS ], true ) ) {
			wp_send_json_error( esc_html__( 'Something went wrong while performing this action.', 'wpforms' ) );
		}

		// Default args to find entries.
		$args = [
			'form_id' => $form_id,
			'select'  => 'entry_ids',
			'status'  => $screen,
			'number'  => '-1',
		];

		// Get entries.
		$entries = wpforms()->obj( 'entry' )->get_entries( $args );

		if ( ! $entries ) {
			wp_send_json_error( esc_html__( 'Something went wrong while performing this action.', 'wpforms' ) );
		}

		$entry_ids = wp_list_pluck( $entries, 'entry_id' );
		$deleted   = 0;

		// Delete media if any.
		// It must be done before removing the entry itself.
		array_map( [ FileUploadField::class, 'delete_uploaded_files_from_entry' ], $entry_ids );

		/**
		 * Allow performing additional actions before deleting entries.
		 *
		 * @since 1.8.9
		 *
		 * @param array $entry_ids Entry IDs.
		 * @param int   $form_id   Form ID.
		 */
		do_action( 'wpforms_pro_admin_entries_page_empty_trash_before', $entry_ids, $form_id );

		// Delete meta only if the related entry has been removed successfully.
		if ( wpforms()->obj( 'entry' )->delete_where_in( 'entry_id', $entry_ids ) ) {
			wpforms()->obj( 'entry_meta' )->delete_where_in( 'entry_id', $entry_ids );
			wpforms()->obj( 'entry_fields' )->delete_where_in( 'entry_id', $entry_ids );

			$deleted = count( $entry_ids );
		}

		$redirect_url = ! empty( $_GET['url'] ) ? add_query_arg( 'deleted', $deleted, esc_url_raw( wp_unslash( $_GET['url'] ) ) ) : '';

		DashboardWidget::clear_widget_cache();

		wp_send_json_success( $redirect_url );
	}

	/**
	 * Entry trash and trigger if needed.
	 *
	 * @since 1.8.5
	 */
	public function process_trash() {

		// Security check.
		if ( ! check_ajax_referer( 'wpforms-admin', 'nonce', false ) ) {
			wp_send_json_error( esc_html__( 'Your session expired. Please reload the builder.', 'wpforms' ) );
		}

		$form_id = $this->get_filtered_form_id();

		// Require data check.
		if ( ! $form_id ) {
			wp_send_json_error( esc_html__( 'Something went wrong while performing this action.', 'wpforms' ) );
		}

		// Permission check.
		if ( ! wpforms_current_user_can( 'delete_entries_form_single', $form_id ) ) {
			wp_send_json_error( esc_html__( 'You do not have permission to perform this action.', 'wpforms' ) );
		}

		if ( $this->is_list_filtered() ) {
			$this->process_filter_dates();
			$this->process_filter_search();
		}

		$entries_id = $this->process_trash_data( $form_id );

		if ( empty( $entries_id ) ) {
			wp_send_json_error( esc_html__( 'Something went wrong while performing this action.', 'wpforms' ) );
		}

		$trashed = $this->process_trash_with_ids( $entries_id, $form_id );

		$redirect_url = ! empty( $_GET['url'] ) ? add_query_arg( 'trashed', $trashed, esc_url_raw( wp_unslash( $_GET['url'] ) ) ) : '';

		DashboardWidget::clear_widget_cache();

		wp_send_json_success( $redirect_url );
	}

	/**
	 * Process entries for trashing.
	 *
	 * @since 1.8.5
	 *
	 * @param int $form_id Form ID.
	 *
	 * @return array $entries_id Entry IDs.
	 */
	private function process_trash_data( $form_id ) {

		// Check if entries filtered.
		// This also checks if there's entry ids provided. See: FilterSearch Trait.
		if ( ! empty( $this->filter['entry_id'] ) ) {
			return $this->filter['entry_id'];
		}

		// Get the screen first.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$screen = isset( $_REQUEST['page'] ) ? sanitize_key( $_REQUEST['page'] ) : '';

		// We can only trash all on all other screens expect trash screen.
		if ( $screen === self::TRASH_ENTRY_STATUS ) {
			return [];
		}

		// Default args to find entries.
		$args = [
			'form_id' => $form_id,
			'select'  => 'entry_ids',
			'number'  => '-1',
		];

		// Apply the date filter if set.
		if ( ! empty( $this->filter['date'] ) ) {
			$args['date'] = $this->filter['date'];
		}

		// Get entries.
		$all_entries  = wpforms()->obj( 'entry' )->get_entries( $args );
		$spam_entries = wpforms()->obj( 'entry' )->get_entries(
			[
				'form_id' => $form_id,
				'status'  => SpamEntry::ENTRY_STATUS,
				'select'  => 'entry_ids',
			]
		);

		return wp_list_pluck( array_merge( $all_entries, $spam_entries ), 'entry_id' );
	}

	/**
	 * Process trash when entry ids are given.
	 *
	 * @since 1.8.5
	 *
	 * @param array $entry_ids Entry IDs.
	 * @param int   $form_id   Form ID.
	 *
	 * @return int  $trashed Number of trashed entries.
	 */
	private function process_trash_with_ids( $entry_ids, $form_id ) {

		$trashed = 0;
		$user_id = get_current_user_id();

		foreach ( $entry_ids as $id ) {
			// Get the entry first.
			$entry = wpforms()->obj( 'entry' )->get( $id );

			if ( ! $entry ) {
				continue;
			}

			$status = $entry->status;

			/**
			 * TODO :: After the support for PHP 7 ends,
			 * we can update the following code to use named arguments and skip the optional params.
			 */
			$success = wpforms()->obj( 'entry' )->update(
				$id,
				[ 'status' => self::TRASH_ENTRY_STATUS ],
				'',
				'',
				[ 'cap' => 'delete_entry_single' ] // Force the cap to trash the entry, since we cant provide edit cap here.
			);

			// If it didn't work continue.
			if ( ! $success ) {
				continue;
			}

			if ( $status !== '' ) {
				wpforms()->obj( 'entry_meta' )->add(
					[
						'entry_id' => $id,
						'form_id'  => $form_id,
						'user_id'  => $user_id,
						'type'     => 'status_prev',
						'data'     => '',
						'status'   => $status,
					],
					'entry_meta'
				);
			}

			++$trashed;
		}

		return $trashed;
	}

	/**
	 * Return validated information about search or FALSE.
	 *
	 * @since 1.8.6
	 *
	 * @return bool|array
	 */
	protected function get_filter_search_parts() {

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( empty( $_GET['search'] ) ) {
			return false;
		}

		$expected = [ 'field', 'comparison', 'term' ];

		foreach ( $expected as $field ) {
			if ( ! isset( $_GET['search'][ $field ] ) || $_GET['search'][ $field ] === '' ) {
				return false;
			}
		}

		return array_map( 'sanitize_text_field', wp_unslash( $_GET['search'] ) );
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
	}

	/**
	 * Return HTML with information about the search filter.
	 *
	 * @since 1.8.6
	 *
	 * @return string
	 */
	protected function get_filter_search_html() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity

		$form_id = $this->get_filtered_form_id();
		$data    = $this->get_filter_search_parts();

		if ( ! $data ) {
			return '';
		}

		$comparisons = [
			'contains'     => __( 'contains', 'wpforms' ),
			'contains_not' => __( 'does not contain', 'wpforms' ),
			'is'           => __( 'is', 'wpforms' ),
			'is_not'       => __( 'is not', 'wpforms' ),
		];
		$comparison  = isset( $comparisons[ $data['comparison'] ] ) ? $comparisons[ $data['comparison'] ] : $comparisons['contains'];
		$field       = isset( $data['field'] ) ? $data['field'] : '';
		$term        = isset( $data['term'] ) ? $data['term'] : '';

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( ! empty( $_GET['search']['term'] ) && wpforms_is_empty_string( $term ) ) {
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			$term = htmlspecialchars( wp_unslash( $_GET['search']['term'] ) );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		if ( is_numeric( $field ) && $form_id ) {
			$meta = wpforms()->obj( 'form' )->get_field( $form_id, $field );

			if ( isset( $meta['label'] ) ) {
				$field = $meta['label'];
			}
		} else {
			$advanced_options = Helpers::get_search_fields_advanced_options();
			$field            = ! empty( $advanced_options[ $field ] ) ? $advanced_options[ $field ] : __( 'any form field', 'wpforms' );
		}

		return sprintf( /* translators: %1$s - field name, %2$s - operation, %3$s term. */
			__( 'where %1$s %2$s "%3$s"', 'wpforms' ),
			'<em>' . esc_html( $field ) . '</em>',
			esc_html( $comparison ),
			'<em>' . esc_html( $term ) . '</em>'
		);
	}

	/**
	 * Get filtered date range.
	 *
	 * @since 1.8.6
	 *
	 * @return array
	 */
	private function get_filtered_dates() {

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( empty( $_GET['date'] ) ) {
			return [];
		}

		$dates = (array) explode( ' - ', sanitize_text_field( wp_unslash( $_GET['date'] ) ) );

		return array_map( 'sanitize_text_field', $dates );
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
	}

	/**
	 * Return an array with information (HTML and id) for each filter for this current view.
	 *
	 * @since 1.8.6
	 *
	 * @return array
	 */
	public function get_filters_html() {

		$filters = [
			'.search-box' => $this->get_filter_search_html(),
		];

		$dates = $this->get_filtered_dates();

		if ( $dates ) {
			$dates = array_map(
				static function ( $date ) {

					return wpforms_date_format( $date );
				},
				$dates
			);

			$html = '';

			switch ( count( $dates ) ) {
				case 1:
					$html = sprintf( /* translators: %s: date. */
						esc_html__( 'on %s', 'wpforms' ),
						'<em>' . $dates[0] . '</em>'
					);
					break;

				case 2:
					$html = sprintf( /* translators: %1$s - date, %2$s - date. */
						esc_html__( 'between %1$s and %2$s', 'wpforms' ),
						'<em>' . $dates[0] . '</em>',
						'<em>' . $dates[1] . '</em>'
					);
					break;
			}

			$filters['.wpforms-filter-date'] = $html;
		}

		return array_filter( $filters );
	}

	/**
	 * Watch for filtering requests from a dates range selection.
	 *
	 * @since 1.8.6
	 */
	public function process_filter_dates() {

		$form_id = $this->get_filtered_form_id();

		if ( empty( $form_id ) ) {
			return;
		}

		$dates = $this->get_filtered_dates();

		if ( empty( $dates ) ) {
			return;
		}

		$this->filter = array_merge(
			$this->filter,
			[
				'date'        => count( $dates ) === 1 ? $dates[0] : $dates,
				'is_filtered' => true,
			]
		);
	}

	/**
	 * Setup entry list page data.
	 *
	 * This function does the error checking and variable setup.
	 *
	 * @since 1.8.6
	 */
	public function setup() {

		if ( wpforms_current_user_can( 'view_forms' ) ) {
			$forms = wpforms()->obj( 'form' )->get(
				'',
				[
					'orderby'   => 'ID',
					'order'     => 'ASC',
					'post_type' => wpforms()->obj( 'entries_overview' )->overview_show_form_templates() ? wpforms()->obj( 'form' )::POST_TYPES : 'wpforms',
				]
			);

			// Fetch all forms.
			$this->forms = wpforms()->obj( 'access' )->filter_forms_by_current_user_capability( $forms, 'view_entries_form_single' );
		}

		// Check that the user has created at least one form.
		if ( empty( $this->forms ) ) {

			$this->alerts[] = [
				'type'    => 'info',
				'message' =>
					sprintf(
						wp_kses(
							/* translators: %s - WPForms Builder page. */
							__( 'Whoops, you haven\'t created a form yet. Want to <a href="%s">give it a go</a>?', 'wpforms' ),
							[
								'a' => [
									'href' => [],
								],
							]
						),
						admin_url( 'admin.php?page=wpforms-builder' )
					),
				'abort'   => true,
			];

		} else {
			$form_id = $this->get_filtered_form_id();

			/**
			 * Filters a default form id on the Entries list page.
			 *
			 * @since 1.1.6
			 *
			 * @param int $form_id Default form id.
			 *
			 * @return int
			 */
			$this->form_id = $form_id ? $form_id : apply_filters( 'wpforms_entry_list_default_form_id', absint( $this->forms[0]->ID ) ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
			$this->form    = wpforms()->obj( 'form' )->get( $this->form_id, [ 'cap' => 'view_entries_form_single' ] );
		}
	}

	/**
	 * Whether the current list of entries is filtered somehow or not.
	 *
	 * @since 1.8.6
	 *
	 * @return bool
	 */
	protected function is_list_filtered() {

		$search_parts = $this->get_filter_search_parts();
		$dates        = $this->get_filtered_dates();
		$is_filtered  = ! empty( $dates ) || ( isset( $search_parts['term'] ) && ! wpforms_is_empty_string( $search_parts['term'] ) );

		/**
		 * Allows to mark the entries list as filtered or not, based on certain conditions.
		 *
		 * By default, the list is considered filtered if the date range is set or
		 * a non-empty search term is applied.
		 *
		 * @since 1.4.4
		 *
		 * @param bool $is_filtered Is the list filtered?
		 */
		return (bool) apply_filters( 'wpforms_entries_list_is_list_filtered', $is_filtered ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
	}

	/**
	 * List all entries in a specific form.
	 *
	 * @since 1.8.6
	 */
	public function list_all() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity

		if ( $this->abort ) {
			return;
		}

		$post_content = $this->form->post_content ?? '';
		$form_data    = $post_content ? wpforms_decode( $post_content ) : [];

		/**
		 * Filter the list all wrap classes.
		 *
		 * @since 1.8.3
		 *
		 * @param array $classes List all wrap classes.
		 */
		$classes = apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
			'wpforms_entries_list_list_all_wrap_classes',
			[
				'wrap',
				'wpforms-admin-wrap',
			]
		);
		?>

		<div id="wpforms-entries-list" class="<?php echo wpforms_sanitize_classes( $classes, true ); ?>">

			<h1 class="page-title"><?php esc_html_e( 'Entries', 'wpforms' ); ?></h1>

			<?php
			$this->entries->form_id   = $this->form_id;
			$this->entries->form_data = $form_data;

			$this->entries->prepare_items();

			$last_entry = wpforms()->obj( 'entry' )->get_last( $this->form_id );
			?>

			<?php $this->entries_disabled_notice(); ?>

			<div class="wpforms-admin-content">

			<?php

			// Show empty entries table after delete bulk action.
			$is_deleted = isset( $_REQUEST['deleted'] ) && $_REQUEST['deleted'] === '1'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

			if (
				empty( $this->entries->items ) &&
				$this->entries->counts['spam'] === 0 &&
				$this->entries->counts['trash'] === 0 &&
				! $is_deleted &&
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				! isset( $_GET['search'] ) && ! isset( $_GET['date'] ) && ! isset( $_GET['type'] ) && ! isset( $_GET['status'] )
			) {

				// Output no entries screen.
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				echo wpforms_render(
					'admin/empty-states/no-entries',
					[
						'message' => ! empty( $this->entries->form_data['settings']['disable_entries'] )
							? __( 'Storing entry information has been disabled for this form.', 'wpforms' )
							: __( 'It looks like you don\'t have any form entries just yet - check back soon!', 'wpforms' ),
					],
					true
				);

			} else {
				/**
				 * Fire before entries table.
				 *
				 * @since 1.1.6
				 *
				 * @param array $form_data    Form content.
				 * @param Page  $entries_list WPForms\Pro\Admin\Entries\Page class instance.
				 */
				do_action( 'wpforms_entry_list_title', $form_data, $this ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

				// Are we on the "Spam" or "Trash" tab?
				// phpcs:disable WordPress.Security.NonceVerification.Recommended
				$has_status = isset( $_GET['status'] ) && in_array( $_GET['status'], [ SpamEntry::ENTRY_STATUS, self::TRASH_ENTRY_STATUS ], true );
				$status     = $has_status ? sanitize_key( $_GET['status'] ) : '';
				// phpcs:enable WordPress.Security.NonceVerification.Recommended
			?>

				<form id="wpforms-entries-table" method="GET"
					action="<?php echo esc_url( admin_url( 'admin.php?page=wpforms-entries' ) ); ?>"
					<?php echo ( ! $this->is_list_filtered() && isset( $last_entry->entry_id ) ) ? 'data-last-entry-id="' . absint( $last_entry->entry_id ) . '"' : ''; ?> <?php printf( 'data-filtered-count-trash="%1d"', absint( $this->entries->counts['total'] ) ); ?>>

					<?php if ( $this->get_filters_html() ) : ?>

						<div id="wpforms-reset-filter">
							<?php

							printf(
								wp_kses( /* translators: %s - number of entries found. */
									_n(
										'Found <strong>%s entry</strong>',
										'Found <strong>%s entries</strong>',
										absint( count( (array) $this->entries->items ) ),
										'wpforms'
									),
									[
										'strong' => [],
									]
								),
								$has_status ? absint( $this->entries->counts[ $status ] ) : absint( $this->entries->counts['total'] )
							);
							?>

							<?php foreach ( $this->get_filters_html() as $id => $html ) : ?>
								<?php
								echo wp_kses(
									$html,
									[ 'em' => [] ]
								);
								?>
								<i class="reset fa fa-times-circle" data-scope="<?php echo esc_attr( $id ); ?>"></i>
							<?php endforeach; ?>
						</div>
					<?php endif ?>

					<input type="hidden" name="page" value="wpforms-entries" />
					<input type="hidden" name="view" value="list" />
					<input type="hidden" name="form_id" value="<?php echo absint( $this->form_id ); ?>" />

					<?php if ( $has_status ) : ?>
						<input type="hidden" name="status" value="<?php echo esc_attr( $status ); ?>" />
					<?php endif; ?>

					<?php $this->entries->views(); ?>

					<?php $this->entries->search_box( esc_html__( 'Search', 'wpforms' ), 'wpforms-entries' ); ?>

					<?php $this->entries->display(); ?>

				</form>

			<?php } ?>

			</div>

		</div>

		<?php
	}

	/**
	 * Display abort message using empty state page.
	 *
	 * @since 1.8.6
	 */
	public function display_abort_message() {

		if ( ! $this->abort ) {
			return;
		}

		?>
		<div id="wpforms-entries-list" class="wrap wpforms-admin-wrap">

			<h1 class="page-title">
				<?php esc_html_e( 'Entries', 'wpforms' ); ?>
			</h1>
			<div class="wpforms-admin-content">
				<?php
				// Output empty state screen.
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				echo wpforms_render(
					'admin/empty-states/no-entries',
					[
						'message' => $this->abort_message,
					],
					true
				);
				?>
			</div>
		</div>
		<?php
	}

	/**
	 * Settings for field column personalization!
	 *
	 * @since 1.8.6
	 */
	public function field_column_setting() {

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo $this->get_columns_multiselect();
	}

	/**
	 * Get columns multiselect menu.
	 *
	 * @since 1.8.6
	 *
	 * @return string HTML menu markup.
	 */
	private function get_columns_multiselect(): string {

		$field_columns = Columns::get_field_columns( $this->form_id );
		$meta_columns  = Columns::get_meta_columns();
		$selected_keys = Columns::get_selected_columns_keys();
		$selected_keys = empty( $selected_keys ) ? Columns::get_default_columns_keys() : $selected_keys;

		$html = '
			<div id="wpforms-list-table-ext-edit-columns-select-container" class="wpforms-hidden wpforms-list-table-ext-edit-columns-select-container wpforms-entries-list-page">
			<form method="post" action="' . esc_url( admin_url( 'admin.php?page=wpforms-entries&view=list&form_id=' . (int) $this->form_id ) ) . '">
				<input type="hidden" name="action" value="wpforms_admin_entries_list_save_columns_order"/>
				<input type="hidden" name="form_id" value="' . (int) $this->form_id . '"/>
				<select name="fields[]"
					id="wpforms-entries-table-edit-columns-select"
					class="wpforms-entries-table-edit-columns-select wpforms-list-table-ext-edit-columns-select"
					name="wpforms-entries-table-edit-columns-select"
					multiple="multiple">
					%s
					%s
				</select>
			</form>
			</div>
		';

		$field_options = $this->get_optgroup_html( $field_columns, $selected_keys, esc_html__( 'Form Fields', 'wpforms' ) );
		$meta_options  = $this->get_optgroup_html( $meta_columns, $selected_keys, esc_html__( 'Entry Meta', 'wpforms' ) );

		return sprintf( $html, $field_options, $meta_options );
	}

	/**
	 * Get columns multiselect options.
	 *
	 * @since 1.8.6
	 *
	 * @param Column[] $columns       List of columns.
	 * @param array    $selected_keys List of selected columns keys.
	 * @param string   $label         Label for the optgroup.
	 *
	 * @return string HTML options markup.
	 */
	private function get_optgroup_html( $columns, $selected_keys, $label ): string {

		if ( empty( $columns ) ) {
			return '';
		}

		$html = '<optgroup label="' . esc_html( $label ) . '">';

		foreach ( $columns as $column ) {
			$selected = in_array( $column->get_id(), $selected_keys, true ) ? 'selected' : '';
			$html    .= sprintf( '<option value="%s" %s>%s</option>', esc_attr( $column->get_id() ), $selected, esc_html( $column->get_label() ) );
		}

		$html .= '</optgroup>';

		return $html;
	}

	/**
	 * Entries list form actions.
	 *
	 * @since 1.8.6
	 *
	 * @param array $form_data Form data and settings.
	 */
	public function list_form_actions( $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity

		$base = add_query_arg(
			[
				'page'    => 'wpforms-entries',
				'view'    => 'list',
				'form_id' => absint( $this->form_id ),
			],
			admin_url( 'admin.php' )
		);

		// Edit Form URL.
		$edit_url = add_query_arg(
			[
				'page'    => 'wpforms-builder',
				'view'    => 'fields',
				'form_id' => absint( $this->form_id ),
			],
			admin_url( 'admin.php' )
		);

		// Payments URL.
		if ( wpforms()->obj( 'payment' )->get_by( 'form_id', $this->form_id ) ) {
			$payments_url = add_query_arg(
				[
					'page'    => 'wpforms-payments',
					'form_id' => absint( $this->form_id ),
				],
				admin_url( 'admin.php' )
			);
		}

		// Preview Entry URL.
		$preview_url = esc_url( wpforms_get_form_preview_url( $this->form_id ) );

		// Export Entry URL.
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$export_url = add_query_arg(
			[
				'page'   => 'wpforms-tools',
				'view'   => 'export',
				'form'   => absint( $this->form_id ),
				'search' => ! empty( $_GET['search'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_GET['search'] ) ) : [],
				'date'   => ! empty( $_GET['date'] ) ? sanitize_text_field( wp_unslash( $_GET['date'] ) ) : [],
			],
			admin_url( 'admin.php' )
		);

		$read_url_args = [ 'action' => 'markread' ];

		if ( isset( $_GET['status'] ) && ! empty( $_GET['status'] ) ) {
			$read_url_args['status'] = sanitize_key( $_GET['status'] );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		// Mark Read URL.
		$read_url = wp_nonce_url(
			add_query_arg(
				$read_url_args,
				$base
			),
			'wpforms_entry_list_markread'
		);

		// Delete all entries.
		$delete_url = wp_nonce_url( $base, 'bulk-entries' );

		// Form title.
		$form_title = isset( $form_data['settings']['form_title'] ) ? $form_data['settings']['form_title'] : '';

		if ( empty( $form_title ) ) {
			$form = wpforms()->obj( 'form' )->get( $this->form_id );

			$form_title = ! empty( $form )
				? $form->post_title
				: sprintf( /* translators: %d - form ID. */
					esc_html__( 'Form (#%d)', 'wpforms' ),
					$this->form_id
				);
		}

		$is_form_template  = wpforms_is_form_template( $this->form_id );
		$form_title_suffix = '';

		if ( $is_form_template ) {
			$form_title_suffix = sprintf( '<span> — %s</span>', esc_html__( 'Template', 'wpforms' ) );
		}
		?>

		<div class="form-details">

			<span class="form-details-sub"><?php esc_html_e( 'Select Form', 'wpforms' ); ?></span>

			<h3 class="form-details-title">
				<?php
				echo esc_html( wp_strip_all_tags( $form_title ) ) . wp_kses( $form_title_suffix, [ 'span' => [] ] );
				$this->form_selector_html();
				?>
			</h3>

			<div class="form-details-actions">

				<?php if ( $this->is_list_filtered() ) : ?>
					<a href="<?php echo esc_url( $base ); ?>" class="form-details-actions-entries">
						<span class="dashicons dashicons-list-view"></span>
						<?php esc_html_e( 'All Entries', 'wpforms' ); ?>
					</a>
				<?php endif; ?>

				<?php if ( isset( $payments_url ) ) : ?>
					<a href="<?php echo esc_url( $payments_url ); ?>" class="form-details-actions-view-payments">
						<span class="fa fa-credit-card"></span>
						<?php esc_html_e( 'View Payments', 'wpforms' ); ?>
					</a>
				<?php endif; ?>

				<?php if ( wpforms_current_user_can( 'edit_form_single', $this->form_id ) ) : ?>
					<a href="<?php echo esc_url( $edit_url ); ?>" class="form-details-actions-edit">
						<span class="dashicons dashicons-edit"></span>
						<?php $is_form_template ? esc_html_e( 'Edit This Template', 'wpforms' ) : esc_html_e( 'Edit This Form', 'wpforms' ); ?>
					</a>
				<?php endif; ?>

				<?php if ( wpforms_current_user_can( 'view_form_single', $this->form_id ) ) : ?>
					<a href="<?php echo esc_url( $preview_url ); ?>" class="form-details-actions-preview" target="_blank" rel="noopener noreferrer">
						<span class="dashicons dashicons-visibility"></span>
						<?php $is_form_template ? esc_html_e( 'Preview Template', 'wpforms' ) : esc_html_e( 'Preview Form', 'wpforms' ); ?>
					</a>
				<?php endif; ?>

				<?php if ( ! $is_form_template ) : ?>
					<a href="<?php echo esc_url( $export_url ); ?>" class="form-details-actions-export">
						<span class="dashicons dashicons-migrate"></span>
						<?php echo $this->is_list_filtered() ? esc_html__( 'Export Filtered', 'wpforms' ) : esc_html__( 'Export All', 'wpforms' ); ?>
					</a>
				<?php endif; ?>

				<a href="<?php echo esc_url( $read_url ); ?>" class="form-details-actions-read">
					<span class="dashicons dashicons-marker"></span>
					<?php esc_html_e( 'Mark All Read', 'wpforms' ); ?>
				</a>

				<?php if ( wpforms_current_user_can( 'delete_entries_form_single', $this->form_id ) ) : ?>
					<?php $status = ! empty( $_GET['status'] ) ? sanitize_key( $_GET['status'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>

					<a href="<?php echo esc_url( $delete_url ); ?>" class="form-details-actions-removeall" data-page="<?php echo esc_attr( $status ); ?>">
						<span class="dashicons dashicons-trash"></span>
						<?php $status === self::TRASH_ENTRY_STATUS ? esc_html_e( 'Empty Trash', 'wpforms' ) : esc_html_e( 'Trash All', 'wpforms' ); ?>
					</a>
				<?php endif; ?>

			</div>

		</div>
		<?php
	}

	/**
	 * Display form selector HTML.
	 *
	 * @since 1.8.6
	 */
	protected function form_selector_html() {

		if ( ! wpforms_current_user_can( 'view_forms' ) ) {
			return;
		}

		if ( empty( $this->forms ) ) {
			return;
		}

		?>
		<div class="form-selector">
			<a href="#" title="<?php esc_attr_e( 'Open form selector', 'wpforms' ); ?>" class="toggle dashicons dashicons-arrow-down-alt2"></a>
			<div class="form-list">
				<ul>
					<?php
					foreach ( $this->forms as $key => $form ) {
						if ( $this->form_id === $form->ID ) {
							continue;
						}

						$form_url = add_query_arg(
							[
								'page'    => 'wpforms-entries',
								'view'    => 'list',
								'form_id' => absint( $form->ID ),
							],
							admin_url( 'admin.php' )
						);

						$form_title = $form->post_type === 'wpforms-template'
							? $form->post_title . ' – ' . __( 'Template', 'wpforms' )
							: $form->post_title;

						printf( '<li><a href="%s">%s</a></li>', esc_url( $form_url ), esc_html( $form_title ) );
					}
					?>
				</ul>
			</div>

		</div>
		<?php
	}

	/**
	 * Add notices and errors.
	 *
	 * @since 1.8.6
	 */
	public function register_alerts() {

		if ( empty( $this->alerts ) ) {
			return;
		}

		foreach ( $this->alerts as $alert ) {
			$type = ! empty( $alert['type'] ) ? $alert['type'] : 'info';

			Notice::add( $alert['message'], $type );

			if ( ! empty( $alert['abort'] ) ) {
				$this->abort = true;

				break;
			}
		}
	}

	/**
	 * Check for new entries using Heartbeat API.
	 *
	 * @since 1.8.6
	 *
	 * @param array  $response  The Heartbeat response.
	 * @param array  $data      The $_POST data sent.
	 * @param string $screen_id The screen id.
	 *
	 * @return array
	 */
	public function heartbeat_new_entries_check( $response, $data, $screen_id ) {

		if ( $screen_id !== 'wpforms_page_wpforms-entries' ) {
			return $response;
		}

		$entry_id = ! empty( $data['wpforms_new_entries_entry_id'] ) ? absint( $data['wpforms_new_entries_entry_id'] ) : 0;
		$form_id  = ! empty( $data['wpforms_new_entries_form_id'] ) ? absint( $data['wpforms_new_entries_form_id'] ) : 0;

		if ( empty( $form_id ) ) {
			return $response;
		}

		$entries_count = wpforms()->obj( 'entry' )->get_next_count( $entry_id, $form_id, '' );

		if ( empty( $entries_count ) ) {
			return $response;
		}

		/* translators: %d - number of form entries. */
		$response['wpforms_new_entries_notification'] = esc_html( sprintf( _n( 'See %d new entry', 'See %d new entries', $entries_count, 'wpforms' ), $entries_count ) );

		return $response;
	}

	/**
	 * Localize needed strings.
	 *
	 * @since 1.8.6
	 *
	 * @param array $strings JS strings.
	 *
	 * @return mixed
	 */
	public function js_strings( $strings ) {

		$strings['lang_code']    = sanitize_key( wpforms_get_language_code() );
		$strings['default_date'] = [];
		$dates                   = $this->get_filtered_dates();

		if ( $dates ) {
			if ( count( $dates ) === 1 ) {
				$dates[1] = $dates[0];
			}
			$strings['default_date'] = [ sanitize_text_field( $dates[0] ), sanitize_text_field( $dates[1] ) ];
		}

		return $strings;
	}

	/**
	 * Display info notice for forms that have entries and disable_entries setting.
	 *
	 * The entries list isn't available when register_alerts runs.
	 *
	 * @since 1.8.6
	 *
	 * @return void
	 */
	protected function entries_disabled_notice() {

		if (
			empty( $this->entries->form_data['settings']['disable_entries'] )
			|| empty( $this->entries->items )
		) {
			return;
		}

		?>

		<div class="notice wpforms-notice notice-info" style="display: block;">
			<p>
				<?php esc_html_e( 'Storing entry information has been disabled for this form.', 'wpforms' ); ?>
			</p>
		</div>

		<?php
	}
}

Filemanager

Name Type Size Permission Actions
Ajax Folder 0750
Export Folder 0750
Overview Folder 0750
Table Folder 0750
Edit.php File 50.88 KB 0640
FilterSearch.php File 4.93 KB 0640
Handler.php File 1.54 KB 0640
Helpers.php File 1.23 KB 0640
ListTable.php File 57.47 KB 0640
Page.php File 37.58 KB 0640
PageOptions.php File 1.86 KB 0640
PrintPreview.php File 14.27 KB 0640
Filemanager