<?php /** * Suppress "error - 0 - No summary was found for this file" on phpdoc generation * * @package WPDataAccess\Simple_Form */ namespace WPDataAccess\Simple_Form; use WPDataAccess\Data_Dictionary\WPDA_List_Columns; use WPDataAccess\Plugin_Table_Models\WPDA_Media_Model; use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model; use WPDataAccess\Utilities\WPDA_Message_Box; use WPDataAccess\WPDA; use WPDataAccess\Dashboard\WPDA_Dashboard; /** * Class WPDA_Simple_Form * * Generates a simple dynamic data entry form on request. Data entry form consists of the following components: * + WPDA_Simple_Form (layout management) * + WPDA_Simple_Form_Data (data management) * + WPDA_Simple_Form_Item (data item management) * + WPDA_Simple_Form_Type_Icon (data type icon) * * Simple forms can be generated for tables only. It is not possible to generate simple forms for views. * * Simple forms can be generated for tables with a primary key only. For tables that do not have a primary key it * is not possible to generate a simple form as records in the table cannot be recognized uniquely. * * Primary key fields are disable in update mode. This is to prevent inconsistency. Use method * {@see WPDA_Simple_Form::set_update_keys()} to allow updating primary key items. Make sure you understand to * consequences!!! * * @author Peter Schulz * @since 1.0.0 */ class WPDA_Simple_Form { /** * Static id to create unique form names on the page * * @var int */ protected static $form_id = 0; /** * Warning icon */ const WARNING_ICON = '<span class="dashicons dashicons-warning"></span> '; /** * Form id * * @var int */ protected $current_form_id; /** * Page title * * @var string */ protected $title = null; /** * Add action to page title? * * @var string TRUE = add action */ protected $add_action_to_title; /** * Page subtitle * * @var string */ protected $subtitle = ''; /** * Page fieldset title * * @var string */ protected $fieldset_title = ''; /** * Hides warning update text * * @var string TRUE = hide warning (overwrites plugin settings) */ protected $no_warning_update_text = 'FALSE'; /** * Database schema name * * @var string */ protected $schema_name; /** * Database table name * * @var string */ protected $table_name; /** * Handle to data management component * * @var WPDA_Simple_Form_Data */ protected $row_data; /** * Handle to database record * * @var object */ protected $row; /** * Handle to WPDA_List_Columns * * @var WPDA_List_Columns */ protected $wpda_list_columns; /** * Access column names * * @var array */ protected $table_columns; /** * Access column headers * * @var array */ protected $table_column_headers; /** * Display column headers * * @var array */ protected $table_column_header; /** * Column headers (labels, arguments) * * @var array */ protected $column_headers; /** * Form items * * @var array */ protected $form_items = array(); /** * Form items named array * * Use this array to quickly find an item in the form * * @var array */ protected $form_items_named = array(); /** * Form items old values (if applicable) * * @var array */ protected $form_items_old_values = array(); /** * Form items new values (if applicable) * * @var array */ protected $form_items_new_values = array(); /** * Menu slug current page * * @var string */ protected $page; /** * Primary page action * * @var string */ protected $action; /** * Secondary page action * * @var string */ protected $action2 = ''; /** * Auto increment value * * @var int */ protected $auto_increment_value = -1; /** * Defines it keys are updatable * * @var bool */ protected $update_keys_allowed = false; /** * Error message number * * @var int */ protected $wpda_err = 0; /** * Error message text * * @var string */ protected $wpda_msg = ''; /** * Indicates whether the title should be displayed or not * * @var bool */ protected $show_title = true; /** * Indicates whether the back button should be displayed or not * * @var bool */ protected $show_back_button = true; /** * Indicates whether the back icon in the title should be displayed or not * * @var bool */ protected $show_back_icon = true; /** * Indicates whether table type should be checked to display subtitle. * * @var bool */ protected $check_table_type = true; /** * Page number item name (default 'page_number') * * The name can be changed for pages on multiple levels. This is needed to get back to the right page in * parent-child page. * * @var string */ protected $page_number_item_name = 'page_number'; /** * Real page number * * @var null */ protected $page_number_link = ''; /** * Page number text item * * @var null */ protected $page_number_item = ''; /** * Used to changed button text * * @var string */ protected $back_to_list_text = ''; /** * Table settings (taken from plugin table settings table) * * @var mixed|null */ protected $wpda_table_settings = null; /** * Show help icon if help url is available * * @var null|string */ protected $help_url = null; /** * Hide Add New button * * @var null|string */ protected $hide_add_new = false; /** * Group items into fieldsets * * @var array */ protected $fieldsets = array(); /** * WPDA_Simple_Form constructor * * Performs the following steps: * + Check if requested action is allowed * + Check if table is provided * + Save OLD and NEW request values * + Create WPDA_Simple_Form_Data object * * @param string $schema_name Database schema name. * @param string $table_name Database table name. * @param WPDA_List_Columns $wpda_list_columns Reference to column array. * @param array $args Messages (named array). * * @since 1.0.0 * * @see WPDA_Simple_Form_Data */ public function __construct( $schema_name, $table_name, &$wpda_list_columns, $args = array() ) { // Get page and handling arguments. if ( isset( $_REQUEST['page'] ) ) { $this->page = sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ); // input var okay. } else { wp_die( __( 'ERROR: Wrong arguments [missing page argument]', 'wp-data-access' ) ); } if ( isset( $_REQUEST['action'] ) ) { // Possible values: "new", "edit" and "view". $this->action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // input var okay. } else { if ( isset( $args['action'] ) ) { $this->action = $args['action']; } else { wp_die( __( 'ERROR: Wrong arguments [missing action argument]', 'wp-data-access' ) ); } } if ( isset( $_REQUEST['action2'] ) ) { $this->action2 = sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ); // input var okay. } $this->schema_name = $schema_name; $this->table_name = $table_name; if ( '' === $this->table_name ) { // Without a table name it makes no sense to continue. wp_die( __( 'ERROR: Wrong arguments [missing table_name argument]' ) ); } if ( !WPDA::is_wpda_table( $this->table_name ) ) { // Check access rights for tables that do not belong to the plugin. if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_ALLOW_INSERT ) && 'new' === $this->action ) { // Insert not allowed. wp_die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); } if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_VIEW_LINK ) && 'view' === $this->action ) { // Viewing not allowed. wp_die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); } if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_ALLOW_UPDATE ) && 'edit' === $this->action ) { // Update not allowed. wp_die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); } } // Get columns information. $this->wpda_list_columns = $wpda_list_columns; $this->table_columns = $this->wpda_list_columns->get_table_columns(); $this->table_column_headers = $this->wpda_list_columns->get_table_column_headers(); // Set page title. if ( isset( $args['title'] ) ) { $this->title = $args['title']; $this->add_action_to_title = true; if ( isset( $args['add_action_to_title'] ) && 'FALSE' === $args['add_action_to_title'] ) { $this->add_action_to_title = false; } } // Set page subtitle. if ( isset( $args['subtitle'] ) ) { $this->subtitle = $args['subtitle']; } else { if ( $this->check_table_type ) { global $wpdb; $wp_tables = $wpdb->tables( 'all', true ); if ( isset( $wp_tables[substr( $this->table_name, strlen( $wpdb->prefix ) )] ) ) { $this->subtitle = self::WARNING_ICON . WPDA::get_table_type_text( WPDA::TABLE_TYPE_WP ); } elseif ( WPDA::is_wpda_table( $this->table_name ) ) { $this->subtitle = self::WARNING_ICON . WPDA::get_table_type_text( WPDA::TABLE_TYPE_WPDA ); } } } if ( isset( $args['no_warning_update_text'] ) ) { $this->no_warning_update_text = $args['no_warning_update_text']; } // Add customizable success and failure messages to support i18n. // This allows to overwrite message in classes extending WPDA_Simple_Form. $args = wp_parse_args( $args, array( 'wpda_success_msg' => __( 'Succesfully saved changes to database', 'wp-data-access' ), 'wpda_failure_msg' => __( 'Saving changes to database failed', 'wp-data-access' ), 'show_title' => true, 'show_back_button' => true, 'show_back_icon' => true, ) ); // Get arguments from URL (old and new values). $this->get_url_arguments(); // Add data object for DML. $this->row_data = new WPDA_Simple_Form_Data( $this->schema_name, $this->table_name, $this->wpda_list_columns, $this, $args['wpda_success_msg'], $args['wpda_failure_msg'] ); $this->current_form_id = 'wpda_simple_form_' . self::$form_id++; if ( isset( $args['show_title'] ) ) { $this->show_title = $args['show_title']; } if ( isset( $args['show_back_button'] ) ) { $this->show_back_button = $args['show_back_button']; } if ( isset( $args['show_back_icon'] ) ) { $this->show_back_icon = $args['show_back_icon']; } // Overwrite column header text if column headers were provided. $this->column_headers = ( isset( $args['column_headers'] ) ? $args['column_headers'] : '' ); // Get current page number of list table if ( 'page_number' !== $this->page_number_item_name ) { if ( isset( $_REQUEST['page_number'] ) ) { $requested_page_number = sanitize_text_field( wp_unslash( $_REQUEST['page_number'] ) ); // input var okay. $this->page_number_link = '&page_number=' . $requested_page_number; $this->page_number_item = "<input type='hidden' name='page_number' value='{$requested_page_number}'/>"; } } if ( isset( $_REQUEST[$this->page_number_item_name] ) ) { $requested_page_number = sanitize_text_field( wp_unslash( $_REQUEST[$this->page_number_item_name] ) ); // input var okay. $this->page_number_link .= '&paged=' . $requested_page_number; $this->page_number_item .= "<input type='hidden' name='" . $this->page_number_item_name . "' value='{$requested_page_number}'/>"; } // Add search arguments to link to return to same page foreach ( $_REQUEST as $key => $value ) { if ( substr( $key, 0, 19 ) === 'wpda_search_column_' ) { $this->page_number_link .= "&{$key}={$value}"; $this->page_number_item .= "<input type='hidden' name='{$key}' value='{$value}' />"; } } // Check if button text "back to list" should be changed if ( isset( $args['back_to_list_text'] ) && '' !== $args['back_to_list_text'] ) { $this->back_to_list_text = $args['back_to_list_text']; } else { $this->back_to_list_text = __( 'List', 'wp-data-access' ); } // Get table settings $wpda_table_settings = WPDA_Table_Settings_Model::query( $this->table_name, $this->schema_name ); if ( isset( $wpda_table_settings[0]['wpda_table_settings'] ) ) { $this->wpda_table_settings = json_decode( $wpda_table_settings[0]['wpda_table_settings'] ); } if ( isset( $args['help_url'] ) ) { $this->help_url = $args['help_url']; } if ( isset( $args['hide_add_new'] ) ) { $this->hide_add_new = $args['hide_add_new']; } global $wpda_project_mode; if ( isset( $wpda_project_mode['allow_insert'] ) && 'only' === $wpda_project_mode['allow_insert'] ) { $this->hide_add_new = true; } } /** * Get URL arguments. * * @since 1.5.0 */ protected function get_url_arguments() { // Get OLD and NEW values for all items. foreach ( $this->wpda_list_columns->get_table_columns() as $column ) { if ( isset( $_REQUEST[$column['column_name'] . '_old'] ) ) { $this->form_items_old_values[$column['column_name']] = wp_unslash( $_REQUEST[$column['column_name'] . '_old'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput } if ( isset( $_REQUEST[$column['column_name']] ) ) { if ( is_array( $_REQUEST[$column['column_name']] ) ) { $column_array = ''; foreach ( $_REQUEST[$column['column_name']] as $column_value ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $column_array .= wp_unslash( $column_value ) . ','; } if ( '' !== $column_array ) { $this->form_items_new_values[$column['column_name']] = substr( $column_array, 0, strlen( $column_array ) - 1 ); } } else { $this->form_items_new_values[$column['column_name']] = wp_unslash( $_REQUEST[$column['column_name']] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput } } } } /** * Prepare form items and handle transactions * * Performs the following steps: * + Checks for posted data * + Saves changes if applicable (displays success or failure message) * + Prepares simple form * * @param bool $allow_save */ public function prepare_form( $allow_save = true ) { $set_back_form_values = false; if ( $allow_save && ('new' === $this->action || 'edit' === $this->action) && 'save' === $this->action2 ) { // Security check (is action allowed?). $wp_nonce = ( isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '' ); // input var okay. if ( !wp_verify_nonce( $wp_nonce, $this->get_nonce_action() ) ) { wp_die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); } if ( 'new' === $this->action ) { // Prepare row and items for validation $this->row = $this->row_data->new_row(); $this->prepare_items( true ); // Save new record. if ( !$this->validate( true ) ) { $set_back_form_values = true; } else { // Insert record. $add_row_result = $this->row_data->add_row(); if ( $add_row_result ) { // Insert succeeded: // (1) save auto_increment value (if applicable) // (2) change action to edit if ( is_numeric( $add_row_result ) ) { // save auto_increment value (1). $this->auto_increment_value = $add_row_result; } // change action to edit (2). $this->action = 'edit'; $this->prepare_row(); } else { // Insert failed: // (1) set back form items $set_back_form_values = true; } } } else { // Prepare row and items for validation $this->row = $this->row_data->get_row( $this->auto_increment_value, $this->wpda_err ); $this->prepare_items( true ); // Update existing record. if ( $this->validate() ) { // Update record. $this->row_data->set_row(); // Get values updated from database triggers $this->row = $this->row_data->get_row( $this->auto_increment_value, $this->wpda_err ); foreach ( $this->form_items_new_values as $key => $value ) { if ( isset( $this->row[0][$key] ) ) { $this->form_items_new_values[$key] = $this->row[0][$key]; } } } $this->prepare_row(); $set_back_form_values = true; } } else { $this->prepare_row(); } $this->prepare_items( $set_back_form_values ); if ( '1' === $this->wpda_err && $this->update_keys_allowed && 'edit' === $this->action && 'save' === $this->action2 ) { $keys_have_changed = false; // There was an error! If key updates are allowed, we might have needed to set back the keys to their // original values. We'll inform the user with a message box. foreach ( $this->wpda_list_columns->get_table_primary_key() as $pk_column ) { if ( $this->get_old_value( $pk_column ) !== $this->get_new_value( $pk_column ) ) { $keys_have_changed = true; break; } } if ( $keys_have_changed ) { $msg = new WPDA_Message_Box(array( 'message_text' => __( 'Key columns have been reversed to their original values', 'wp-data-access' ), )); $msg->box(); } } if ( null === $this->title ) { if ( 'new' === $this->action ) { $action_in_title = __( 'Add new row to', 'wp-data-access' ); } else { $action_in_title = ucfirst( $this->action ); } $this->title = $action_in_title . ' ' . __( 'table', 'wp-data-access' ) . ' ' . strtoupper( $this->table_name ); } else { if ( 'new' === $this->action ) { $title_action = 'Add New '; } else { $title_action = ucfirst( $this->action ); } if ( $this->add_action_to_title ) { $this->title = $title_action . ' ' . $this->title; } } if ( is_admin() && ($this->page === \WP_Data_Access_Admin::PAGE_MAIN || substr( $this->page, 0, 13 ) === \WP_Data_Access_Admin::PAGE_EXPLORER) ) { $this->fieldset_title = $this->title; $this->title = 'Data Explorer'; } } /** * Overwrite to group items into fieldsets */ protected function add_fieldsets() { $fields = array(); foreach ( $this->form_items as $item ) { $fields[] = $item->get_item_name(); } // Add just one default fieldset which contains all fields $this->fieldsets[$this->fieldset_title] = array( 'id' => '', 'fields' => $fields, ); } /** * Show simple form * * Performs the following steps: * + Shows simple form for requested table (HTML and Javascript) * * @param boolean $allow_save Allow to save data * @param string $add_param Parameter to be added to form action. * * @since 1.0.0 */ public function show( $allow_save = true, $add_param = '' ) { $this->add_fieldsets(); // Prepare url if ( is_admin() ) { $url = "?page={$this->page}"; } else { $url = ''; } $url_back = $url; $url .= $add_param; ?> <div class="wrap"> <?php if ( $this->show_title ) { ?> <h1 class="wp-heading-inline"> <?php if ( is_admin() && $this->show_back_icon ) { ?> <a href="javascript:void(0)" onclick="jQuery('#<?php echo esc_attr( $this->current_form_id ); ?>_backbutton').submit()" class="dashicons dashicons-arrow-left-alt2 wpda_tooltip" title="<?php echo esc_attr( $this->back_to_list_text ); ?>" ></a> <?php } ?> <?php echo esc_attr( $this->title ); ?> <?php if ( substr( $this->page, 0, 13 ) === \WP_Data_Access_Admin::PAGE_EXPLORER || !is_admin() ) { // Button is available on web pages only if ( 'view' !== $this->action && !$this->hide_add_new ) { //phpcs:ignore - 8.1 proof if ( WPDA::is_wpda_table( $this->table_name ) || ('on' === WPDA::get_option( WPDA::OPTION_BE_ALLOW_INSERT ) && count( $this->wpda_list_columns->get_table_primary_key() )) > 0 ) { $title = __( 'Add new row to table', 'wp-data-access' ); ?> <form method="post" action="<?php echo esc_attr( $url ); ?>" style="display: inline-block; vertical-align: bottom;" > <div> <?php if ( is_admin() ) { // Hide schema and table name on front-end ?> <input type="hidden" name="wpdaschema_name" value="<?php echo esc_attr( $this->schema_name ); ?>"> <input type="hidden" name="table_name" value="<?php echo esc_attr( $this->table_name ); ?>"> <?php } ?> <input type="hidden" name="action" value="new"> <button type="submit" class="page-title-action wpda_tooltip" title="<?php echo esc_attr( $title ); ?>" > <i class="fas fa-plus-circle wpda_icon_on_button"></i> <?php echo __( 'Add New', 'wp-data-access' ); ?> </button> </div> </form> <?php } } } ?> </h1> <div class="wpda_subtitle"><strong><?php echo wp_kses( $this->subtitle, array( 'span' => array( 'class' => array(), ), ) ); ?></strong> </div> <?php // Add custom code before the data entry form do_action_ref_array( 'wpda_before_simple_form', array($this) ); ?> <p></p> <?php } ?> <form id="<?php echo esc_attr( $this->current_form_id ); ?>" method="post" enctype="multipart/form-data" action="<?php echo esc_attr( $url ); ?>"> <div> <?php $js_code = ''; // All column JS code will be stored here and added to the end of the form. foreach ( $this->fieldsets as $fieldset_title => $fieldset ) { if ( isset( $fieldset['id'] ) && '' !== trim( $fieldset['id'] ) ) { $id = trim( $fieldset['id'] ); } else { $id = ''; } $expandable = ( isset( $fieldset['expandable'] ) && true === $fieldset['expandable'] ? true : false ); $expandable_state = ( isset( $_REQUEST["wpda_fieldset_expand_{$id}"] ) ? sanitize_text_field( $_REQUEST["wpda_fieldset_expand_{$id}"] ) : 'off' ); $expandable_icons = ( 'on' === $expandable_state ? 'minus-circle' : 'plus-circle' ); ?> <fieldset class="wpda_fieldset"> <?php if ( '' !== $fieldset_title ) { ?> <legend <?php echo ( '' === $id ? '' : 'id="' . esc_attr( $id ) . '"' ); ?>> <?php if ( $expandable && '' !== $id ) { echo '<div class="wpda-fieldset-expand" onclick="expandFieldset(\'' . esc_attr( $id ) . '\')">' . '<i id="wpda_field_expand_' . esc_attr( $id ) . '" class="wpda-fieldset-expand fas fa-' . esc_attr( $expandable_icons ) . '"></i> ' . '<span class="wpda-fieldset-expand">' . esc_html( $fieldset_title ) . '</span>' . '<input type="hidden" id="wpda_fieldset_expand_' . esc_attr( $id ) . '" name="wpda_fieldset_expand_' . esc_attr( $id ) . '" value="' . esc_attr( $expandable_state ) . '" />' . '</div>'; } else { echo esc_html( $fieldset_title ); } ?> </legend> <?php } ?> <table id="wpda_table_expand_<?php echo esc_attr( $id ); ?>" class="wpda_simple_table <?php echo esc_attr( $this->table_name ); ?>" <?php echo ( $expandable && 'off' === $expandable_state ? 'style="display: none"' : '' ); ?> cellspacing="0" cellpadding="0" > <?php $fieldset_columns = array_flip( $fieldset['fields'] ); //phpcs:ignore - 8.1 proof foreach ( $this->form_items as $item ) { if ( isset( $fieldset_columns[$item->get_item_name()] ) ) { $item->show( $this->action, $this->update_keys_allowed ); $js_code .= $item->get_item_js(); // Add column specific JS code. } } ?> </table> </fieldset> <?php } ?> </div> <div><?php $this->add_form_logic(); ?></div> <?php // Add custom code after the data entry form do_action_ref_array( 'wpda_after_simple_form', array($this) ); ?> <p></p> <?php if ( is_admin() ) { // Hide schema and table name on front-end ?> <input type="hidden" name="wpdaschema_name" value="<?php echo esc_attr( $this->schema_name ); ?>"> <input type="hidden" name="table_name" value="<?php echo esc_attr( $this->table_name ); ?>"> <?php } ?> <input type="hidden" name="action" value="<?php echo esc_attr( $this->action ); ?>"/> <input type="hidden" name="action2" value="save"/> <input type="hidden" name="wpda_message" value=""/> <?php if ( 'view' !== $this->action ) { ?> <input type="hidden" name="postaction" id="postaction" value=""/> <?php } ?> <?php $this->add_parent_args(); echo $this->page_number_item; // phpcs:ignore WordPress.Security.EscapeOutput echo $this->add_case_sensitive_search(); wp_nonce_field( $this->get_nonce_action( false ), '_wpnonce', false ); ?> <?php if ( 'view' !== $this->action ) { ?> <button type="submit" class="button button-primary" name="submit_button" onclick="return submit_form(event)"> <i class="fas fa-check wpda_icon_on_button"></i> <?php echo __( 'Submit', 'wp-data-access' ); ?> </button> <?php if ( $this->show_back_button && $this->show_back_icon ) { ?> <button type="submit" class="button button-secondary" name="submit_button" onclick="return submit_form(event)"> <i class="fas fa-check wpda_icon_on_button"></i> <?php echo __( 'Submit', 'wp-data-access' ); ?> <i class="fas fa-angle-right wpda_icon_on_button"></i> <?php echo esc_attr( $this->back_to_list_text ); ?> </button> <?php } if ( $this->show_back_button ) { ?> <button type="button" onclick="jQuery('#<?php echo esc_attr( $this->current_form_id ); ?>_backbutton').submit();" class="button button-secondary"> <i class="fas fa-angle-left wpda_icon_on_button"></i> <?php echo esc_attr( $this->back_to_list_text ); ?> </button> <?php } ?> <span style="float:right;"><?php $this->add_buttons(); ?></span> <?php } ?> <?php if ( 'view' === $this->action ) { ?> <button type="button" onclick="jQuery('#<?php echo esc_attr( $this->current_form_id ); ?>_backbutton').submit()" class="button button-secondary"> <i class="fas fa-angle-left wpda_icon_on_button"></i> <?php echo esc_attr( $this->back_to_list_text ); ?> </button> <?php } ?> </form> <form id="<?php echo esc_attr( $this->current_form_id ); ?>_backbutton" method="post" style="display:none" action="<?php echo esc_attr( $url_back ); ?>"> <?php $this->add_parent_args(); echo $this->page_number_item; // phpcs:ignore WordPress.Security.EscapeOutput echo $this->add_case_sensitive_search(); ?> <?php if ( is_admin() ) { // Hide schema and table name on front-end ?> <input type="hidden" name="wpdaschema_name" value="<?php echo esc_attr( $this->schema_name ); ?>"> <input type="hidden" name="table_name" value="<?php echo esc_attr( $this->table_name ); ?>"> <?php } ?> <input type="hidden" name="action" value="list"> </form> </div> <script type='text/javascript'> <?php if ( 'view' !== $this->action ) { ?> function submit_form(e) { if (typeof pre_submit_form === "function") { // Perform pre submit pre_submit = pre_submit_form(); if (!pre_submit) { return false; } } if ( jQuery(e.target).hasClass("button-secondary") || jQuery(e.target).parent().hasClass("button-secondary") ) { <?php if ( 'child_page_number' === $this->page_number_item_name ) { ?> jQuery("#postaction").val("childlist"); <?php } else { ?> jQuery("#postaction").val("list"); <?php } ?> } else { jQuery("#postaction").val(""); } var failed = false; jQuery('.wpda_not_null').each(function(i, obj) { if (jQuery(obj).val() === '') { objData = jQuery(obj).data(); if (objData.dbIsNull===undefined || objData.dbIsNull!==false) { alert(<?php echo __( '\'Item\'', 'wp-data-access' ); ?> +' ' + jQuery(obj).attr('name') + ' ' + <?php echo __( '\'must be entered\'', 'wp-data-access' ); ?>); failed = true; } else { element_old = jQuery("input[name=" + jQuery(obj).attr("name") + "_old" + "]"); if (element_old && element_old.val()!=='') { alert(<?php echo __( '\'Item\'', 'wp-data-access' ); ?> +' ' + jQuery(obj).attr('name') + ' ' + <?php echo __( '\'must be entered\'', 'wp-data-access' ); ?>); failed = true; } } } }); jQuery('.wpda_input_error').each(function(i, obj) { alert(<?php echo __( '\'Column\'', 'wp-data-access' ); ?> +' ' + jQuery(obj).attr('name') + <?php echo __( '\': max size exceeded\'', 'wp-data-access' ); ?>); failed = true; }); jQuery('.wpda_hyperlink').each(function(i, obj) { hyperlink_name = jQuery(obj).attr('name'); hyperlink_label = jQuery('#' + hyperlink_name + '_label').val(); hyperlink_url = jQuery('#' + hyperlink_name + '_url').val(); hyperlink_target = jQuery('#' + hyperlink_name + '_target').is(':checked') ? '_blank' : ''; hyperlink_update = { "label" : hyperlink_label, "url" : hyperlink_url, "target" : hyperlink_target }; jQuery(obj).val(JSON.stringify(hyperlink_update)); }); return !failed; } <?php } ?> jQuery(function () { <?php if ( 'view' === $this->action ) { ?> jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> input").not(':button').prop("readonly", true); jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> textarea").prop("readonly", true); jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> select").prop("disabled", true); <?php } ?> <?php if ( !$this->update_keys_allowed && 'new' !== $this->action ) { ?> jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> input.wpda_primary_key").prop("readonly", true); jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> select.wpda_primary_key").prop("disabled", true); <?php } ?> <?php if ( 'new' === $this->action ) { ?> jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> input.auto_increment").prop("readonly", true); <?php } ?> jQuery("#<?php echo esc_attr( $this->current_form_id ); ?> input.wpda_readonly").prop("readonly", true); jQuery('.wpda_data_type_number').on('keyup paste', function () { numberFormat = jQuery(this).data('numberFormat').split(","); this.value = this.value.replace(/[^\d\-]/g, ''); // Allow only 0-9 if (isNaN(this.value) || (numberFormat[0]!='' && this.value.length>numberFormat[0])) { jQuery(this).addClass('wpda_input_error'); if (this.value.length>numberFormat[0]) { jQuery.notify('<?php echo __( 'Max size exceeded' ); ?>','error'); } } else { jQuery(this).removeClass('wpda_input_error'); } }); jQuery('.wpda_data_type_float').on('keyup paste', function () { numberFormat = jQuery(this).data('numberFormat').split(","); maxNumber = Math.pow(10, numberFormat[0] - numberFormat[1]); this.value = this.value.replace(/[^\d\-\.\,]/g, ''); // Allow only 0-9 . , if (isNaN(this.value) || this.value>=maxNumber) { jQuery(this).addClass('wpda_input_error'); if (this.value>=maxNumber) { jQuery.notify('<?php echo __( 'Max size exceeded' ); ?>','error'); } } else { jQuery(this).removeClass('wpda_input_error'); } currentNumber = this.value.split("."); if (currentNumber.length===1) { currentNumber = this.value.split(","); } if (currentNumber.length===2 && currentNumber[1].length>numberFormat[1]) { jQuery(this).addClass('wpda_input_error'); jQuery.notify('<?php echo __( 'Max size exceeded' ); ?>','error'); } }); jQuery( '.wpda_tooltip' ).tooltip(); // Add toolbar icons jQuery("#wpda_toolbar_icon_add_row").on("click", function() { jQuery("#wpda_new_row_table_name").val("<?php echo esc_attr( $this->table_name ); ?>"); jQuery("#wpda_new_row").submit(); }); }); <?php echo $js_code; // phpcs:ignore WordPress.Security.EscapeOutput ?> </script> <?php } private function add_case_sensitive_search() { if ( isset( $_REQUEST['wpda_c'] ) && 'true' === $_REQUEST['wpda_c'] ) { return '<input type="hidden" name="wpda_c" value="true">'; } else { return ''; } } /** * Overwrite to add logic to form * * @since 2.0.15 */ public function add_form_logic() { } /** * Overwrite to add buttons to right bottom * * @since 2.0.15 */ public function add_buttons() { } /** * Creates a wpnonce action * * Set wp_nonce action for security check: * prefix + table name + primary key values * * @param boolean $use_old_value TRUE = use old key values, FALSE = use new key values. * * @return string wp_nonce action holding: prefix + table name + primary key values. * @since 1.0.0 */ public function get_nonce_action( $use_old_value = true ) { // Add prefix + table name to wp_nonce action. $wp_nonce_action = "wpda-simple-form-{$this->table_name}"; if ( $this->wpda_list_columns->get_table_alternative_keys() ) { $wp_nonce_action .= '-*'; } else { foreach ( $this->wpda_list_columns->get_table_primary_key() as $pk_column ) { // Add primary key value to wp_nonce action. if ( 'new' === $this->action ) { // New records have no key values on form startup. $wp_nonce_action .= '-?'; } else { // Add primary key value to wp_nonce action. if ( 'save' === $this->action2 && $use_old_value ) { // Use old value (in cases where primary key update is allowed). $wp_nonce_action .= ( isset( $_REQUEST[$pk_column . '_old'] ) ? '-' . sanitize_text_field( wp_unslash( $_REQUEST[$pk_column . '_old'] ) ) : '-?' ); // input var okay. } else { if ( isset( $_REQUEST[$pk_column] ) && '' !== sanitize_text_field( wp_unslash( $_REQUEST[$pk_column] ) ) ) { // input var okay. // Use new value. $wp_nonce_action .= '-' . sanitize_text_field( wp_unslash( $_REQUEST[$pk_column] ) ); // input var okay. } elseif ( -1 !== $this->auto_increment_value ) { // Use auto increment value (updated wp_nonce action after insert). $wp_nonce_action .= '-' . $this->auto_increment_value; } else { // No value found, let security check handle wrong wp_nonce action. $wp_nonce_action .= '-?'; } } } } } return str_replace( ' ', '_', $wp_nonce_action ); } /** * Perform validation check * * Called to perform default validation before insert and update. * * Extend class WPDA_Simple_Form and override this method if you need validation on insert and/or update or * if you prefer to change error messages. If you want to handle inserts and updates differently, the * following information might be helpful: * + on insert: $this->action = 'new' * + on update: $this->action = 'edit' * * Use set_message to show messages (info as well as error). * * @param boolean $pre_insert Do not check auto_increment during pre-insert * * @return boolean TRUE = validation succeeded, FALSE = validation failed. * @since 1.0.0 */ protected function validate( $pre_insert = false ) { foreach ( $this->form_items as $item ) { if ( !$item->is_valid( $pre_insert ) ) { return false; } } return true; } /** * Get current from database table * * Handle insert, update and save differently. * * @since 1.0.0 */ protected function prepare_row() { if ( 'edit' === $this->action || 'view' === $this->action || 'save' === $this->action2 ) { // Get record by primary key, use auto_increment for new records. $this->row = $this->row_data->get_row( $this->auto_increment_value, $this->wpda_err ); } else { // There's no record yet. $this->row = $this->row_data->new_row(); } } /** * Set item attributes * * If you want to change the layout of your simple form(s), consider to extend class WPDA_Simple_Form and * override this method. * * @param boolean $set_back_form_values TRUE = set back user entered value, FALSE = set to database value. * * @since 1.0.0 */ protected function prepare_items( $set_back_form_values = false ) { $count_cols = count( $this->table_columns ); //phpcs:ignore - 8.1 proof for ($i = 0; $i < $count_cols; $i++) { $column_name = $this->table_columns[$i]['column_name']; $item_enum = ''; if ( 'enum' === $this->table_columns[$i]['data_type'] || 'set' === $this->table_columns[$i]['data_type'] ) { $item_enum = $this->table_columns[$i]['column_type']; } if ( $set_back_form_values ) { // Set value to what user entered. $item_value = $this->get_new_value( $column_name ); } else { // Get value from database. $item_value = ( isset( $this->row ) ? $this->row[0][$column_name] : null ); } $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item'; $check_data_type = WPDA::get_type( $this->table_columns[$i]['data_type'] ); if ( 'enum' === $this->table_columns[$i]['data_type'] ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Enum'; } elseif ( 'set' === $this->table_columns[$i]['data_type'] ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Set'; } elseif ( 'date' === $check_data_type || 'time' === $check_data_type ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_DateTime'; // Always initially use database data and time format $item_value = ( isset( $this->row ) ? $this->row[0][$column_name] : null ); } elseif ( 'tinytext' === $this->table_columns[$i]['data_type'] || 'text' === $this->table_columns[$i]['data_type'] || 'mediumtext' === $this->table_columns[$i]['data_type'] || 'longtext' === $this->table_columns[$i]['data_type'] ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Textarea'; } elseif ( 'tinyint(1)' === $this->table_columns[$i]['column_type'] ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Boolean'; } // Media support only available to logged-in users if ( 0 < WPDA::get_current_user_id() ) { $media_type = WPDA_Media_Model::get_column_media( $this->table_name, $column_name, $this->schema_name ); if ( 'Image' === $media_type ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Image'; } elseif ( 'Attachment' === $media_type ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Media'; } elseif ( 'Hyperlink' === $media_type ) { if ( !(isset( $this->wpda_table_settings->table_settings->hyperlink_definition ) && 'text' === $this->wpda_table_settings->table_settings->hyperlink_definition) ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Hyperlink'; } } elseif ( 'Audio' === $media_type ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Audio'; } elseif ( 'Video' === $media_type ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_Video'; } elseif ( 'File' === $media_type ) { $wpda_simple_form_item_class = 'WPDataAccess\\Simple_Form\\WPDA_Simple_Form_Item_File'; } } $item_label = ''; if ( isset( $this->column_headers[$column_name] ) ) { $item_label = $this->column_headers[$column_name]; } elseif ( isset( $this->table_column_headers[$column_name] ) ) { $item_label = $this->table_column_headers[$column_name]; } $item = new $wpda_simple_form_item_class(array( 'item_name' => $column_name, 'data_type' => $this->table_columns[$i]['data_type'], 'item_label' => $item_label, 'item_value' => $item_value, 'item_default_value' => $this->table_columns[$i]['column_default'], 'item_extra' => $this->table_columns[$i]['extra'], 'item_enum' => $item_enum, 'column_type' => $this->table_columns[$i]['column_type'], 'is_nullable' => $this->table_columns[$i]['is_nullable'], 'user_update' => $set_back_form_values, 'character_maximum_length' => $this->table_columns[$i]['character_maximum_length'], 'numeric_precision' => $this->table_columns[$i]['numeric_precision'], 'numeric_scale' => ( null === $this->table_columns[$i]['numeric_scale'] ? 0 : $this->table_columns[$i]['numeric_scale'] ), )); $item->set_is_key_column( $this->is_key_column( $column_name ) ); $this->add_form_item( $i, $item ); } // Add dynamic hyperlinks (if applicable) if ( isset( $this->wpda_table_settings->hyperlinks ) ) { foreach ( $this->wpda_table_settings->hyperlinks as $hyperlink ) { $hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' ); $hyperlink_form = ( isset( $hyperlink->hyperlink_form ) ? $hyperlink->hyperlink_form : false ); $hyperlink_html = ( isset( $hyperlink->hyperlink_html ) ? $hyperlink->hyperlink_html : '' ); if ( true === $hyperlink_form && $hyperlink_label !== '' && $hyperlink_html !== '' ) { $hyperlink_target = ( isset( $hyperlink->hyperlink_form ) ? $hyperlink->hyperlink_target : false ); foreach ( $this->form_items as $item ) { $item_name = $item->get_item_name(); $item_value = $item->get_item_value(); $hyperlink_html = str_replace( "\$\${$item_name}\$\$", $item_value, $hyperlink_html ); } $item = new WPDA_Simple_Form_Item_Dynamic_Hyperlink(array( 'item_name' => $hyperlink_label, 'data_type' => 'varchar2', 'hyperlink_label' => $hyperlink_label, 'hyperlink_target' => $hyperlink_target, 'hyperlink_html' => $hyperlink_html, )); $this->add_form_item( $i++, $item ); } } } } /** * Get new value for item * * Or empty if no new value available. * * @param string $column_name Column name. * * @return mixed|string New value for column or empty. * @since 1.0.0 */ public function get_new_value( $column_name ) { return ( isset( $this->form_items_new_values[$column_name] ) ? $this->form_items_new_values[$column_name] : null ); } /** * Add item to form * * @param int $index Item sequence number. * @param WPDA_Simple_Form_Item $item Reference to simple form item. * * @since 1.0.0 * * @see WPDA_Simple_Form_Item */ protected function add_form_item( $index, $item ) { // Add item to form $this->form_items[$index] = $item; // Add position to named array for quick access of single items $item_name = $item->get_item_name(); $this->form_items_named[$item_name] = $index; } /** * Get item position * * @param string $item_name Form item name * * @return bool|int Position item or false if not found * * @since 2.0.15 */ protected function get_item_index( $item_name ) { if ( isset( $this->form_items_named[$item_name] ) ) { return $this->form_items_named[$item_name]; } else { return false; } } /** * Get old value form item * * Or empty if no old value available. * * @param string $column_name Column name. * * @return mixed|string Old value for column or empty. * @since 1.0.0 */ public function get_old_value( $column_name ) { return ( isset( $this->form_items_old_values[$column_name] ) ? $this->form_items_old_values[$column_name] : null ); } public function revert_column_value( $column_name ) { @($this->form_items_new_values[$column_name] = $this->form_items_old_values[$column_name]); } public function insert_column_default( $column_name, $item_default_value ) { if ( isset( $this->form_items_old_values ) ) { @($this->form_items_new_values[$column_name] = $item_default_value); } } /** * Is column part of primary key? * * @param string $column_name Column name. * * @return bool TRUE = column is part of primary key, FALSE = column is not part of primary key. * @since 1.0.0 */ protected function is_key_column( $column_name ) { foreach ( $this->wpda_list_columns->get_table_primary_key() as $pk_column ) { if ( $column_name === $pk_column ) { return true; } } return false; } /** * Get primary form action * * @return string Primary page action * @since 1.0.0 */ public function get_form_action() { return $this->action; } /** * Get secondary form action * * @return string Secondary page action * @since 1.0.0 */ public function get_form_action2() { return $this->action2; } /** * Defines whether primary key item can be updated * * @param boolean $update_keys_allowed Allow keys to be updated. * * @since 1.0.0 */ protected function set_update_keys( $update_keys_allowed ) { $this->update_keys_allowed = $update_keys_allowed; } /** * Reorder columns * * Reorders the column array in the order as defined in argument $columns_ordered. * * @param array $columns_ordered Ordered column names. * * @since 1.0.0 */ protected function order_and_filter_columns( $columns_ordered ) { $column_array_ordered = array(); $i = 0; foreach ( $columns_ordered as $key => $value ) { $column_array_ordered[$i++] = $this->table_columns[$this->get_column_position( $this->table_columns, $value )]; } $this->table_columns = $column_array_ordered; } /** * Get column position in column array * * @param array $column_array Column array. * @param string $column_name Column name. * * @return int Position of $column_name in $column_array * @since 1.0.0 */ protected function get_column_position( $column_array, $column_name ) { if ( !is_array( $column_array ) ) { return -1; } $count_cols = count( $column_array ); //phpcs:ignore - 8.1 proof for ($i = 0; $i < $count_cols; $i++) { if ( $column_array[$i]['column_name'] === $column_name ) { return $i; } } return -1; } /** * Add dummy column to form * * @param string $column_name Column name. * * @since 1.0.0 */ protected function add_dummy_column( $column_name ) { $this->table_columns[] = array( 'column_name' => $column_name, 'data_type' => 'varchar', 'extra' => '', 'column_type' => '', 'is_nullable' => 'YES', 'column_default' => '', ); } /** * Set message number and text * * Assigns values to $this->wpda_err and $this->wpda_msg. * * @param string $wpda_err '0' = INFO, '1' = ERROR. * @param string $wpda_msg Message to be displayed. * * @since 1.0.0 */ protected function set_message( $wpda_err, $wpda_msg ) { // Wrong values will be handled by message box class. $this->wpda_err = $wpda_err; $this->wpda_msg = $wpda_msg; } /** * Use this method to build parent child relationships. * * Overwrite this function if you want to use the form as a child form related to some parent * form. You can add parent arguments to calls to make sure you get back to the right parent. * * @since 1.5.0 */ protected function add_parent_args() { } /** * Use this method to build parent child relationships. * * Overwrite this function if you want to use the form as a child form related to some parent * form. You can add parent arguments to calls to make sure you get back to the right parent. * * @since 1.6.9 */ protected function add_parent_args_to_back_button() { } /** * Set item labels * * @param array $item_labels Named array containing item name/label pairs * * @since 2.0.15 */ public function set_labels( $item_labels ) { if ( is_array( $item_labels ) ) { foreach ( $item_labels as $key => $label ) { foreach ( $this->form_items as $form_item ) { if ( $form_item->get_item_name() === $key ) { $form_item->set_label( $label ); } } } } } /** * Hide items * * @param array $items_to_hide Array contains item names of items to be defined as hidden * * @since 2.0.15 */ public function hide_items( $items_to_hide ) { if ( is_array( $items_to_hide ) ) { foreach ( $items_to_hide as $column_name ) { foreach ( $this->form_items as $form_item ) { if ( $form_item->get_item_name() === $column_name ) { $form_item->set_hide_item_init( true ); } } } } } /** * Number of items * * @return int * * @since 2.0.15 */ public function count() { return count( (array) $this->form_items ); } public function get_row() { return $this->row; } }