PluginProbe
Property Hive / 2.4.0
Property Hive v2.4.0
2.4.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 All 262 releases
← All changes | includes/admin/settings/class-ph-settings-general.php +709 -104 1.4.47 → 2.4.0 View file →
@@ -1,5 +1,8 @@
1 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 +
2 5 /**
3 6 * PropertyHive General Settings
4 7 *
5 8 * @author PropertyHive
@@ -16,8 +19,9 @@
16 19
17 20 /**
18 21 * PH_Settings_General
19 22 */
23 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Legacy public global class PH_Settings_General; preserving the existing PH_* class name is required for plugin and extension compatibility.
20 24 class PH_Settings_General extends PH_Settings_Page {
21 25
22 26 /**
23 27 * Constructor.
@@ -40,11 +44,14 @@
40 44 public function get_sections() {
41 45 $sections = array(
42 46 '' => __( 'General', 'propertyhive' ),
43 47 'modules' => __( 'Modules', 'propertyhive' ),
48 + 'map' => __( 'Map', 'propertyhive' ),
49 + 'media' => __( 'Media', 'propertyhive' ),
44 50 'international' => __( 'International', 'propertyhive' ),
45 - 'map' => __( 'Map', 'propertyhive' ),
46 51 'gdpr' => __( 'GDPR', 'propertyhive' ),
52 + 'captcha' => __( 'CAPTCHA', 'propertyhive' ),
53 + 'text-substitution' => __( 'Text Substitution', 'propertyhive' ),
47 54 'misc' => __( 'Miscellaneous', 'propertyhive' ),
48 55 );
49 56
50 57 return $sections;
@@ -56,10 +63,12 @@
56 63 *
57 64 * @return array
58 65 */
59 66 public function get_settings() {
60 -
67 +
68 + $default_departments = ph_get_departments(true);
61 69 $departments = ph_get_departments();
70 + $custom_departments = ph_get_custom_departments(false);
62 71
63 72 $settings = array(
64 73
65 74 array( 'title' => __( 'General Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'general_options' ),
@@ -65,28 +74,87 @@
65 74 array( 'title' => __( 'General Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'general_options' ),
66 75
67 76 );
68 77
69 - $i = 0;
78 + $active_departments_html = '<div id="active_departments">';
79 +
70 80 foreach ( $departments as $key => $value )
71 81 {
72 - $checkboxgroup = 'middle';
73 - if ( $i == 0 ) { $checkboxgroup = 'start'; }
74 - if ( $i == (count($departments) - 1) ) { $checkboxgroup = 'end'; }
82 + if ( isset($custom_departments[$key]) )
83 + {
84 +
85 + }
86 + else
87 + {
88 + $active_departments_html .= '<fieldset>
89 + <legend class="screen-reader-text"><span>' . esc_html(__( 'Active Departments', 'propertyhive' )) . '</span></legend>
90 + <label for="propertyhive_active_departments_' . esc_attr(str_replace("residential-", "", $key)) . '">
91 + <input name="propertyhive_active_departments_' . esc_attr(str_replace("residential-", "", $key)) . '" id="propertyhive_active_departments_' . esc_attr(str_replace("residential-", "", $key)) . '" type="checkbox" value="1" ' . checked( get_option('propertyhive_active_departments_' . str_replace("residential-", "", $key)) , 'yes', false ) . '> ' . esc_html($value) . '
92 + </label>
93 + </fieldset>';
94 + }
95 + }
75 96
76 - $settings[] = array(
77 - 'title' => __( 'Active Departments', 'propertyhive' ),
78 - 'desc' => $value,
79 - 'id' => 'propertyhive_active_departments_' . str_replace("residential-", "", $key),
80 - 'type' => 'checkbox',
81 - 'default' => ( ( in_array($key, array('residential-sales', 'residential-lettings', 'commercial')) ) ? 'yes' : '' ),
82 - 'checkboxgroup' => $checkboxgroup,
83 - );
97 + if ( !empty($custom_departments) )
98 + {
99 + foreach ( $custom_departments as $key => $custom_department )
100 + {
101 + // key will be custom-0, for example
102 + $active_departments_html .= '<fieldset id="propertyhive_active_department_fieldset_' . esc_attr($key) . '">
103 + <legend class="screen-reader-text"><span>' . esc_html(__( 'Active Departments', 'propertyhive' )) . '</span></legend>
104 + <label>
105 + <input name="propertyhive_active_departments_' . esc_attr($key) . '" type="checkbox" value="1" ' . checked( get_option('propertyhive_active_departments_' . $key), 'yes', false ) . '>
106 + <input type="text" name="propertyhive_active_departments_name_' . esc_attr($key) . '" value="' . $custom_department['name'] . '">
107 + ' . __( 'based on', 'propertyhive' ) . '
108 + <select name="propertyhive_active_departments_based_on_' . esc_attr($key) . '">
109 + <option value=""></option>';
110 + foreach ( $default_departments as $dept_key => $value )
111 + {
112 + $active_departments_html .= '<option value="' . esc_attr($dept_key) . '"' . selected( $custom_department['based_on'], $dept_key, false ) . '>' . esc_html($value) . '</option>';
113 + }
114 + $active_departments_html .= '
115 + </select>
116 + <a href="" class="delete-department" data-department="' . esc_attr($key) . '">Delete</a>
117 + </label>
118 + </fieldset>';
119 + }
120 + }
84 121
85 - ++$i;
86 - }
122 + $active_departments_html .= '</div>
123 + <a href="" id="add_department">+ ' . esc_html(__( 'Add Department', 'propertyhive' )) . '</a>
124 + <input type="hidden" name="propertyhive_new_custom_departments" id="propertyhive_new_custom_departments" value="0">
125 + <input type="hidden" name="propertyhive_custom_departments" id="propertyhive_custom_departments" value="' . esc_attr(implode(",", array_keys($custom_departments))) . '">
126 + <input type="hidden" name="propertyhive_custom_departments_original" id="propertyhive_custom_departments_original" value="' . esc_attr(implode(",", array_keys($custom_departments))) . '">
127 + ';
87 128
129 + $active_departments_html .= '<div id="active_department_template" style="display:none">
130 + <fieldset id="propertyhive_active_department_fieldset_template">
131 + <legend class="screen-reader-text"><span>' . __( 'Active Departments', 'propertyhive' ) . '</span></legend>
132 + <label>
133 + <input name="propertyhive_active_departments_template" type="checkbox" value="1" checked>
134 + <input type="text" name="propertyhive_active_departments_name_template" value="">
135 + ' . __( 'based on', 'propertyhive' ) . '
136 + <select name="propertyhive_active_departments_based_on_template">
137 + <option value=""></option>';
138 + foreach ( $default_departments as $key => $value )
139 + {
140 + $active_departments_html .= '<option value="' . esc_attr($key) . '">' . esc_html($value) . '</option>';
141 + }
142 + $active_departments_html .= '
143 + </select>
144 + <a href="" class="delete-department" data-department="template">Delete</a>
145 + </label>
146 + </fieldset>
147 + </div>';
148 +
88 149 $settings[] = array(
150 + 'title' => __( 'Active Departments', 'propertyhive' ),
151 + 'id' => 'propertyhive_active_departments',
152 + 'type' => 'html',
153 + 'html' => $active_departments_html,
154 + );
155 +
156 + $settings[] = array(
89 157 'title' => __( 'Primary Department', 'propertyhive' ),
90 158 'id' => 'propertyhive_primary_department',
91 159 'type' => 'radio',
92 160 'default' => 'residential-sales',
@@ -94,9 +162,8 @@
94 162 );
95 163
96 164 $settings[] = array(
97 165 'title' => __( 'Property Search Results Page', 'propertyhive' ),
98 - //'desc' => '<br/>' . sprintf( __( 'The base page can also be used in your <a href="%s">product permalinks</a>.', 'propertyhive' ), admin_url( 'options-permalink.php' ) ),
99 166 'id' => 'propertyhive_search_results_page_id',
100 167 'type' => 'single_select_page',
101 168 'default' => '',
102 169 'css' => 'min-width:300px;',
@@ -191,8 +258,17 @@
191 258 ),
192 259
193 260 array(
194 261 'title' => __( 'Disabled Modules', 'propertyhive' ),
262 + 'desc' => __( 'Tenancies', 'propertyhive' ),
263 + 'id' => 'propertyhive_module_disabled_tenancies',
264 + 'type' => 'checkbox',
265 + 'default' => '',
266 + 'checkboxgroup' => 'middle'
267 + ),
268 +
269 + array(
270 + 'title' => __( 'Disabled Modules', 'propertyhive' ),
195 271 'desc' => __( 'Enquiries', 'propertyhive' ),
196 272 'id' => 'propertyhive_module_disabled_enquiries',
197 273 'type' => 'checkbox',
198 274 'default' => '',
@@ -214,15 +290,8 @@
214 290 $settings = array(
215 291
216 292 array( 'title' => __( 'International Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'international_options' ),
217 293
218 - array(
219 - 'title' => __( 'Default Country', 'propertyhive' ),
220 - 'id' => 'propertyhive_default_country',
221 - 'type' => 'single_select_country',
222 - 'css' => 'min-width:300px;',
223 - ),
224 -
225 294 array(
226 295 'title' => __( 'Countries Where You Operate', 'propertyhive' ),
227 296 'id' => 'propertyhive_countries',
228 297 'type' => 'multi_select_countries',
@@ -230,13 +299,21 @@
230 299 'desc' => __( 'Hold ctrl/cmd whilst clicking to select multiple', 'propertyhive' )
231 300 ),
232 301
233 302 array(
303 + 'title' => __( 'Default Country', 'propertyhive' ),
304 + 'id' => 'propertyhive_default_country',
305 + 'type' => 'single_select_country',
306 + 'css' => 'min-width:300px;',
307 + ),
308 +
309 + array(
234 310 'title' => __( 'Price Thousand Separator', 'propertyhive' ),
235 311 'id' => 'propertyhive_price_thousand_separator',
236 312 'type' => 'text',
237 313 'default' => ',',
238 314 'css' => 'width:50px;',
315 + 'desc' => __( 'This only effects prices output on the frontend. Prices entered and displayed in the backend will use the comma character (,) as the thousand separator.', 'propertyhive' )
239 316 ),
240 317
241 318 array(
242 319 'title' => __( 'Price Decimal Separator', 'propertyhive' ),
@@ -243,8 +320,9 @@
243 320 'id' => 'propertyhive_price_decimal_separator',
244 321 'type' => 'text',
245 322 'default' => '.',
246 323 'css' => 'width:50px;',
324 + 'desc' => __( 'This only effects prices output on the frontend. Prices entered and displayed in the backend will use the period character (.) as the decimal separator.', 'propertyhive' )
247 325 )
248 326 );
249 327
250 328 $ph_countries = new PH_Countries();
@@ -277,9 +355,9 @@
277 355 $settings[] = array(
278 356 'type' => 'html',
279 357 'html' => '<script>
280 358
281 - var countries = '. json_encode( $countries ) . ';
359 + var countries = '. wp_json_encode( $countries, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ';
282 360
283 361 </script>'
284 362 );
285 363
@@ -292,13 +370,24 @@
292 370 * @return array
293 371 */
294 372 public function get_general_map_setting() {
295 373
296 - return apply_filters( 'propertyhive_general_map_settings', array(
374 + $settings = array(
297 375
298 376 array( 'title' => __( 'Map Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'map_options' ),
299 377
300 378 array(
379 + 'title' => __( 'Maps Provider', 'propertyhive' ),
380 + 'id' => 'propertyhive_maps_provider',
381 + 'type' => 'radio',
382 + 'options' => array(
383 + '' => 'Google Maps',
384 + 'mapbox' => 'Mapbox',
385 + 'osm' => 'OpenStreetMap',
386 + ),
387 + ),
388 +
389 + array(
301 390 'title' => __( 'Google Maps API Key', 'propertyhive' ),
302 391 'id' => 'propertyhive_google_maps_api_key',
303 392 'type' => 'text',
304 393 'desc' => '<p>' . __( 'If you have a Google Maps API key you can enter it here. You can generate an API key <a href="https://developers.google.com/maps/documentation/javascript/get-api-key" target="_blank">here</a>.<br>This is used when displaying the map when adding/editing properties, and if using our <a href="https://wp-property-hive.com/addons/map-search/" target="_blank">Map Search</a> or <a href="https://wp-property-hive.com/addons/radial-search/" target="_blank">Radial Search</a> add ons.<br>When creating your API key we recommend that you enable the Geocoding library. More about this can be found <a href="https://docs.wp-property-hive.com/user-guide/maps-co-ordinates-and-geocoding/" target="_blank">here</a>.', 'propertyhive' ) . '</p>'
@@ -303,14 +392,122 @@
303 392 'type' => 'text',
304 393 'desc' => '<p>' . __( 'If you have a Google Maps API key you can enter it here. You can generate an API key <a href="https://developers.google.com/maps/documentation/javascript/get-api-key" target="_blank">here</a>.<br>This is used when displaying the map when adding/editing properties, and if using our <a href="https://wp-property-hive.com/addons/map-search/" target="_blank">Map Search</a> or <a href="https://wp-property-hive.com/addons/radial-search/" target="_blank">Radial Search</a> add ons.<br>When creating your API key we recommend that you enable the Geocoding library. More about this can be found <a href="https://docs.wp-property-hive.com/user-guide/maps-co-ordinates-and-geocoding/" target="_blank">here</a>.', 'propertyhive' ) . '</p>'
305 394 ),
306 395
307 - array( 'type' => 'sectionend', 'id' => 'map_options'),
396 + array(
397 + 'title' => __( 'Mapbox API Key', 'propertyhive' ),
398 + 'id' => 'propertyhive_mapbox_api_key',
399 + 'type' => 'text',
400 + 'desc' => '<p>' . __( 'If you have a Mapbox API key you can enter it here. You can generate an API key <a href="https://account.mapbox.com/" target="_blank">here</a>.', 'propertyhive' ) . '</p>'
401 + ),
308 402
309 - ) ); // End general map settings
403 + array(
404 + 'title' => __( 'Geocoding Provider', 'propertyhive' ),
405 + 'id' => 'propertyhive_geocoding_provider',
406 + 'type' => 'radio',
407 + 'options' => array(
408 + '' => 'Google Maps',
409 + //'mapbox' => 'Mapbox',
410 + 'osm' => 'OpenStreetMap',
411 + ),
412 + ),
413 +
414 + array(
415 + 'id' => 'propertyhive_osm_html',
416 + 'type' => 'html',
417 + 'html' => '<p>' . __( 'Note: OSM is an open source project maintained by volunteers and the geocoding results returned are reliant on the data sets available. If you find some addresses/search terms don\'t return results this is likely the issue, as opposed to it being an issue with Property Hive.', 'propertyhive' ) . '</p>'
418 + ),
419 + );
420 +
421 + if ( apply_filters( 'propertyhive_use_google_maps_geocoding_api_key', false) === true )
422 + {
423 + $settings[] = array(
424 + 'title' => __( 'Google Maps Geocoding API Key', 'propertyhive' ),
425 + 'id' => 'propertyhive_google_maps_geocoding_api_key',
426 + 'type' => 'text',
427 + 'desc' => '<p>' . __( 'If you have referer restrictions applied to the main API key entered then server side geocoding requests will be blocked. To get around this you can setup a separate API key specifically for geocoding and enter it here, with IP restrictions applied instead if required.<br>More about this can be found <a href="https://docs.wp-property-hive.com/user-guide/maps-co-ordinates-and-geocoding/" target="_blank">here</a>.', 'propertyhive' ) . '</p>'
428 + );
429 +
430 + $settings[] = array(
431 + 'title' => __( 'Mapbox Geocoding API Key', 'propertyhive' ),
432 + 'id' => 'propertyhive_mapbox_geocoding_api_key',
433 + 'type' => 'text',
434 + 'desc' => '<p>' . __( 'If you have referer restrictions applied to the main API key entered then server side geocoding requests will be blocked. To get around this you can setup a separate API key specifically for geocoding and enter it here, with IP restrictions applied instead if required.<br>More about this can be found <a href="https://docs.wp-property-hive.com/user-guide/maps-co-ordinates-and-geocoding/" target="_blank">here</a>.', 'propertyhive' ) . '</p>'
435 + );
436 + }
437 +
438 + $settings[] = array( 'type' => 'sectionend', 'id' => 'map_options');
439 +
440 + return apply_filters( 'propertyhive_general_map_settings', $settings );
310 441 }
311 442
312 443 /**
444 + * Get media settings array
445 + *
446 + * @return array
447 + */
448 + public function get_general_media_setting() {
449 +
450 + $settings = array(
451 +
452 + array( 'title' => __( 'Property Media Storage', 'propertyhive' ), 'type' => 'title', 'desc' => 'By default media attached to properties will be stored in the WordPress media library. If the property media is hosted elsewhere (for example if you import properties from a third party and they allow you to link direct to the files on their server) you can choose to store media as URL\'s. It also means that the images are not downloaded onto your server, thus saving diskspace.<br><br>Note: If you change this you\'ll need to re-add all of the property media for existing properties.<br>Note: Changing this will not delete all existing media or URLs entered.<br>Note: Choosing to store the media as URLs will mean you don\'t benefit from having access to different sized images (i.e. small, medium, large etc).', 'id' => 'media_storage_options' ),
453 +
454 + array(
455 + 'title' => __( 'Images Stored As', 'propertyhive' ),
456 + 'id' => 'propertyhive_images_stored_as',
457 + 'type' => 'select',
458 + 'default' => 'files',
459 + 'options' => array(
460 + 'files' => __( 'Media Files', 'propertyhive' ),
461 + 'urls' => __( 'URLs', 'propertyhive' ),
462 + ),
463 + 'desc' => ''
464 + ),
465 +
466 + array(
467 + 'title' => __( 'Floorplans Stored As', 'propertyhive' ),
468 + 'id' => 'propertyhive_floorplans_stored_as',
469 + 'type' => 'select',
470 + 'default' => 'files',
471 + 'options' => array(
472 + 'files' => __( 'Media Files', 'propertyhive' ),
473 + 'urls' => __( 'URLs', 'propertyhive' ),
474 + ),
475 + 'desc' => ''
476 + ),
477 +
478 + array(
479 + 'title' => __( 'Brochures Stored As', 'propertyhive' ),
480 + 'id' => 'propertyhive_brochures_stored_as',
481 + 'type' => 'select',
482 + 'default' => 'files',
483 + 'options' => array(
484 + 'files' => __( 'Media Files', 'propertyhive' ),
485 + 'urls' => __( 'URLs', 'propertyhive' ),
486 + ),
487 + 'desc' => ''
488 + ),
489 +
490 + array(
491 + 'title' => __( 'EPCs Stored As', 'propertyhive' ),
492 + 'id' => 'propertyhive_epcs_stored_as',
493 + 'type' => 'select',
494 + 'default' => 'files',
495 + 'options' => array(
496 + 'files' => __( 'Media Files', 'propertyhive' ),
497 + 'urls' => __( 'URLs', 'propertyhive' ),
498 + ),
499 + 'desc' => ''
500 + ),
501 +
502 + array( 'type' => 'sectionend', 'id' => 'media_storage_options')
503 +
504 + );
505 +
506 + return apply_filters( 'propertyhive_general_media_settings', $settings );
507 + }
508 +
509 + /**
313 510 * Get GDPR settings array
314 511 *
315 512 * @return array
316 513 */
@@ -346,8 +543,167 @@
346 543
347 544 ) ); // End general GDPR settings
348 545 }
349 546
547 + /**
548 + * Get CAPTCHA settings array
549 + *
550 + * @return array
551 + */
552 + public function get_general_captcha_setting() {
553 +
554 + return apply_filters( 'propertyhive_general_captcha_settings', array(
555 +
556 + array( 'title' => __( 'CAPTCHA Settings', 'propertyhive' ), 'type' => 'title', 'id' => 'captcha_options', 'desc' => __( 'Prevent spam and bots on forms provided by Property Hive by signing up to a CAPTCHA service and entering the details below.<br><br>When enabled, a CAPTCHA will be added to the register, property enquiry and send to friend forms.', 'propertyhive' ) ),
557 +
558 + array(
559 + 'title' => __( 'CAPTCHA service', 'propertyhive' ),
560 + 'id' => 'propertyhive_captcha_service',
561 + 'type' => 'radio',
562 + 'options' => array(
563 + '' => __( 'None', 'propertyhive' ),
564 + 'recaptcha' => __( 'Google reCaptcha v2', 'propertyhive' ) . ' (<a href="https://www.google.com/recaptcha/admin/create" target="_blank">register</a>)',
565 + 'recaptcha-v3' => __( 'Google reCaptcha v3', 'propertyhive' ) . ' (<a href="https://www.google.com/recaptcha/admin/create" target="_blank">register</a>)',
566 + 'hCaptcha' => __( 'hCaptcha', 'propertyhive' ) . ' (<a href="https://www.hcaptcha.com/" target="_blank">register</a>)',
567 + 'turnstile' => __( 'Cloudflare Turnstile', 'propertyhive' ) . ' (<a href="https://www.cloudflare.com/en-gb/application-services/products/turnstile/" target="_blank">register</a>)', // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent -- Registration hyperlink for the optional CAPTCHA provider.
568 + ),
569 + ),
570 +
571 + array(
572 + 'title' => __( 'Site Key', 'propertyhive' ),
573 + 'id' => 'propertyhive_captcha_site_key',
574 + 'type' => 'text',
575 + ),
576 +
577 + array(
578 + 'title' => __( 'Secret', 'propertyhive' ),
579 + 'id' => 'propertyhive_captcha_secret',
580 + 'type' => 'text',
581 + ),
582 +
583 + array(
584 + 'title' => __( 'Score Threshold', 'propertyhive' ),
585 + 'id' => 'propertyhive_captcha_score_threshold',
586 + 'type' => 'text',
587 + 'default' => 0.5,
588 + 'desc' => __( 'Set the minimum score required to pass reCAPTCHA v3 verification (between 0 and 1). Lower values allow more submissions through but increase spam risk.', 'propertyhive' ),
589 + ),
590 +
591 + array(
592 + //'title' => __( 'CAPTCHA service', 'propertyhive' ),
593 + 'id' => 'propertyhive_captcha_html',
594 + 'type' => 'html',
595 + 'html' => '<script>
596 + jQuery(document).ready(function()
597 + {
598 + jQuery(\'input[name=\\\'propertyhive_captcha_service\\\']\').change(function()
599 + {
600 + ph_captcha_service_update();
601 + });
602 +
603 + ph_captcha_service_update();
604 + });
605 +
606 + function ph_captcha_service_update()
607 + {
608 + jQuery(\'#row_propertyhive_captcha_site_key\').hide();
609 + jQuery(\'#row_propertyhive_captcha_secret\').hide();
610 + jQuery(\'#row_propertyhive_captcha_score_threshold\').hide();
611 +
612 + var selected_captcha_service = jQuery(\'input[name=\\\'propertyhive_captcha_service\\\']:checked\').val();
613 +
614 + if ( selected_captcha_service != \'\' )
615 + {
616 + jQuery(\'#row_propertyhive_captcha_site_key\').show();
617 + jQuery(\'#row_propertyhive_captcha_secret\').show();
618 +
619 + if ( selected_captcha_service == \'recaptcha-v3\' )
620 + {
621 + jQuery(\'#row_propertyhive_captcha_score_threshold\').show();
622 + }
623 + }
624 + }
625 + </script>',
626 + ),
627 +
628 + array( 'type' => 'sectionend', 'id' => 'captcha_options'),
629 +
630 + ) ); // End general CAPTCHA settings
631 + }
632 +
633 + /**
634 + * Get text substitution settings array
635 + *
636 + * @return array
637 + */
638 + public function get_general_text_substitution_setting() {
639 +
640 + $current_settings = get_option( 'propertyhive_template_assistant', array() );
641 +
642 + $settings = array(
643 +
644 + array( 'title' => __( 'Text Substitution', 'propertyhive' ), 'type' => 'title', 'desc' => 'Replace specific words or phrases used throughout Property Hive with your own preferred wording.', 'id' => 'template_assistant_text_translation_settings' )
645 +
646 + );
647 +
648 + $existing_translations = array();
649 + if ( isset($current_settings['text_translations']) && is_array($current_settings['text_translations']) && !empty($current_settings['text_translations']) )
650 + {
651 + foreach ( $current_settings['text_translations'] as $text_translation )
652 + {
653 + $existing_translations[] = '<tr>
654 + <td><input type="text" name="search[]" class="regular-text" value="' . esc_attr($text_translation['search']) . '"></td>
655 + <td><input type="text" name="replace[]" class="regular-text" value="' . esc_attr($text_translation['replace']) . '"></td>
656 + <td><a href="" class="delete-text-substitution" title="Delete Text Substitution"><span class="dashicons dashicons-trash"></span></a></td>
657 + </tr>';
658 + }
659 + }
660 +
661 + $settings[] = array(
662 + 'type' => 'html',
663 + 'full_width' => true,
664 + 'html' => '
665 +
666 + <table class="widefat striped" style="max-width:520px;" >
667 + <thead>
668 + <tr>
669 + <th style="padding:8px 10px;" scope="col">Text To Replace</th>
670 + <th style="padding:8px 10px;" scope="col">Replace With</th>
671 + <th style="padding:8px 10px;" scope="col">&nbsp;</th>
672 + </tr>
673 + </thead>
674 + <tbody>
675 + ' . implode("", $existing_translations) . '
676 + <tr>
677 + <td><input type="text" name="search[]" class="regular-text" placeholder="e.g. Make Enquiry"></td>
678 + <td><input type="text" name="replace[]" class="regular-text" placeholder="e.g. Request Viewing"></td>
679 + <td>&nbsp;</td>
680 + </tr>
681 + </tbody>
682 + </table>
683 +
684 + <script>
685 + jQuery(document).ready(function()
686 + {
687 + jQuery(\'a.delete-text-substitution\').on(\'click\', function(e)
688 + {
689 + e.preventDefault();
690 +
691 + jQuery(this).closest(\'tr\').find(\'input\').val(\'\');
692 +
693 + setTimeout(function() {
694 + jQuery(\'.submit button[type="submit"]\').trigger(\'click\');
695 + }, 0);
696 + });
697 + });
698 + </script>'
699 + );
700 +
701 + $settings[] = array( 'type' => 'sectionend', 'id' => 'template_assistant_text_translation_settings');
702 +
703 + return $settings;
704 + }
705 +
350 706 /**
351 707 * Get misc settings array
352 708 *
353 709 * @return array
@@ -365,13 +721,40 @@
365 721 'default' => '=',
366 722 'options' => array(
367 723 '=' => __( 'Match Keyword Exactly', 'propertyhive' ),
368 724 'LIKE' => __( 'Perform Loose Search', 'propertyhive' ),
725 + 'polygon' => __( 'Search Within Location Perimeter', 'propertyhive' ),
369 726 ),
370 - 'desc_tip' => __( 'Applicable if you allow users to search by entering a location. If \'Match Keyword Exactly\' is selected a search for \'Walton\' would not return properties in \'Walton On Thames\', but would prevent properties in \'Lincolnshire\' appearing when searching for \'Lincoln\'. \'Perform Loose Search\' would do the opposite.', 'propertyhive' )
727 + 'desc_tip' => __( 'Applicable if you allow users to search by entering a location. If \'Match Keyword Exactly\' is selected a search for \'Walton\' would not return properties in \'Walton On Thames\', but would prevent properties in \'Lincolnshire\' appearing when searching for \'Lincoln\'. \'Perform Loose Search\' would do the opposite. \'Search Within Location Perimeter\' will make an API request to Nominatim to get the perimeter of the entered location and will search within the returned polygon.', 'propertyhive' )
371 728 ),
372 729
373 730 array(
731 + 'title' => __( 'Commercial Display In Search Results', 'propertyhive' ),
732 + 'id' => 'propertyhive_commercial_display',
733 + 'type' => 'select',
734 + 'default' => '',
735 + 'css' => 'min-width:300px;',
736 + 'options' => array(
737 + '' => __( 'Display top level properties and units', 'propertyhive' ),
738 + 'top_level_only' => __( 'Display top level properties only', 'propertyhive' ),
739 + 'top_level_only_but_units_when_filtered' => __( 'Display top level properties only but units as well if matching filters', 'propertyhive' ),
740 + ),
741 + ),
742 +
743 + array(
744 + 'title' => __( 'When An Off Market Property URL Is Viewed', 'propertyhive' ),
745 + 'id' => 'propertyhive_off_market_behaviour',
746 + 'type' => 'select',
747 + 'default' => '',
748 + 'css' => 'min-width:300px;',
749 + 'options' => array(
750 + '' => __( 'Still show the property details', 'propertyhive' ),
751 + 'redirect' => __( 'Do a 301 redirect to the search results page', 'propertyhive' ),
752 + ),
753 + 'desc' => __( 'If 301 redirect is selected, this will only apply to non-logged in users', 'propertyhive' )
754 + ),
755 +
756 + array(
374 757 'title' => __( 'When Entering Features', 'propertyhive' ),
375 758 'id' => 'propertyhive_features_type',
376 759 'type' => 'radio',
377 760 'options' => array(
@@ -377,11 +760,24 @@
377 760 'options' => array(
378 761 '' => __( 'Allow Features To Be Freetyped', 'propertyhive' ),
379 762 'checkbox' => __( 'Select From A Predefined List (Editable from \'Custom Fields\')', 'propertyhive' ),
380 763 ),
381 - 'desc' => __( '', 'propertyhive' )
382 764 ),
383 765
766 + array(
767 + 'title' => __( 'Enable Auto-Incremental Reference Numbers', 'propertyhive' ),
768 + 'id' => 'propertyhive_auto_incremental_reference_numbers',
769 + 'type' => 'checkbox',
770 + 'desc' => __( 'Will prefill the property reference with an auto-incremental number when adding a new property', 'propertyhive' )
771 + ),
772 +
773 + array(
774 + 'title' => __( 'Next Incremental Reference Number', 'propertyhive' ),
775 + 'id' => 'propertyhive_auto_incremental_next',
776 + 'type' => 'number',
777 + 'default' => 1,
778 + ),
779 +
384 780 array( 'type' => 'sectionend', 'id' => 'property_options'),
385 781
386 782 array( 'title' => __( 'Applicant Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'applicant_registration_options' ),
387 783
@@ -404,12 +800,39 @@
404 800 'id' => 'propertyhive_my_account_page_id',
405 801 'type' => 'single_select_page',
406 802 'default' => '',
407 803 'css' => 'min-width:300px;',
408 - 'desc' => __( 'This sets the \'My Account\' page. This page should contain the [propertyhive_my_account] shortcode', 'propertyhive' ),
804 + 'desc' => __( 'This page should contain the [propertyhive_my_account] shortcode', 'propertyhive' ),
409 805 ),
410 806
411 807 array(
808 + 'title' => __( 'Applicant Login Page', 'propertyhive' ),
809 + 'id' => 'propertyhive_applicant_login_page_id',
810 + 'type' => 'single_select_page',
811 + 'default' => '',
812 + 'css' => 'min-width:300px;',
813 + 'desc' => __( 'This page should contain the [propertyhive_login_form] shortcode', 'propertyhive' ),
814 + ),
815 +
816 + array(
817 + 'title' => __( 'Applicant Reset Password Page', 'propertyhive' ),
818 + 'id' => 'propertyhive_applicant_reset_password_page_id',
819 + 'type' => 'single_select_page',
820 + 'default' => '',
821 + 'css' => 'min-width:300px;',
822 + 'desc' => __( 'This page should contain the [propertyhive_reset_password_form] shortcode', 'propertyhive' ),
823 + ),
824 +
825 + array(
826 + 'title' => __( 'Applicant Registration Page', 'propertyhive' ),
827 + 'id' => 'propertyhive_applicant_registration_page_id',
828 + 'type' => 'single_select_page',
829 + 'default' => '',
830 + 'css' => 'min-width:300px;',
831 + 'desc' => __( 'This page should contain the [applicant_registration_form] shortcode', 'propertyhive' ),
832 + ),
833 +
834 + array(
412 835 'title' => __( 'Match Price Range % (Lower)', 'propertyhive' ),
413 836 'id' => 'propertyhive_applicant_match_price_range_percentage_lower',
414 837 'type' => 'number',
415 838 'default' => '20',
@@ -422,61 +845,32 @@
422 845 'type' => 'number',
423 846 'default' => '5',
424 847 ),
425 848
426 - array( 'type' => 'sectionend', 'id' => 'applicant_registration_options'),
427 -
428 - array( 'title' => __( 'Property Media Storage', 'propertyhive' ), 'type' => 'title', 'desc' => 'By default media atttached to properties will be stored in the WordPress media library. If the property media is hosted elsewhere (for example if you import properties from a third party and they allow you to link direct to the files on their server) you can choose to store media as URL\'s. It also means that the images are not downloaded onto your server, thus saving diskspace.<br><br>Note: If you change this you\'ll need to re-add all of the property media for existing properties.<br>Note: Changing this will not delete all existing media or URLs entered.<br>Note: Choosing to store the media as URLs will mean you don\'t benefit from having access to different sized images (i.e. small , medium, large etc).', 'id' => 'media_storage_options' ),
429 -
430 849 array(
431 - 'title' => __( 'Images Stored As', 'propertyhive' ),
432 - 'id' => 'propertyhive_images_stored_as',
433 - 'type' => 'select',
434 - 'default' => 'files',
850 + 'title' => __( 'When Selecting Applicant Locations', 'propertyhive' ),
851 + 'id' => 'propertyhive_applicant_locations_type',
852 + 'type' => 'radio',
435 853 'options' => array(
436 - 'files' => __( 'Media Files', 'propertyhive' ),
437 - 'urls' => __( 'URLs', 'propertyhive' ),
854 + 'text' => __( 'Allow Locations To Be Freetyped', 'propertyhive' ),
855 + '' => __( 'Select From A Predefined List (Editable from \'Custom Fields\')', 'propertyhive' ),
438 856 ),
439 - 'desc' => __( '', 'propertyhive' )
857 + 'desc' => '<i>' . __( 'When this setting is changed, locations selected using the other method will no longer be used for matching', 'propertyhive' ) . '</i>',
440 858 ),
441 859
442 - array(
443 - 'title' => __( 'Floorplans Stored As', 'propertyhive' ),
444 - 'id' => 'propertyhive_floorplans_stored_as',
445 - 'type' => 'select',
446 - 'default' => 'files',
447 - 'options' => array(
448 - 'files' => __( 'Media Files', 'propertyhive' ),
449 - 'urls' => __( 'URLs', 'propertyhive' ),
450 - ),
451 - 'desc' => __( '', 'propertyhive' )
452 - ),
860 + array( 'type' => 'sectionend', 'id' => 'applicant_registration_options'),
453 861
454 - array(
455 - 'title' => __( 'Brochures Stored As', 'propertyhive' ),
456 - 'id' => 'propertyhive_brochures_stored_as',
457 - 'type' => 'select',
458 - 'default' => 'files',
459 - 'options' => array(
460 - 'files' => __( 'Media Files', 'propertyhive' ),
461 - 'urls' => __( 'URLs', 'propertyhive' ),
462 - ),
463 - 'desc' => __( '', 'propertyhive' )
464 - ),
862 + array( 'title' => __( 'Improve Property Hive', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'stat_tracking_options' ),
465 863
466 864 array(
467 - 'title' => __( 'EPCs Stored As', 'propertyhive' ),
468 - 'id' => 'propertyhive_epcs_stored_as',
469 - 'type' => 'select',
470 - 'default' => 'files',
471 - 'options' => array(
472 - 'files' => __( 'Media Files', 'propertyhive' ),
473 - 'urls' => __( 'URLs', 'propertyhive' ),
474 - ),
475 - 'desc' => __( '', 'propertyhive' )
865 + 'title' => __( 'Usage Data Sharing', 'propertyhive' ),
866 + 'id' => 'propertyhive_data_sharing',
867 + 'type' => 'checkbox',
868 + 'value' => ( get_option('propertyhive_data_sharing', FALSE) === FALSE ? 'yes' : get_option('propertyhive_data_sharing', '') ),
869 + 'desc' => __( 'Help improve Property Hive by periodically sending us non-sensitive plugin data. Untick this option to opt-out. <a href="https://docs.wp-property-hive.com/user-guide/share-usage-data/" target="_blank">Learn more</a>', 'propertyhive' )
476 870 ),
477 871
478 - array( 'type' => 'sectionend', 'id' => 'media_storage_options'),
872 + array( 'type' => 'sectionend', 'id' => 'stat_tracking_options'),
479 873
480 874 ) ); // End general misc settings
481 875 }
482 876
@@ -492,9 +886,12 @@
492 886 {
493 887 case "modules": { $settings = $this->get_general_modules_setting(); break; }
494 888 case "international": { $settings = $this->get_general_international_setting(); break; }
495 889 case "map": { $settings = $this->get_general_map_setting(); break; }
890 + case "media": { $settings = $this->get_general_media_setting(); break; }
496 891 case "gdpr": { $settings = $this->get_general_gdpr_setting(); break; }
892 + case "captcha": { $settings = $this->get_general_captcha_setting(); break; }
893 + case "text-substitution": { $settings = $this->get_general_text_substitution_setting(); break; }
497 894 case "misc": { $settings = $this->get_general_misc_setting(); break; }
498 895 default: { die("Unknown setting section"); }
499 896 }
500 897 }
@@ -516,9 +913,9 @@
516 913 * @param string $desc (default: '')
517 914 * @return void
518 915 */
519 916 function color_picker( $name, $id, $value, $desc = '' ) {
520 - echo '<div class="color_box"><strong><img class="help_tip" data-tip="' . esc_attr( $desc ) . '" src="' . PH()->plugin_url() . '/assets/images/help.png" height="16" width="16" /> ' . esc_html( $name ) . '</strong>
917 + echo '<div class="color_box"><strong><img class="help_tip" data-tip="' . esc_attr( $desc ) . '" src="' . esc_url(PH()->plugin_url() . '/assets/images/help.png') . '" height="16" width="16" /> ' . esc_html( $name ) . '</strong>
521 918 <input name="' . esc_attr( $id ). '" id="' . esc_attr( $id ) . '" type="text" value="' . esc_attr( $value ) . '" class="colorpick" /> <div id="colorPickerDiv_' . esc_attr( $id ) . '" class="colorpickdiv"></div>
522 919 </div>';
523 920 }
524 921
@@ -525,8 +922,12 @@
525 922 /**
526 923 * Save settings
527 924 */
528 925 public function save() {
926 + 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' ) ) {
927 + return;
928 + }
929 +
529 930 global $current_section;
530 931
531 932 if ( $current_section != '' )
532 933 {
@@ -538,36 +939,48 @@
538 939
539 940 PH_Admin_Settings::save_fields( $settings );
540 941 break;
541 942 }
542 - case 'international':
543 - {
544 - if (!isset($_POST['propertyhive_countries']) || (isset($_POST['propertyhive_countries']) && empty($_POST['propertyhive_countries'])))
545 - {
546 - // If we haven't selected which countries we operate in
547 - update_option( 'propertyhive_countries', array( ph_clean($_POST['propertyhive_default_country']) ) );
548 - }
549 - else
550 - {
551 - // We have default country and countries set
552 - // Make sure default country is in list of countries selected
553 - if ( !in_array(ph_clean($_POST['propertyhive_default_country']), ph_clean($_POST['propertyhive_countries'])) ) {
554 - $_POST['propertyhive_default_country'] = $_POST['propertyhive_countries'][0];
555 - }
556 -
557 - update_option( 'propertyhive_default_country', ph_clean($_POST['propertyhive_default_country']) );
558 - update_option( 'propertyhive_countries', ph_clean($_POST['propertyhive_countries']) );
559 - }
560 -
561 - update_option( 'propertyhive_price_thousand_separator', ph_clean($_POST['propertyhive_price_thousand_separator']) );
562 - update_option( 'propertyhive_price_decimal_separator', ph_clean($_POST['propertyhive_price_decimal_separator']) );
563 -
564 - update_option( 'propertyhive_search_form_currency', ph_clean($_POST['propertyhive_search_form_currency']) );
565 -
566 - do_action( 'propertyhive_update_currency_exchange_rates' );
567 -
568 - break;
569 - }
943 + case 'international':
944 + {
945 + $international = array();
946 + foreach ( array( 'propertyhive_default_country', 'propertyhive_price_thousand_separator', 'propertyhive_price_decimal_separator', 'propertyhive_search_form_currency' ) as $input_key ) {
947 + if ( ! isset( $_POST[$input_key] ) || ! is_string( $_POST[$input_key] ) ) {
948 + return;
949 + }
950 + $international[$input_key] = sanitize_text_field( wp_unslash( $_POST[$input_key] ) );
951 + }
952 + if ( isset( $_POST['propertyhive_countries'] ) && ! is_array( $_POST['propertyhive_countries'] ) ) {
953 + return;
954 + }
955 + $countries = array();
956 + if ( isset( $_POST['propertyhive_countries'] ) ) {
957 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each country is validated as a string, unslashed and sanitized in the loop before use.
958 + foreach ( $_POST['propertyhive_countries'] as $country ) {
959 + if ( ! is_string( $country ) ) {
960 + return;
961 + }
962 + $countries[] = sanitize_text_field( wp_unslash( $country ) );
963 + }
964 + }
965 + if ( empty( $countries ) ) {
966 + // Preserve the existing default-country fallback when no list is selected.
967 + update_option( 'propertyhive_countries', array( $international['propertyhive_default_country'] ) );
968 + } else {
969 + if ( ! in_array( $international['propertyhive_default_country'], $countries, true ) ) {
970 + $international['propertyhive_default_country'] = $countries[0];
971 + // Keep the normalized selection available to existing save-hook consumers.
972 + $_POST['propertyhive_default_country'] = wp_slash( $countries[0] );
973 + }
974 + update_option( 'propertyhive_default_country', $international['propertyhive_default_country'] );
975 + update_option( 'propertyhive_countries', $countries );
976 + }
977 + update_option( 'propertyhive_price_thousand_separator', $international['propertyhive_price_thousand_separator'] );
978 + update_option( 'propertyhive_price_decimal_separator', $international['propertyhive_price_decimal_separator'] );
979 + update_option( 'propertyhive_search_form_currency', $international['propertyhive_search_form_currency'] );
980 + do_action( 'propertyhive_update_currency_exchange_rates' );
981 + break;
982 + }
570 983 case 'map':
571 984 {
572 985 $settings = $this->get_general_map_setting();
573 986
@@ -573,8 +986,15 @@
573 986
574 987 PH_Admin_Settings::save_fields( $settings );
575 988 break;
576 989 }
990 + case 'media':
991 + {
992 + $settings = $this->get_general_media_setting();
993 +
994 + PH_Admin_Settings::save_fields( $settings );
995 + break;
996 + }
577 997 case 'gdpr':
578 998 {
579 999 $settings = $this->get_general_gdpr_setting();
580 1000
@@ -580,8 +1000,57 @@
580 1000
581 1001 PH_Admin_Settings::save_fields( $settings );
582 1002 break;
583 1003 }
1004 + case 'captcha':
1005 + {
1006 + $settings = $this->get_general_captcha_setting();
1007 +
1008 + PH_Admin_Settings::save_fields( $settings );
1009 + break;
1010 + }
1011 + case 'text-substitution':
1012 + {
1013 + $current_settings = get_option( 'propertyhive_template_assistant', array() );
1014 +
1015 + if ( ! is_array( $current_settings ) ) {
1016 + $current_settings = array();
1017 + }
1018 + foreach ( array( 'search', 'replace' ) as $field ) {
1019 + if ( isset( $_POST[ $field ] ) && ! is_array( $_POST[ $field ] ) ) {
1020 + return;
1021 + }
1022 + }
1023 + $text_translations = array();
1024 + if ( isset($_POST['search']) && is_array($_POST['search']) && !empty($_POST['search']) && isset($_POST['replace']) && is_array($_POST['replace']) && !empty($_POST['replace']) )
1025 + {
1026 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Search members and paired replacement strings are shape-checked, unslashed and sanitized below.
1027 + foreach ( $_POST['search'] as $i => $search )
1028 + {
1029 + if ( ! is_string( $search ) || ! isset( $_POST['replace'][$i] ) || ! is_string( $_POST['replace'][$i] ) ) {
1030 + return;
1031 + }
1032 + $search = sanitize_text_field( wp_unslash( $search ) );
1033 + $replace = sanitize_text_field( wp_unslash( $_POST['replace'][$i] ) );
1034 + if ( trim( $search ) !== '' && trim( $replace ) !== '' )
1035 + {
1036 + $text_translations[] = array(
1037 + 'search' => $search,
1038 + 'replace' => $replace,
1039 + );
1040 + }
1041 + }
1042 + }
1043 +
1044 + $propertyhive_template_assistant = array(
1045 + 'text_translations' => $text_translations,
1046 + );
1047 +
1048 + $propertyhive_template_assistant = array_merge($current_settings, $propertyhive_template_assistant);
1049 +
1050 + update_option( 'propertyhive_template_assistant', $propertyhive_template_assistant );
1051 + break;
1052 + }
584 1053 case 'misc':
585 1054 {
586 1055 $settings = $this->get_general_misc_setting();
587 1056
@@ -592,13 +1061,149 @@
592 1061 }
593 1062 }
594 1063 else
595 1064 {
1065 + // Validate the complete custom-department form before any options are changed.
1066 + $department_lists = array();
1067 + foreach ( array( 'propertyhive_custom_departments', 'propertyhive_custom_departments_original' ) as $field ) {
1068 + if ( isset( $_POST[ $field ] ) && ! is_string( $_POST[ $field ] ) ) {
1069 + return;
1070 + }
1071 + $raw_list = isset( $_POST[ $field ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field ] ) ) : '';
1072 + $department_lists[ $field ] = array_filter( explode( ',', $raw_list ) );
1073 + }
1074 + $department_details = array();
1075 + foreach ( $department_lists['propertyhive_custom_departments'] as $department_id ) {
1076 + foreach ( array( 'name', 'based_on' ) as $detail ) {
1077 + $field = 'propertyhive_active_departments_' . $detail . '_' . $department_id;
1078 + if ( ! isset( $_POST[ $field ] ) || ! is_string( $_POST[ $field ] ) ) {
1079 + return;
1080 + }
1081 + $department_details[ $department_id ][ $detail ] = sanitize_text_field( wp_unslash( $_POST[ $field ] ) );
1082 + }
1083 + }
1084 +
596 1085 $settings = $this->get_settings();
597 1086
598 1087 PH_Admin_Settings::save_fields( $settings );
599 1088
600 - flush_rewrite_rules();
1089 + $departments = ph_get_departments();
1090 +
1091 + foreach ( $departments as $key => $value )
1092 + {
1093 + if ( substr($key, 0, 6) == 'phnew-' )
1094 + {
1095 + // Ignore new departments as we'll deal with them separately
1096 + continue;
1097 + }
1098 +
1099 + if (
1100 + isset($_POST['propertyhive_active_departments_' . str_replace("residential-", "", $key)])
1101 + )
1102 + {
1103 + $option_value = 'yes';
1104 + }
1105 + else
1106 + {
1107 + $option_value = 'no';
1108 + }
1109 +
1110 + update_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key), $option_value );
1111 + }
1112 +
1113 + $custom_departments = array();
1114 + if ( ! empty( $department_lists['propertyhive_custom_departments'] ) )
1115 + {
1116 + $submitted_custom_departments = $department_lists['propertyhive_custom_departments'];
1117 + $submitted_custom_departments = array_filter($submitted_custom_departments);
1118 + if ( !empty($submitted_custom_departments) )
1119 + {
1120 + foreach ( $submitted_custom_departments as $submitted_custom_department )
1121 + {
1122 + if (
1123 + isset($_POST['propertyhive_active_departments_' . $submitted_custom_department])
1124 + )
1125 + {
1126 + $option_value = 'yes';
1127 + }
1128 + else
1129 + {
1130 + $option_value = 'no';
1131 + }
1132 +
1133 + $key = $submitted_custom_department;
1134 + if ( substr($submitted_custom_department, 0, 6) == 'phnew-' )
1135 + {
1136 + $key = sanitize_title( $department_details[ $submitted_custom_department ]['name'] );
1137 + }
1138 +
1139 + $custom_departments[$key] = array(
1140 + 'name' => $department_details[ $submitted_custom_department ]['name'],
1141 + 'based_on' => $department_details[ $submitted_custom_department ]['based_on']
1142 + );
1143 +
1144 + update_option( 'propertyhive_active_departments_' . $key, $option_value );
1145 + }
1146 + }
1147 + }
1148 +
1149 + update_option( 'propertyhive_custom_departments', $custom_departments );
1150 +
1151 + // TO DO: Cater for deleted departments
1152 + if ( ! empty( $department_lists['propertyhive_custom_departments_original'] ) )
1153 + {
1154 + $original_custom_departments = $department_lists['propertyhive_custom_departments_original'];
1155 + $original_custom_departments = array_filter($original_custom_departments);
1156 + if ( !empty($original_custom_departments) )
1157 + {
1158 + $submitted_custom_departments = $department_lists['propertyhive_custom_departments'];
1159 + $submitted_custom_departments = array_filter($submitted_custom_departments);
1160 +
1161 + foreach ( $original_custom_departments as $original_custom_department )
1162 + {
1163 + if ( !in_array($original_custom_department, $submitted_custom_departments) )
1164 + {
1165 + // no longer present
1166 + delete_option( 'propertyhive_active_departments_' . $original_custom_department );
1167 + }
1168 + }
1169 + }
1170 + }
1171 +
1172 + // Update departments in any search forms
1173 + $current_settings = get_option( 'propertyhive_template_assistant', array() );
1174 +
1175 + if ( isset($current_settings['search_forms']) && !empty($current_settings['search_forms']) )
1176 + {
1177 + foreach ( $current_settings['search_forms'] as $id => $form )
1178 + {
1179 + if ( isset($form['active_fields']) && isset($form['active_fields']['department']) && isset($form['active_fields']['department']['options']) )
1180 + {
1181 + // We have a department field in this form. Check options match current department settings
1182 +
1183 + $departments = ph_get_departments();
1184 +
1185 + foreach ( $departments as $key => $value )
1186 + {
1187 + $department_active = get_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key) );
1188 +
1189 + if ( $department_active != 'yes' && isset($form['active_fields']['department']['options'][$key]) )
1190 + {
1191 + unset($form['active_fields']['department']['options'][$key]);
1192 + }
1193 +
1194 + if ( $department_active == 'yes' && !isset($form['active_fields']['department']['options'][$key]) )
1195 + {
1196 + $form['active_fields']['department']['options'][$key] = $value;
1197 + }
1198 + }
1199 +
1200 + $current_settings['search_forms'][$id]['active_fields'] = $form['active_fields'];
1201 + }
1202 + }
1203 + }
1204 +
1205 + update_option( 'propertyhive_template_assistant', $current_settings );
601 1206 }
602 1207 }
603 1208
604 1209 }