PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.3.33
HTML Forms – Simple WordPress Forms Plugin v1.3.33
1.7.0 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 All 67 releases
← All changes | src/admin/class-admin.php +232 -26 1.3.151.3.33 View file →
@@ -41,9 +41,19 @@
41 41 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_gutenberg_assets' ) );
42 42 }
43 43
44 44 public function enqueue_gutenberg_assets() {
45 - 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' ) );
45 + wp_enqueue_script(
46 + 'html-forms-block',
47 + plugins_url( 'assets/js/gutenberg-block.js', $this->plugin_file ),
48 + array(
49 + 'wp-blocks',
50 + 'wp-i18n',
51 + 'wp-element',
52 + 'wp-components',
53 + 'wp-block-editor',
54 + )
55 + );
46 56 $forms = hf_get_forms();
47 57 $data = array();
48 58 foreach ( $forms as $form ) {
49 59 $data[] = array(
@@ -74,8 +84,9 @@
74 84 }
75 85
76 86 /**
77 87 * @param array $dirty
88 + *
78 89 * @return array
79 90 */
80 91 public function sanitize_settings( $dirty ) {
81 92 return $dirty;
@@ -81,20 +92,27 @@
81 92 return $dirty;
82 93 }
83 94
84 95 public function listen() {
85 - $request = array_merge( $_GET, $_POST );
86 - if ( empty( $request['_hf_admin_action'] ) ) {
96 + if ( isset( $_GET['_hf_admin_action'] ) ) {
97 + $action = (string) $_GET['_hf_admin_action'];
98 + } elseif ( isset( $_POST['_hf_admin_action'] ) ) {
99 + $action = (string) $_POST['_hf_admin_action'];
100 + } else {
87 101 return;
88 102 }
89 103
104 + // verify nonce
105 + if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], '_hf_admin_action' ) ) {
106 + wp_nonce_ays( $action );
107 + exit;
108 + }
109 +
90 110 // do nothing if logged in user is not of role administrator
91 111 if ( ! current_user_can( 'edit_forms' ) ) {
92 112 return;
93 113 }
94 114
95 - $action = (string) $request['_hf_admin_action'];
96 -
97 115 /**
98 116 * Allows you to hook into requests containing `_hf_admin_action` => action name.
99 117 *
100 118 * The dynamic portion of the hook name, `$action`, refers to the action name.
@@ -116,12 +134,10 @@
116 134 if ( empty( $_GET['page'] ) || strpos( $_GET['page'], 'html-forms' ) !== 0 ) {
117 135 return;
118 136 }
119 137
120 - $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
121 -
122 - wp_enqueue_style( 'html-forms-admin', plugins_url( 'assets/css/admin' . $suffix . '.css', $this->plugin_file ), array(), HTML_FORMS_VERSION );
123 - wp_enqueue_script( 'html-forms-admin', plugins_url( 'assets/js/admin' . $suffix . '.js', $this->plugin_file ), array(), HTML_FORMS_VERSION, true );
138 + wp_enqueue_style( 'html-forms-admin', plugins_url( 'assets/css/admin.css', $this->plugin_file ), array(), HTML_FORMS_VERSION );
139 + wp_enqueue_script( 'html-forms-admin', plugins_url( 'assets/js/admin.js', $this->plugin_file ), array(), HTML_FORMS_VERSION, true );
124 140 wp_localize_script(
125 141 'html-forms-admin',
126 142 'hf_options',
127 143 array(
@@ -135,16 +151,67 @@
135 151 public function menu() {
136 152 $capability = 'edit_forms';
137 153 $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)"
138 154 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>';
139 - 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' );
140 - add_submenu_page( 'html-forms', __( 'Forms', 'html-forms' ), __( 'All Forms', 'html-forms' ), $capability, 'html-forms', array( $this, 'page_overview' ) );
141 - add_submenu_page( 'html-forms', __( 'Add new form', 'html-forms' ), __( 'Add New', 'html-forms' ), $capability, 'html-forms-add-form', array( $this, 'page_new_form' ) );
142 - add_submenu_page( 'html-forms', __( 'Settings', 'html-forms' ), __( 'Settings', 'html-forms' ), $capability, 'html-forms-settings', array( $this, 'page_settings' ) );
155 + add_menu_page(
156 + 'HTML Forms',
157 + 'HTML Forms',
158 + $capability,
159 + 'html-forms',
160 + array(
161 + $this,
162 + 'page_overview',
163 + ),
164 + 'data:image/svg+xml;base64,' . base64_encode( $svg_icon ),
165 + '99.88491'
166 + );
167 + add_submenu_page(
168 + 'html-forms',
169 + __( 'Forms', 'html-forms' ),
170 + __( 'All Forms', 'html-forms' ),
171 + $capability,
172 + 'html-forms',
173 + array(
174 + $this,
175 + 'page_overview',
176 + )
177 + );
178 + add_submenu_page(
179 + 'html-forms',
180 + __( 'Add New Form', 'html-forms' ),
181 + __( 'Add New', 'html-forms' ),
182 + $capability,
183 + 'html-forms-add-form',
184 + array(
185 + $this,
186 + 'page_new_form',
187 + )
188 + );
189 + add_submenu_page(
190 + 'html-forms',
191 + __( 'Settings', 'html-forms' ),
192 + __( 'Settings', 'html-forms' ),
193 + $capability,
194 + 'html-forms-settings',
195 + array(
196 + $this,
197 + 'page_settings',
198 + )
199 + );
143 200
144 - // if( ! defined( 'HF_PREMIUM_VERSION' ) ) {
145 - // add_submenu_page( 'html-forms', 'Premium', '<span style="color: #ea6ea6;">Premium</span>', $capability, 'html-forms-premium', array( $this, 'page_premium' ) );
146 - // }
201 + if ( ! defined( 'HF_PREMIUM_VERSION' ) ) {
202 + add_submenu_page(
203 + 'html-forms',
204 + 'Premium',
205 + '<span style="color: #ea6ea6;">Premium</span>',
206 + $capability,
207 + 'html-forms-premium',
208 + array(
209 + $this,
210 + 'page_premium',
211 + )
212 + );
213 + }
147 214 }
148 215
149 216 public function add_screen_options() {
150 217 // only run on the submissions overview page (not detail)
@@ -162,9 +229,9 @@
162 229 $submissions = hf_get_form_submissions( $_GET['form_id'] );
163 230 $columns = $this->get_submission_columns( $submissions );
164 231 add_filter(
165 232 'manage_toplevel_page_html-forms_columns',
166 - function( $unused ) use ( $columns ) {
233 + function ( $unused ) use ( $columns ) {
167 234 return $columns;
168 235 }
169 236 );
170 237 add_screen_option( 'layout_columns' );
@@ -172,8 +239,9 @@
172 239
173 240 public function page_overview() {
174 241 if ( ! empty( $_GET['view'] ) && $_GET['view'] === 'edit' ) {
175 242 $this->page_edit_form();
243 +
176 244 return;
177 245 }
178 246
179 247 $settings = hf_get_settings();
@@ -241,8 +309,9 @@
241 309 $columns[ $field ] = esc_html( ucfirst( strtolower( str_replace( '_', ' ', $field ) ) ) );
242 310 }
243 311 }
244 312 }
313 +
245 314 return $columns;
246 315 }
247 316
248 317 public function tab_submissions_list( Form $form ) {
@@ -249,9 +318,21 @@
249 318 if ( ! empty( $_GET['submission_id'] ) ) {
250 319 return;
251 320 }
252 321
253 - $submissions = hf_get_form_submissions( $form->ID );
322 + $items_per_page = 500;
323 + $total_items = hf_count_form_submissions( $form->ID );
324 + $total_pages = max( 1, ceil( $total_items / $items_per_page ) );
325 + $current_page = isset( $_GET['paged'] ) ? intval( $_GET['paged'] ) : 1;
326 + $current_page = max( 1, $current_page );
327 + $current_page = min( $total_pages, $current_page );
328 + $submissions = hf_get_form_submissions(
329 + $form->ID,
330 + array(
331 + 'limit' => $items_per_page,
332 + 'offset' => ( $current_page - 1 ) * $items_per_page,
333 + )
334 + );
254 335 $columns = $this->get_submission_columns( $submissions );
255 336 $hidden_columns = get_hidden_columns( get_current_screen() );
256 337
257 338 require dirname( $this->plugin_file ) . '/views/tab-submissions-list.php';
@@ -293,8 +374,13 @@
293 374
294 375 // Fix for MultiSite stripping KSES for roles other than administrator
295 376 remove_all_filters( 'content_save_pre' );
296 377
378 + // run our own kses filter
379 + if ( ! current_user_can( 'unfiltered_html' ) ) {
380 + $data['markup'] = $this->kses( $data['markup'] );
381 + }
382 +
297 383 // strip <form> tag from markup
298 384 $data['markup'] = preg_replace( '/<\/?form(.|\s)*?>/i', '', $data['markup'] );
299 385
300 386 $form_id = wp_insert_post(
@@ -313,9 +399,13 @@
313 399 }
314 400
315 401 // save form messages in individual meta keys
316 402 foreach ( $data['messages'] as $key => $message ) {
317 - update_post_meta( $form_id, 'hf_message_' . $key, $message );
403 + if ( current_user_can( 'unfiltered_html' ) ) {
404 + update_post_meta( $form_id, 'hf_message_' . $key, $message );
405 + } else {
406 + update_post_meta( $form_id, 'hf_message_' . $key, wp_kses_post( $message ) );
407 + }
318 408 }
319 409
320 410 $redirect_url_args = array(
321 411 'form_id' => $form_id,
@@ -328,12 +418,13 @@
328 418
329 419 /**
330 420 * Get URL for a tab on the current page.
331 421 *
422 + * @param $tab
423 + *
424 + * @return string
332 425 * @since 3.0
333 426 * @internal
334 - * @param $tab
335 - * @return string
336 427 */
337 428 public function get_tab_url( $tab ) {
338 429 return add_query_arg( array( 'tab' => $tab ), remove_query_arg( 'tab' ) );
339 430 }
@@ -360,13 +451,15 @@
360 451 if ( empty( $_POST['id'] ) ) {
361 452 return;
362 453 }
363 454
364 - $ids = $_POST['id'];
365 - $table = $wpdb->prefix . 'hf_submissions';
366 - $ids = join( ',', array_map( 'esc_sql', $ids ) );
367 - $wpdb->query( sprintf( "DELETE FROM {$table} WHERE id IN( %s );", $ids ) );
368 - $wpdb->query( sprintf( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN ( %s ) AND meta_key LIKE '_hf_%%';", $ids ) );
455 + $args = array_map( 'intval', $_POST['id'] );
456 + $table = $wpdb->prefix . 'hf_submissions';
457 + $placeholders = rtrim( str_repeat( '%d,', count( $args ) ), ',' );
458 + $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE id IN( {$placeholders} );", $args ) );
459 +
460 + $args[] = '_hf_%%';
461 + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN ( {$placeholders} ) AND meta_key LIKE %s;", $args ) );
369 462 }
370 463
371 464 private function get_default_form_content() {
372 465 $html = '';
@@ -374,8 +467,121 @@
374 467 $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;
375 468 $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;
376 469 $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;
377 470 $html .= sprintf( "<p>\n\t<input type=\"submit\" value=\"%s\" />\n</p>", __( 'Send', 'html-forms' ) );
471 +
378 472 return $html;
379 473 }
380 474
475 +
476 + /**
477 + * Filters string and strips out all HTML tags and attributes, except what's in our whitelist.
478 + *
479 + * @param string $string The string to apply KSES whitelist on
480 + * @return string
481 + */
482 + private function kses( $string ) {
483 + $always_allowed_attr = array_fill_keys(
484 + array(
485 + 'aria-describedby',
486 + 'aria-details',
487 + 'aria-label',
488 + 'aria-labelledby',
489 + 'aria-hidden',
490 + 'aria-*',
491 + 'class',
492 + 'id',
493 + 'style',
494 + 'title',
495 + 'role',
496 + 'data-*',
497 + 'data-confirm',
498 + 'tabindex',
499 + ),
500 + true
501 + );
502 + $input_allowed_attr = array_merge(
503 + $always_allowed_attr,
504 + array_fill_keys(
505 + array(
506 + 'type',
507 + 'required',
508 + 'placeholder',
509 + 'value',
510 + 'name',
511 + 'step',
512 + 'min',
513 + 'max',
514 + 'checked',
515 + 'width',
516 + 'autocomplete',
517 + 'autofocus',
518 + 'minlength',
519 + 'maxlength',
520 + 'size',
521 + 'pattern',
522 + 'disabled',
523 + 'readonly',
524 + ),
525 + true
526 + )
527 + );
528 +
529 + $allowed = array(
530 + 'p' => $always_allowed_attr,
531 + 'label' => array_merge( $always_allowed_attr, array( 'for' => true ) ),
532 + 'input' => $input_allowed_attr,
533 + 'button' => $input_allowed_attr,
534 + 'fieldset' => $always_allowed_attr,
535 + 'legend' => $always_allowed_attr,
536 + 'ul' => $always_allowed_attr,
537 + 'ol' => $always_allowed_attr,
538 + 'li' => $always_allowed_attr,
539 + 'select' => array_merge( $input_allowed_attr, array( 'multiple' => true ) ),
540 + 'option' => array_merge( $input_allowed_attr, array( 'selected' => true ) ),
541 + 'optgroup' => array(
542 + 'disabled' => true,
543 + 'label' => true,
544 + ),
545 + 'textarea' => array_merge(
546 + $input_allowed_attr,
547 + array(
548 + 'rows' => true,
549 + 'cols' => true,
550 + )
551 + ),
552 + 'div' => $always_allowed_attr,
553 + 'strong' => $always_allowed_attr,
554 + 'b' => $always_allowed_attr,
555 + 'i' => $always_allowed_attr,
556 + 'br' => array(),
557 + 'em' => $always_allowed_attr,
558 + 'span' => $always_allowed_attr,
559 + 'a' => array_merge( $always_allowed_attr, array( 'href' => true ) ),
560 + 'img' => array_merge(
561 + $always_allowed_attr,
562 + array(
563 + 'src' => true,
564 + 'alt' => true,
565 + 'width' => true,
566 + 'height' => true,
567 + 'srcset' => true,
568 + 'sizes' => true,
569 + 'referrerpolicy' => true,
570 + 'loading' => true,
571 + 'decoding' => true,
572 + )
573 + ),
574 + 'u' => $always_allowed_attr,
575 + 'table' => $always_allowed_attr,
576 + 'tr' => $always_allowed_attr,
577 + 'td' => $always_allowed_attr,
578 + 'th' => $always_allowed_attr,
579 + 'thead' => $always_allowed_attr,
580 + 'tbody' => $always_allowed_attr,
581 + 'picture' => $always_allowed_attr,
582 + 'video' => $always_allowed_attr,
583 + );
584 +
585 + return wp_kses( $string, $allowed );
586 + }
381 587 }