File: /var/www/html/TriadGov/wp-content/plugins/wpforms/src/Pro/Admin/Entries/Table/Facades/Columns.php
<?php
namespace WPForms\Pro\Admin\Entries\Table\Facades;
use WP_Error; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement
use WPForms\Admin\Base\Tables\Facades\ColumnsBase;
use WPForms\Pro\Admin\Entries\Table\DataObjects\FieldColumn;
use WPForms\Pro\Admin\Entries\Table\DataObjects\MetaColumn;
use WPForms\Pro\Admin\Entries\Table\DataObjects\Column; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement
use WPForms\Pro\Admin\Entries\ListTable;
/**
* Column facade class.
*
* Hides the complexity of columns' collection behind a simple interface.
*
* @since 1.8.6
*/
class Columns extends ColumnsBase {
/**
* The ID of the table column called "Entry ID".
*
* @since 1.8.6
*
* @var int
*/
const COLUMN_ENTRY_ID = -1;
/**
* The ID of the table column called "Entry Notes".
*
* @since 1.8.6
*
* @var int
*/
const COLUMN_NOTES_COUNT = -2;
/**
* Get columns.
*
* Returns all possible columns for Entries table. It returns both entry meta and form fields columns.
*
* @since 1.8.6
*
* @param int|string $form_id Form ID.
*
* @return Column[] Array of columns as objects.
*/
protected static function get_all( $form_id = 0 ): array {
$form_id = $form_id ? absint( $form_id ) : self::get_current_form_id();
static $form_columns = [];
if ( ! isset( $form_columns[ $form_id ] ) ) {
$form_columns[ $form_id ] = self::get_meta_columns() + self::get_field_columns( $form_id );
}
return $form_columns[ $form_id ];
}
/**
* Get field columns.
*
* Returns array of columns for the form fields. Array is indexed by field ID (positive int).
*
* @since 1.8.6
*
* @param int|string $form_id Form ID.
*
* @return FieldColumn[] Array of columns as objects.
*/
public static function get_field_columns( $form_id = 0 ): array {
$fields = self::get_form_fields( $form_id );
$columns = [];
// Default forbidden fields types list.
$default_forbidden_fields = [
'divider',
'layout',
'repeater',
'pagebreak',
'internal-information',
'html',
'content',
'entry-preview',
'captcha',
];
/**
* Filter forbidden field types.
*
* In addition to this list, the following fields are always forbidden:
* divider, layout, pagebreak, internal-information, html, content, entry-preview, captcha,
*
* @since 1.8.6
*
* @param array $forbidden_fields Forbidden field types.
* @param int|string $form_id Form ID.
*/
$filtered_forbidden_fields = (array) apply_filters(
'wpforms_pro_admin_entries_table_facades_columns_get_field_columns_forbidden_fields',
[],
$form_id
);
// Defaults is the strictly forbidden field types.
$forbidden_fields = array_merge( $filtered_forbidden_fields, $default_forbidden_fields );
foreach ( $fields as $id => $field ) {
if ( ! isset( $field['type'] ) || in_array( $field['type'], $forbidden_fields, true ) ) {
continue;
}
$columns[ $id ] = new FieldColumn( $id, $field );
}
return $columns;
}
/**
* Get entry meta-columns.
*
* Returns array of columns for the entry meta. Array is indexed by two different types of indexes:
* - negative int - for entry_id column and entry_notes column.
* - string - for all other columns.
*
* @since 1.8.6
*
* @return MetaColumn[] Array of columns as objects.
*/
public static function get_meta_columns(): array {
$columns_data = [
self::COLUMN_ENTRY_ID => [
'label' => esc_html__( 'Entry ID', 'wpforms' ),
'type' => 'entry_id',
],
self::COLUMN_NOTES_COUNT => [
'label' => esc_html__( 'Entry Notes', 'wpforms' ),
'type' => 'notes_count',
],
'date' => [
'label' => esc_html__( 'Date', 'wpforms' ),
],
'type' => [
'label' => esc_html__( 'Entry Type', 'wpforms' ),
],
'user_ip' => [
'label' => esc_html__( 'User IP', 'wpforms' ),
],
'user_agent' => [
'label' => esc_html__( 'User Agent', 'wpforms' ),
],
'user_uuid' => [
'label' => esc_html__( 'Unique User ID', 'wpforms' ),
],
];
$form_fields = self::get_form_fields( self::get_current_form_id() );
if ( wpforms_has_payment( 'form', $form_fields ) ) {
$columns_data['payment'] = [
'label' => esc_html__( 'Payment', 'wpforms' ),
];
}
/**
* Filter entry meta columns.
*
* @since 1.8.6
*
* @param array $columns_data Array of columns data.
*/
$columns_data = apply_filters( 'wpforms_pro_admin_entries_table_facades_columns_get_meta_columns_columns_data', $columns_data );
$columns_data = array_map(
static function ( $column ) {
$column['type'] = ! empty( $column['type'] ) ? (string) $column['type'] : '';
$column['draggable'] = (bool) ( $column['draggable'] ?? true );
return $column;
},
$columns_data
);
$columns = [];
foreach ( $columns_data as $id => $settings ) {
$columns[ $id ] = new MetaColumn( $id, $settings );
}
return $columns;
}
/**
* Get columns' keys for the columns which user selected to be displayed.
*
* It returns an array of keys in the order they should be displayed,
* e.g., [ -1, 'entry_id', 'notes_count', 'date', 2, 1 ].
* The returned array contains draggable and non-draggable columns.
*
* @since 1.8.6
*
* @return array
*/
public static function get_selected_columns_keys(): array {
$form_id = self::get_current_form_id();
if ( ! $form_id ) {
return [];
}
$form_obj = wpforms()->obj( 'form' );
if ( ! $form_obj ) {
return [];
}
$form = $form_obj->get( $form_id, [ 'content_only' => true ] );
return empty( $form['meta']['entry_columns'] ) ? [] : $form['meta']['entry_columns'];
}
/**
* Get columns' keys for the columns which user selected to be displayed.
*
* @since 1.8.6
*
* @return array
*/
public static function get_default_columns_keys(): array {
$all_columns = self::get_all();
$form_data = self::get_form_data();
$has_payment = wpforms_has_payment( 'form', $form_data );
$field_columns = $has_payment ? 2 : 3;
if ( empty( $form_data['fields'] ) ) {
$default_columns = [];
} else {
$default_columns = array_filter(
$all_columns,
static function ( $column ) {
return $column->is_form_field();
}
);
}
$default_columns = array_slice( $default_columns, 0, $field_columns, true );
if ( $has_payment ) {
$default_columns['payment'] = $all_columns['payment'];
}
/**
* Filters whether to show the status column in the entry table.
* This filter is often used to trigger by add-ons to show the status column for forms.
*
* @since 1.6.0
*
* @param bool $show_status Whether to show the status column. Default false.
* @param array $form_data Form data.
*
* @return bool
*/
if ( apply_filters( 'wpforms_entries_table_column_status', false, $form_data ) ) { // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
$default_columns['type'] = $all_columns['type'];
}
$default_columns['date'] = $all_columns['date'];
return array_keys( $default_columns );
}
/**
* Get draggable columns ordered keys.
*
* The Expected result is array of keys in the order they should be displayed,
* e.g., [ -1, 'entry_id', 'notes_count', 'date', 2, 1 ].
* It will return custom order if user has already saved it, otherwise it will return default order.
*
* @since 1.8.6
*
* @return array
*/
public static function get_draggable_ordered_keys(): array {
// First, let's check if user has already saved custom order.
$custom_order = self::get_selected_columns_keys();
$all_columns = self::get_all();
if ( $custom_order ) {
// If a user has saved custom order, let's filter out columns which are not draggable.
return array_filter(
$custom_order,
static function ( $id ) use ( $all_columns ) {
return isset( $all_columns[ $id ] ) && $all_columns[ $id ]->is_draggable();
}
);
}
return self::get_default_columns_keys();
}
/**
* Save columns' keys array into form's entry_columns meta.
*
* If columns' keys' array is empty, it will delete entry_columns meta.
*
* @since 1.8.6
*
* @param int $form_id Form ID.
* @param array $columns_keys Array of columns keys in desired display order.
*
* @return false|int|WP_Error
*/
public static function sanitize_and_save_columns( int $form_id, array $columns_keys ) {
$columns_keys = array_map( [ __CLASS__, 'sanitize_column_key' ], $columns_keys );
$columns_keys = array_filter( $columns_keys, [ __CLASS__, 'validate_column_key' ] );
$form_obj = wpforms()->obj( 'form' );
if ( ! $form_obj ) {
return false;
}
// Remove KSES filters before updating meta for forms and their fields which contain HTML.
// If we don't do this, forms for users who don't have 'unfiltered_html' capabilities can get corrupt due to conflicts with wp_kses().
kses_remove_filters();
$result = $columns_keys
? $form_obj->update_meta( $form_id, 'entry_columns', $columns_keys, [ 'cap' => 'view_entries_form_single' ] )
: $form_obj->delete_meta( $form_id, 'entry_columns', [ 'cap' => 'view_entries_form_single' ] );
// Re-initialize KSES filters for users who don't have 'unfiltered_html' capabilities.
if ( ! current_user_can( 'unfiltered_html' ) ) {
kses_init_filters();
}
return $result;
}
/**
* Sanitize column key.
*
* @since 1.8.6
*
* @param string|int $key Column key.
*
* @return int|string
*/
public static function sanitize_column_key( $key ) {
return is_numeric( $key ) ? (int) $key : sanitize_key( $key );
}
/**
* Get form data for given form ID.
*
* If form ID is not provided, it will try to get it from $_REQUEST['form_id'].
*
* @since 1.8.6
*
* @param int|string $form_id Form ID.
*
* @return array
*/
private static function get_form_data( $form_id = 0 ): array {
$form_id = $form_id ? absint( $form_id ) : self::get_current_form_id();
if ( ! $form_id ) {
return [];
}
$form_obj = wpforms()->obj( 'form' );
if ( ! $form_obj ) {
return [];
}
$form = $form_obj->get( $form_id, [ 'content_only' => true ] );
if ( ! $form ) {
return [];
}
return $form;
}
/**
* Get form fields for given form ID.
*
* If form ID is not provided, it will try to get it from $_REQUEST['form_id'].
*
* @since 1.8.6
*
* @param int|string $form_id Form ID.
*
* @return array
*/
private static function get_form_fields( $form_id = 0 ): array {
$form = self::get_form_data( $form_id );
return empty( $form['fields'] ) ? [] : $form['fields'];
}
/**
* Get current form ID.
*
* Helper to obtain form ID from $_REQUEST['form_id'].
*
* @since 1.8.6
*
* @return int
*/
private static function get_current_form_id(): int {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
return ! empty( $_REQUEST['form_id'] ) ? absint( $_REQUEST['form_id'] ) : 0;
}
/**
* Get columns' data ready to use in the list table object.
*
* @since 1.8.6
*
* @param ListTable|mixed $list_table List table object.
*
* @return array
*/
public static function get_list_table_columns( $list_table ): array {
if ( ! $list_table instanceof ListTable ) {
return [];
}
$columns = [
'cb' => '<input type="checkbox" />',
'indicators' => '',
];
$order = self::get_draggable_ordered_keys();
$all_columns = self::get_all();
foreach ( $order as $column_id ) {
$columns[ $all_columns[ $column_id ]->get_slug() ] = $all_columns[ $column_id ]->get_label();
}
if ( ! $list_table->is_trash_list() || wpforms_current_user_can( 'delete_entries_form_single', $list_table->form_id ) ) {
$columns['actions'] = esc_html__( 'Actions', 'wpforms' );
}
/**
* Filters of all the Entries list table columns.
*
* @since 1.0.0
*
* @param array $columns The Entries list table columns.
* @param array $form_data Form data.
*
* @return bool
*/
return apply_filters( 'wpforms_entries_table_columns', $columns, self::get_form_data() ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
}
}