get_error_message(); } printf( '
%s
', $message ); do_action('wu_form_scripts', false); die; } /** * Renders a registered form, when requested. * * @since 2.0.0 * @return void */ public function display_form() { $this->security_checks(); $form = $this->get_form(wu_request('form')); printf( "
", $form['id'], $this->get_form_url( $form['id'], array( 'action' => 'wu_form_handler', ) ) ); printf( '
', $form['id'] . '_errors', htmlspecialchars(json_encode(array('errors' => array()))) ); call_user_func($form['render']); echo ''; wp_nonce_field('wu_form_' . $form['id']); echo '
'; do_action('wu_form_scripts', $form); exit; } /** * Handles the submission of a registered form. * * @since 2.0.0 * @return void */ public function handle_form() { $this->security_checks(); $form = $this->get_form(wu_request('form')); if ( ! wp_verify_nonce(wu_request('_wpnonce'), 'wu_form_' . $form['id'])) { wp_send_json_error(); } /** * The handler is supposed to send a wp_json message back. * However, if it returns a WP_Error object, we know * something went wrong and that we should display the error message. */ $check = call_user_func($form['handler']); if (is_wp_error($check)) { $this->display_form_unavailable($check); } exit; } /** * Checks that the form exists and that the user has permission to see it. * * @since 2.0.0 * @return mixed */ public function security_checks() { /* * We only want ajax requests. */ if ((empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower((string) $_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest')) { wp_die(0); } $form = $this->get_form(wu_request('form')); if ( ! $form) { return $this->display_form_unavailable(); } if ( ! current_user_can($form['capability'])) { return $this->display_form_unavailable(); } } /** * Returns a list of all the registered gateways. * * @since 2.0.0 * @return array */ public function get_registered_forms() { return $this->registered_forms; } /** * Checks if a form is already registered. * * @since 2.0.0 * * @param string $id The id of the form. * @return boolean */ public function is_form_registered($id) { return is_array($this->registered_forms) && isset($this->registered_forms[ $id ]); } /** * Returns a registered form. * * @since 2.0.0 * * @param string $id The id of the form to return. * @return array */ public function get_form($id) { return $this->is_form_registered($id) ? $this->registered_forms[ $id ] : false; } /** * Registers a new Ajax Form. * * Ajax forms are forms that get loaded via an ajax call using thickbox (or rather our fork). * This is useful for displaying inline edit forms that support Vue and our * Form/Fields API. * * @since 2.0.0 * * @param string $id Form id. * @param array $atts Form attributes, check wp_parse_atts call below. * @return void */ public function register_form($id, $atts = array()) { $atts = wp_parse_args( $atts, array( 'id' => $id, 'form' => '', 'capability' => 'manage_network', 'handler' => '__return_false', 'render' => '__return_empty_string', ) ); // Checks if gateway was already added if ($this->is_form_registered($id)) { return; } $this->registered_forms[ $id ] = $atts; return true; } /** * Returns the ajax URL for a given form. * * @since 2.0.0 * * @param string $form_id The id of the form to return. * @param array $atts List of parameters, check wp_parse_args below. * @return string */ public function get_form_url($form_id, $atts = array()) { $atts = wp_parse_args( $atts, array( 'form' => $form_id, 'action' => 'wu_form_display', 'width' => '400', 'height' => '360', ) ); return add_query_arg($atts, wu_ajax_url('init')); } /** * Register the confirmation modal form to delete a customer. * * @since 2.0.0 */ public function register_action_forms() { $model = wu_request('model'); wu_register_form( 'delete_modal', array( 'render' => array($this, 'render_model_delete_form'), 'handler' => array($this, 'handle_model_delete_form'), 'capability' => "wu_delete_{$model}s", ) ); wu_register_form( 'bulk_actions', array( 'render' => array($this, 'render_bulk_action_form'), 'handler' => array($this, 'handle_bulk_action_form'), ) ); add_action('wu_handle_bulk_action_form', array($this, 'default_bulk_action_handler'), 100, 3); } /** * Renders the deletion confirmation form. * * @since 2.0.0 * @return void */ public function render_model_delete_form() { $model = wu_request('model'); $id = wu_request('id'); $meta_key = false; if ($model) { /* * Handle metadata elements passed as model */ if (strpos((string) $model, '_meta_') !== false) { $elements = explode('_meta_', (string) $model); $model = $elements[0]; $meta_key = $elements[1]; } try { $object = call_user_func("wu_get_{$model}", $id); } catch (\Throwable $exception) { // No need to do anything, but cool to stop fatal errors. } $object = apply_filters("wu_delete_form_get_object_{$model}", $object, $id, $model); if ( ! $object) { $this->display_form_unavailable(new \WP_Error('not-found', __('Object not found.', 'wp-ultimo'))); return; } $fields = apply_filters( "wu_form_fields_delete_{$model}_modal", array( 'confirm' => array( 'type' => 'toggle', 'title' => __('Confirm Deletion', 'wp-ultimo'), 'desc' => __('This action can not be undone.', 'wp-ultimo'), 'html_attr' => array( 'v-model' => 'confirmed', ), ), 'submit_button' => array( 'type' => 'submit', 'title' => __('Delete', 'wp-ultimo'), 'placeholder' => __('Delete', 'wp-ultimo'), 'value' => 'save', 'classes' => 'button button-primary wu-w-full', 'wrapper_classes' => 'wu-items-end', 'html_attr' => array( 'v-bind:disabled' => '!confirmed', ), ), 'id' => array( 'type' => 'hidden', 'value' => $object->get_id(), ), 'meta_key' => array( 'type' => 'hidden', 'value' => $meta_key, ), 'redirect_to' => array( 'type' => 'hidden', 'value' => wu_request('redirect_to'), ), 'model' => array( 'type' => 'hidden', 'value' => $model, ), ), $object ); $form_attributes = apply_filters( "wu_form_attributes_delete_{$model}_modal", array( 'title' => 'Delete', 'views' => 'admin-pages/fields', 'classes' => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0', 'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid', 'html_attr' => array( 'data-wu-app' => 'true', 'data-state' => json_encode( array( 'confirmed' => false, ) ), ), ) ); $form = new \WP_Ultimo\UI\Form('total-actions', $fields, $form_attributes); do_action("wu_before_render_delete_{$model}_modal", $form); $form->render(); } } /** * Handles the deletion of customer. * * @since 2.0.0 * @return void */ public function handle_model_delete_form() { global $wpdb; $model = wu_request('model'); $id = wu_request('id'); $meta_key = wu_request('meta_key'); $redirect_to = wu_request('redirect_to', wp_get_referer()); $plural_name = str_replace('_', '-', (string) $model) . 's'; if ($model) { /* * Handle meta key deletion */ if ($meta_key) { $status = delete_metadata('wu_membership', wu_request('id'), 'pending_site'); $data_json_success = array( 'redirect_url' => add_query_arg('deleted', 1, $redirect_to), ); wp_send_json_success($data_json_success); exit; } try { $object = call_user_func("wu_get_{$model}", $id); } catch (\Throwable $exception) { // No need to do anything, but cool to stop fatal errors. } $object = apply_filters("wu_delete_form_get_object_{$model}", $object, $id, $model); if ( ! $object) { wp_send_json_error(new \WP_Error('not-found', __('Object not found.', 'wp-ultimo'))); } /* * Handle objects (default state) */ do_action("wu_before_delete_{$model}_modal", $object); $saved = $object->delete(); if (is_wp_error($saved)) { wp_send_json_error($saved); } do_action("wu_after_delete_{$model}_modal", $object); $data_json_success = apply_filters( "wu_data_json_success_delete_{$model}_modal", array( 'redirect_url' => wu_network_admin_url("wp-ultimo-{$plural_name}", array('deleted' => 1)), ) ); wp_send_json_success($data_json_success); } else { wp_send_json_error(new \WP_Error('model-not-found', __('Something went wrong.', 'wp-ultimo'))); } } /** * Renders the deletion confirmation form. * * @since 2.0.0 * @return void */ public function render_bulk_action_form() { $action = wu_request('bulk_action'); $model = wu_request('model'); $fields = apply_filters( "wu_bulk_actions_{$model}_{$action}", array( 'confirm' => array( 'type' => 'toggle', 'title' => __('Confirm Action', 'wp-ultimo'), 'desc' => __('Review this action carefully.', 'wp-ultimo'), 'html_attr' => array( 'v-model' => 'confirmed', ), ), 'submit_button' => array( 'type' => 'submit', 'title' => wu_slug_to_name($action), 'placeholder' => wu_slug_to_name($action), 'value' => 'save', 'classes' => 'button button-primary wu-w-full', 'wrapper_classes' => 'wu-items-end', 'html_attr' => array( 'v-bind:disabled' => '!confirmed', ), ), 'model' => array( 'type' => 'hidden', 'value' => $model, ), 'bulk_action' => array( 'type' => 'hidden', 'value' => wu_request('bulk_action'), ), 'ids' => array( 'type' => 'hidden', 'value' => implode(',', wu_request('bulk-delete', '')), ), ) ); $form_attributes = apply_filters( "wu_bulk_actions_{$action}_form", array( 'views' => 'admin-pages/fields', 'classes' => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0', 'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid', 'html_attr' => array( 'data-wu-app' => 'true', 'data-state' => json_encode( array( 'confirmed' => false, ) ), ), ) ); $form = new \WP_Ultimo\UI\Form('total-actions', $fields, $form_attributes); $form->render(); } /** * Handles the deletion of customer. * * @since 2.0.0 * @return void */ public function handle_bulk_action_form() { global $wpdb; $action = wu_request('bulk_action'); $model = wu_request('model'); $ids = explode(',', (string) wu_request('ids', '')); do_action("wu_handle_bulk_action_form_{$model}_{$action}", $action, $model, $ids); do_action('wu_handle_bulk_action_form', $action, $model, $ids); } /** * Default handler for bulk actions. * * @since 2.0.0 * * @param string $action The action. * @param string $model The model. * @param array $ids The ids list. * @return void */ public function default_bulk_action_handler($action, $model, $ids) { $status = \WP_Ultimo\List_Tables\Base_List_Table::process_bulk_action(); if (is_wp_error($status)) { wp_send_json_error($status); } wp_send_json_success( array( 'redirect_url' => add_query_arg($action, count($ids), wu_get_current_url()), ) ); } }