--- /dev/null
+<?php
+
+namespace HTML_Forms\Actions;
+
+use HTML_Forms\Form;
+use HTML_Forms\Submission;
+
+abstract class Action {
+
+ public $type = '';
+ public $label = '';
+
+ public function hook() {
+ add_filter( 'hf_available_form_actions', array( $this, 'register' ) );
+ add_action( 'hf_output_form_action_' . $this->type . '_settings', array( $this, 'page_settings' ), 10, 2 );
+ add_action( 'hf_process_form_action_' . $this->type, array( $this, 'process' ), 10, 3 );
+ }
+
+ /**
+ * Renders the settings for this action.
+ *
+ * @param array $settings
+ * @param string $index
+ */
+ abstract function page_settings( $settings, $index );
+
+ abstract function process( array $settings, Submission $submission, Form $form );
+
+ /**
+ * @param array $actions
+ * @return array
+ */
+ public function register( array $actions ) {
+ $actions[ $this->type ] = $this->label;
+ return $actions;
+ }
+}
--- /dev/null
+<?php
+
+namespace HTML_Forms\Actions;
+
+use HTML_Forms\Form;
+use HTML_Forms\Submission;
+
+class Email extends Action {
+
+ public $type = 'email';
+ public $label = 'Send Email';
+
+ public function __construct() {
+ $this->label = __( 'Send Email', 'html-forms' );
+ }
+
+ /**
+ * @return array
+ */
+ private function get_default_settings() {
+ $defaults = array(
+ 'from' => get_option( 'admin_email' ),
+ 'to' => get_option( 'admin_email' ),
+ 'subject' => '',
+ 'message' => '',
+ 'headers' => '',
+ 'content_type' => 'text/html',
+ );
+ return $defaults;
+ }
+
+ /**
+ * @param array $settings
+ * @param string|int $index
+ */
+ public function page_settings( $settings, $index ) {
+ $settings = array_merge( $this->get_default_settings(), $settings );
+ ?>
+ <span class="hf-action-summary"><?php printf( 'From %s. To %s.', $settings['from'], $settings['to'] ); ?></span>
+ <input type="hidden" name="form[settings][actions][<?php echo $index; ?>][type]" value="<?php echo $this->type; ?>" />
+ <table class="form-table">
+ <tr>
+ <th><label><?php echo __( 'From', 'html-forms' ); ?> <span class="hf-required">*</span></label></th>
+ <td>
+ <input name="form[settings][actions][<?php echo $index; ?>][from]" value="<?php echo esc_attr( $settings['from'] ); ?>" type="text" class="regular-text" placeholder="jane@email.com" required />
+ </td>
+ </tr>
+ <tr>
+ <th><label><?php echo __( 'To', 'html-forms' ); ?> <span class="hf-required">*</span></label></th>
+ <td>
+ <input name="form[settings][actions][<?php echo $index; ?>][to]" value="<?php echo esc_attr( $settings['to'] ); ?>" type="text" class="regular-text" placeholder="john@email.com" required />
+ </td>
+ </tr>
+ <tr>
+ <th><label><?php echo __( 'Subject', 'html-forms' ); ?></label></th>
+ <td>
+ <input name="form[settings][actions][<?php echo $index; ?>][subject]" value="<?php echo esc_attr( $settings['subject'] ); ?>" type="text" class="regular-text" placeholder="<?php echo esc_attr( __( 'Your email subject', 'html-forms' ) ); ?>" />
+ </td>
+ </tr>
+
+ <tr>
+ <th><label><?php echo __( 'Message', 'html-forms' ); ?> <span class="hf-required">*</span></label></th>
+ <td>
+ <textarea name="form[settings][actions][<?php echo $index; ?>][message]" rows="8" class="widefat" placeholder="<?php echo esc_attr( __( 'Your email message', 'html-forms' ) ); ?>" required><?php echo esc_textarea( $settings['message'] ); ?></textarea>
+ <p class="help"><?php _e( 'You can use the following variables (in all fields): ', 'html-forms' ); ?><br /><span class="hf-field-names"></span></p>
+ </td>
+ </tr>
+
+ <tr>
+ <th><label><?php echo __( 'Content Type', 'html-forms' ); ?></label></th>
+ <td>
+ <select name="form[settings][actions][<?php echo $index; ?>][content_type]" required>
+ <option <?php selected( $settings['content_type'], 'text/plain' ); ?>>text/plain</option>
+ <option <?php selected( $settings['content_type'], 'text/html' ); ?>>text/html</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <th><label><?php echo __( 'Additional headers', 'html-forms' ); ?></label></th>
+ <td>
+ <textarea name="form[settings][actions][<?php echo $index; ?>][headers]" rows="4" class="widefat" placeholder="<?php echo esc_attr( 'Reply-To: [NAME] <[EMAIL]>' ); ?>"><?php echo esc_textarea( $settings['headers'] ); ?></textarea>
+ </td>
+ </tr>
+ </table>
+ <?php
+ }
+
+ /**
+ * Processes this action
+ *
+ * @param array $settings
+ * @param Submission $submission
+ * @param Form $form
+ */
+ public function process( array $settings, Submission $submission, Form $form ) {
+ if ( empty( $settings['to'] ) || empty( $settings['message'] ) ) {
+ return false;
+ }
+
+ $settings = array_merge( $this->get_default_settings(), $settings );
+ $html_email = $settings['content_type'] === 'text/html';
+
+ $to = apply_filters( 'hf_action_email_to', hf_replace_data_variables( $settings['to'], $submission->data, 'strip_tags' ), $submission );
+ $subject = ! empty( $settings['subject'] ) ? hf_replace_data_variables( $settings['subject'], $submission->data, 'strip_tags' ) : '';
+ $subject = apply_filters( 'hf_action_email_subject', $subject, $submission );
+ $message = apply_filters( 'hf_action_email_message', hf_replace_data_variables( $settings['message'], $submission->data, $html_email ? 'esc_html' : null ), $submission );
+
+ // parse additional email headers from settings
+ $headers = array();
+ if ( ! empty( $settings['headers'] ) ) {
+ $headers = explode( PHP_EOL, hf_replace_data_variables( $settings['headers'], $submission->data, 'strip_tags' ) );
+ }
+
+ $content_type = $html_email ? 'text/html' : 'text/plain';
+ $charset = get_bloginfo( 'charset' );
+ $headers[] = sprintf( 'Content-Type: %s; charset=%s', $content_type, $charset );
+
+ if ( ! empty( $settings['from'] ) ) {
+ $from = apply_filters( 'hf_action_email_from', hf_replace_data_variables( $settings['from'], $submission->data, 'strip_tags' ), $submission );
+ $headers[] = sprintf( 'From: %s', $from );
+ }
+
+ return wp_mail( $to, $subject, $message, $headers );
+ }
+}
--- /dev/null
+<?php
+
+namespace HTML_Forms\Actions;
+
+use HTML_Forms\Form;
+use HTML_Forms\Submission;
+
+class MailChimp extends Action {
+ public $type = 'mailchimp';
+ public $label = 'MailChimp';
+
+ public function __construct() {
+ $this->label = __( 'MailChimp', 'html-forms' );
+ }
+
+ /**
+ * @return array
+ */
+ private function get_default_settings() {
+ $defaults = array(
+ 'list_id' => '',
+ );
+ return $defaults;
+ }
+
+ /**
+ * @param array $settings
+ * @param string|int $index
+ */
+ public function page_settings( $settings, $index ) {
+ $settings = array_merge( $this->get_default_settings(), $settings );
+ $mailchimp = new \MC4WP_MailChimp();
+ $lists = $mailchimp->get_lists();
+
+ if ( ! empty( $settings['list_id'] ) ) {
+ $selected_list = $mailchimp->get_list( $settings['list_id'] );
+ }
+ ?>
+
+ <?php if ( ! empty( $selected_list ) ) { ?>
+ <span class="hf-action-summary"><?php printf( __( 'Subscribe to %s', 'html-forms' ), $selected_list->name ); ?></span>
+ <?php } ?>
+ <input type="hidden" name="form[settings][actions][<?php echo $index; ?>][type]" value="<?php echo $this->type; ?>" />
+ <table class="form-table">
+ <tr valign="top">
+ <th scope="row"><?php _e( 'List', 'html-forms' ); ?></th>
+ <td>
+ <?php if ( ! empty( $lists ) ) { ?>
+ <select name="form[settings][actions][<?php echo $index; ?>][list_id]">
+ <option value="" style="color: #AAA;" readonly><?php _e( 'Select MailChimp list', 'html-forms' ); ?></option>
+ <?php
+ foreach ( $lists as $list ) {
+ $selected = $settings['list_id'] === $list->id ? 'selected' : '';
+ echo sprintf( '<option value="%s" %s>%s</option>', $list->id, $selected, $list->name );
+ }
+ ?>
+ </select>
+ <?php
+ } else {
+ echo '<p><a href="' . admin_url( 'admin.php?page=mailchimp-for-wp' ) . '">' . __( 'Please connect your MailChimp account first.', 'html-forms' ) . '</a></p>';
+ }
+ ?>
+ </td>
+
+ </tr>
+ </table>
+ <?php
+ }
+
+ public function process( array $settings, Submission $submission, Form $form ) {
+ if ( empty( $settings['list_id'] ) ) {
+ return;
+ }
+
+ $mailchimp_list_id = $settings['list_id'];
+ $email_address = '';
+
+ // find email field
+ foreach ( $submission->data as $field => $value ) {
+ if ( is_email( $value ) ) {
+ $email_address = $value;
+ }
+ }
+
+ // bail if no email address found
+ if ( empty( $email_address ) ) {
+ return;
+ }
+
+ $merge_fields = array();
+ $merge_fields = apply_filters( 'hf_mailchimp_action_merge_fields', $merge_fields, $submission, $form );
+ $mailchimp_data = array(
+ 'merge_fields' => $merge_fields,
+ 'status' => 'pending',
+ );
+ $mailchimp_data = apply_filters( 'hf_mailchimp_action_subscriber_data', $mailchimp_data, $submission, $form );
+
+ // subscribe the email address to the selected list
+ $mailchimp = new \MC4WP_MailChimp();
+ $result = $mailchimp->list_subscribe( $mailchimp_list_id, $email_address, $mailchimp_data );
+
+ // if result failed, show error message
+ $log = mc4wp_get_debug_log();
+ $name = sprintf( 'HTML Forms: %s', $form->title );
+ if ( ! $result ) {
+ if ( $mailchimp->get_error_code() == 214 ) {
+ $log->warning( sprintf( '%s: %s is already subscribed to the selected list(s)', $name, $email_address ) );
+ } else {
+ $log->error( sprintf( '%s > Mailchimp API Error: %s', $name, $mailchimp->get_error_message() ) );
+ }
+
+ return;
+ }
+
+ $log->info( sprintf( '%s > Successfully subscribed %s', $name, $email_address ) );
+ }
+}
--- /dev/null
+<?php
+
+namespace HTML_Forms\Admin;
+
+use HTML_Forms\Form;
+use HTML_Forms\Submission;
+
+class Admin {
+
+ /**
+ * @var string
+ */
+ private $plugin_file;
+
+ /**
+ * Admin constructor.
+ *
+ * @param string $plugin_file
+ */
+ public function __construct( $plugin_file ) {
+ $this->plugin_file = $plugin_file;
+ }
+
+ public function hook() {
+ add_action( 'admin_menu', array( $this, 'menu' ) );
+ add_action( 'init', array( $this, 'register_settings' ) );
+ add_action( 'admin_init', array( $this, 'run_migrations' ) );
+ add_action( 'admin_init', array( $this, 'listen' ) );
+ add_action( 'admin_print_styles', array( $this, 'assets' ) );
+ add_action( 'admin_head', array( $this, 'add_screen_options' ) );
+ add_action( 'hf_admin_action_create_form', array( $this, 'process_create_form' ) );
+ add_action( 'hf_admin_action_save_form', array( $this, 'process_save_form' ) );
+ add_action( 'hf_admin_action_bulk_delete_submissions', array( $this, 'process_bulk_delete_submissions' ) );
+
+ add_action( 'hf_admin_output_form_tab_fields', array( $this, 'tab_fields' ) );
+ add_action( 'hf_admin_output_form_tab_messages', array( $this, 'tab_messages' ) );
+ add_action( 'hf_admin_output_form_tab_settings', array( $this, 'tab_settings' ) );
+ add_action( 'hf_admin_output_form_tab_actions', array( $this, 'tab_actions' ) );
+ add_action( 'hf_admin_output_form_tab_submissions', array( $this, 'tab_submissions_list' ) );
+ add_action( 'hf_admin_output_form_tab_submissions', array( $this, 'tab_submissions_detail' ) );
+ add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_gutenberg_assets' ) );
+ }
+
+ public function enqueue_gutenberg_assets() {
+ wp_enqueue_script( 'html-forms-block', plugins_url( 'assets/js/gutenberg-block.js', $this->plugin_file ), array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-components' ) );
+ $forms = hf_get_forms();
+ $data = array();
+ foreach ( $forms as $form ) {
+ $data[] = array(
+ 'title' => $form->title,
+ 'slug' => $form->slug,
+ 'id' => $form->ID,
+ );
+ }
+ wp_localize_script( 'html-forms-block', 'html_forms', $data );
+ }
+
+ public function register_settings() {
+ // register settings
+ register_setting( 'hf_settings', 'hf_settings', array( $this, 'sanitize_settings' ) );
+ }
+
+ public function run_migrations() {
+ $version_from = get_option( 'hf_version', '0.0' );
+ $version_to = HTML_FORMS_VERSION;
+
+ if ( version_compare( $version_from, $version_to, '>=' ) ) {
+ return;
+ }
+
+ $migrations = new Migrations( $version_from, $version_to, dirname( $this->plugin_file ) . '/migrations' );
+ $migrations->run();
+ update_option( 'hf_version', HTML_FORMS_VERSION );
+ }
+
+ /**
+ * @param array $dirty
+ * @return array
+ */
+ public function sanitize_settings( $dirty ) {
+ return $dirty;
+ }
+
+ public function listen() {
+ $request = array_merge( $_GET, $_POST );
+ if ( empty( $request['_hf_admin_action'] ) ) {
+ return;
+ }
+
+ // do nothing if logged in user is not of role administrator
+ if ( ! current_user_can( 'edit_forms' ) ) {
+ return;
+ }
+
+ $action = (string) $request['_hf_admin_action'];
+
+ /**
+ * Allows you to hook into requests containing `_hf_admin_action` => action name.
+ *
+ * The dynamic portion of the hook name, `$action`, refers to the action name.
+ *
+ * By the time this hook is fired, the user is already authorized. After processing all the registered hooks,
+ * the request is redirected back to the referring URL.
+ *
+ * @since 3.0
+ */
+ do_action( 'hf_admin_action_' . $action );
+
+ // redirect back to where we came from
+ $redirect_url = ! empty( $_REQUEST['_redirect_to'] ) ? $_REQUEST['_redirect_to'] : remove_query_arg( '_hf_admin_action' );
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+
+ public function assets() {
+ if ( empty( $_GET['page'] ) || strpos( $_GET['page'], 'html-forms' ) !== 0 ) {
+ return;
+ }
+
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ wp_enqueue_style( 'html-forms-admin', plugins_url( 'assets/css/admin' . $suffix . '.css', $this->plugin_file ), array(), HTML_FORMS_VERSION );
+ wp_enqueue_script( 'html-forms-admin', plugins_url( 'assets/js/admin' . $suffix . '.js', $this->plugin_file ), array(), HTML_FORMS_VERSION, true );
+ wp_localize_script(
+ 'html-forms-admin',
+ 'hf_options',
+ array(
+ 'page' => $_GET['page'],
+ 'view' => empty( $_GET['view'] ) ? '' : $_GET['view'],
+ 'form_id' => empty( $_GET['form_id'] ) ? 0 : (int) $_GET['form_id'],
+ )
+ );
+ }
+
+ public function menu() {
+ $capability = 'edit_forms';
+ $svg_icon = '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="256.000000pt" height="256.000000pt" viewBox="0 0 256.000000 256.000000" preserveAspectRatio="xMidYMid meet"><g transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"
+ fill="#000000" stroke="none"><path d="M0 1280 l0 -1280 1280 0 1280 0 0 1280 0 1280 -1280 0 -1280 0 0 -1280z m2031 593 c8 -8 9 -34 4 -78 -6 -56 -9 -65 -23 -60 -43 16 -98 15 -132 -2 -50 -26 -72 -72 -78 -159 l-5 -74 92 0 91 0 0 -70 0 -70 -90 0 -90 0 0 -345 0 -345 -90 0 -90 0 0 345 0 345 -55 0 -55 0 0 70 0 70 55 0 55 0 0 38 c0 63 20 153 45 202 54 105 141 152 273 147 45 -2 87 -8 93 -14z m-1291 -288 l0 -235 230 0 230 0 0 235 0 235 90 0 90 0 0 -575 0 -575 -90 0 -90 0 0 260 0 260 -230 0 -230 0 0 -260 0 -260 -90 0 -90 0 0 575 0 575 90 0 90 0 0 -235z"/></g></svg>';
+ add_menu_page( 'HTML Forms', 'HTML Forms', $capability, 'html-forms', array( $this, 'page_overview' ), 'data:image/svg+xml;base64,' . base64_encode( $svg_icon ), '99.88491' );
+ add_submenu_page( 'html-forms', __( 'Forms', 'html-forms' ), __( 'All Forms', 'html-forms' ), $capability, 'html-forms', array( $this, 'page_overview' ) );
+ add_submenu_page( 'html-forms', __( 'Add new form', 'html-forms' ), __( 'Add New', 'html-forms' ), $capability, 'html-forms-add-form', array( $this, 'page_new_form' ) );
+ add_submenu_page( 'html-forms', __( 'Settings', 'html-forms' ), __( 'Settings', 'html-forms' ), $capability, 'html-forms-settings', array( $this, 'page_settings' ) );
+
+ // if( ! defined( 'HF_PREMIUM_VERSION' ) ) {
+ // add_submenu_page( 'html-forms', 'Premium', '<span style="color: #ea6ea6;">Premium</span>', $capability, 'html-forms-premium', array( $this, 'page_premium' ) );
+ // }
+ }
+
+ public function add_screen_options() {
+ // only run on the submissions overview page (not detail)
+ if ( empty( $_GET['page'] ) || $_GET['page'] !== 'html-forms' || empty( $_GET['view'] ) || $_GET['view'] !== 'edit' || empty( $_GET['form_id'] ) || ! empty( $_GET['submission_id'] ) ) {
+ return;
+ }
+
+ // don't run if form does not have submissions enabled
+ $form = hf_get_form( $_GET['form_id'] );
+ if ( ! $form->settings['save_submissions'] ) {
+ return;
+ }
+
+ // tell screen options to show columns option
+ $submissions = hf_get_form_submissions( $_GET['form_id'] );
+ $columns = $this->get_submission_columns( $submissions );
+ add_filter(
+ 'manage_toplevel_page_html-forms_columns',
+ function( $unused ) use ( $columns ) {
+ return $columns;
+ }
+ );
+ add_screen_option( 'layout_columns' );
+ }
+
+ public function page_overview() {
+ if ( ! empty( $_GET['view'] ) && $_GET['view'] === 'edit' ) {
+ $this->page_edit_form();
+ return;
+ }
+
+ $settings = hf_get_settings();
+
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
+ $table = new Table( $settings );
+
+ require dirname( $this->plugin_file ) . '/views/page-overview.php';
+ }
+
+ public function page_new_form() {
+ require dirname( $this->plugin_file ) . '/views/page-add-form.php';
+ }
+
+ public function page_settings() {
+ $settings = hf_get_settings();
+ require dirname( $this->plugin_file ) . '/views/page-global-settings.php';
+ }
+
+ public function page_premium() {
+ require dirname( $this->plugin_file ) . '/views/page-premium.php';
+ }
+
+ public function page_edit_form() {
+ $active_tab = ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'fields';
+ $form_id = (int) $_GET['form_id'];
+ $form = hf_get_form( $form_id );
+ $settings = hf_get_settings();
+ require dirname( $this->plugin_file ) . '/views/page-edit-form.php';
+ }
+
+ public function tab_fields( Form $form ) {
+ $form_preview_url = add_query_arg(
+ array(
+ 'hf_preview_form' => $form->ID,
+ ),
+ site_url( '/', 'admin' )
+ );
+ require dirname( $this->plugin_file ) . '/views/tab-fields.php';
+ }
+
+ public function tab_messages( Form $form ) {
+ require dirname( $this->plugin_file ) . '/views/tab-messages.php';
+ }
+
+
+ public function tab_settings( Form $form ) {
+ require dirname( $this->plugin_file ) . '/views/tab-settings.php';
+ }
+
+
+ public function tab_actions( Form $form ) {
+ require dirname( $this->plugin_file ) . '/views/tab-actions.php';
+ }
+
+ public function get_submission_columns( array $submissions ) {
+ $columns = array();
+ foreach ( $submissions as $s ) {
+ if ( ! is_array( $s->data ) ) {
+ continue;
+ }
+
+ foreach ( $s->data as $field => $value ) {
+ if ( ! isset( $columns[ $field ] ) ) {
+ $columns[ $field ] = esc_html( ucfirst( strtolower( str_replace( '_', ' ', $field ) ) ) );
+ }
+ }
+ }
+ return $columns;
+ }
+
+ public function tab_submissions_list( Form $form ) {
+ if ( ! empty( $_GET['submission_id'] ) ) {
+ return;
+ }
+
+ $submissions = hf_get_form_submissions( $form->ID );
+ $columns = $this->get_submission_columns( $submissions );
+ $hidden_columns = get_hidden_columns( get_current_screen() );
+
+ require dirname( $this->plugin_file ) . '/views/tab-submissions-list.php';
+ }
+
+ public function tab_submissions_detail( Form $form ) {
+ if ( empty( $_GET['submission_id'] ) ) {
+ return;
+ }
+
+ $submission = hf_get_form_submission( (int) $_GET['submission_id'] );
+ require dirname( $this->plugin_file ) . '/views/tab-submissions-detail.php';
+ }
+
+
+ public function process_create_form() {
+ // Fix for MultiSite stripping KSES for roles other than administrator
+ remove_all_filters( 'content_save_pre' );
+
+ $data = $_POST['form'];
+ $form_title = sanitize_text_field( $data['title'] );
+ $form_id = wp_insert_post(
+ array(
+ 'post_type' => 'html-form',
+ 'post_status' => 'publish',
+ 'post_title' => $form_title,
+ 'post_content' => $this->get_default_form_content(),
+ )
+ );
+
+ wp_safe_redirect( admin_url( 'admin.php?page=html-forms&view=edit&form_id=' . $form_id ) );
+ exit;
+ }
+
+ public function process_save_form() {
+ $form_id = (int) $_POST['form_id'];
+ $form = hf_get_form( $form_id );
+ $data = $_POST['form'];
+
+ // Fix for MultiSite stripping KSES for roles other than administrator
+ remove_all_filters( 'content_save_pre' );
+
+ // strip <form> tag from markup
+ $data['markup'] = preg_replace( '/<\/?form(.|\s)*?>/i', '', $data['markup'] );
+
+ $form_id = wp_insert_post(
+ array(
+ 'ID' => $form_id,
+ 'post_type' => 'html-form',
+ 'post_status' => 'publish',
+ 'post_title' => sanitize_text_field( $data['title'] ),
+ 'post_content' => $data['markup'],
+ 'post_name' => sanitize_title_with_dashes( $data['slug'] ),
+ )
+ );
+
+ if ( ! empty( $data['settings'] ) ) {
+ update_post_meta( $form_id, '_hf_settings', $data['settings'] );
+ }
+
+ // save form messages in individual meta keys
+ foreach ( $data['messages'] as $key => $message ) {
+ update_post_meta( $form_id, 'hf_message_' . $key, $message );
+ }
+
+ $redirect_url_args = array(
+ 'form_id' => $form_id,
+ 'saved' => 1,
+ );
+ $redirect_url = add_query_arg( $redirect_url_args, admin_url( 'admin.php?page=html-forms&view=edit' ) );
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+
+ /**
+ * Get URL for a tab on the current page.
+ *
+ * @since 3.0
+ * @internal
+ * @param $tab
+ * @return string
+ */
+ public function get_tab_url( $tab ) {
+ return add_query_arg( array( 'tab' => $tab ), remove_query_arg( 'tab' ) );
+ }
+
+ /**
+ * @return array
+ */
+ public function get_available_form_actions() {
+ $actions = array();
+
+ /**
+ * Filters the available form actions
+ *
+ * @param array $actions
+ */
+ $actions = apply_filters( 'hf_available_form_actions', $actions );
+
+ return $actions;
+ }
+
+ public function process_bulk_delete_submissions() {
+ global $wpdb;
+
+ if ( empty( $_POST['id'] ) ) {
+ return;
+ }
+
+ $ids = $_POST['id'];
+ $table = $wpdb->prefix . 'hf_submissions';
+ $ids = join( ',', array_map( 'esc_sql', $ids ) );
+ $wpdb->query( sprintf( "DELETE FROM {$table} WHERE id IN( %s );", $ids ) );
+ $wpdb->query( sprintf( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN ( %s ) AND meta_key LIKE '_hf_%%';", $ids ) );
+ }
+
+ private function get_default_form_content() {
+ $html = '';
+ $html .= sprintf( "<p>\n\t<label>%1\$s</label>\n\t<input type=\"text\" name=\"NAME\" placeholder=\"%1\$s\" required />\n</p>", __( 'Your name', 'html-forms' ) ) . PHP_EOL;
+ $html .= sprintf( "<p>\n\t<label>%1\$s</label>\n\t<input type=\"email\" name=\"EMAIL\" placeholder=\"%1\$s\" required />\n</p>", __( 'Your email', 'html-forms' ) ) . PHP_EOL;
+ $html .= sprintf( "<p>\n\t<label>%1\$s</label>\n\t<input type=\"text\" name=\"SUBJECT\" placeholder=\"%1\$s\" required />\n</p>", __( 'Subject', 'html-forms' ) ) . PHP_EOL;
+ $html .= sprintf( "<p>\n\t<label>%1\$s</label>\n\t<textarea name=\"MESSAGE\" placeholder=\"%1\$s\" required></textarea>\n</p>", __( 'Message', 'html-forms' ) ) . PHP_EOL;
+ $html .= sprintf( "<p>\n\t<input type=\"submit\" value=\"%s\" />\n</p>", __( 'Send', 'html-forms' ) );
+ return $html;
+ }
+
+}
--- /dev/null
+<?php
+
+namespace HTML_Forms\Admin;
+
+use HTML_Forms\Submission;
+
+class GDPR {
+ public function hook() {
+ add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'register_exporter' ), 90 );
+ add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'register_eraser' ), 90 );
+ }
+
+ public function register_exporter( $exporters ) {
+ $exporters['html-forms'] = array(
+ 'exporter_friendly_name' => 'HTML Forms',
+ 'callback' => array( $this, 'export' ),
+ );
+ return $exporters;
+ }
+
+ public function register_eraser( $erasers ) {
+ $erasers['html-forms'] = array(
+ 'eraser_friendly_name' => 'HTML Forms',
+ 'callback' => array( $this, 'erase' ),
+ );
+ return $erasers;
+ }
+
+ public function export( $email_address, $page = 1 ) {
+ $submissions = $this->find_submissions_for_email_address( $email_address );
+ $data_to_export = array();
+
+ foreach ( $submissions as $s ) {
+ $data_to_export[] = array(
+ 'group_id' => 'html_forms_submissions',
+ 'group_label' => __( 'Form submissions', 'html-forms' ),
+ 'item_id' => sprintf( 'html-forms-submission-%d', $s->id ),
+ 'data' => $this->export_submission( $s ),
+ );
+ }
+
+ return array(
+ 'data' => $data_to_export,
+ 'done' => true,
+ );
+ }
+
+ public function export_submission( Submission $submission ) {
+ $data = array(
+ array(
+ 'name' => 'Submitted at',
+ 'value' => $submission->submitted_at,
+ ),
+ );
+
+ if ( ! empty( $submission->ip_address ) ) {
+ $data[] = array(
+ 'name' => 'IP address',
+ 'value' => $submission->ip_address,
+ );
+ }
+
+ if ( ! empty( $submission->user_agent ) ) {
+ $data[] = array(
+ 'name' => 'User agent',
+ 'value' => $submission->user_agent,
+ );
+ }
+
+ foreach ( $submission->data as $field => $value ) {
+ $data[] = array(
+ 'name' => $field,
+ 'value' => is_array( $value ) ? join( ', ', $value ) : $value,
+ );
+ }
+
+ return $data;
+ }
+
+ public function erase( $email_address, $page = 1 ) {
+ global $wpdb;
+ $table = $wpdb->prefix . 'hf_submissions';
+
+ $items_removed = false;
+ $submissions = $this->find_submissions_for_email_address( $email_address );
+ foreach ( $submissions as $submission ) {
+ $wpdb->delete( $table, array( 'id' => $submission->id ) );
+ $items_removed = true;
+ }
+
+ return array(
+ 'items_removed' => $items_removed,
+ 'items_retained' => false,
+ 'messages' => array(),
+ 'done' => true,
+ );
+ }
+
+ private function find_submissions_for_email_address( $email_address ) {
+ global $wpdb;
+ $table = $wpdb->prefix . 'hf_submissions';
+ $like = '%"' . $email_address . '"%';
+ $results = $wpdb->get_results( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.data LIKE %s ORDER BY s.submitted_at DESC", $like ), OBJECT_K );
+
+ $submissions = array();
+ foreach ( $results as $key => $object ) {
+ $submission = Submission::from_object( $object );
+ $submissions[ $key ] = $submission;
+ }
+
+ return $submissions;
+ }
+}
--- /dev/null
+<?php
+
+namespace HTML_Forms\Admin;
+
+/**
+ * Class Migrations
+ *
+ * This class takes care of loading migration files from the specified migrations directory.
+ * Migration files should only use default WP functions and NOT use code which might not be there in the future.
+ *
+ * @ignore
+ */
+class Migrations {
+
+ /**
+ * @var float
+ */
+ protected $version_from = 0;
+
+ /**
+ * @var float
+ */
+ protected $version_to = 0;
+
+ /**
+ * @var string
+ */
+ protected $migrations_dir = '';
+
+ /**
+ * @param string $from
+ * @param string $to
+ * @param string $migrations_dir
+ */
+ public function __construct( $from, $to, $migrations_dir ) {
+ $this->version_from = $from;
+ $this->version_to = $to;
+ $this->migrations_dir = $migrations_dir;
+ }
+
+ /**
+ * Run the various upgrade routines, all the way up to the latest version
+ */
+ public function run() {
+ $migrations = $this->find_migrations();
+
+ // run in function for scope
+ array_map( array( $this, 'run_migration' ), $migrations );
+ }
+
+ /**
+ * @return array
+ */
+ public function find_migrations() {
+
+ $files = glob( rtrim( $this->migrations_dir, '/' ) . '/*.php' );
+ $migrations = array();
+
+ // return empty array when glob returns non-array value.
+ if ( ! is_array( $files ) ) {
+ return $migrations;
+ }
+
+ foreach ( $files as $file ) {
+ $migration = basename( $file );
+ $parts = explode( '-', $migration );
+ $version = $parts[0];
+
+ if ( version_compare( $this->version_from, $version, '<' ) ) {
+ $migrations[] = $file;
+ }
+ }
+
+ return $migrations;
+ }
+
+ /**
+ * Include a migration file and runs it.
+ *
+ * @param string $file
+ */
+ protected function run_migration( $file ) {
+ include $file;
+ }
+
+}
--- /dev/null
+<?php
+
+namespace HTML_Forms\Admin;
+use HTML_Forms\Form;
+use WP_List_Table, WP_Post;
+
+// Check if WP Core class exists so that we can keep testing rest of HTML Forms in isolation..
+if ( class_exists( 'WP_List_Table' ) ) {
+
+ class Table extends WP_List_Table {
+
+ /**
+ * @var bool
+ */
+ public $is_trash = false;
+
+ /**
+ * @var array
+ */
+ private $settings = array();
+
+ /**
+ * Constructor
+ */
+ public function __construct( array $settings ) {
+ parent::__construct(
+ array(
+ 'singular' => 'form',
+ 'plural' => 'forms',
+ 'ajax' => false,
+ )
+ );
+
+ $this->settings = $settings;
+ $this->process_bulk_action();
+
+ $columns = $this->get_columns();
+ $sortable = $this->get_sortable_columns();
+ $hidden = array();
+ $this->_column_headers = array( $columns, $hidden, $sortable );
+ $this->is_trash = isset( $_REQUEST['post_status'] ) && $_REQUEST['post_status'] === 'trash';
+ $this->items = $this->get_items();
+ $this->set_pagination_args(
+ array(
+ 'per_page' => 50,
+ 'total_items' => count( $this->items ),
+ )
+ );
+ }
+
+ /**
+ * Get an associative array ( id => link ) with the list
+ * of views available on this table.
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return array
+ */
+ public function get_views() {
+ $counts = wp_count_posts( 'html-form' );
+ $current = isset( $_GET['post_status'] ) ? $_GET['post_status'] : '';
+ $count_any = $counts->publish + $counts->draft + $counts->future + $counts->pending;
+
+ return array(
+ '' => sprintf( '<a href="%s" class="%s">%s</a> (%d)', remove_query_arg( 'post_status' ), $current == '' ? 'current' : '', __( 'All', 'html-forms' ), $count_any ),
+ 'trash' => sprintf( '<a href="%s" class="%s">%s</a> (%d)', add_query_arg( array( 'post_status' => 'trash' ) ), $current == 'trash' ? 'current' : '', __( 'Trash', 'html-forms' ), $counts->trash ),
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function get_bulk_actions() {
+
+ $actions = array();
+
+ if ( $this->is_trash ) {
+ $actions['untrash'] = __( 'Restore', 'html-forms' );
+ $actions['delete'] = __( 'Delete Permanently', 'html-forms' );
+ return $actions;
+ }
+
+ $actions['trash'] = __( 'Move to Trash', 'html-forms' );
+ $actions['duplicate'] = __( 'Duplicate', 'html-forms' );
+ return $actions;
+ }
+
+ public function get_default_primary_column_name() {
+ return 'form_name';
+ }
+
+ /**
+ * @return array
+ */
+ public function get_table_classes() {
+ return array( 'widefat', 'fixed', 'striped', 'html-forms-table' );
+ }
+
+ /**
+ * @return array
+ */
+ public function get_columns() {
+ return array(
+ 'cb' => '<input type="checkbox" />',
+ 'form_name' => __( 'Form', 'html-forms' ),
+ 'shortcode' => __( 'Shortcode', 'html-forms' ),
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function get_sortable_columns() {
+ return array();
+ }
+
+ /**
+ * @return array
+ */
+ public function get_items() {
+
+ $args = array();
+
+ if ( ! empty( $_GET['s'] ) ) {
+ $args['s'] = sanitize_text_field( $_GET['s'] );
+ }
+
+ if ( ! empty( $_GET['post_status'] ) ) {
+ $args['post_status'] = sanitize_text_field( $_GET['post_status'] );
+ }
+
+ $items = hf_get_forms( $args );
+ return $items;
+ }
+
+ /**
+ * @param Form $form
+ * @return string
+ */
+ public function column_cb( $form ) {
+ return sprintf( '<input type="checkbox" name="forms[]" value="%s" />', $form->ID );
+ }
+
+ /**
+ * @param Form $form
+ *
+ * @return mixed
+ */
+ public function column_ID( Form $form ) {
+ return $form->ID;
+ }
+
+ /**
+ * @param Form $form
+ * @return string
+ */
+ public function column_form_name( Form $form ) {
+ if ( $this->is_trash ) {
+ return sprintf( '<strong>%s</strong>', esc_html( $form->title ) );
+ }
+
+ $edit_link = admin_url( 'admin.php?page=html-forms&view=edit&form_id=' . $form->ID );
+ $title = '<strong><a class="row-title" href="' . $edit_link . '">' . esc_html( $form->title ) . '</a></strong>';
+
+ $actions = array();
+ $tabs = array(
+ 'fields' => __( 'Fields', 'html-forms' ),
+ 'messages' => __( 'Messages', 'html-forms' ),
+ 'settings' => __( 'Settings', 'html-forms' ),
+ 'actions' => __( 'Actions', 'html-forms' ),
+ );
+
+ if ( $form->settings['save_submissions'] ) {
+ $tabs['submissions'] = __( 'Submissions', 'html-forms' );
+ }
+
+ foreach ( $tabs as $tab_slug => $tab_title ) {
+ $actions[ $tab_slug ] = '<a href="' . esc_attr( add_query_arg( array( 'tab' => $tab_slug ), $edit_link ) ) . '">' . $tab_title . '</a>';
+ }
+
+ return $title . $this->row_actions( $actions );
+ }
+
+ /**
+ * @param Form $form
+ * @return string
+ */
+ public function column_shortcode( Form $form ) {
+ if ( $this->is_trash ) {
+ return '';
+ }
+
+ return sprintf( '<input style="width: 260px;" type="text" onfocus="this.select();" readonly="readonly" value="%s">', esc_attr( '[hf_form slug="' . $form->slug . '"]' ) );
+ }
+
+ /**
+ * The text that is shown when there are no items to show
+ */
+ public function no_items() {
+ echo sprintf( __( 'No forms found. <a href="%s">Would you like to create one now</a>?', 'html-forms' ), admin_url( 'admin.php?page=html-forms-add-form' ) );
+ }
+
+ /**
+ *
+ */
+ public function process_bulk_action() {
+ $action = $this->current_action();
+ if ( empty( $action ) ) {
+ return false;
+ }
+
+ $method = 'process_bulk_action_' . $action;
+ $forms = (array) $_REQUEST['forms'];
+ if ( method_exists( $this, $method ) ) {
+ return call_user_func_array( array( $this, $method ), array( $forms ) );
+ }
+
+ return false;
+ }
+
+ public function process_bulk_action_duplicate( $forms ) {
+ foreach ( $forms as $form_id ) {
+ $post = get_post( $form_id );
+ $post_meta = get_post_meta( $form_id );
+
+ $new_post_id = wp_insert_post(
+ array(
+ 'post_title' => $post->post_title,
+ 'post_content' => $post->post_content,
+ 'post_type' => 'html-form',
+ 'post_status' => 'publish',
+ )
+ );
+ foreach ( $post_meta as $meta_key => $meta_value ) {
+ $meta_value = maybe_unserialize( $meta_value[0] );
+ update_post_meta( $new_post_id, $meta_key, $meta_value );
+ }
+ }
+ }
+
+ public function process_bulk_action_trash( $forms ) {
+ return array_map( 'wp_trash_post', $forms );
+ }
+
+ public function process_bulk_action_delete( $forms ) {
+ return array_map( 'wp_delete_post', $forms );
+ }
+
+ public function process_bulk_action_untrash( $forms ) {
+ return array_map( 'wp_untrash_post', $forms );
+ }
+
+ /**
+ * Generates content for a single row of the table
+ *
+ * @since 3.1.0
+ *
+ * @param Form $form The current item
+ */
+ public function single_row( $form ) {
+ echo sprintf( '<tr id="hf-forms-item-%d">', $form->ID );
+ $this->single_row_columns( $form );
+ echo '</tr>';
+ }
+
+ }
+
+}