PluginProbe
Property Hive / 2.3.0
Property Hive v2.3.0
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
propertyhive / includes / admin / class-ph-admin-settings.php

class-ph-admin-settings.php in Property Hive 2.3.0, at includes/admin/class-ph-admin-settings.php

986 lines 39.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] ph_clean
3 // ph_clean() recursively sanitizes text; presence, shape and unslashing checks remain separate.
4
5 /**
6 * PropertyHive Admin Settings Class.
7 *
8 * @author PropertyHive
9 * @category Admin
10 * @package PropertyHive/Admin
11 * @version 1.0.0
12 */
13
14 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
15
16 if ( ! class_exists( 'PH_Admin_Settings' ) ) :
17
18 /**
19 * PH_Admin_Settings
20 */
21 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Legacy public global class PH_Admin_Settings; preserving the existing PH_* class name is required for plugin and extension compatibility.
22 class PH_Admin_Settings {
23
24 private static $settings = array();
25 private static $errors = array();
26 private static $messages = array();
27
28 /**
29 * Include the settings page classes
30 */
31 public static function get_settings_pages() {
32 if ( empty( self::$settings ) ) {
33 $settings = array();
34
35 include_once( 'settings/class-ph-settings-page.php' );
36
37 $settings[] = include( 'settings/class-ph-settings-general.php' );
38 $settings[] = include( 'settings/class-ph-settings-offices.php' );
39 $settings[] = include( 'settings/class-ph-settings-custom-fields.php' );
40 $settings[] = include( 'settings/class-ph-settings-frontend.php' );
41 $settings[] = include( 'settings/class-ph-settings-emails.php' );
42 $settings[] = include( 'settings/class-ph-settings-features.php' );
43 $settings[] = include( 'settings/class-ph-settings-licenses.php' );
44
45 // Only show demo data tab if demo data add on not active, tab not dismissed and if newly installed since 2021-04-13 00:00:00
46 if (
47 !class_exists('PH_Demo_Data') &&
48 get_option( 'propertyhive_install_timestamp', '' ) >= 1618268400 &&
49 get_option( 'propertyhive_hide_demo_data_tab', '' ) != 'yes'
50 )
51 {
52 $settings[] = include( 'settings/class-ph-settings-demo-data.php' );
53 }
54
55 self::$settings = apply_filters( 'propertyhive_get_settings_pages', $settings );
56 }
57 return self::$settings;
58 }
59
60 /**
61 * Save the settings
62 */
63 public static function save() {
64 global $current_section, $current_tab;
65
66 if ( ! current_user_can( 'manage_options' ) ) {
67 wp_die( esc_html__( 'Insufficient permissions', 'propertyhive' ), '', array( 'response' => 403 ) );
68 }
69
70 if ( empty( $_REQUEST['_wpnonce'] ) || ! is_string( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'propertyhive-settings' ) )
71 die( esc_html(__( 'Action failed. Please refresh the page and retry.', 'propertyhive' )) );
72
73 // Trigger actions
74 do_action( 'propertyhive_settings_save_' . $current_tab );
75 do_action( 'propertyhive_update_options_' . $current_tab );
76 do_action( 'propertyhive_update_options' );
77
78 self::add_message( __( 'Your settings have been saved.', 'propertyhive' ) );
79
80 update_option( 'propertyhive_queue_flush_rewrite_rules', 'yes' );
81
82 do_action( 'propertyhive_settings_saved' );
83 }
84
85 /**
86 * Add a message
87 * @param string $text
88 */
89 public static function add_message( $text ) {
90 self::$messages[] = $text;
91 }
92
93 /**
94 * Add an error
95 * @param string $text
96 */
97 public static function add_error( $text ) {
98 self::$errors[] = $text;
99 }
100
101 /**
102 * Output messages + errors
103 */
104 public static function show_messages() {
105 if ( sizeof( self::$errors ) > 0 ) {
106 foreach ( self::$errors as $error )
107 {
108 $allowed_tags = array(
109 'a' => array(
110 'href' => array(),
111 ),
112 );
113
114 $error = wp_kses($error, $allowed_tags);
115
116 echo '<div id="message" class="error fade"><p><strong>' . wp_kses( $error, $allowed_tags ) . '</strong></p></div>';
117 }
118 } elseif ( sizeof( self::$messages ) > 0 ) {
119 foreach ( self::$messages as $message )
120 {
121 $allowed_tags = array(
122 'a' => array(
123 'href' => array(),
124 ),
125 );
126
127 $message = wp_kses($message, $allowed_tags);
128
129 echo '<div id="message" class="updated fade"><p><strong>' . wp_kses( $message, $allowed_tags ) . '</strong></p></div>';
130 }
131 }
132 }
133
134 /**
135 * Settings page.
136 *
137 * Handles the display of the main propertyhive settings page in admin.
138 *
139 * @access public
140 * @return void
141 */
142 public static function output() {
143 global $current_section, $current_tab, $redirect_after_save;
144
145 do_action( 'propertyhive_settings_start' );
146
147 //wp_enqueue_script( 'propertyhive_settings', PH()->plugin_url() . '/assets/js/admin/settings.min.js', array( 'jquery'/*, 'jquery-ui-datepicker', 'jquery-ui-sortable', 'iris', 'chosen'*/ ), PH()->version, true );
148
149 /*wp_localize_script( 'propertyhive_settings', 'propertyhive_settings_params', array(
150 'i18n_nav_warning' => __( 'The changes you made will be lost if you navigate away from this page.', 'propertyhive' )
151 ) );*/
152
153 // Include settings pages
154 self::get_settings_pages();
155
156 // Get current tab/section
157 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- These values only select the read-only settings view; settings writes are handled by save_fields() after the settings nonce and capability checks.
158 $request_get = wp_unslash( $_GET );
159 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- These values only select the read-only settings view; settings writes are handled by save_fields() after the settings nonce and capability checks.
160 $request_request = wp_unslash( $_REQUEST );
161 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Shared admin settings-view state; this global is intentionally used to control the common settings template and is not an arbitrary application global.
162 $current_tab = ( isset( $request_get['tab'] ) && is_string( $request_get['tab'] ) && '' !== $request_get['tab'] ) ? sanitize_title( $request_get['tab'] ) : 'general';
163 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Shared admin settings-view state; this global is intentionally used to control the common settings template and is not an arbitrary application global.
164 $current_section = ( isset( $request_request['section'] ) && is_string( $request_request['section'] ) ) ? sanitize_title( $request_request['section'] ) : '';
165
166 // Save settings if data has been posted
167 //if ( ! empty( $_POST ) )
168 // self::save();
169
170 // Add any posted messages
171 $message_allowed_tags = array(
172 'a' => array(
173 'href' => array(),
174 ),
175 );
176 if ( isset( $request_get['ph_error'] ) && is_scalar( $request_get['ph_error'] ) && '' !== (string) $request_get['ph_error'] )
177 self::add_error( wp_kses( (string) $request_get['ph_error'], $message_allowed_tags ) );
178
179 if ( isset( $request_get['ph_message'] ) && is_scalar( $request_get['ph_message'] ) && '' !== (string) $request_get['ph_message'] )
180 self::add_message( wp_kses( (string) $request_get['ph_message'], $message_allowed_tags ) );
181
182 self::show_messages();
183
184 // Get tabs for the settings page
185 $tabs = apply_filters( 'propertyhive_settings_tabs_array', array() );
186
187 include 'views/html-admin-settings.php';
188 }
189
190 /**
191 * Get a setting from the settings API.
192 *
193 * @param mixed $option
194 * @return string
195 */
196 public static function get_option( $option_name, $default = '' ) {
197 // Array value
198 if ( strstr( $option_name, '[' ) ) {
199
200 parse_str( $option_name, $option_array );
201
202 // Option name is first key
203 $option_name = current( array_keys( $option_array ) );
204
205 // Get value
206 $option_values = get_option( $option_name, '' );
207
208 $key = key( $option_array[ $option_name ] );
209
210 if ( isset( $option_values[ $key ] ) )
211 $option_value = $option_values[ $key ];
212 else
213 $option_value = null;
214
215 // Single value
216 } else {
217 $option_value = get_option( $option_name, null );
218 }
219
220 if ( is_array( $option_value ) )
221 $option_value = array_map( 'stripslashes', $option_value );
222 elseif ( ! is_null( $option_value ) )
223 $option_value = stripslashes( $option_value );
224
225 return $option_value === null ? $default : $option_value;
226 }
227
228 /**
229 * Output admin fields.
230 *
231 * Loops though the propertyhive options array and outputs each field.
232 *
233 * @access public
234 * @param array $options Opens array to output
235 */
236 public static function output_fields( $options ) {
237 foreach ( $options as $value ) {
238 if ( ! isset( $value['type'] ) ) continue;
239 if ( ! isset( $value['id'] ) ) $value['id'] = '';
240 if ( ! isset( $value['title'] ) ) $value['title'] = isset( $value['name'] ) ? $value['name'] : '';
241 if ( ! isset( $value['class'] ) ) $value['class'] = '';
242 if ( ! isset( $value['css'] ) ) $value['css'] = '';
243 if ( ! isset( $value['default'] ) ) $value['default'] = '';
244 if ( ! isset( $value['desc'] ) ) $value['desc'] = '';
245 if ( ! isset( $value['desc_tip'] ) ) $value['desc_tip'] = false;
246
247 // Custom attribute handling
248 $custom_attributes = array();
249
250 if ( ! empty( $value['custom_attributes'] ) && is_array( $value['custom_attributes'] ) )
251 foreach ( $value['custom_attributes'] as $attribute => $attribute_value )
252 $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
253
254 // Description handling
255 if ( $value['desc_tip'] === true ) {
256 $description = '';
257 $tip = $value['desc'];
258 } elseif ( ! empty( $value['desc_tip'] ) ) {
259 $description = $value['desc'];
260 $tip = $value['desc_tip'];
261 } elseif ( ! empty( $value['desc'] ) ) {
262 $description = $value['desc'];
263 $tip = '';
264 } else {
265 $description = $tip = '';
266 }
267
268 if ( $description && in_array( $value['type'], array( 'textarea', 'radio' ) ) ) {
269 $description = '<p style="margin-top:0">' . wp_kses_post( $description ) . '</p>';
270 } elseif ( $description && in_array( $value['type'], array( 'checkbox' ) ) ) {
271 $description = wp_kses_post( $description );
272 } elseif ( $description ) {
273 $description = '<span class="description">' . wp_kses_post( $description ) . '</span>';
274 }
275
276 if ( $tip && in_array( $value['type'], array( 'checkbox' ) ) ) {
277
278 $tip = '<p class="description">' . wp_kses_post( $tip ) . '</p>';
279
280 } elseif ( $tip ) {
281
282 $tip = '<img class="help_tip" data-tip="' . esc_attr( wp_kses_post( $tip ) ) . '" src="' . esc_url( PH()->plugin_url() . '/assets/images/help.png' ) . '" height="16" width="16" />';
283
284 }
285
286 // Switch based on type
287 switch( $value['type'] ) {
288
289 // Section Titles
290 case 'title':
291 if ( ! empty( $value['title'] ) ) {
292 echo '<h3>' . esc_html( $value['title'] ) . '</h3>';
293 }
294 if ( ! empty( $value['desc'] ) ) {
295 echo wp_kses_post( wpautop( wptexturize( wp_kses_post( $value['desc'] ) ) ) );
296 }
297 echo '<table class="form-table">'. "\n\n";
298 if ( ! empty( $value['id'] ) ) {
299 do_action( 'propertyhive_settings_' . sanitize_title( $value['id'] ) );
300 }
301 break;
302
303 // Section Ends
304 case 'sectionend':
305 if ( ! empty( $value['id'] ) ) {
306 do_action( 'propertyhive_settings_' . sanitize_title( $value['id'] ) . '_end' );
307 }
308 echo '</table>';
309 if ( ! empty( $value['id'] ) ) {
310 do_action( 'propertyhive_settings_' . sanitize_title( $value['id'] ) . '_after' );
311 }
312 break;
313
314 case 'html':
315 $full_width = ( isset($value['full_width']) && is_bool($value['full_width']) ) ? $value['full_width'] : false;
316 ?>
317 <tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
318 <?php if ( $full_width !== true ) { ?>
319 <th scope="row" class="titledesc">
320 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
321 <?php echo wp_kses_post($tip); ?>
322 </th>
323 <?php } ?>
324 <td class="forminp forminp-<?php echo esc_attr(sanitize_title( $value['type'] )); ?>">
325 <?php
326 $allowed_html = wp_kses_allowed_html( 'post' );
327
328 $allowed_html['fieldset'] = array(
329 'id' => true,
330 'class' => true,
331 );
332
333 $allowed_html['legend'] = array(
334 'class' => true,
335 );
336
337 $allowed_html['label'] = array(
338 'for' => true,
339 'class' => true,
340 );
341
342 $allowed_html['input'] = array(
343 'type' => true,
344 'name' => true,
345 'id' => true,
346 'value' => true,
347 'class' => true,
348 'style' => true,
349 'checked' => true,
350 'disabled' => true,
351 'placeholder' => true,
352 );
353
354 $allowed_html['select'] = array(
355 'name' => true,
356 'id' => true,
357 'class' => true,
358 'style' => true,
359 'multiple' => true,
360 'disabled' => true,
361 );
362
363 $allowed_html['option'] = array(
364 'value' => true,
365 'selected' => true,
366 'disabled' => true,
367 );
368
369 /**
370 * Scripts are permitted for backward compatibility because existing
371 * Property Hive extensions use HTML settings fields to output inline
372 * administration scripts. To be revised in future after mentioned
373 * extensions have been updated
374 */
375 $allowed_html['script'] = array(
376 'type' => true,
377 'src' => true,
378 );
379
380 $allowed_html['a']['data-department'] = true;
381
382 $allowed_html = apply_filters(
383 'propertyhive_admin_settings_html_allowed_tags',
384 $allowed_html,
385 $value
386 );
387
388 echo wp_kses( $value['html'], $allowed_html );
389 ?>
390 </td>
391 </tr>
392 <?php
393 break;
394
395 // Standard text inputs and subtypes like 'number'
396 case 'text':
397 case 'email':
398 case 'number':
399 case 'color' :
400 case 'password' :
401
402 $type = $value['type'];
403 $class = '';
404 $option_value = self::get_option( $value['id'], $value['default'] );
405
406 if ( $value['type'] == 'color' ) {
407 $type = 'text';
408 $value['class'] .= 'colorpick';
409 $description .= '<div id="colorPickerDiv_' . esc_attr( $value['id'] ) . '" class="colorpickdiv" style="z-index: 100;background:#eee;border:1px solid #ccc;position:absolute;display:none;"></div>';
410 }
411
412 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
413 <th scope="row" class="titledesc">
414 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
415 <?php echo wp_kses_post( $tip ); ?>
416 </th>
417 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ) ?>">
418 <input
419 name="<?php echo esc_attr( $value['id'] ); ?>"
420 id="<?php echo esc_attr( $value['id'] ); ?>"
421 type="<?php echo esc_attr( $type ); ?>"
422 style="<?php echo esc_attr( $value['css'] ); ?>"
423 value="<?php echo esc_attr( $option_value ); ?>"
424 class="<?php echo esc_attr( $value['class'] ); ?>"
425 <?php
426 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every custom attribute name and value is escaped when assembled above; retain trusted PHP settings attributes.
427 echo implode( ' ', $custom_attributes );
428 ?>
429 /> <?php echo wp_kses_post( $description ); ?>
430 </td>
431 </tr><?php
432 break;
433
434 // Hidden
435 case 'hidden':
436
437 $option_value = self::get_option( $value['id'], $value['default'] );
438
439 ?><input type="hidden"
440 name="<?php echo esc_attr( $value['id'] ); ?>"
441 value="<?php echo esc_attr( $option_value ); ?>"
442 /><?php
443
444 break;
445
446 // Textarea
447 case 'textarea':
448
449 $option_value = self::get_option( $value['id'], $value['default'] );
450
451 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
452 <th scope="row" class="titledesc">
453 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
454 <?php echo wp_kses_post( $tip ); ?>
455 </th>
456 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ) ?>">
457 <?php echo wp_kses_post( $description ); ?>
458
459 <textarea
460 name="<?php echo esc_attr( $value['id'] ); ?>"
461 id="<?php echo esc_attr( $value['id'] ); ?>"
462 style="<?php echo esc_attr( $value['css'] ); ?>"
463 class="<?php echo esc_attr( $value['class'] ); ?>"
464 <?php
465 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every custom attribute name and value is escaped when assembled above; retain trusted PHP settings attributes.
466 echo implode( ' ', $custom_attributes );
467 ?>
468 ><?php echo esc_textarea( $option_value ); ?></textarea>
469 </td>
470 </tr><?php
471 break;
472
473 // WYSIWYG
474 case 'wysiwyg':
475
476 $option_value = self::get_option( $value['id'], $value['default'] );
477
478 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
479 <th scope="row" class="titledesc">
480 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
481 <?php echo wp_kses_post( $tip ); ?>
482 </th>
483 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ) ?>">
484
485 <?php wp_editor( $option_value, esc_attr( $value['id'] ), array( 'media_buttons' => false, 'textarea_rows' => 3, 'teeny' => true ) ); ?>
486
487 <?php echo '<br>' . wp_kses_post( $description ); ?>
488
489 <?php /*<textarea
490 name="<?php echo esc_attr( $value['id'] ); ?>"
491 id="<?php echo esc_attr( $value['id'] ); ?>"
492 <?php
493 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every custom attribute name and value is escaped when assembled above; retain trusted PHP settings attributes.
494 echo implode( ' ', $custom_attributes );
495 ?>
496 ><?php echo esc_textarea( $option_value ); ?></textarea>*/ ?>
497 </td>
498 </tr><?php
499 break;
500
501 // Select boxes
502 case 'select' :
503 case 'multiselect' :
504
505 $option_value = self::get_option( $value['id'], $value['default'] );
506
507 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
508 <th scope="row" class="titledesc">
509 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
510 <?php echo wp_kses_post( $tip ); ?>
511 </th>
512 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ) ?>">
513 <select
514 name="<?php echo esc_attr( $value['id'] ); ?><?php if ( $value['type'] == 'multiselect' ) echo '[]'; ?>"
515 id="<?php echo esc_attr( $value['id'] ); ?>"
516 style="<?php echo esc_attr( $value['css'] ); ?>"
517 class="<?php echo esc_attr( $value['class'] ); ?>"
518 <?php
519 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every custom attribute name and value is escaped when assembled above; retain trusted PHP settings attributes.
520 echo implode( ' ', $custom_attributes );
521 ?>
522 <?php if ( $value['type'] == 'multiselect' ) echo 'multiple="multiple"'; ?>
523 >
524 <?php
525 foreach ( $value['options'] as $key => $val ) {
526 ?>
527 <option value="<?php echo esc_attr( $key ); ?>" <?php
528
529 if ( is_array( $option_value ) )
530 selected( in_array( $key, $option_value ), true );
531 else
532 selected( $option_value, $key );
533
534 ?>><?php echo esc_html( $val ); ?></option>
535 <?php
536 }
537 ?>
538 </select> <?php echo wp_kses_post( $description ); ?>
539 </td>
540 </tr><?php
541 break;
542
543 // Radio inputs
544 case 'radio' :
545
546 $option_value = self::get_option( $value['id'], $value['default'] );
547
548 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
549 <th scope="row" class="titledesc">
550 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
551 <?php echo wp_kses_post( $tip ); ?>
552 </th>
553 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ) ?>">
554 <fieldset>
555 <?php echo wp_kses_post( $description ); ?>
556 <ul>
557 <?php
558 foreach ( $value['options'] as $key => $val ) {
559 ?>
560 <li>
561 <label><input
562 name="<?php echo esc_attr( $value['id'] ); ?>"
563 value="<?php echo esc_attr( $key ); ?>"
564 type="radio"
565 style="<?php echo esc_attr( $value['css'] ); ?>"
566 class="<?php echo esc_attr( $value['class'] ); ?>"
567 <?php
568 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every custom attribute name and value is escaped when assembled above; retain trusted PHP settings attributes.
569 echo implode( ' ', $custom_attributes );
570 ?>
571 <?php checked( $key, $option_value ); ?>
572 /> <?php echo wp_kses_post( $val ); ?></label>
573 </li>
574 <?php
575 }
576 ?>
577 </ul>
578 </fieldset>
579 </td>
580 </tr><?php
581 break;
582
583 // Checkbox input
584 case 'checkbox' :
585
586 $name = isset($value['name']) && $value['name'] != '' ? ph_clean($value['name']) : $value['id'];
587 $option_value = isset($value['value']) ? ph_clean($value['value']) : self::get_option( $value['id'], $value['default'] );
588 $fieldset_css = isset($value['fieldset_css']) ? ph_clean($value['fieldset_css']) : '';
589
590 $visbility_class = array();
591
592 if ( ! isset( $value['hide_if_checked'] ) ) {
593 $value['hide_if_checked'] = false;
594 }
595 if ( ! isset( $value['show_if_checked'] ) ) {
596 $value['show_if_checked'] = false;
597 }
598 if ( $value['hide_if_checked'] == 'yes' || $value['show_if_checked'] == 'yes' ) {
599 $visbility_class[] = 'hidden_option';
600 }
601 if ( $value['hide_if_checked'] == 'option' ) {
602 $visbility_class[] = 'hide_options_if_checked';
603 }
604 if ( $value['show_if_checked'] == 'option' ) {
605 $visbility_class[] = 'show_options_if_checked';
606 }
607
608 if ( ! isset( $value['checkboxgroup'] ) || 'start' == $value['checkboxgroup'] ) {
609 ?>
610 <tr valign="top" class="<?php echo esc_attr( implode( ' ', $visbility_class ) ); ?>" id="row_<?php echo esc_attr( $value['id'] ); ?>">
611 <th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?></th>
612 <td class="forminp forminp-checkbox">
613 <fieldset style="<?php echo esc_attr( $fieldset_css ); ?>">
614 <?php
615 } else {
616 ?>
617 <fieldset style="<?php echo esc_attr( $fieldset_css ); ?>" class="<?php echo esc_attr( implode( ' ', $visbility_class ) ); ?>">
618 <?php
619 }
620
621 if ( ! empty( $value['title'] ) ) {
622 ?>
623 <legend class="screen-reader-text"><span><?php echo esc_html( $value['title'] ) ?></span></legend>
624 <?php
625 }
626
627 ?>
628 <label for="<?php echo esc_attr( $value['id'] ); ?>">
629 <input
630 name="<?php echo esc_attr( $name ); ?>"
631 id="<?php echo esc_attr( $value['id'] ); ?>"
632 type="checkbox"
633 value="1"
634 <?php checked( $option_value, 'yes'); ?>
635 <?php
636 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every custom attribute name and value is escaped when assembled above; retain trusted PHP settings attributes.
637 echo implode( ' ', $custom_attributes );
638 ?>
639 /> <?php echo wp_kses_post( $description ); ?>
640 </label> <?php echo wp_kses_post( $tip ); ?>
641 <?php
642
643 if ( ! isset( $value['checkboxgroup'] ) || 'end' == $value['checkboxgroup'] ) {
644 ?>
645 </fieldset>
646 </td>
647 </tr>
648 <?php
649 } else {
650 ?>
651 </fieldset>
652 <?php
653 }
654 break;
655
656 // Image width settings
657 case 'image_width' :
658
659 $width = self::get_option( $value['id'] . '[width]', $value['default']['width'] );
660 $height = self::get_option( $value['id'] . '[height]', $value['default']['height'] );
661
662 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
663 <th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?> <?php echo wp_kses_post( $tip ); ?></th>
664 <td class="forminp image_width_settings">
665
666 <input name="<?php echo esc_attr( $value['id'] ); ?>[width]" id="<?php echo esc_attr( $value['id'] ); ?>-width" type="text" size="3" value="<?php echo esc_attr( $width ); ?>" /> &times; <input name="<?php echo esc_attr( $value['id'] ); ?>[height]" id="<?php echo esc_attr( $value['id'] ); ?>-height" type="text" size="3" value="<?php echo esc_attr( $height ); ?>" />px
667
668 <label><input name="<?php echo esc_attr( $value['id'] ); ?>[crop]" id="<?php echo esc_attr( $value['id'] ); ?>-crop" type="checkbox" <?php checked( 1, self::get_option( $value['id'] . '[crop]', $value['default']['crop'] ) ); ?> /> <?php esc_html_e( 'Hard Crop?', 'propertyhive' ); ?></label>
669
670 </td>
671 </tr><?php
672 break;
673
674 // Image
675 case 'image' :
676
677 $option_value = self::get_option( $value['id'], $value['default'] );
678
679 ?>
680 <tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>_uploaded" <?php if ( $option_value == '' ) { echo ' style="display:none"'; } ?>>
681 <th scope="row" class="titledesc"><?php echo esc_html( __( 'Uploaded', 'propertyhive' ) . ' ' . $value['title'] ); ?></th>
682 <td class="forminp image_settings">
683 <?php
684 $image = wp_get_attachment_image_src( $option_value, 'thumbnail' );
685 if ($image !== FALSE)
686 {
687 echo '<img src="' . esc_url( $image[0] ) . '" width="150" alt="">';
688 }
689 else
690 {
691 echo 'Image doesn\'t exist';
692 }
693 ?>
694 </td>
695 </tr>
696 <tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
697 <th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?> <?php echo wp_kses_post( $tip ); ?></th>
698 <td class="forminp image_settings">
699
700 <a href="" data-ph-image-field="<?php echo esc_attr( $value['id'] ); ?>" class="button button-primary ph_upload_photo_button<?php echo esc_attr( $value['id'] ); ?>">Select Image</a>
701 <input name="<?php echo esc_attr( $value['id'] ); ?>" id="<?php echo esc_attr( $value['id'] ); ?>" type="hidden" value="<?php echo esc_attr( $option_value ); ?>" />
702
703 </td>
704 </tr><?php
705 echo '<script>
706 (function(fieldId) {
707 jQuery(function($) {
708 $(document.body).on("click", "[data-ph-image-field]", function(event) {
709 if ($(this).attr("data-ph-image-field") !== fieldId) { return; }
710 event.preventDefault();
711 var frameKey = "file_frame" + fieldId;
712 var frame = wp.media.frames[frameKey] || window[frameKey];
713 if (frame) { frame.open(); return; }
714 frame = wp.media({
715 title: $(this).data("uploader_title"),
716 button: { text: $(this).data("uploader_button_text") },
717 multiple: false
718 });
719 wp.media.frames[frameKey] = window[frameKey] = frame;
720 frame.on("select", function() {
721 frame.state().get("selection").map(function(attachment) {
722 attachment = attachment.toJSON();
723 var row = $(document.getElementById("row_" + fieldId + "_uploaded"));
724 row.show().find("td").empty().append($("<img>", { src: attachment.url, width: 150, alt: "" }));
725 $(document.getElementById(fieldId)).val(attachment.id);
726 });
727 });
728 frame.open();
729 });
730 });
731 })(' . wp_json_encode( (string) $value['id'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ');
732 </script>';
733 break;
734
735 // Single page selects
736 case 'single_select_page' :
737
738 $args = array( 'name' => $value['id'],
739 'id' => $value['id'],
740 'sort_column' => 'menu_order',
741 'sort_order' => 'ASC',
742 'show_option_none' => ' ',
743 'class' => $value['class'],
744 'echo' => false,
745 'selected' => absint( self::get_option( $value['id'] ) )
746 );
747
748 if( isset( $value['args'] ) )
749 $args = wp_parse_args( $value['args'], $args );
750
751 ?><tr valign="top" class="single_select_page" id="row_<?php echo esc_attr( $value['id'] ); ?>">
752 <th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?> <?php echo wp_kses_post( $tip ); ?></th>
753 <td class="forminp">
754 <?php
755 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_dropdown_pages() produces escaped select HTML; all inserted attribute values are escaped here and trusted core filters retain their HTML contract.
756 echo str_replace(' id=', " data-placeholder='" . esc_attr__( 'Select a page&hellip;', 'propertyhive' ) . "' style='" . esc_attr( $value['css'] ) . "' class='" . esc_attr( $value['class'] ) . "' id=", wp_dropdown_pages( $args ) ); ?> <?php echo wp_kses_post( $description ); ?>
757 </td>
758 </tr><?php
759 break;
760
761 // Single country selects
762 case 'single_select_country' :
763 $country_setting = (string) self::get_option( $value['id'] );
764 $countries = PH()->countries->countries;
765
766 if ( strstr( $country_setting, ':' ) ) {
767 $country_setting = explode( ':', $country_setting );
768 $country = current( $country_setting );
769 } else {
770 $country = $country_setting;
771 }
772 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
773 <th scope="row" class="titledesc">
774 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
775 <?php echo wp_kses_post( $tip ); ?>
776 </th>
777 <td class="forminp">
778 <select name="<?php echo esc_attr( $value['id'] ); ?>" style="<?php echo esc_attr( $value['css'] ); ?>">
779 <?php PH()->countries->country_dropdown_options( $country ); ?>
780 </select>
781 <?php echo wp_kses_post( $description ); ?>
782 </td>
783 </tr><?php
784 break;
785
786 // Country multiselects
787 case 'multi_select_countries' :
788
789 $selections = (array) self::get_option( $value['id'] );
790
791 if ( ! empty( $value['options'] ) )
792 $countries = $value['options'];
793 else
794 $countries = PH()->countries->countries;
795
796 asort( $countries );
797 ?><tr valign="top" id="row_<?php echo esc_attr( $value['id'] ); ?>">
798 <th scope="row" class="titledesc">
799 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
800 <?php echo wp_kses_post( $tip ); ?>
801 </th>
802 <td class="forminp">
803 <select multiple="multiple" name="<?php echo esc_attr( $value['id'] ); ?>[]" style="<?php echo esc_attr( $value['css'] ); ?>">
804 <?php
805 if ( $countries )
806 foreach ( $countries as $key => $val )
807 echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $selections ), true, false ).'>' . esc_html( $val['name'] ) . '</option>';
808 ?>
809 </select> <?php if ( $description ) echo wp_kses_post( $description ); ?>
810 </td>
811 </tr><?php
812 break;
813
814 // Default: run an action
815 default:
816 do_action( 'propertyhive_admin_field_' . $value['type'], $value );
817 break;
818 }
819 }
820 }
821
822 /**
823 * Save admin fields.
824 *
825 * Loops though the propertyhive options array and outputs each field.
826 *
827 * @access public
828 * @param array $options Opens array to output
829 * @return bool
830 */
831 public static function save_fields( $options ) {
832 if ( ! current_user_can( 'manage_options' ) || ! isset( $_REQUEST['_wpnonce'] ) || ! is_string( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'propertyhive-settings' ) ) {
833 return;
834 }
835
836 if ( empty( $_POST ) )
837 return false;
838
839 // The settings nonce and manage_options capability were verified above.
840 $request_post = wp_unslash( $_POST );
841
842 // Options to update will be stored here
843 $update_options = array();
844
845 // Loop options and get values to save
846 foreach ( $options as $value ) {
847
848 if ( ! isset( $value['id'] ) )
849 continue;
850
851 $type = isset( $value['type'] ) ? sanitize_title( $value['type'] ) : '';
852
853 // Get the option name
854 $option_value = null;
855
856 switch ( $type ) {
857
858 // Standard types
859 case "checkbox" :
860
861 if ( isset( $request_post[ $value['id'] ] ) ) {
862 $option_value = 'yes';
863 } else {
864 $option_value = 'no';
865 }
866
867 break;
868
869 case "textarea" :
870 case "wysiwyg" :
871
872 if ( isset( $request_post[$value['id']] ) && is_scalar( $request_post[$value['id']] ) ) {
873 $option_value = wp_kses_post( trim( $request_post[ $value['id'] ] ) );
874 } else {
875 $option_value = '';
876 }
877
878 break;
879
880 case "text" :
881 case 'email':
882 case 'number':
883 case "select" :
884 case "color" :
885 case 'password' :
886 case "single_select_page" :
887 case "single_select_country" :
888 case 'radio' :
889
890 if ( isset( $request_post[$value['id']] ) && is_scalar( $request_post[$value['id']] ) ) {
891 $option_value = sanitize_text_field( $request_post[ $value['id'] ] );
892 } else {
893 $option_value = '';
894 }
895
896 break;
897
898 // Special types
899 case "multiselect" :
900 case "multi_select_countries" :
901
902 // Get countries array
903 $selected_countries = array();
904 if ( isset( $request_post[ $value['id'] ] ) ) {
905 foreach ( (array) $request_post[ $value['id'] ] as $selected_country ) {
906 if ( is_scalar( $selected_country ) ) {
907 $selected_countries[] = ph_clean( $selected_country );
908 }
909 }
910 }
911
912 $option_value = $selected_countries;
913
914 break;
915
916 case "image_width" :
917
918 $image_dimensions = ( isset( $request_post[ $value['id'] ] ) && is_array( $request_post[ $value['id'] ] ) ) ? $request_post[ $value['id'] ] : array();
919 if ( isset( $image_dimensions['width'] ) && is_scalar( $image_dimensions['width'] ) ) {
920
921 $update_options[ $value['id'] ]['width'] = ph_clean( $image_dimensions['width'] );
922 $update_options[ $value['id'] ]['height'] = ( isset( $image_dimensions['height'] ) && is_scalar( $image_dimensions['height'] ) ) ? ph_clean( $image_dimensions['height'] ) : $value['default']['height'];
923
924 if ( isset( $image_dimensions['crop'] ) )
925 $update_options[ $value['id'] ]['crop'] = 1;
926 else
927 $update_options[ $value['id'] ]['crop'] = 0;
928
929 } else {
930 $update_options[ $value['id'] ]['width'] = $value['default']['width'];
931 $update_options[ $value['id'] ]['height'] = $value['default']['height'];
932 $update_options[ $value['id'] ]['crop'] = $value['default']['crop'];
933 }
934
935 break;
936
937 // Custom handling
938 default :
939
940 do_action( 'propertyhive_update_option_' . $type, $value );
941
942 break;
943
944 }
945
946 if ( ! is_null( $option_value ) ) {
947 // Check if option is an array
948 if ( strstr( $value['id'], '[' ) ) {
949
950 parse_str( $value['id'], $option_array );
951
952 // Option name is first key
953 $option_name = current( array_keys( $option_array ) );
954
955 // Get old option value
956 if ( ! isset( $update_options[ $option_name ] ) )
957 $update_options[ $option_name ] = get_option( $option_name, array() );
958
959 if ( ! is_array( $update_options[ $option_name ] ) )
960 $update_options[ $option_name ] = array();
961
962 // Set keys and value
963 $key = key( $option_array[ $option_name ] );
964
965 $update_options[ $option_name ][ $key ] = $option_value;
966
967 // Single value
968 } else {
969 $update_options[ $value['id'] ] = $option_value;
970 }
971 }
972
973 // Custom handling
974 do_action( 'propertyhive_update_option', $value );
975 }
976
977 // Now save the options
978 foreach( $update_options as $name => $value )
979 update_option( $name, $value );
980
981 return true;
982 }
983 }
984
985 endif;
986