PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.3.34
HTML Forms – Simple WordPress Forms Plugin v1.3.34
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.3.34, at src/admin/class-admin.php

608 lines 17.6 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 return $dirty;
93 }
94
95 public function listen() {
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 {
101 return;
102 }
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
110 // do nothing if logged in user is not of role administrator
111 if ( ! current_user_can( 'edit_forms' ) ) {
112 return;
113 }
114
115 /**
116 * Allows you to hook into requests containing `_hf_admin_action` => action name.
117 *
118 * The dynamic portion of the hook name, `$action`, refers to the action name.
119 *
120 * By the time this hook is fired, the user is already authorized. After processing all the registered hooks,
121 * the request is redirected back to the referring URL.
122 *
123 * @since 3.0
124 */
125 do_action( 'hf_admin_action_' . $action );
126
127 // redirect back to where we came from
128 $redirect_url = ! empty( $_REQUEST['_redirect_to'] ) ? $_REQUEST['_redirect_to'] : remove_query_arg( '_hf_admin_action' );
129 wp_safe_redirect( $redirect_url );
130 exit;
131 }
132
133 public function assets() {
134 if ( empty( $_GET['page'] ) || strpos( $_GET['page'], 'html-forms' ) !== 0 ) {
135 return;
136 }
137
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 );
140 wp_localize_script(
141 'html-forms-admin',
142 'hf_options',
143 array(
144 'page' => $_GET['page'],
145 'view' => empty( $_GET['view'] ) ? '' : $_GET['view'],
146 'form_id' => empty( $_GET['form_id'] ) ? 0 : (int) $_GET['form_id'],
147 )
148 );
149 }
150
151 public function menu() {
152 $capability = 'edit_forms';
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)"
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>';
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 );
200
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 }
214 }
215
216 public function add_screen_options() {
217 // only run on the submissions overview page (not detail)
218 if ( empty( $_GET['page'] ) || $_GET['page'] !== 'html-forms' || empty( $_GET['view'] ) || $_GET['view'] !== 'edit' || empty( $_GET['form_id'] ) || ! empty( $_GET['submission_id'] ) ) {
219 return;
220 }
221
222 // don't run if form does not have submissions enabled
223 $form = hf_get_form( $_GET['form_id'] );
224 if ( ! $form->settings['save_submissions'] ) {
225 return;
226 }
227
228 // tell screen options to show columns option
229 $submissions = hf_get_form_submissions( $_GET['form_id'] );
230 $columns = $this->get_submission_columns( $submissions );
231 add_filter(
232 'manage_toplevel_page_html-forms_columns',
233 function ( $unused ) use ( $columns ) {
234 return $columns;
235 }
236 );
237 add_screen_option( 'layout_columns' );
238 }
239
240 public function page_overview() {
241 if ( ! empty( $_GET['view'] ) && $_GET['view'] === 'edit' ) {
242 $this->page_edit_form();
243
244 return;
245 }
246
247 $settings = hf_get_settings();
248
249 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
250 $table = new Table( $settings );
251
252 require dirname( $this->plugin_file ) . '/views/page-overview.php';
253 }
254
255 public function page_new_form() {
256 require dirname( $this->plugin_file ) . '/views/page-add-form.php';
257 }
258
259 public function page_settings() {
260 $settings = hf_get_settings();
261 require dirname( $this->plugin_file ) . '/views/page-global-settings.php';
262 }
263
264 public function page_premium() {
265 require dirname( $this->plugin_file ) . '/views/page-premium.php';
266 }
267
268 public function page_edit_form() {
269 $active_tab = ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'fields';
270 $form_id = (int) $_GET['form_id'];
271 $form = hf_get_form( $form_id );
272 $settings = hf_get_settings();
273 require dirname( $this->plugin_file ) . '/views/page-edit-form.php';
274 }
275
276 public function tab_fields( Form $form ) {
277 $form_preview_url = add_query_arg(
278 array(
279 'hf_preview_form' => $form->ID,
280 ),
281 site_url( '/', 'admin' )
282 );
283 require dirname( $this->plugin_file ) . '/views/tab-fields.php';
284 }
285
286 public function tab_messages( Form $form ) {
287 require dirname( $this->plugin_file ) . '/views/tab-messages.php';
288 }
289
290
291 public function tab_settings( Form $form ) {
292 require dirname( $this->plugin_file ) . '/views/tab-settings.php';
293 }
294
295
296 public function tab_actions( Form $form ) {
297 require dirname( $this->plugin_file ) . '/views/tab-actions.php';
298 }
299
300 public function get_submission_columns( array $submissions ) {
301 $columns = array();
302 foreach ( $submissions as $s ) {
303 if ( ! is_array( $s->data ) ) {
304 continue;
305 }
306
307 foreach ( $s->data as $field => $value ) {
308 if ( ! isset( $columns[ $field ] ) ) {
309 $columns[ $field ] = esc_html( ucfirst( strtolower( str_replace( '_', ' ', $field ) ) ) );
310 }
311 }
312 }
313
314 return $columns;
315 }
316
317 public function tab_submissions_list( Form $form ) {
318 if ( ! empty( $_GET['submission_id'] ) ) {
319 return;
320 }
321
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 );
335 $columns = $this->get_submission_columns( $submissions );
336 $hidden_columns = get_hidden_columns( get_current_screen() );
337
338 require dirname( $this->plugin_file ) . '/views/tab-submissions-list.php';
339 }
340
341 public function tab_submissions_detail( Form $form ) {
342 if ( empty( $_GET['submission_id'] ) ) {
343 return;
344 }
345
346 $submission = hf_get_form_submission( (int) $_GET['submission_id'] );
347 require dirname( $this->plugin_file ) . '/views/tab-submissions-detail.php';
348 }
349
350
351 public function process_create_form() {
352 // Fix for MultiSite stripping KSES for roles other than administrator
353 remove_all_filters( 'content_save_pre' );
354
355 $data = $_POST['form'];
356 $form_title = sanitize_text_field( $data['title'] );
357 $form_id = wp_insert_post(
358 array(
359 'post_type' => 'html-form',
360 'post_status' => 'publish',
361 'post_title' => $form_title,
362 'post_content' => $this->get_default_form_content(),
363 )
364 );
365
366 wp_safe_redirect( admin_url( 'admin.php?page=html-forms&view=edit&form_id=' . $form_id ) );
367 exit;
368 }
369
370 public function process_save_form() {
371 $form_id = (int) $_POST['form_id'];
372 $form = hf_get_form( $form_id );
373 $data = $_POST['form'];
374
375 // Fix for MultiSite stripping KSES for roles other than administrator
376 remove_all_filters( 'content_save_pre' );
377
378 // run our own kses filter
379 if ( ! current_user_can( 'unfiltered_html' ) ) {
380 $data['markup'] = $this->kses( $data['markup'] );
381 }
382
383 // strip <form> tag from markup
384 $data['markup'] = preg_replace( '/<\/?form(.|\s)*?>/i', '', $data['markup'] );
385
386 $form_id = wp_insert_post(
387 array(
388 'ID' => $form_id,
389 'post_type' => 'html-form',
390 'post_status' => 'publish',
391 'post_title' => sanitize_text_field( $data['title'] ),
392 'post_content' => $data['markup'],
393 'post_name' => sanitize_title_with_dashes( $data['slug'] ),
394 )
395 );
396
397 if ( ! empty( $data['settings'] ) ) {
398 update_post_meta( $form_id, '_hf_settings', $data['settings'] );
399 }
400
401 // save form messages in individual meta keys
402 foreach ( $data['messages'] as $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 }
408 }
409
410 $redirect_url_args = array(
411 'form_id' => $form_id,
412 'saved' => 1,
413 );
414 $redirect_url = add_query_arg( $redirect_url_args, admin_url( 'admin.php?page=html-forms&view=edit' ) );
415 wp_safe_redirect( $redirect_url );
416 exit;
417 }
418
419 /**
420 * Get URL for a tab on the current page.
421 *
422 * @param $tab
423 *
424 * @return string
425 * @since 3.0
426 * @internal
427 */
428 public function get_tab_url( $tab ) {
429 $tab_url = add_query_arg( array( 'tab' => $tab ), remove_query_arg( 'tab' ) );
430
431 $url_parts = parse_url($tab_url);
432 if ( isset( $url_parts['query'] ) ) {
433 parse_str( $url_parts['query'], $query_params );
434
435 if ( isset( $query_params['submission_id'] ) ) {
436 unset( $query_params['submission_id'] );
437 }
438
439 $new_query = http_build_query( $query_params );
440 $new_tab_url = $url_parts['path'];
441
442 if ( ! empty( $new_query ) ) {
443 $new_tab_url .= '?' . $new_query;
444 }
445
446 return $new_tab_url;
447 }
448
449 return $tab_url;
450 }
451
452 /**
453 * @return array
454 */
455 public function get_available_form_actions() {
456 $actions = array();
457
458 /**
459 * Filters the available form actions
460 *
461 * @param array $actions
462 */
463 $actions = apply_filters( 'hf_available_form_actions', $actions );
464
465 return $actions;
466 }
467
468 public function process_bulk_delete_submissions() {
469 global $wpdb;
470
471 if ( empty( $_POST['id'] ) ) {
472 return;
473 }
474
475 $args = array_map( 'intval', $_POST['id'] );
476 $table = $wpdb->prefix . 'hf_submissions';
477 $placeholders = rtrim( str_repeat( '%d,', count( $args ) ), ',' );
478 $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE id IN( {$placeholders} );", $args ) );
479
480 $args[] = '_hf_%%';
481 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN ( {$placeholders} ) AND meta_key LIKE %s;", $args ) );
482 }
483
484 private function get_default_form_content() {
485 $html = '';
486 $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;
487 $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;
488 $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;
489 $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;
490 $html .= sprintf( "<p>\n\t<input type=\"submit\" value=\"%s\" />\n</p>", __( 'Send', 'html-forms' ) );
491
492 return $html;
493 }
494
495
496 /**
497 * Filters string and strips out all HTML tags and attributes, except what's in our whitelist.
498 *
499 * @param string $string The string to apply KSES whitelist on
500 * @return string
501 */
502 private function kses( $string ) {
503 $always_allowed_attr = array_fill_keys(
504 array(
505 'aria-describedby',
506 'aria-details',
507 'aria-label',
508 'aria-labelledby',
509 'aria-hidden',
510 'aria-*',
511 'class',
512 'id',
513 'style',
514 'title',
515 'role',
516 'data-*',
517 'data-confirm',
518 'tabindex',
519 ),
520 true
521 );
522 $input_allowed_attr = array_merge(
523 $always_allowed_attr,
524 array_fill_keys(
525 array(
526 'type',
527 'required',
528 'placeholder',
529 'value',
530 'name',
531 'step',
532 'min',
533 'max',
534 'checked',
535 'width',
536 'autocomplete',
537 'autofocus',
538 'minlength',
539 'maxlength',
540 'size',
541 'pattern',
542 'disabled',
543 'readonly',
544 ),
545 true
546 )
547 );
548
549 $allowed = array(
550 'p' => $always_allowed_attr,
551 'label' => array_merge( $always_allowed_attr, array( 'for' => true ) ),
552 'input' => $input_allowed_attr,
553 'button' => $input_allowed_attr,
554 'fieldset' => $always_allowed_attr,
555 'legend' => $always_allowed_attr,
556 'ul' => $always_allowed_attr,
557 'ol' => $always_allowed_attr,
558 'li' => $always_allowed_attr,
559 'select' => array_merge( $input_allowed_attr, array( 'multiple' => true ) ),
560 'option' => array_merge( $input_allowed_attr, array( 'selected' => true ) ),
561 'optgroup' => array(
562 'disabled' => true,
563 'label' => true,
564 ),
565 'textarea' => array_merge(
566 $input_allowed_attr,
567 array(
568 'rows' => true,
569 'cols' => true,
570 )
571 ),
572 'div' => $always_allowed_attr,
573 'strong' => $always_allowed_attr,
574 'b' => $always_allowed_attr,
575 'i' => $always_allowed_attr,
576 'br' => array(),
577 'em' => $always_allowed_attr,
578 'span' => $always_allowed_attr,
579 'a' => array_merge( $always_allowed_attr, array( 'href' => true ) ),
580 'img' => array_merge(
581 $always_allowed_attr,
582 array(
583 'src' => true,
584 'alt' => true,
585 'width' => true,
586 'height' => true,
587 'srcset' => true,
588 'sizes' => true,
589 'referrerpolicy' => true,
590 'loading' => true,
591 'decoding' => true,
592 )
593 ),
594 'u' => $always_allowed_attr,
595 'table' => $always_allowed_attr,
596 'tr' => $always_allowed_attr,
597 'td' => $always_allowed_attr,
598 'th' => $always_allowed_attr,
599 'thead' => $always_allowed_attr,
600 'tbody' => $always_allowed_attr,
601 'picture' => $always_allowed_attr,
602 'video' => $always_allowed_attr,
603 );
604
605 return wp_kses( $string, $allowed );
606 }
607 }
608