diff --git a/projects/packages/forms/.phan/baseline.php b/projects/packages/forms/.phan/baseline.php index 51cec46cb58ba..30a571dc80d2c 100644 --- a/projects/packages/forms/.phan/baseline.php +++ b/projects/packages/forms/.phan/baseline.php @@ -20,14 +20,12 @@ // PhanDeprecatedClass : 1 occurrence // PhanPluginMixedKeyNoKey : 1 occurrence // PhanPossiblyNullTypeMismatchProperty : 1 occurrence - // PhanTypeArraySuspiciousNullable : 1 occurrence // PhanTypeMismatchReturnNullable : 1 occurrence // PhanUnreferencedUseNormal : 1 occurrence // Currently, file_suppressions and directory_suppressions are the only supported suppressions 'file_suppressions' => [ 'src/abilities/class-forms-abilities.php' => ['PhanUndeclaredFunction'], - 'src/contact-form/class-admin.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeArraySuspiciousNullable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchReturn'], 'src/contact-form/class-contact-form-field.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanPossiblyNullTypeMismatchProperty', 'PhanTypeConversionFromArray', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturnProbablyReal'], 'src/contact-form/class-contact-form-plugin.php' => ['PhanPluginDuplicateAdjacentStatement', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchReturnProbablyReal'], 'src/contact-form/class-contact-form-shortcode.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeMismatchReturnProbablyReal'], diff --git a/projects/packages/forms/changelog/remove-contact-form-legacy-admin-files b/projects/packages/forms/changelog/remove-contact-form-legacy-admin-files new file mode 100644 index 0000000000000..fb662a20fa101 --- /dev/null +++ b/projects/packages/forms/changelog/remove-contact-form-legacy-admin-files @@ -0,0 +1,4 @@ +Significance: minor +Type: removed + +Forms: remove admin class files diff --git a/projects/packages/forms/src/contact-form/class-admin.php b/projects/packages/forms/src/contact-form/class-admin.php deleted file mode 100644 index 1b66e306240c7..0000000000000 --- a/projects/packages/forms/src/contact-form/class-admin.php +++ /dev/null @@ -1,1610 +0,0 @@ -id, array( 'edit-feedback', 'feedback_page_feedback-export' ), true ) ) { - return; - } - add_thickbox(); - $localized_strings = array( - 'exportError' => esc_js( __( 'There was an error exporting your results', 'jetpack-forms' ) ), - 'waitingConnection' => esc_js( __( 'Waiting for connection...', 'jetpack-forms' ) ), - ); - wp_localize_script( 'grunion-admin', 'exportParameters', $localized_strings ); - } - - /** - * Prints the modal markup with export buttons/content. - */ - public function print_export_modal() { - if ( ! current_user_can( 'export' ) ) { - return; - } - - $current_screen = get_current_screen(); - if ( ! in_array( $current_screen->id, array( 'edit-feedback', 'feedback_page_feedback-export' ), true ) ) { - return; - } - - // if there aren't any feedbacks, bail out - if ( ! (int) wp_count_posts( 'feedback' )->publish ) { - return; - } - - ?> - - {$opener_label}" - : "{$opener_label}"; - ?> - - export_nonce_field_gdrive ] ) ) - || ! wp_verify_nonce( sanitize_text_field( $post_data[ $this->export_nonce_field_gdrive ] ), 'feedback_export' ) - ) { - wp_send_json_error( - __( 'You aren\'t authorized to do that.', 'jetpack-forms' ), - 403, - JSON_UNESCAPED_SLASHES - ); - - return; - } - - $grunion = Contact_Form_Plugin::init(); - $export_data = $grunion->get_feedback_entries_from_post(); - - $fields = is_array( $export_data ) ? array_keys( $export_data ) : array(); - $row_count = ! is_array( $export_data ) || empty( $export_data ) ? 0 : count( reset( $export_data ) ); - - $sheet_data = array( $fields ); - - for ( $i = 0; $i < $row_count; $i++ ) { - - $current_row = array(); - - /** - * Put all the fields in `$current_row` array. - */ - foreach ( $fields as $single_field_name ) { - $current_row[] = $export_data[ $single_field_name ][ $i ]; - } - - $sheet_data[] = $current_row; - } - - $user_id = (int) get_current_user_id(); - - if ( ! empty( $post_data['post'] ) && $post_data['post'] !== 'all' ) { - $spreadsheet_title = sprintf( - '%1$s - %2$s', - $this->get_export_filename( get_the_title( (int) $post_data['post'] ) ), - gmdate( 'Y-m-d H:i' ) - ); - } else { - $spreadsheet_title = sprintf( '%s - %s', $this->get_export_filename(), gmdate( 'Y-m-d H:i' ) ); - } - - $sheet = Google_Drive::create_sheet( $user_id, $spreadsheet_title, $sheet_data ); - - $grunion->record_tracks_event( 'forms_export_responses', array( 'format' => 'gsheets' ) ); - - wp_send_json( - array( - 'success' => ! is_wp_error( $sheet ), - 'data' => $sheet, - ), - 200, - JSON_UNESCAPED_SLASHES - ); - } - - /** - * Return HTML markup for the CSV download button. - */ - public function get_csv_export_section() { - $button_csv_html = get_submit_button( - esc_html__( 'Download', 'jetpack-forms' ), - 'primary export-button export-csv', - 'jetpack-export-feedback-csv', - false, - array( 'data-nonce-name' => $this->export_nonce_field_csv ) - ); - ?> -
-
- - - -
-
-
-
- -
-
- export_nonce_field_csv, false, false ); - ?> -
-
-
- is_user_connected( get_current_user_id() ); - if ( ! $user_connected ) { - return; - } - - $has_valid_connection = Google_Drive::has_valid_connection(); - - if ( $has_valid_connection ) { - $button_html = $this->get_gdrive_export_button_markup(); - } else { - $slug = 'jetpack-form-responses-connect'; - $button_html = sprintf( - '%3$s', - esc_url( Redirect::get_url( $slug ) ), - esc_attr__( 'connect to Google Drive', 'jetpack-forms' ), - esc_html__( 'Connect Google Drive', 'jetpack-forms' ), - $slug, - $this->export_nonce_field_gdrive - ); - } - - ?> -
-
- - - -
-
-
-
-
- -
-
-
- export_nonce_field_gdrive, false, false ); - ?> -
-
-
- export_nonce_field_gdrive ] ) ) || - ! wp_verify_nonce( sanitize_text_field( $post_data[ $this->export_nonce_field_gdrive ] ), 'feedback_export' ) - ) { - wp_send_json_error( - __( 'You aren\'t authorized to do that.', 'jetpack-forms' ), - 403, - JSON_UNESCAPED_SLASHES - ); - - return; - } - - $has_valid_connection = Google_Drive::has_valid_connection(); - - $replacement_html = $has_valid_connection - ? $this->get_gdrive_export_button_markup() - : ''; - - wp_send_json( - array( - 'connection' => $has_valid_connection, - 'html' => $replacement_html, - ), - 200, - JSON_UNESCAPED_SLASHES - ); - } - - /** - * Markup helper so we DRY, returns the button markup for the export to GDrive feature. - * - * @return string The HTML button markup - */ - public function get_gdrive_export_button_markup() { - return get_submit_button( - esc_html__( 'Export', 'jetpack-forms' ), - 'primary export-button export-gdrive', - 'jetpack-export-feedback-gdrive', - false, - array( 'data-nonce-name' => $this->export_nonce_field_gdrive ) - ); - } - - /** - * Get a filename for export tasks - * - * @param string $source The filtered source for exported data. - * @return string The filename without source nor date suffix. - */ - public function get_export_filename( $source = '' ) { - return $source === '' - ? sprintf( - /* translators: Site title, used to craft the export filename, eg "MySite - Jetpack Form Responses" */ - __( '%s - Jetpack Form Responses', 'jetpack-forms' ), - sanitize_file_name( get_bloginfo( 'name' ) ) - ) - : sprintf( - /* translators: 1: Site title; 2: post title. Used to craft the export filename, eg "MySite - Jetpack Form Responses - Contact" */ - __( '%1$s - Jetpack Form Responses - %2$s', 'jetpack-forms' ), - sanitize_file_name( get_bloginfo( 'name' ) ), - sanitize_file_name( $source ) - ); - } - - /** - * Build contact form button. - * - * @return void - */ - public function grunion_media_button() { - global $post_ID, $temp_ID, $pagenow;// phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - if ( 'press-this.php' === $pagenow ) { - return; - } - - $iframe_post_id = (int) ( 0 === $post_ID ? $temp_ID : $post_ID );// phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $title = __( 'Add Contact Form', 'jetpack-forms' ); - $site_url = esc_url( admin_url( "/admin-ajax.php?post_id={$iframe_post_id}&action=grunion_form_builder&TB_iframe=true&width=768" ) ); - ?> - - - - - - id - ) { - return; - } - - wp_enqueue_script( 'wp-lists' ); - - wp_register_style( 'grunion-admin.css', plugin_dir_url( __FILE__ ) . '/../../../dist/contact-form/css/grunion-admin.css', array(), \JETPACK__VERSION ); - wp_style_add_data( 'grunion-admin.css', 'rtl', 'replace' ); - - wp_enqueue_style( 'grunion-admin.css' ); - } - - /** - * Enqueue scripts. - * - * @return void - */ - public function grunion_admin_js() { - global $current_screen; - if ( - $current_screen === null - || 'edit-feedback' !== $current_screen->id - ) { - return; - } - - $script = 'var __grunionPostStatusNonce = ' . wp_json_encode( wp_create_nonce( 'grunion-post-status' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';'; - wp_add_inline_script( 'grunion-admin', $script, 'before' ); - } - - /** - * Hack a 'Bulk Spam' option for bulk edit in other than spam view - * Hack a 'Bulk Delete' option for bulk edit in spam view - * - * There isn't a better way to do this until - * https://core.trac.wordpress.org/changeset/17297 is resolved - */ - public function grunion_add_bulk_edit_option() { - - $screen = get_current_screen(); - - if ( $screen === null ) { - return; - } - - if ( 'edit-feedback' !== $screen->id ) { - return; - } - - // When viewing spam we want to be able to be able to bulk delete - // When viewing anything we want to be able to bulk move to spam - if ( isset( $_GET['post_status'] ) && 'spam' === $_GET['post_status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- no changes to the site, we're only rendering the option to choose bulk delete/spam. - // Create Delete Permanently bulk item - $option_val = 'delete'; - $option_txt = __( 'Delete Permanently', 'jetpack-forms' ); - $pseudo_selector = 'last-child'; - - } else { - // Create Mark Spam bulk item - $option_val = 'spam'; - $option_txt = __( 'Mark as Spam', 'jetpack-forms' ); - $pseudo_selector = 'first-child'; - } - - ?> - - $post_id, - 'post_status' => 'spam', - ); - $akismet_values = get_post_meta( $post_id, '_feedback_akismet_values', true ); - wp_update_post( $post ); - - /** - * Fires after a comment has been marked by Akismet. - * - * Typically this means the comment is spam. - * - * @module contact-form - * - * @since 2.2.0 - * - * @param string $comment_status Usually is 'spam', otherwise 'ham'. - * @param array $akismet_values From '_feedback_akismet_values' in comment meta - */ - do_action( 'contact_form_akismet', 'spam', $akismet_values ); - } - - $redirect_url = add_query_arg( 'message', 'marked-spam', wp_get_referer() ); - wp_safe_redirect( $redirect_url ); - exit( 0 ); - } - - /** - * Display spam message. - * - * @return void - */ - public function grunion_message_bulk_spam() { - echo '

' . esc_html__( 'Feedback(s) marked as spam', 'jetpack-forms' ) . '

'; - } - - /** - * Unset edit option when bulk editing. - * - * @param array $actions List of actions available. - * @return array $actions - */ - public function grunion_admin_bulk_actions( $actions ) { - global $current_screen; - if ( - $current_screen === null - || 'edit-feedback' !== $current_screen->id - ) { - return $actions; - } - - unset( $actions['edit'] ); - return $actions; - } - - /** - * Unset publish button when editing feedback. - * - * @param array $views List of post views. - * @return array $views - */ - public function grunion_admin_view_tabs( $views ) { - global $current_screen; - if ( - $current_screen === null - || 'edit-feedback' !== $current_screen->id - ) { - return $views; - } - - unset( $views['publish'] ); - - preg_match( '|post_type=feedback\'( class="current")?\>(.*)\ '', - 'feedback_from' => __( 'From', 'jetpack-forms' ), - 'feedback_source' => __( 'Source', 'jetpack-forms' ), - 'feedback_date' => __( 'Date', 'jetpack-forms' ), - 'feedback_response' => __( 'Response Data', 'jetpack-forms' ), - ); - } - - /** - * Displays the value for the source column. (This function runs within the loop.) - * - * @return void - */ - public function grunion_manage_post_column_date() { - echo esc_html( date_i18n( 'Y/m/d', get_the_time( 'U' ) ) ); - } - - /** - * Displays the value for the from column. - * - * @param \WP_Post $post Current post. - * @return void - */ - public function grunion_manage_post_column_from( $post ) { - $content_fields = Contact_Form_Plugin::parse_fields_from_content( $post->ID ); - - if ( ! empty( $content_fields['_feedback_author'] ) ) { - echo esc_html( $content_fields['_feedback_author'] ); - return; - } - - if ( ! empty( $content_fields['_feedback_author_email'] ) ) { - printf( - "%2\$s
", - esc_url( 'mailto:' . $content_fields['_feedback_author_email'] ), - esc_html( $content_fields['_feedback_author_email'] ) - ); - return; - } - - if ( ! empty( $content_fields['_feedback_ip'] ) ) { - echo esc_html( $content_fields['_feedback_ip'] ); - return; - } - - echo esc_html__( 'Unknown', 'jetpack-forms' ); - } - - /** - * Displays the value for the response column. - * - * @param \WP_Post $post Current post. - * @return void - */ - public function grunion_manage_post_column_response( $post ) { - - $post_content = get_post_field( 'post_content', $post->ID ); - $content = explode( '', $post_content ); - $content = str_ireplace( array( '
', ')

' ), '', $content[1] ); - $chunks = explode( "\nJSON_DATA", $content ); - // Get content fields. - $content_fields = Contact_Form_Plugin::parse_fields_from_content( $post->ID ); - - if ( empty( $content_fields ) ) { - return; - } - - $chunks = explode( "\nArray", $content ); - if ( ! empty( $chunks[1] ) ) { - // re-construct the array string - $array = 'Array' . $chunks[1]; - // re-construct the array - $rearray = Contact_Form_Plugin::reverse_that_print( $array, true ); - $response_fields = is_array( $rearray ) ? $rearray : array(); - } else { - // couldn't reconstruct array, use the old method - $content_fields = Contact_Form_Plugin::parse_fields_from_content( $post->ID ); - $response_fields = isset( $content_fields['_feedback_all_fields'] ) ? $content_fields['_feedback_all_fields'] : array(); - } - - // Extract IP address if we still do not have it at this point. - if ( - ! isset( $content_fields['_feedback_ip'] ) - && ! empty( $chunks[0] ) - ) { - preg_match( '/^IP: (.+)$/m', $chunks[0], $matches ); - if ( ! empty( $matches[1] ) ) { - $content_fields['_feedback_ip'] = $matches[1]; - } - } - - $url = get_permalink( $post->post_parent ); - if ( isset( $response_fields['entry_page'] ) ) { - $url = add_query_arg( 'page', $response_fields['entry_page'], $url ); - } - - $response_fields = array_diff_key( $response_fields, array_flip( array_keys( Contact_Form_Plugin::NON_PRINTABLE_FIELDS ) ) ); - - echo '
'; - echo '
'; - - foreach ( $response_fields as $key => $display_value ) { - if ( Contact_Form::is_file_upload_field( $display_value ) ) { - printf( - ''; - continue; - } elseif ( is_array( $display_value ) ) { - // Regular array, format it nicely for display - $display_value = Contact_Form_Plugin::format_value_for_display( $display_value ); - } - - printf( - '', - esc_html( preg_replace( '#^\d+_#', '', $key ) ), - nl2br( esc_html( $display_value ) ) - ); - } - - echo '
'; - echo '
'; - - echo '
'; - if ( ! empty( $content_fields['_feedback_ip'] ) ) { - echo ''; - echo ''; - } - echo ''; - echo ''; - echo '
'; - } - - /** - * Displays the value for the source column. - * - * @param \WP_Post $post Current post. - * @return void - */ - public function grunion_manage_post_column_source( $post ) { - if ( ! isset( $post->post_parent ) ) { - return; - } - - $form_url = get_permalink( $post->post_parent ); - $parsed_url = wp_parse_url( $form_url ); - - printf( - '/%s', - esc_url( $form_url ), - esc_html( basename( $parsed_url['path'] ) ) - ); - } - - /** - * Parse message content and display in appropriate columns. - * - * @param array $col List of columns available on admin page. - * @param int $post_id The current post ID. - * @return void - */ - public function grunion_manage_post_columns( $col, $post_id ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable - global $post; - - /** - * Only call parse_fields_from_content if we're dealing with a Grunion custom column. - */ - if ( ! in_array( $col, array( 'feedback_date', 'feedback_from', 'feedback_response', 'feedback_source' ), true ) ) { - return; - } - - switch ( $col ) { - case 'feedback_date': - $this->grunion_manage_post_column_date(); - return; - case 'feedback_from': - $this->grunion_manage_post_column_from( $post ); - return; - case 'feedback_response': - $this->grunion_manage_post_column_response( $post ); - return; - case 'feedback_source': - $this->grunion_manage_post_column_source( $post ); - return; - } - } - - /** - * Add a post filter dropdown at the top of the admin page. - * - * @return void - */ - public function grunion_source_filter() { - $screen = get_current_screen(); - - if ( 'edit-feedback' !== $screen->id ) { - return; - } - - $parent_id = intval( isset( $_GET['jetpack_form_parent_id'] ) ? $_GET['jetpack_form_parent_id'] : 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended - Contact_Form_Plugin::form_posts_dropdown( $parent_id ); - } - - /** - * Filter feedback posts by parent_id if present. - * - * @param \WP_Query $query Current query. - * - * @return void - */ - public function grunion_source_filter_results( $query ) { - $parent_id = intval( isset( $_GET['jetpack_form_parent_id'] ) ? $_GET['jetpack_form_parent_id'] : 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended - - if ( ! $parent_id || $query->query_vars['post_type'] !== 'feedback' ) { - return; - } - - /** - * In the wp-admin list we perform two queries that trigger the `pre_get_posts` hook. - * One is for the main list and the other is for the `source` dropdown filter. - * We need to explicitly check one unique parameter between the two queries to avoid - * filtering the dropdown query. The dropdown query is in `get_all_parent_post_ids`. - */ - if ( $query->query_vars['posts_per_page'] === 100000 ) { - return; - } - - $query->query_vars['post_parent'] = $parent_id; - } - - /** - * Add actions to feedback response rows in WP Admin. - * - * @param string[] $actions Default actions. - * @return string[] - */ - public function grunion_manage_post_row_actions( $actions ) { - global $post; - - if ( ! ( $post instanceof \WP_Post ) || 'feedback' !== $post->post_type ) { - return $actions; - } - - $post_type_object = get_post_type_object( $post->post_type ); - $actions = array(); - - if ( $post->post_status === 'trash' ) { - $actions['untrash'] = sprintf( - '%s', - esc_attr__( 'Restore this item from the Trash', 'jetpack-forms' ), - esc_url( wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', rawurlencode( (string) $post->ID ) ) ) ), 'untrash-' . $post->post_type . '_' . $post->ID ), - esc_html__( 'Restore', 'jetpack-forms' ) - ); - $actions['delete'] = sprintf( - '%s', - esc_attr( __( 'Delete this item permanently', 'jetpack-forms' ) ), - get_delete_post_link( $post->ID, '', true ), - esc_html__( 'Delete Permanently', 'jetpack-forms' ) - ); - } elseif ( $post->post_status === 'publish' ) { - $actions['spam'] = sprintf( - '%s', - esc_html__( 'Mark this message as spam', 'jetpack-forms' ), - esc_url( wp_nonce_url( admin_url( 'admin-ajax.php?post_id=' . rawurlencode( (string) $post->ID ) . '&action=spam' ) ), 'spam-feedback_' . $post->ID ), - esc_html__( 'Spam', 'jetpack-forms' ) - ); - $actions['trash'] = sprintf( - '%s', - esc_attr_x( 'Trash', 'verb', 'jetpack-forms' ), - get_delete_post_link( $post->ID ), - esc_html_x( 'Trash', 'verb', 'jetpack-forms' ) - ); - } elseif ( $post->post_status === 'spam' ) { - $actions['unspam unapprove'] = sprintf( - '%s', - esc_html__( 'Mark this message as NOT spam', 'jetpack-forms' ), - esc_html__( 'Not Spam', 'jetpack-forms' ) - ); - $actions['delete'] = sprintf( - '%s', - esc_attr( __( 'Delete this item permanently', 'jetpack-forms' ) ), - get_delete_post_link( $post->ID, '', true ), - esc_html__( 'Delete Permanently', 'jetpack-forms' ) - ); - } - - return $actions; - } - - /** - * Escape grunion attributes. - * - * @param string $attr - the attribute we're escaping. - * - * @return string - */ - public function grunion_esc_attr( $attr ) { - $out = esc_attr( $attr ); - // we also have to entity-encode square brackets so they don't interfere with the shortcode parser - // FIXME: do this better - just stripping out square brackets for now since they mysteriously keep reappearing - $out = str_replace( '[', '', $out ); - $out = str_replace( ']', '', $out ); - return $out; - } - - /** - * Sort grunion items. - * - * @param array $a - the first item we're sorting. - * @param array $b - the second item we're sorting. - * - * @return string - */ - public function grunion_sort_objects( $a, $b ) { - if ( isset( $a['order'] ) && isset( $b['order'] ) ) { - return $a['order'] <=> $b['order']; - } - return 0; - } - - /** - * Take an array of field types from the form builder, and construct a shortcode form. - * returns both the shortcode form, and HTML markup representing a preview of the form - * - * @return never - */ - public function grunion_ajax_shortcode() { - check_ajax_referer( 'grunion_shortcode' ); - - if ( ! current_user_can( 'edit_posts' ) ) { - die( '-1' ); - } - - $attributes = array(); - - foreach ( array( 'subject', 'to' ) as $attribute ) { - if ( isset( $_POST[ $attribute ] ) && is_scalar( $_POST[ $attribute ] ) && (string) $_POST[ $attribute ] !== '' ) { - $attributes[ $attribute ] = sanitize_text_field( wp_unslash( $_POST[ $attribute ] ) ); - } - } - - $field_shortcodes = array(); - - if ( isset( $_POST['fields'] ) && is_array( $_POST['fields'] ) ) { - $fields = array_map( - function ( $field ) { - if ( is_array( $field ) ) { - - foreach ( array( 'label', 'type', 'required' ) as $key ) { - if ( isset( $field[ $key ] ) ) { - $field[ $key ] = sanitize_text_field( wp_unslash( $field[ $key ] ) ); - } - } - - if ( isset( $field['options'] ) && is_array( $field['options'] ) ) { - $field['options'] = array_map( 'sanitize_text_field', array_map( 'wp_unslash', $field['options'] ) ); - } - } - return $field; - }, - $_POST['fields'] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- each item sanitized above. - ); - usort( $fields, array( $this, 'grunion_sort_objects' ) ); - - foreach ( $fields as $field ) { - $field_attributes = array(); - - if ( isset( $field['required'] ) && 'true' === $field['required'] ) { - $field_attributes['required'] = 'true'; - } - - foreach ( array( 'options', 'label', 'type' ) as $attribute ) { - if ( isset( $field[ $attribute ] ) ) { - $field_attributes[ $attribute ] = $field[ $attribute ]; - } - } - - $field_shortcodes[] = new Contact_Form_Field( $field_attributes ); - } - } - - $grunion = new Contact_Form( $attributes, $field_shortcodes ); - - die( "\n$grunion\n" ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * Takes a post_id, extracts the contact-form shortcode from that post (if there is one), parses it, - * and constructs a json object representing its contents and attributes. - * - * @return never - */ - public function grunion_ajax_shortcode_to_json() { - global $post; - - check_ajax_referer( 'grunion_shortcode_to_json' ); - - if ( ! empty( $_POST['post_id'] ) && ! current_user_can( 'edit_post', (int) $_POST['post_id'] ) ) { - wp_send_json( -1, 200, JSON_UNESCAPED_SLASHES ); - exit( 0 ); // wp_send_json never returns, but Phan doesn't know that. - } elseif ( ! current_user_can( 'edit_posts' ) ) { - wp_send_json( -1, 200, JSON_UNESCAPED_SLASHES ); - exit( 0 ); // wp_send_json never returns, but Phan doesn't know that. - } - - if ( ! isset( $_POST['content'] ) || ! is_numeric( $_POST['post_id'] ) ) { - wp_send_json( -1, 200, JSON_UNESCAPED_SLASHES ); - exit( 0 ); // wp_send_json never returns, but Phan doesn't know that. - } - - $content = sanitize_text_field( wp_unslash( $_POST['content'] ) ); - - // doesn't look like a post with a [contact-form] already. - if ( false === has_shortcode( $content, 'contact-form' ) ) { - die( '' ); - } - - $post = get_post( (int) $_POST['post_id'] ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - - do_shortcode( $content ); - - $grunion = Contact_Form::$last; - - $out = array( - 'to' => '', - 'subject' => '', - 'fields' => array(), - ); - - foreach ( $grunion->fields as $field ) { - $out['fields'][ $field->get_attribute( 'id' ) ] = $field->attributes; - } - - foreach ( array( 'to', 'subject' ) as $attribute ) { - $value = $grunion->get_attribute( $attribute ); - if ( isset( $grunion->defaults[ $attribute ] ) && $value === $grunion->defaults[ $attribute ] ) { - $value = ''; - } - $out[ $attribute ] = $value; - } - - wp_send_json( $out, 200, JSON_UNESCAPED_SLASHES ); - } - - /** - * Handle marking feedback as spam. - */ - public function grunion_ajax_spam() { - global $wpdb; - - if ( empty( $_POST['make_it'] ) ) { - return; - } - - $post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0; - check_ajax_referer( 'grunion-post-status' ); - if ( ! current_user_can( 'edit_page', $post_id ) ) { - wp_die( esc_html__( 'You are not allowed to manage this item.', 'jetpack-forms' ) ); - } - - // init will construct/get the instance and make sure all the filters and actions - // are in place for this process to go through - Contact_Form_Plugin::init(); - - $current_menu = ''; - if ( isset( $_POST['sub_menu'] ) && preg_match( '|post_type=feedback|', sanitize_text_field( wp_unslash( $_POST['sub_menu'] ) ) ) ) { - if ( preg_match( '|post_status=spam|', sanitize_text_field( wp_unslash( $_POST['sub_menu'] ) ) ) ) { - $current_menu = 'spam'; - } elseif ( preg_match( '|post_status=trash|', sanitize_text_field( wp_unslash( $_POST['sub_menu'] ) ) ) ) { - $current_menu = 'trash'; - } else { - $current_menu = 'messages'; - } - } - - $post = get_post( $post_id ); - $post_type_object = get_post_type_object( $post->post_type ); - $akismet_values = get_post_meta( $post_id, '_feedback_akismet_values', true ); - if ( $_POST['make_it'] === 'spam' ) { - - $status = wp_update_post( - array( - 'ID' => $post_id, - 'post_status' => 'spam', - ) - ); - - /** This action is already documented in \Automattic\Jetpack\Forms\ContactForm\Admin */ - do_action( 'contact_form_akismet', 'spam', $akismet_values ); - } elseif ( $_POST['make_it'] === 'ham' ) { - $status = wp_update_post( - array( - 'ID' => $post_id, - 'post_status' => 'publish', - ) - ); - - /** This action is already documented in \Automattic\Jetpack\Forms\ContactForm\Admin */ - do_action( 'contact_form_akismet', 'ham', $akismet_values ); - - $comment_author_email = false; - $reply_to_addr = false; - $message = false; - $to = false; - $headers = false; - $blog_url = wp_parse_url( site_url() ); - - // resend the original email - $email = get_post_meta( $post_id, '_feedback_email', true ); - $content_fields = Contact_Form_Plugin::parse_fields_from_content( $post_id ); - - if ( ! empty( $email ) && ! empty( $content_fields ) ) { - if ( isset( $content_fields['_feedback_author_email'] ) ) { - $comment_author_email = $content_fields['_feedback_author_email']; - } - - if ( isset( $email['to'] ) ) { - $to = $email['to']; - } - - if ( isset( $email['message'] ) ) { - $message = $email['message']; - } - - if ( isset( $email['headers'] ) ) { - $headers = $email['headers']; - } else { - $headers = 'From: "' . $content_fields['_feedback_author'] . '" \r\n"; - - if ( ! empty( $comment_author_email ) ) { - $reply_to_addr = $comment_author_email; - } elseif ( is_array( $to ) ) { - $reply_to_addr = $to[0]; - } - - if ( $reply_to_addr ) { - $headers .= 'Reply-To: "' . $content_fields['_feedback_author'] . '" <' . $reply_to_addr . ">\r\n"; - } - - $headers .= 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . '"'; - } - - /** - * Filters the subject of the email sent after a contact form submission. - * - * @module contact-form - * - * @since 3.0.0 - * - * @param string $content_fields['_feedback_subject'] Feedback's subject line. - * @param array $content_fields['_feedback_all_fields'] Feedback's data from old fields. - */ - $subject = apply_filters( 'contact_form_subject', $content_fields['_feedback_subject'], $content_fields['_feedback_all_fields'] ); - - Contact_Form::wp_mail( $to, $subject, $message, $headers ); - } - } elseif ( $_POST['make_it'] === 'publish' ) { - if ( ! current_user_can( $post_type_object->cap->delete_post, $post_id ) ) { - wp_die( esc_html__( 'You are not allowed to move this item out of the Trash.', 'jetpack-forms' ) ); - } - - if ( ! wp_untrash_post( $post_id ) ) { - wp_die( esc_html__( 'Error in restoring from Trash.', 'jetpack-forms' ) ); - } - } elseif ( $_POST['make_it'] === 'trash' ) { - if ( ! current_user_can( $post_type_object->cap->delete_post, $post_id ) ) { - wp_die( esc_html__( 'You are not allowed to move this item to the Trash.', 'jetpack-forms' ) ); - } - - if ( ! wp_trash_post( $post_id ) ) { - wp_die( esc_html__( 'Error in moving to Trash.', 'jetpack-forms' ) ); - } - } elseif ( $_POST['make_it'] === 'delete' ) { - if ( ! current_user_can( $post_type_object->cap->delete_post, $post_id ) ) { - wp_die( esc_html__( 'You are not allowed to move this item to the Trash.', 'jetpack-forms' ) ); - } - - if ( ! wp_delete_post( $post_id, true ) ) { - wp_die( esc_html__( 'Error in deleting post.', 'jetpack-forms' ) ); - } - } - - $sql = " - SELECT post_status, - COUNT( * ) AS post_count - FROM `{$wpdb->posts}` - WHERE post_type = 'feedback' - GROUP BY post_status - "; - $status_count = (array) $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching - - $status = array(); - $status_html = ''; - foreach ( $status_count as $row ) { - $status[ $row['post_status'] ] = $row['post_count']; - } - - if ( isset( $status['publish'] ) ) { - $status_html .= '
  • '; - $status_html .= '(' . number_format( $status['publish'] ) . ')'; - $status_html .= ' |
  • '; - } - - if ( isset( $status['trash'] ) ) { - $status_html .= '
  • '; - $status_html .= '(' . number_format( $status['trash'] ) . ')'; - $status_html .= ''; - if ( isset( $status['spam'] ) ) { - $status_html .= ' |'; - } - $status_html .= '
  • '; - } - - if ( isset( $status['spam'] ) ) { - $status_html .= '
  • '; - $status_html .= '(' . number_format( $status['spam'] ) . ')'; - $status_html .= '
  • '; - } - - echo $status_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- we're building the html to echo. - exit( 0 ); - } - - /** - * Add the scripts that will add the "Check for Spam" button to the Feedbacks dashboard page. - */ - public function grunion_enable_spam_recheck() { - if ( ! defined( 'AKISMET_VERSION' ) ) { - return; - } - - $screen = get_current_screen(); - - // Only add to feedback, only to non-spam view - if ( empty( $screen ) || 'edit-feedback' !== $screen->id || ( ! empty( $_GET['post_status'] ) && 'spam' === $_GET['post_status'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- not making site changes with this check. - return; - } - - // Add the actual "Check for Spam" button. - add_action( 'admin_head', array( $this, 'grunion_check_for_spam_button' ) ); - } - - /** - * Add the JS and CSS necessary for the Feedback admin page to function. - */ - public function grunion_add_admin_scripts() { - $screen = get_current_screen(); - - if ( empty( $screen ) || 'edit-feedback' !== $screen->id ) { - return; - } - - // Add the scripts that handle the spam check event. - Assets::register_script( - 'grunion-admin', - '../../dist/contact-form/js/grunion-admin.js', - __FILE__, - array( - 'enqueue' => true, - 'dependencies' => array( 'jquery' ), - 'version' => \JETPACK__VERSION, - 'in_footer' => true, - ) - ); - - if ( Contact_Form_Plugin::can_use_analytics() ) { - Tracking::register_tracks_functions_scripts( true ); - - wp_localize_script( - 'grunion-admin', - 'jetpack_forms_tracking', - array( - 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(), - ) - ); - } - - wp_enqueue_style( 'grunion.css' ); - - // Only add to feedback, only to spam view. - if ( empty( $_GET['post_status'] ) || 'spam' !== $_GET['post_status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- not making site changes with this check - return; - } - - $feedbacks_count = wp_count_posts( 'feedback' ); - $nonce = wp_create_nonce( 'jetpack_delete_spam_feedbacks' ); - $success_url = remove_query_arg( array( 'jetpack_empty_feedback_spam_error', 'post_status' ) ); // Go to the "All Feedback" page. - $failure_url = add_query_arg( 'jetpack_empty_feedback_spam_error', '1' ); // Refresh the current page and show an error. - $spam_count = $feedbacks_count->spam; - - $button_parameters = array( - /* translators: The placeholder is for showing how much of the process has completed, as a percent. e.g., "Emptying Spam (40%)" */ - 'progress_label' => __( 'Emptying Spam (%1$s%%)', 'jetpack-forms' ), - 'success_url' => $success_url, - 'failure_url' => $failure_url, - 'spam_count' => $spam_count, - 'nonce' => $nonce, - 'label' => __( 'Empty Spam', 'jetpack-forms' ), - ); - - wp_localize_script( 'grunion-admin', 'jetpack_empty_spam_button_parameters', $button_parameters ); - } - - /** - * Adds the 'Export' button to the feedback dashboard page. - * - * @return void - */ - public function grunion_export_button() { - $current_screen = get_current_screen(); - if ( ! in_array( $current_screen->id, array( 'edit-feedback', 'feedback_page_feedback-export' ), true ) ) { - return; - } - - if ( ! current_user_can( 'export' ) ) { - return; - } - - // if there aren't any feedbacks, bail out - if ( ! (int) wp_count_posts( 'feedback' )->publish ) { - return; - } - - $nonce_name = 'feedback_export_nonce'; - - $button_html = get_submit_button( - __( 'Export', 'jetpack-forms' ), - 'primary', - 'jetpack-export-feedback', - false, - array( - 'data-nonce-name' => $nonce_name, - ) - ); - - $button_html .= wp_nonce_field( 'feedback_export', $nonce_name, false, false ); - ?> - - add_query_arg( 'jetpack_check_feedback_spam_error', '1' ), // Refresh the current page and show an error. - 'data-nonce-name' => $nonce_name, - ) - ); - $button_html .= ''; - $button_html .= wp_nonce_field( 'grunion_recheck_queue', $nonce_name, false, false ); - - // Add the button next to the filter button via js. - ?> - - ID, '_feedback_akismet_values', true ); - - if ( ! $meta ) { - // _feedback_akismet_values is eventually deleted when it's no longer - // within a reasonable time period to check the feedback for spam, so - // if it's gone, don't attempt a spam recheck. - continue; - } - - $meta['recheck_reason'] = 'recheck_queue'; - - /** - * Filter whether the submitted feedback is considered as spam. - * - * @module contact-form - * - * @since 3.4.0 - * - * @param bool false Is the submitted feedback spam? Default to false. - * @param array $meta Feedack values returned by the Akismet plugin. - */ - $is_spam = apply_filters( 'jetpack_contact_form_is_spam', false, $meta ); - - if ( $is_spam ) { - wp_update_post( - array( - 'ID' => $feedback->ID, - 'post_status' => 'spam', - ) - ); - /** This action is already documented in \Automattic\Jetpack\Forms\ContactForm\Admin */ - do_action( 'contact_form_akismet', 'spam', $meta ); - } - } - - wp_send_json( - array( - 'processed' => count( $approved_feedbacks ), - ), - 200, - JSON_UNESCAPED_SLASHES - ); - } - - /** - * Delete a number of spam feedbacks via an AJAX request. - */ - public function grunion_delete_spam_feedbacks() { - if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'jetpack_delete_spam_feedbacks' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- core doesn't sanitize nonce checks either. - wp_send_json_error( - __( 'You aren\'t authorized to do that.', 'jetpack-forms' ), - 403, - JSON_UNESCAPED_SLASHES - ); - - return; - } - - if ( ! current_user_can( 'delete_others_posts' ) ) { - wp_send_json_error( - __( 'You don\'t have permission to do that.', 'jetpack-forms' ), - 403, - JSON_UNESCAPED_SLASHES - ); - - return; - } - - $deleted_feedbacks = 0; - - $delete_limit = 25; - /** - * Filter the amount of Spam feedback one can delete at once. - * - * @module contact-form - * - * @since 8.7.0 - * - * @param int $delete_limit Number of spam to process at once. Default to 25. - */ - $delete_limit = apply_filters( 'jetpack_delete_spam_feedbacks_limit', $delete_limit ); - $delete_limit = (int) $delete_limit; - $delete_limit = max( 1, min( 100, $delete_limit ) ); // Allow a range of 1-100 for the delete limit. - - $query_args = array( - 'post_type' => 'feedback', - 'post_status' => 'spam', - 'posts_per_page' => $delete_limit, - ); - - $query = new \WP_Query( $query_args ); - $spam_feedbacks = $query->get_posts(); - - foreach ( $spam_feedbacks as $feedback ) { - wp_delete_post( $feedback->ID, true ); - - ++$deleted_feedbacks; - } - - wp_send_json( - array( - 'success' => true, - 'data' => array( - 'counts' => array( - 'deleted' => $deleted_feedbacks, - 'limit' => $delete_limit, - ), - ), - ), - 200, - JSON_UNESCAPED_SLASHES - ); - } - - /** - * Show an admin notice if the "Empty Spam" or "Check Spam" process was unable to complete, probably due to a permissions error. - */ - public function grunion_feedback_admin_notice() { - $message = ''; - - if ( isset( $_GET['jetpack_empty_feedback_spam_error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended - $message = esc_html__( 'An error occurred while trying to empty the Feedback spam folder.', 'jetpack-forms' ); - } elseif ( isset( $_GET['jetpack_check_feedback_spam_error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended - $message = esc_html__( 'An error occurred while trying to check for spam among the feedback you received.', 'jetpack-forms' ); - } - - if ( empty( $message ) ) { - return; - } - - wp_admin_notice( - $message, - array( - 'type' => 'error', - ) - ); - } -} diff --git a/projects/packages/forms/src/contact-form/class-editor-view.php b/projects/packages/forms/src/contact-form/class-editor-view.php index cda0195d7d51e..4b98237bb4667 100644 --- a/projects/packages/forms/src/contact-form/class-editor-view.php +++ b/projects/packages/forms/src/contact-form/class-editor-view.php @@ -32,7 +32,6 @@ public static function add_hooks( $screen ) { * Admin header. */ public static function admin_head() { - remove_action( 'media_buttons', array( Admin::init(), 'grunion_media_button' ), 999 ); add_action( 'media_buttons', array( __CLASS__, 'grunion_media_button' ), 999 ); } diff --git a/projects/packages/forms/src/contact-form/class-form-view.php b/projects/packages/forms/src/contact-form/class-form-view.php deleted file mode 100644 index 20bd0baa439e9..0000000000000 --- a/projects/packages/forms/src/contact-form/class-form-view.php +++ /dev/null @@ -1,289 +0,0 @@ - array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-draggable' ), - 'version' => \JETPACK__VERSION, - ) - ); - - wp_localize_script( - 'grunion', - 'GrunionFB_i18n', - array( - 'nameLabel' => esc_attr( _x( 'Name', 'Label for HTML form "Name" field in contact form builder', 'jetpack-forms' ) ), - 'emailLabel' => esc_attr( _x( 'Email', 'Label for HTML form "Email" field in contact form builder', 'jetpack-forms' ) ), - 'urlLabel' => esc_attr( _x( 'Website', 'Label for HTML form "URL/Website" field in contact form builder', 'jetpack-forms' ) ), - 'commentLabel' => esc_attr( _x( 'Comment', 'noun', 'jetpack-forms' ) ), - 'newLabel' => esc_attr( _x( 'New Field', 'Default label for new HTML form field in contact form builder', 'jetpack-forms' ) ), - 'optionsLabel' => esc_attr( _x( 'Options', 'Label for the set of options to be included in a user-created dropdown in contact form builder', 'jetpack-forms' ) ), - 'optionLabel' => esc_attr( _x( 'Option', 'Label for an option to be included in a user-created dropdown in contact form builder', 'jetpack-forms' ) ), - 'firstOptionLabel' => esc_attr( _x( 'First option', 'Default label for the first option to be included in a user-created dropdown in contact form builder', 'jetpack-forms' ) ), - 'problemGeneratingForm' => esc_attr( _x( "Oops, there was a problem generating your form. You'll likely need to try again.", 'error message in contact form builder', 'jetpack-forms' ) ), - 'moveInstructions' => esc_attr__( "Drag up or down\nto re-arrange", 'jetpack-forms' ), - 'moveLabel' => esc_attr( _x( 'move', 'Label to drag HTML form fields around to change their order in contact form builder', 'jetpack-forms' ) ), - 'editLabel' => esc_attr( _x( 'edit', 'Link to edit an HTML form field in contact form builder', 'jetpack-forms' ) ), - 'savedMessage' => esc_attr__( 'Saved successfully', 'jetpack-forms' ), - 'requiredLabel' => esc_attr( _x( '(required)', 'This HTML form field is marked as required by the user in contact form builder', 'jetpack-forms' ) ), - 'exitConfirmMessage' => esc_attr__( 'Are you sure you want to exit the form editor without saving? Any changes you have made will be lost.', 'jetpack-forms' ), - 'maxNewFields' => (int) $max_new_fields, - ) - ); - - ?> - - - - - <?php esc_html_e( 'Contact Form', 'jetpack-forms' ); ?> - - - - - - - - > -
    - -
      -
    • -
    • -
    -
    -
    -
    -

    -

    -

    -

    - ' . esc_html__( 'Click here', 'jetpack-forms' ) . '' - ); - ?> -

    -

    -

    - ' . esc_html__( 'Feedback', 'jetpack-forms' ) . '' - ); - ?> -

    -
    -
    - - -
    -
    -
    -

    -
    - -
    - - -
    - -
    - -
    - - -