PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.5.6
HTML Forms – Simple WordPress Forms Plugin v1.5.6
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 1.3.17 All 66 releases
html-forms / src / admin / class-admin.php

class-admin.php in HTML Forms – Simple WordPress Forms Plugin 1.5.6, at src/admin/class-admin.php

619 lines 18.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace HTML_Forms\Admin;
4
5 use HTML_Forms\Form;
6 use HTML_Forms\Submission;
7
8 class Admin {
9
10 /**
11 * @var string
12 */
13 private $plugin_file;
14
15 /**
16 * Admin constructor.
17 *
18 * @param string $plugin_file
19 */
20 public function __construct( $plugin_file ) {
21 $this->plugin_file = $plugin_file;
22 }
23
24 public function hook() {
25 add_action( 'admin_menu', array( $this, 'menu' ) );
26 add_action( 'init', array( $this, 'register_settings' ) );
27 add_action( 'admin_init', array( $this, 'run_migrations' ) );
28 add_action( 'admin_init', array( $this, 'listen' ) );
29 add_action( 'admin_print_styles', array( $this, 'assets' ) );
30 add_action( 'admin_head', array( $this, 'add_screen_options' ) );
31 add_action( 'hf_admin_action_create_form', array( $this, 'process_create_form' ) );
32 add_action( 'hf_admin_action_save_form', array( $this, 'process_save_form' ) );
33 add_action( 'hf_admin_action_bulk_delete_submissions', array( $this, 'process_bulk_delete_submissions' ) );
34
35 add_action( 'hf_admin_output_form_tab_fields', array( $this, 'tab_fields' ) );
36 add_action( 'hf_admin_output_form_tab_messages', array( $this, 'tab_messages' ) );
37 add_action( 'hf_admin_output_form_tab_settings', array( $this, 'tab_settings' ) );
38 add_action( 'hf_admin_output_form_tab_actions', array( $this, 'tab_actions' ) );
39 add_action( 'hf_admin_output_form_tab_submissions', array( $this, 'tab_submissions_list' ) );
40 add_action( 'hf_admin_output_form_tab_submissions', array( $this, 'tab_submissions_detail' ) );
41 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_gutenberg_assets' ) );
42 }
43
44 public function enqueue_gutenberg_assets() {
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 );
56 $forms = hf_get_forms();
57 $data = array();
58 foreach ( $forms as $form ) {
59 $data[] = array(
60 'title' => $form->title,
61 'slug' => $form->slug,
62 'id' => $form->ID,
63 );
64 }
65 wp_localize_script( 'html-forms-block', 'html_forms', $data );
66 }
67
68 public function register_settings() {
69 // register settings
70 register_setting( 'hf_settings', 'hf_settings', array( $this, 'sanitize_settings' ) );
71 }
72
73 public function run_migrations() {
74 $version_from = get_option( 'hf_version', '0.0' );
75 $version_to = HTML_FORMS_VERSION;
76
77 if ( version_compare( $version_from, $version_to, '>=' ) ) {
78 return;
79 }
80
81 $migrations = new Migrations( $version_from, $version_to, dirname( $this->plugin_file ) . '/migrations' );
82 $migrations->run();
83 update_option( 'hf_version', HTML_FORMS_VERSION );
84 }
85
86 /**
87 * @param array $dirty
88 *
89 * @return array
90 */
91 public function sanitize_settings( $dirty ) {
92 if ( isset( $dirty['wrapper_tag'] ) ) {
93 $dirty['wrapper_tag'] = sanitize_text_field( $dirty['wrapper_tag'] );
94 }
95
96 return $dirty;
97 }
98
99 public function listen() {
100 if ( isset( $_GET['_hf_admin_action'] ) ) {
101 $action = (string) $_GET['_hf_admin_action'];
102 } elseif ( isset( $_POST['_hf_admin_action'] ) ) {
103 $action = (string) $_POST['_hf_admin_action'];
104 } else {
105 return;
106 }
107
108 // verify nonce
109 if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], '_hf_admin_action' ) ) {
110 wp_nonce_ays( $action );
111 exit;
112 }
113
114 // do nothing if logged in user is not of role administrator
115 if ( ! current_user_can( 'edit_forms' ) ) {
116 return;
117 }
118
119 /**
120 * Allows you to hook into requests containing `_hf_admin_action` => action name.
121 *
122 * The dynamic portion of the hook name, `$action`, refers to the action name.
123 *
124 * By the time this hook is fired, the user is already authorized. After processing all the registered hooks,
125 * the request is redirected back to the referring URL.
126 *
127 * @since 3.0
128 */
129 do_action( 'hf_admin_action_' . $action );
130
131 // redirect back to where we came from
132 $redirect_url = ! empty( $_REQUEST['_redirect_to'] ) ? $_REQUEST['_redirect_to'] : remove_query_arg( '_hf_admin_action' );
133 wp_safe_redirect( $redirect_url );
134 exit;
135 }
136
137 public function assets() {
138 if ( empty( $_GET['page'] ) || strpos( $_GET['page'], 'html-forms' ) !== 0 ) {
139 return;
140 }
141
142 $settings = hf_get_settings();
143
144 wp_enqueue_style( 'html-forms-admin', plugins_url( 'assets/css/admin.css', $this->plugin_file ), array(), HTML_FORMS_VERSION );
145 wp_enqueue_script( 'html-forms-admin', plugins_url( 'assets/js/admin.js', $this->plugin_file ), array(), HTML_FORMS_VERSION, true );
146 wp_localize_script(
147 'html-forms-admin',
148 'hf_options',
149 array(
150 'page' => $_GET['page'],
151 'view' => empty( $_GET['view'] ) ? '' : $_GET['view'],
152 'form_id' => empty( $_GET['form_id'] ) ? 0 : (int) $_GET['form_id'],
153 'wrapper_tag' => empty( $settings['wrapper_tag'] ) ? 'p' : $settings['wrapper_tag'],
154 )
155 );
156 }
157
158 public function menu() {
159 $capability = 'edit_forms';
160 $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)"
161 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>';
162 add_menu_page(
163 'HTML Forms',
164 'HTML Forms',
165 $capability,
166 'html-forms',
167 array(
168 $this,
169 'page_overview',
170 ),
171 'data:image/svg+xml;base64,' . base64_encode( $svg_icon ),
172 '99.88491'
173 );
174 add_submenu_page(
175 'html-forms',
176 __( 'Forms', 'html-forms' ),
177 __( 'All Forms', 'html-forms' ),
178 $capability,
179 'html-forms',
180 array(
181 $this,
182 'page_overview',
183 )
184 );
185 add_submenu_page(
186 'html-forms',
187 __( 'Add New Form', 'html-forms' ),
188 __( 'Add New', 'html-forms' ),
189 $capability,
190 'html-forms-add-form',
191 array(
192 $this,
193 'page_new_form',
194 )
195 );
196 add_submenu_page(
197 'html-forms',
198 __( 'Settings', 'html-forms' ),
199 __( 'Settings', 'html-forms' ),
200 $capability,
201 'html-forms-settings',
202 array(
203 $this,
204 'page_settings',
205 )
206 );
207
208 if ( ! defined( 'HF_PREMIUM_VERSION' ) ) {
209 add_submenu_page(
210 'html-forms',
211 'Premium',
212 '<span style="color: #ea6ea6;">Premium</span>',
213 $capability,
214 'html-forms-premium',
215 array(
216 $this,
217 'page_premium',
218 )
219 );
220 }
221 }
222
223 public function add_screen_options() {
224 // only run on the submissions overview page (not detail)
225 if ( empty( $_GET['page'] ) || $_GET['page'] !== 'html-forms' || empty( $_GET['view'] ) || $_GET['view'] !== 'edit' || empty( $_GET['form_id'] ) || ! empty( $_GET['submission_id'] ) ) {
226 return;
227 }
228
229 // don't run if form does not have submissions enabled
230 $form = hf_get_form( $_GET['form_id'] );
231 if ( ! $form->settings['save_submissions'] ) {
232 return;
233 }
234
235 // tell screen options to show columns option
236 $submissions = hf_get_form_submissions( $_GET['form_id'] );
237 $columns = $this->get_submission_columns( $submissions );
238 add_filter(
239 'manage_toplevel_page_html-forms_columns',
240 function ( $unused ) use ( $columns ) {
241 return $columns;
242 }
243 );
244 add_screen_option( 'layout_columns' );
245 }
246
247 public function page_overview() {
248 if ( ! empty( $_GET['view'] ) && $_GET['view'] === 'edit' ) {
249 $this->page_edit_form();
250
251 return;
252 }
253
254 $settings = hf_get_settings();
255
256 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
257 $table = new Table( $settings );
258
259 require dirname( $this->plugin_file ) . '/views/page-overview.php';
260 }
261
262 public function page_new_form() {
263 require dirname( $this->plugin_file ) . '/views/page-add-form.php';
264 }
265
266 public function page_settings() {
267 $settings = hf_get_settings();
268 $wrapper_tags = array ( 'p', 'div', 'span' );
269
270 require dirname( $this->plugin_file ) . '/views/page-global-settings.php';
271 }
272
273 public function page_premium() {
274 require dirname( $this->plugin_file ) . '/views/page-premium.php';
275 }
276
277 public function page_edit_form() {
278 $active_tab = ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'fields';
279 $form_id = (int) $_GET['form_id'];
280 $form = hf_get_form( $form_id );
281 $settings = hf_get_settings();
282 require dirname( $this->plugin_file ) . '/views/page-edit-form.php';
283 }
284
285 public function tab_fields( Form $form ) {
286 $form_preview_url = add_query_arg(
287 array(
288 'hf_preview_form' => $form->ID,
289 ),
290 site_url( '/', 'admin' )
291 );
292 require dirname( $this->plugin_file ) . '/views/tab-fields.php';
293 }
294
295 public function tab_messages( Form $form ) {
296 require dirname( $this->plugin_file ) . '/views/tab-messages.php';
297 }
298
299
300 public function tab_settings( Form $form ) {
301 require dirname( $this->plugin_file ) . '/views/tab-settings.php';
302 }
303
304
305 public function tab_actions( Form $form ) {
306 require dirname( $this->plugin_file ) . '/views/tab-actions.php';
307 }
308
309 public function get_submission_columns( array $submissions ) {
310 $columns = array();
311 foreach ( $submissions as $s ) {
312 if ( ! is_array( $s->data ) ) {
313 continue;
314 }
315
316 foreach ( $s->data as $field => $value ) {
317 if ( ! isset( $columns[ $field ] ) ) {
318 $columns[ $field ] = esc_html( ucfirst( strtolower( str_replace( '_', ' ', $field ) ) ) );
319 }
320 }
321 }
322
323 return $columns;
324 }
325
326 public function tab_submissions_list( Form $form ) {
327 if ( ! empty( $_GET['submission_id'] ) ) {
328 return;
329 }
330
331 $items_per_page = 500;
332 $total_items = hf_count_form_submissions( $form->ID );
333 $total_pages = max( 1, ceil( $total_items / $items_per_page ) );
334 $current_page = isset( $_GET['paged'] ) ? intval( $_GET['paged'] ) : 1;
335 $current_page = max( 1, $current_page );
336 $current_page = min( $total_pages, $current_page );
337 $submissions = hf_get_form_submissions(
338 $form->ID,
339 array(
340 'limit' => $items_per_page,
341 'offset' => ( $current_page - 1 ) * $items_per_page,
342 )
343 );
344 $columns = $this->get_submission_columns( $submissions );
345 $hidden_columns = get_hidden_columns( get_current_screen() );
346
347 require dirname( $this->plugin_file ) . '/views/tab-submissions-list.php';
348 }
349
350 public function tab_submissions_detail( Form $form ) {
351 if ( empty( $_GET['submission_id'] ) ) {
352 return;
353 }
354
355 $submission = hf_get_form_submission( (int) $_GET['submission_id'] );
356 do_action( 'hf_admin_form_submissions_detail', $submission );
357 require dirname( $this->plugin_file ) . '/views/tab-submissions-detail.php';
358 }
359
360 public function process_create_form() {
361 // Fix for MultiSite stripping KSES for roles other than administrator
362 remove_all_filters( 'content_save_pre' );
363
364 $data = $_POST['form'];
365 $form_title = sanitize_text_field( $data['title'] );
366 $form_id = wp_insert_post(
367 array(
368 'post_type' => 'html-form',
369 'post_status' => 'publish',
370 'post_title' => $form_title,
371 'post_content' => $this->get_default_form_content(),
372 )
373 );
374
375 wp_safe_redirect( admin_url( 'admin.php?page=html-forms&view=edit&form_id=' . $form_id ) );
376 exit;
377 }
378
379 public function process_save_form() {
380 $form_id = (int) $_POST['form_id'];
381 $form = hf_get_form( $form_id );
382 $data = $_POST['form'];
383
384 // Fix for MultiSite stripping KSES for roles other than administrator
385 remove_all_filters( 'content_save_pre' );
386
387 // run our own kses filter
388 if ( ! current_user_can( 'unfiltered_html' ) ) {
389 $data['markup'] = $this->kses( $data['markup'] );
390 }
391
392 // strip <form> tag from markup
393 $data['markup'] = preg_replace( '/<\/?form(.|\s)*?>/i', '', $data['markup'] );
394
395 $form_id = wp_insert_post(
396 array(
397 'ID' => $form_id,
398 'post_type' => 'html-form',
399 'post_status' => 'publish',
400 'post_title' => sanitize_text_field( $data['title'] ),
401 'post_content' => $data['markup'],
402 'post_name' => sanitize_title_with_dashes( $data['slug'] ),
403 )
404 );
405
406 if ( ! empty( $data['settings'] ) ) {
407 update_post_meta( $form_id, '_hf_settings', $data['settings'] );
408 }
409
410 // save form messages in individual meta keys
411 foreach ( $data['messages'] as $key => $message ) {
412 if ( current_user_can( 'unfiltered_html' ) ) {
413 update_post_meta( $form_id, 'hf_message_' . $key, $message );
414 } else {
415 update_post_meta( $form_id, 'hf_message_' . $key, wp_kses_post( $message ) );
416 }
417 }
418
419 $redirect_url_args = array(
420 'form_id' => $form_id,
421 'saved' => 1,
422 );
423 $redirect_url = add_query_arg( $redirect_url_args, admin_url( 'admin.php?page=html-forms&view=edit' ) );
424 wp_safe_redirect( $redirect_url );
425 exit;
426 }
427
428 /**
429 * Get URL for a tab on the current page.
430 *
431 * @param $tab
432 *
433 * @return string
434 * @since 3.0
435 * @internal
436 */
437 public function get_tab_url( $tab ) {
438 $tab_url = add_query_arg( array( 'tab' => $tab ), remove_query_arg( 'tab' ) );
439
440 $url_parts = parse_url($tab_url);
441 if ( isset( $url_parts['query'] ) ) {
442 parse_str( $url_parts['query'], $query_params );
443
444 if ( isset( $query_params['submission_id'] ) ) {
445 unset( $query_params['submission_id'] );
446 }
447
448 $new_query = http_build_query( $query_params );
449 $new_tab_url = $url_parts['path'];
450
451 if ( ! empty( $new_query ) ) {
452 $new_tab_url .= '?' . $new_query;
453 }
454
455 return $new_tab_url;
456 }
457
458 return $tab_url;
459 }
460
461 /**
462 * @return array
463 */
464 public function get_available_form_actions() {
465 $actions = array();
466
467 /**
468 * Filters the available form actions
469 *
470 * @param array $actions
471 */
472 $actions = apply_filters( 'hf_available_form_actions', $actions );
473
474 return $actions;
475 }
476
477 public function process_bulk_delete_submissions() {
478 global $wpdb;
479
480 if ( empty( $_POST['id'] ) ) {
481 return;
482 }
483
484 $args = array_map( 'intval', $_POST['id'] );
485 $table = $wpdb->prefix . 'hf_submissions';
486 $placeholders = rtrim( str_repeat( '%d,', count( $args ) ), ',' );
487 $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE id IN( {$placeholders} );", $args ) );
488
489 $args[] = '_hf_%%';
490 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN ( {$placeholders} ) AND meta_key LIKE %s;", $args ) );
491 }
492
493 private function get_default_form_content() {
494 $settings = hf_get_settings();
495 $wrapper_tag = ( isset( $settings['wrapper_tag'] ) ) ? $settings['wrapper_tag'] : 'p';
496
497 $html = '';
498 $html .= sprintf( "<%1\$s>\n\t<label>%2\$s</label>\n\t<input type=\"text\" name=\"NAME\" placeholder=\"%2\$s\" required />\n</%1\$s>", $wrapper_tag, __( 'Your name', 'html-forms' ) ) . PHP_EOL;
499 $html .= sprintf( "<%1\$s>\n\t<label>%2\$s</label>\n\t<input type=\"email\" name=\"EMAIL\" placeholder=\"%2\$s\" required />\n</%1\$s>", $wrapper_tag, __( 'Your email', 'html-forms' ) ) . PHP_EOL;
500 $html .= sprintf( "<%1\$s>\n\t<label>%2\$s</label>\n\t<input type=\"text\" name=\"SUBJECT\" placeholder=\"%2\$s\" required />\n</%1\$s>", $wrapper_tag, __( 'Subject', 'html-forms' ) ) . PHP_EOL;
501 $html .= sprintf( "<%1\$s>\n\t<label>%2\$s</label>\n\t<textarea name=\"MESSAGE\" placeholder=\"%2\$s\" required></textarea>\n</%1\$s>", $wrapper_tag, __( 'Message', 'html-forms' ) ) . PHP_EOL;
502 $html .= sprintf( "<%1\$s>\n\t<input type=\"submit\" value=\"%2\$s\" />\n</%1\$s>", $wrapper_tag, __( 'Send', 'html-forms' ) );
503
504 return $html;
505 }
506
507 /**
508 * Filters string and strips out all HTML tags and attributes, except what's in our whitelist.
509 *
510 * @param string $string The string to apply KSES whitelist on
511 * @return string
512 */
513 private function kses( $string ) {
514 $always_allowed_attr = array_fill_keys(
515 array(
516 'aria-describedby',
517 'aria-details',
518 'aria-label',
519 'aria-labelledby',
520 'aria-hidden',
521 'aria-*',
522 'class',
523 'id',
524 'style',
525 'title',
526 'role',
527 'data-*',
528 'data-confirm',
529 'tabindex',
530 ),
531 true
532 );
533 $input_allowed_attr = array_merge(
534 $always_allowed_attr,
535 array_fill_keys(
536 array(
537 'type',
538 'required',
539 'placeholder',
540 'value',
541 'name',
542 'step',
543 'min',
544 'max',
545 'checked',
546 'width',
547 'autocomplete',
548 'autofocus',
549 'minlength',
550 'maxlength',
551 'size',
552 'pattern',
553 'disabled',
554 'readonly',
555 ),
556 true
557 )
558 );
559
560 $allowed = array(
561 'p' => $always_allowed_attr,
562 'label' => array_merge( $always_allowed_attr, array( 'for' => true ) ),
563 'input' => $input_allowed_attr,
564 'button' => $input_allowed_attr,
565 'fieldset' => $always_allowed_attr,
566 'legend' => $always_allowed_attr,
567 'ul' => $always_allowed_attr,
568 'ol' => $always_allowed_attr,
569 'li' => $always_allowed_attr,
570 'select' => array_merge( $input_allowed_attr, array( 'multiple' => true ) ),
571 'option' => array_merge( $input_allowed_attr, array( 'selected' => true ) ),
572 'optgroup' => array(
573 'disabled' => true,
574 'label' => true,
575 ),
576 'textarea' => array_merge(
577 $input_allowed_attr,
578 array(
579 'rows' => true,
580 'cols' => true,
581 )
582 ),
583 'div' => $always_allowed_attr,
584 'strong' => $always_allowed_attr,
585 'b' => $always_allowed_attr,
586 'i' => $always_allowed_attr,
587 'br' => array(),
588 'em' => $always_allowed_attr,
589 'span' => $always_allowed_attr,
590 'a' => array_merge( $always_allowed_attr, array( 'href' => true ) ),
591 'img' => array_merge(
592 $always_allowed_attr,
593 array(
594 'src' => true,
595 'alt' => true,
596 'width' => true,
597 'height' => true,
598 'srcset' => true,
599 'sizes' => true,
600 'referrerpolicy' => true,
601 'loading' => true,
602 'decoding' => true,
603 )
604 ),
605 'u' => $always_allowed_attr,
606 'table' => $always_allowed_attr,
607 'tr' => $always_allowed_attr,
608 'td' => $always_allowed_attr,
609 'th' => $always_allowed_attr,
610 'thead' => $always_allowed_attr,
611 'tbody' => $always_allowed_attr,
612 'picture' => $always_allowed_attr,
613 'video' => $always_allowed_attr,
614 );
615
616 return wp_kses( $string, $allowed );
617 }
618 }
619