PluginProbe
Property Hive / 2.2.3
Property Hive v2.2.3
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 1.4.62 All 260 releases
propertyhive / includes / admin / settings / class-ph-settings-general.php

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

1,161 lines 53.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PropertyHive General Settings
4 *
5 * @author PropertyHive
6 * @category Admin
7 * @package PropertyHive/Admin
8 * @version 1.0.0
9 */
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly
13 }
14
15 if ( ! class_exists( 'PH_Settings_General' ) ) :
16
17 /**
18 * PH_Settings_General
19 */
20 class PH_Settings_General extends PH_Settings_Page {
21
22 /**
23 * Constructor.
24 */
25 public function __construct() {
26 $this->id = 'general';
27 $this->label = __( 'General', 'propertyhive' );
28
29 add_filter( 'propertyhive_settings_tabs_array', array( $this, 'add_settings_page' ), 5 );
30 add_action( 'propertyhive_sections_' . $this->id, array( $this, 'output_sections' ) );
31 add_action( 'propertyhive_settings_' . $this->id, array( $this, 'output' ) );
32 add_action( 'propertyhive_settings_save_' . $this->id, array( $this, 'save' ) );
33 }
34
35 /**
36 * Get sections
37 *
38 * @return array
39 */
40 public function get_sections() {
41 $sections = array(
42 '' => __( 'General', 'propertyhive' ),
43 'modules' => __( 'Modules', 'propertyhive' ),
44 'map' => __( 'Map', 'propertyhive' ),
45 'media' => __( 'Media', 'propertyhive' ),
46 'international' => __( 'International', 'propertyhive' ),
47 'gdpr' => __( 'GDPR', 'propertyhive' ),
48 'captcha' => __( 'CAPTCHA', 'propertyhive' ),
49 'text-substitution' => __( 'Text Substitution', 'propertyhive' ),
50 'misc' => __( 'Miscellaneous', 'propertyhive' ),
51 );
52
53 return $sections;
54 }
55
56
57 /**
58 * Get general settings array
59 *
60 * @return array
61 */
62 public function get_settings() {
63
64 $default_departments = ph_get_departments(true);
65 $departments = ph_get_departments();
66 $custom_departments = ph_get_custom_departments(false);
67
68 $settings = array(
69
70 array( 'title' => __( 'General Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'general_options' ),
71
72 );
73
74 $active_departments_html = '<div id="active_departments">';
75
76 foreach ( $departments as $key => $value )
77 {
78 if ( isset($custom_departments[$key]) )
79 {
80
81 }
82 else
83 {
84 $active_departments_html .= '<fieldset>
85 <legend class="screen-reader-text"><span>' . esc_html(__( 'Active Departments', 'propertyhive' )) . '</span></legend>
86 <label for="propertyhive_active_departments_' . esc_attr(str_replace("residential-", "", $key)) . '">
87 <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) . '
88 </label>
89 </fieldset>';
90 }
91 }
92
93 if ( !empty($custom_departments) )
94 {
95 foreach ( $custom_departments as $key => $custom_department )
96 {
97 // key will be custom-0, for example
98 $active_departments_html .= '<fieldset id="propertyhive_active_department_fieldset_' . esc_attr($key) . '">
99 <legend class="screen-reader-text"><span>' . esc_html(__( 'Active Departments', 'propertyhive' )) . '</span></legend>
100 <label>
101 <input name="propertyhive_active_departments_' . esc_attr($key) . '" type="checkbox" value="1" ' . checked( get_option('propertyhive_active_departments_' . $key), 'yes', false ) . '>
102 <input type="text" name="propertyhive_active_departments_name_' . esc_attr($key) . '" value="' . $custom_department['name'] . '">
103 ' . __( 'based on', 'propertyhive' ) . '
104 <select name="propertyhive_active_departments_based_on_' . esc_attr($key) . '">
105 <option value=""></option>';
106 foreach ( $default_departments as $dept_key => $value )
107 {
108 $active_departments_html .= '<option value="' . esc_attr($dept_key) . '"' . selected( $custom_department['based_on'], $dept_key, false ) . '>' . esc_html($value) . '</option>';
109 }
110 $active_departments_html .= '
111 </select>
112 <a href="" class="delete-department" data-department="' . esc_attr($key) . '">Delete</a>
113 </label>
114 </fieldset>';
115 }
116 }
117
118 $active_departments_html .= '</div>
119 <a href="" id="add_department">+ ' . esc_html(__( 'Add Department', 'propertyhive' )) . '</a>
120 <input type="hidden" name="propertyhive_new_custom_departments" id="propertyhive_new_custom_departments" value="0">
121 <input type="hidden" name="propertyhive_custom_departments" id="propertyhive_custom_departments" value="' . esc_attr(implode(",", array_keys($custom_departments))) . '">
122 <input type="hidden" name="propertyhive_custom_departments_original" id="propertyhive_custom_departments_original" value="' . esc_attr(implode(",", array_keys($custom_departments))) . '">
123 ';
124
125 $active_departments_html .= '<div id="active_department_template" style="display:none">
126 <fieldset id="propertyhive_active_department_fieldset_template">
127 <legend class="screen-reader-text"><span>' . __( 'Active Departments', 'propertyhive' ) . '</span></legend>
128 <label>
129 <input name="propertyhive_active_departments_template" type="checkbox" value="1" checked>
130 <input type="text" name="propertyhive_active_departments_name_template" value="">
131 ' . __( 'based on', 'propertyhive' ) . '
132 <select name="propertyhive_active_departments_based_on_template">
133 <option value=""></option>';
134 foreach ( $default_departments as $key => $value )
135 {
136 $active_departments_html .= '<option value="' . esc_attr($key) . '">' . esc_html($value) . '</option>';
137 }
138 $active_departments_html .= '
139 </select>
140 <a href="" class="delete-department" data-department="template">Delete</a>
141 </label>
142 </fieldset>
143 </div>';
144
145 $settings[] = array(
146 'title' => __( 'Active Departments', 'propertyhive' ),
147 'id' => 'propertyhive_active_departments',
148 'type' => 'html',
149 'html' => $active_departments_html,
150 );
151
152 $settings[] = array(
153 'title' => __( 'Primary Department', 'propertyhive' ),
154 'id' => 'propertyhive_primary_department',
155 'type' => 'radio',
156 'default' => 'residential-sales',
157 'options' => $departments,
158 );
159
160 $settings[] = array(
161 'title' => __( 'Property Search Results Page', 'propertyhive' ),
162 'id' => 'propertyhive_search_results_page_id',
163 'type' => 'single_select_page',
164 'default' => '',
165 'css' => 'min-width:300px;',
166 'desc' => __( 'This sets the page of your property search results', 'propertyhive' ),
167 );
168
169 $settings[] = array(
170 'title' => __( 'Lettings Fees (Residential)', 'propertyhive' ),
171 'id' => 'propertyhive_lettings_fees',
172 'type' => 'textarea',
173 'css' => 'height:150px; width:100%; max-width:400px'
174 );
175
176 $settings[] = array(
177 'title' => __( 'Lettings Fees (Commercial)', 'propertyhive' ),
178 'id' => 'propertyhive_lettings_fees_commercial',
179 'type' => 'textarea',
180 'css' => 'height:150px; width:100%; max-width:400px'
181 );
182
183 $settings[] = array(
184 'title' => __( 'Display Link To Lettings Fees Next To Price', 'propertyhive' ),
185 'desc' => __( 'In Search Results', 'propertyhive' ),
186 'id' => 'propertyhive_lettings_fees_display_search_results',
187 'type' => 'checkbox',
188 'checkboxgroup' => 'start',
189 );
190
191 $settings[] = array(
192 'title' => __( 'Display Link To Lettings Fees Next To Price', 'propertyhive' ),
193 'desc' => __( 'On Property Details Page', 'propertyhive' ),
194 'id' => 'propertyhive_lettings_fees_display_single_property',
195 'type' => 'checkbox',
196 'checkboxgroup' => 'end',
197 );
198
199 $settings[] = array( 'type' => 'sectionend', 'id' => 'general_options');
200
201 return apply_filters( 'propertyhive_general_settings', $settings );
202 }
203
204 /**
205 * Get general modules settings array
206 *
207 * @return array
208 */
209 public function get_general_modules_setting() {
210
211 return apply_filters( 'propertyhive_general_modules_settings', array(
212
213 array( 'title' => __( 'Disabled Modules', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'modules_options' ),
214
215 array(
216 'type' => 'html',
217 'html' => __( 'Here you can choose which modules are enabled or disabled within Property Hive. Check the modules you <strong>DO NOT</strong> wish to use from the list below', 'propertyhive' ) . ':',
218 ),
219
220 array(
221 'title' => __( 'Disabled Modules', 'propertyhive' ),
222 'desc' => __( 'Contacts (Applicants, Owners/Landlords and Third Party Contacts)', 'propertyhive' ),
223 'id' => 'propertyhive_module_disabled_contacts',
224 'type' => 'checkbox',
225 'default' => '',
226 'checkboxgroup' => 'start'
227 ),
228
229 array(
230 'title' => __( 'Disabled Modules', 'propertyhive' ),
231 'desc' => __( 'Appraisals', 'propertyhive' ),
232 'id' => 'propertyhive_module_disabled_appraisals',
233 'type' => 'checkbox',
234 'default' => '',
235 'checkboxgroup' => 'middle'
236 ),
237
238 array(
239 'title' => __( 'Disabled Modules', 'propertyhive' ),
240 'desc' => __( 'Viewings', 'propertyhive' ),
241 'id' => 'propertyhive_module_disabled_viewings',
242 'type' => 'checkbox',
243 'default' => '',
244 'checkboxgroup' => 'middle'
245 ),
246
247 array(
248 'title' => __( 'Disabled Modules', 'propertyhive' ),
249 'desc' => __( 'Offers and Sales', 'propertyhive' ),
250 'id' => 'propertyhive_module_disabled_offers_sales',
251 'type' => 'checkbox',
252 'default' => '',
253 'checkboxgroup' => 'middle'
254 ),
255
256 array(
257 'title' => __( 'Disabled Modules', 'propertyhive' ),
258 'desc' => __( 'Tenancies', 'propertyhive' ),
259 'id' => 'propertyhive_module_disabled_tenancies',
260 'type' => 'checkbox',
261 'default' => '',
262 'checkboxgroup' => 'middle'
263 ),
264
265 array(
266 'title' => __( 'Disabled Modules', 'propertyhive' ),
267 'desc' => __( 'Enquiries', 'propertyhive' ),
268 'id' => 'propertyhive_module_disabled_enquiries',
269 'type' => 'checkbox',
270 'default' => '',
271 'checkboxgroup' => 'end'
272 ),
273
274 array( 'type' => 'sectionend', 'id' => 'modules_options'),
275
276 ) ); // End general module settings
277 }
278
279 /**
280 * Get international settings array
281 *
282 * @return array
283 */
284 public function get_general_international_setting() {
285
286 $settings = array(
287
288 array( 'title' => __( 'International Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'international_options' ),
289
290 array(
291 'title' => __( 'Countries Where You Operate', 'propertyhive' ),
292 'id' => 'propertyhive_countries',
293 'type' => 'multi_select_countries',
294 'css' => 'min-width:300px;',
295 'desc' => __( 'Hold ctrl/cmd whilst clicking to select multiple', 'propertyhive' )
296 ),
297
298 array(
299 'title' => __( 'Default Country', 'propertyhive' ),
300 'id' => 'propertyhive_default_country',
301 'type' => 'single_select_country',
302 'css' => 'min-width:300px;',
303 ),
304
305 array(
306 'title' => __( 'Price Thousand Separator', 'propertyhive' ),
307 'id' => 'propertyhive_price_thousand_separator',
308 'type' => 'text',
309 'default' => ',',
310 'css' => 'width:50px;',
311 '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' )
312 ),
313
314 array(
315 'title' => __( 'Price Decimal Separator', 'propertyhive' ),
316 'id' => 'propertyhive_price_decimal_separator',
317 'type' => 'text',
318 'default' => '.',
319 'css' => 'width:50px;',
320 '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' )
321 )
322 );
323
324 $ph_countries = new PH_Countries();
325 $ph_countries = $ph_countries->countries;
326
327 $currencies = array();
328 $countries = array();
329 if ( !empty($ph_countries) )
330 {
331 foreach ( $ph_countries as $country_code => $country )
332 {
333 $currencies[$country['currency_code']] = $country['currency_code'];
334 $countries[$country_code] = $country;
335 }
336 }
337 $currencies = array_unique($currencies);
338 ksort($currencies);
339
340 $settings[] = array(
341 'title' => __( 'Currency Used In Search Forms', 'propertyhive' ),
342 'id' => 'propertyhive_search_form_currency',
343 'type' => 'select',
344 'options' => $currencies,
345 'default' => 'GBP',
346 'desc' => __( 'Please note that this doesn\'t change the currency symbol shown in price dropdowns within search forms. The easiest way to achieve that is to use our free <a href="https://wp-property-hive.com/addons/template-assistant/" target="_blank">Template Assistant add on</a>.', 'propertyhive' ),
347 );
348
349 $settings[] = array( 'type' => 'sectionend', 'id' => 'international_options');
350
351 $settings[] = array(
352 'type' => 'html',
353 'html' => '<script>
354
355 var countries = '. json_encode( $countries ) . ';
356
357 </script>'
358 );
359
360 return apply_filters( 'propertyhive_general_international_settings', $settings );
361 }
362
363 /**
364 * Get map settings array
365 *
366 * @return array
367 */
368 public function get_general_map_setting() {
369
370 $settings = array(
371
372 array( 'title' => __( 'Map Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'map_options' ),
373
374 array(
375 'title' => __( 'Maps Provider', 'propertyhive' ),
376 'id' => 'propertyhive_maps_provider',
377 'type' => 'radio',
378 'options' => array(
379 '' => 'Google Maps',
380 'mapbox' => 'Mapbox',
381 'osm' => 'OpenStreetMap',
382 ),
383 ),
384
385 array(
386 'title' => __( 'Google Maps API Key', 'propertyhive' ),
387 'id' => 'propertyhive_google_maps_api_key',
388 'type' => 'text',
389 '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>'
390 ),
391
392 array(
393 'title' => __( 'Mapbox API Key', 'propertyhive' ),
394 'id' => 'propertyhive_mapbox_api_key',
395 'type' => 'text',
396 '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>'
397 ),
398
399 array(
400 'title' => __( 'Geocoding Provider', 'propertyhive' ),
401 'id' => 'propertyhive_geocoding_provider',
402 'type' => 'radio',
403 'options' => array(
404 '' => 'Google Maps',
405 //'mapbox' => 'Mapbox',
406 'osm' => 'OpenStreetMap',
407 ),
408 ),
409
410 array(
411 'id' => 'propertyhive_osm_html',
412 'type' => 'html',
413 '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>'
414 ),
415 );
416
417 if ( apply_filters( 'propertyhive_use_google_maps_geocoding_api_key', false) === true )
418 {
419 $settings[] = array(
420 'title' => __( 'Google Maps Geocoding API Key', 'propertyhive' ),
421 'id' => 'propertyhive_google_maps_geocoding_api_key',
422 'type' => 'text',
423 '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>'
424 );
425
426 $settings[] = array(
427 'title' => __( 'Mapbox Geocoding API Key', 'propertyhive' ),
428 'id' => 'propertyhive_mapbox_geocoding_api_key',
429 'type' => 'text',
430 '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>'
431 );
432 }
433
434 $settings[] = array( 'type' => 'sectionend', 'id' => 'map_options');
435
436 return apply_filters( 'propertyhive_general_map_settings', $settings );
437 }
438
439 /**
440 * Get media settings array
441 *
442 * @return array
443 */
444 public function get_general_media_setting() {
445
446 $settings = array(
447
448 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' ),
449
450 array(
451 'title' => __( 'Images Stored As', 'propertyhive' ),
452 'id' => 'propertyhive_images_stored_as',
453 'type' => 'select',
454 'default' => 'files',
455 'options' => array(
456 'files' => __( 'Media Files', 'propertyhive' ),
457 'urls' => __( 'URLs', 'propertyhive' ),
458 ),
459 'desc' => ''
460 ),
461
462 array(
463 'title' => __( 'Floorplans Stored As', 'propertyhive' ),
464 'id' => 'propertyhive_floorplans_stored_as',
465 'type' => 'select',
466 'default' => 'files',
467 'options' => array(
468 'files' => __( 'Media Files', 'propertyhive' ),
469 'urls' => __( 'URLs', 'propertyhive' ),
470 ),
471 'desc' => ''
472 ),
473
474 array(
475 'title' => __( 'Brochures Stored As', 'propertyhive' ),
476 'id' => 'propertyhive_brochures_stored_as',
477 'type' => 'select',
478 'default' => 'files',
479 'options' => array(
480 'files' => __( 'Media Files', 'propertyhive' ),
481 'urls' => __( 'URLs', 'propertyhive' ),
482 ),
483 'desc' => ''
484 ),
485
486 array(
487 'title' => __( 'EPCs Stored As', 'propertyhive' ),
488 'id' => 'propertyhive_epcs_stored_as',
489 'type' => 'select',
490 'default' => 'files',
491 'options' => array(
492 'files' => __( 'Media Files', 'propertyhive' ),
493 'urls' => __( 'URLs', 'propertyhive' ),
494 ),
495 'desc' => ''
496 ),
497
498 array( 'type' => 'sectionend', 'id' => 'media_storage_options')
499
500 );
501
502 return apply_filters( 'propertyhive_general_media_settings', $settings );
503 }
504
505 /**
506 * Get GDPR settings array
507 *
508 * @return array
509 */
510 public function get_general_gdpr_setting() {
511
512 return apply_filters( 'propertyhive_general_gdpr_settings', array(
513
514 array( 'title' => __( 'GDPR Settings', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'gdpr_options' ),
515
516 array(
517 'title' => __( 'Store Property Enquiries', 'propertyhive' ),
518 'id' => 'propertyhive_store_property_enquiries',
519 'type' => 'checkbox',
520 'default' => 'yes',
521 'desc' => __( 'If using the default property enquiry form that comes with Property Hive, select this option if enquiries should be saved in the \'Enquiries\' section of Property Hive. Note that regardless of whether this is ticked or not, the enquiry will still be sent via email. This option simply determines whether we save it to the database or not.', 'propertyhive' )
522 ),
523
524 array(
525 'title' => __( 'Property Enquiry Form Disclaimer', 'propertyhive' ),
526 'id' => 'propertyhive_property_enquiry_form_disclaimer',
527 'type' => 'wysiwyg',
528 'desc' => __( 'Add disclaimer text, including a link to a privacy policy, that will appear on the property enquiry form.', 'propertyhive' )
529 ),
530
531 array(
532 'title' => __( 'Applicant Registration Form Disclaimer', 'propertyhive' ),
533 'id' => 'propertyhive_applicant_registration_form_disclaimer',
534 'type' => 'wysiwyg',
535 'desc' => __( 'Add disclaimer text, including a link to a privacy policy, that will appear on the applicant registration form.', 'propertyhive' )
536 ),
537
538 array( 'type' => 'sectionend', 'id' => 'gdpr_options'),
539
540 ) ); // End general GDPR settings
541 }
542
543 /**
544 * Get CAPTCHA settings array
545 *
546 * @return array
547 */
548 public function get_general_captcha_setting() {
549
550 return apply_filters( 'propertyhive_general_captcha_settings', array(
551
552 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' ) ),
553
554 array(
555 'title' => __( 'CAPTCHA service', 'propertyhive' ),
556 'id' => 'propertyhive_captcha_service',
557 'type' => 'radio',
558 'options' => array(
559 '' => __( 'None', 'propertyhive' ),
560 'recaptcha' => __( 'Google reCaptcha v2', 'propertyhive' ) . ' (<a href="https://www.google.com/recaptcha/admin/create" target="_blank">register</a>)',
561 'recaptcha-v3' => __( 'Google reCaptcha v3', 'propertyhive' ) . ' (<a href="https://www.google.com/recaptcha/admin/create" target="_blank">register</a>)',
562 'hCaptcha' => __( 'hCaptcha', 'propertyhive' ) . ' (<a href="https://www.hcaptcha.com/" target="_blank">register</a>)',
563 'turnstile' => __( 'Cloudflare Turnstile', 'propertyhive' ) . ' (<a href="https://www.cloudflare.com/en-gb/application-services/products/turnstile/" target="_blank">register</a>)',
564 ),
565 ),
566
567 array(
568 'title' => __( 'Site Key', 'propertyhive' ),
569 'id' => 'propertyhive_captcha_site_key',
570 'type' => 'text',
571 ),
572
573 array(
574 'title' => __( 'Secret', 'propertyhive' ),
575 'id' => 'propertyhive_captcha_secret',
576 'type' => 'text',
577 ),
578
579 array(
580 'title' => __( 'Score Threshold', 'propertyhive' ),
581 'id' => 'propertyhive_captcha_score_threshold',
582 'type' => 'text',
583 'default' => 0.5,
584 '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' ),
585 ),
586
587 array(
588 //'title' => __( 'CAPTCHA service', 'propertyhive' ),
589 'id' => 'propertyhive_captcha_html',
590 'type' => 'html',
591 'html' => '<script>
592 jQuery(document).ready(function()
593 {
594 jQuery(\'input[name=\\\'propertyhive_captcha_service\\\']\').change(function()
595 {
596 ph_captcha_service_update();
597 });
598
599 ph_captcha_service_update();
600 });
601
602 function ph_captcha_service_update()
603 {
604 jQuery(\'#row_propertyhive_captcha_site_key\').hide();
605 jQuery(\'#row_propertyhive_captcha_secret\').hide();
606 jQuery(\'#row_propertyhive_captcha_score_threshold\').hide();
607
608 var selected_captcha_service = jQuery(\'input[name=\\\'propertyhive_captcha_service\\\']:checked\').val();
609
610 if ( selected_captcha_service != \'\' )
611 {
612 jQuery(\'#row_propertyhive_captcha_site_key\').show();
613 jQuery(\'#row_propertyhive_captcha_secret\').show();
614
615 if ( selected_captcha_service == \'recaptcha-v3\' )
616 {
617 jQuery(\'#row_propertyhive_captcha_score_threshold\').show();
618 }
619 }
620 }
621 </script>',
622 ),
623
624 array( 'type' => 'sectionend', 'id' => 'captcha_options'),
625
626 ) ); // End general CAPTCHA settings
627 }
628
629 /**
630 * Get text substitution settings array
631 *
632 * @return array
633 */
634 public function get_general_text_substitution_setting() {
635
636 $current_settings = get_option( 'propertyhive_template_assistant', array() );
637
638 $settings = array(
639
640 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' )
641
642 );
643
644 $existing_translations = array();
645 if ( isset($current_settings['text_translations']) && is_array($current_settings['text_translations']) && !empty($current_settings['text_translations']) )
646 {
647 foreach ( $current_settings['text_translations'] as $text_translation )
648 {
649 $existing_translations[] = '<tr>
650 <td><input type="text" name="search[]" class="regular-text" value="' . esc_attr($text_translation['search']) . '"></td>
651 <td><input type="text" name="replace[]" class="regular-text" value="' . esc_attr($text_translation['replace']) . '"></td>
652 <td><a href="" class="delete-text-substitution" title="Delete Text Substitution"><span class="dashicons dashicons-trash"></span></a></td>
653 </tr>';
654 }
655 }
656
657 $settings[] = array(
658 'type' => 'html',
659 'html' => '
660
661 <style type="text/css">.form-table .titledesc { display:none; }</style>
662
663 <table class="widefat striped" style="max-width:520px;" >
664 <thead>
665 <tr>
666 <th style="padding:8px 10px;" scope="col">Text To Replace</th>
667 <th style="padding:8px 10px;" scope="col">Replace With</th>
668 <th style="padding:8px 10px;" scope="col">&nbsp;</th>
669 </tr>
670 </thead>
671 <tbody>
672 ' . implode("", $existing_translations) . '
673 <tr>
674 <td><input type="text" name="search[]" class="regular-text" placeholder="e.g. Make Enquiry"></td>
675 <td><input type="text" name="replace[]" class="regular-text" placeholder="e.g. Request Viewing"></td>
676 <td>&nbsp;</td>
677 </tr>
678 </tbody>
679 </table>
680
681 <script>
682 jQuery(document).ready(function()
683 {
684 jQuery(\'a.delete-text-substitution\').on(\'click\', function(e)
685 {
686 e.preventDefault();
687
688 jQuery(this).closest(\'tr\').find(\'input\').val(\'\');
689
690 setTimeout(function() {
691 jQuery(\'.submit button[type="submit"]\').trigger(\'click\');
692 }, 0);
693 });
694 });
695 </script>'
696 );
697
698 $settings[] = array( 'type' => 'sectionend', 'id' => 'template_assistant_text_translation_settings');
699
700 return $settings;
701 }
702
703 /**
704 * Get misc settings array
705 *
706 * @return array
707 */
708 public function get_general_misc_setting() {
709
710 return apply_filters( 'propertyhive_general_misc_settings', array(
711
712 array( 'title' => __( 'Property Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'property_options' ),
713
714 array(
715 'title' => __( 'Search By Address Should', 'propertyhive' ),
716 'id' => 'propertyhive_address_keyword_compare',
717 'type' => 'radio',
718 'default' => '=',
719 'options' => array(
720 '=' => __( 'Match Keyword Exactly', 'propertyhive' ),
721 'LIKE' => __( 'Perform Loose Search', 'propertyhive' ),
722 'polygon' => __( 'Search Within Location Perimeter', 'propertyhive' ),
723 ),
724 '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' )
725 ),
726
727 array(
728 'title' => __( 'Commercial Display In Search Results', 'propertyhive' ),
729 'id' => 'propertyhive_commercial_display',
730 'type' => 'select',
731 'default' => '',
732 'css' => 'min-width:300px;',
733 'options' => array(
734 '' => __( 'Display top level properties and units', 'propertyhive' ),
735 'top_level_only' => __( 'Display top level properties only', 'propertyhive' ),
736 'top_level_only_but_units_when_filtered' => __( 'Display top level properties only but units as well if matching filters', 'propertyhive' ),
737 ),
738 ),
739
740 array(
741 'title' => __( 'When An Off Market Property URL Is Viewed', 'propertyhive' ),
742 'id' => 'propertyhive_off_market_behaviour',
743 'type' => 'select',
744 'default' => '',
745 'css' => 'min-width:300px;',
746 'options' => array(
747 '' => __( 'Still show the property details', 'propertyhive' ),
748 'redirect' => __( 'Do a 301 redirect to the search results page', 'propertyhive' ),
749 ),
750 'desc' => __( 'If 301 redirect is selected, this will only apply to non-logged in users', 'propertyhive' )
751 ),
752
753 array(
754 'title' => __( 'When Entering Features', 'propertyhive' ),
755 'id' => 'propertyhive_features_type',
756 'type' => 'radio',
757 'options' => array(
758 '' => __( 'Allow Features To Be Freetyped', 'propertyhive' ),
759 'checkbox' => __( 'Select From A Predefined List (Editable from \'Custom Fields\')', 'propertyhive' ),
760 ),
761 ),
762
763 array(
764 'title' => __( 'Enable Auto-Incremental Reference Numbers', 'propertyhive' ),
765 'id' => 'propertyhive_auto_incremental_reference_numbers',
766 'type' => 'checkbox',
767 'desc' => __( 'Will prefill the property reference with an auto-incremental number when adding a new property', 'propertyhive' )
768 ),
769
770 array(
771 'title' => __( 'Next Incremental Reference Number', 'propertyhive' ),
772 'id' => 'propertyhive_auto_incremental_next',
773 'type' => 'number',
774 'default' => 1,
775 ),
776
777 array( 'type' => 'sectionend', 'id' => 'property_options'),
778
779 array( 'title' => __( 'Applicant Options', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'applicant_registration_options' ),
780
781 array(
782 'title' => __( 'Allow Applicants To Login and Manage Account', 'propertyhive' ),
783 'id' => 'propertyhive_applicant_users',
784 'type' => 'checkbox',
785 'desc' => __( 'Applicable when you allow users to register on a form using the [applicant_registration_form] shortcode.<br><br>Selecting this will allow applicants to create a password when registering, then login to manage their details and requirements. They will be created as a WordPress user with \'Property Hive Contact\' role.<br><br>If unticked applicants will still be able to register and they\'ll go into Property Hive as an applicant, they just won\'t be able to login at a later date.', 'propertyhive' )
786 ),
787
788 array(
789 'title' => __( 'Send Email When Applicant Registers', 'propertyhive' ),
790 'id' => 'propertyhive_new_registration_alert',
791 'type' => 'checkbox',
792 'desc' => __( 'Choose whether an email should be sent alerting you to the fact someone has registered. The email will be sent to the chosen office. Offices can be managed click selecting the \'Offices\' tab above.', 'propertyhive' )
793 ),
794
795 array(
796 'title' => __( 'My Account Page', 'propertyhive' ),
797 'id' => 'propertyhive_my_account_page_id',
798 'type' => 'single_select_page',
799 'default' => '',
800 'css' => 'min-width:300px;',
801 'desc' => __( 'This page should contain the [propertyhive_my_account] shortcode', 'propertyhive' ),
802 ),
803
804 array(
805 'title' => __( 'Applicant Login Page', 'propertyhive' ),
806 'id' => 'propertyhive_applicant_login_page_id',
807 'type' => 'single_select_page',
808 'default' => '',
809 'css' => 'min-width:300px;',
810 'desc' => __( 'This page should contain the [propertyhive_login_form] shortcode', 'propertyhive' ),
811 ),
812
813 array(
814 'title' => __( 'Applicant Reset Password Page', 'propertyhive' ),
815 'id' => 'propertyhive_applicant_reset_password_page_id',
816 'type' => 'single_select_page',
817 'default' => '',
818 'css' => 'min-width:300px;',
819 'desc' => __( 'This page should contain the [propertyhive_reset_password_form] shortcode', 'propertyhive' ),
820 ),
821
822 array(
823 'title' => __( 'Applicant Registration Page', 'propertyhive' ),
824 'id' => 'propertyhive_applicant_registration_page_id',
825 'type' => 'single_select_page',
826 'default' => '',
827 'css' => 'min-width:300px;',
828 'desc' => __( 'This page should contain the [applicant_registration_form] shortcode', 'propertyhive' ),
829 ),
830
831 array(
832 'title' => __( 'Match Price Range % (Lower)', 'propertyhive' ),
833 'id' => 'propertyhive_applicant_match_price_range_percentage_lower',
834 'type' => 'number',
835 'default' => '20',
836 'desc' => '<p>' . __( 'When a maximum price is entered against an applicants requirements we create a \'Match Price Range\' which determines the price of properties that would get matched to the applicant.<br>We do this because you:<br>a) Wouldn\'t want to send them properties that were way below their specified maximum price and<br>b) Would probably want to send them properties which are slightly just over the price specified as, if the perfect property came along, a lot of people would actually be able to increase their maximum.<br>These settings determine the % above and below the maximum price entered that the \'Match Price Range\' will default to per applicant.<br>For example, if the maximum price entered was &pound;500,000, the lower setting was 20% and the higher setting was 5%, the applicant would actually match to properties that were priced &pound;400,000 - &pound;525,000.<br>This price range can be overwritten on a per-applicant basis, or disabled completely by leaving these settings empty.<br>Note that this currently only applies to applicants looking for sales properties and changing this value at a later date will only effect applicants that don\'t already have a match price range set.', 'propertyhive' ) . '</p>',
837 ),
838
839 array(
840 'title' => __( 'Match Price Range % (Higher)', 'propertyhive' ),
841 'id' => 'propertyhive_applicant_match_price_range_percentage_higher',
842 'type' => 'number',
843 'default' => '5',
844 ),
845
846 array(
847 'title' => __( 'When Selecting Applicant Locations', 'propertyhive' ),
848 'id' => 'propertyhive_applicant_locations_type',
849 'type' => 'radio',
850 'options' => array(
851 'text' => __( 'Allow Locations To Be Freetyped', 'propertyhive' ),
852 '' => __( 'Select From A Predefined List (Editable from \'Custom Fields\')', 'propertyhive' ),
853 ),
854 'desc' => '<i>' . __( 'When this setting is changed, locations selected using the other method will no longer be used for matching', 'propertyhive' ) . '</i>',
855 ),
856
857 array( 'type' => 'sectionend', 'id' => 'applicant_registration_options'),
858
859 array( 'title' => __( 'Improve Property Hive', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'stat_tracking_options' ),
860
861 array(
862 'title' => __( 'Usage Data Sharing', 'propertyhive' ),
863 'id' => 'propertyhive_data_sharing',
864 'type' => 'checkbox',
865 'value' => ( get_option('propertyhive_data_sharing', FALSE) === FALSE ? 'yes' : get_option('propertyhive_data_sharing', '') ),
866 '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' )
867 ),
868
869 array( 'type' => 'sectionend', 'id' => 'stat_tracking_options'),
870
871 ) ); // End general misc settings
872 }
873
874 /**
875 * Output the settings
876 */
877 public function output() {
878 global $current_section;
879
880 if ( $current_section )
881 {
882 switch ($current_section)
883 {
884 case "modules": { $settings = $this->get_general_modules_setting(); break; }
885 case "international": { $settings = $this->get_general_international_setting(); break; }
886 case "map": { $settings = $this->get_general_map_setting(); break; }
887 case "media": { $settings = $this->get_general_media_setting(); break; }
888 case "gdpr": { $settings = $this->get_general_gdpr_setting(); break; }
889 case "captcha": { $settings = $this->get_general_captcha_setting(); break; }
890 case "text-substitution": { $settings = $this->get_general_text_substitution_setting(); break; }
891 case "misc": { $settings = $this->get_general_misc_setting(); break; }
892 default: { die("Unknown setting section"); }
893 }
894 }
895 else
896 {
897 $settings = $this->get_settings();
898 }
899
900 PH_Admin_Settings::output_fields( $settings );
901 }
902
903 /**
904 * Output a colour picker input box.
905 *
906 * @access public
907 * @param mixed $name
908 * @param mixed $id
909 * @param mixed $value
910 * @param string $desc (default: '')
911 * @return void
912 */
913 function color_picker( $name, $id, $value, $desc = '' ) {
914 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>
915 <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>
916 </div>';
917 }
918
919 /**
920 * Save settings
921 */
922 public function save() {
923 global $current_section;
924
925 if ( $current_section != '' )
926 {
927 switch ($current_section)
928 {
929 case 'modules':
930 {
931 $settings = $this->get_general_modules_setting();
932
933 PH_Admin_Settings::save_fields( $settings );
934 break;
935 }
936 case 'international':
937 {
938 if (!isset($_POST['propertyhive_countries']) || (isset($_POST['propertyhive_countries']) && empty($_POST['propertyhive_countries'])))
939 {
940 // If we haven't selected which countries we operate in
941 update_option( 'propertyhive_countries', array( ph_clean($_POST['propertyhive_default_country']) ) );
942 }
943 else
944 {
945 // We have default country and countries set
946 // Make sure default country is in list of countries selected
947 if ( !in_array(ph_clean($_POST['propertyhive_default_country']), ph_clean($_POST['propertyhive_countries'])) ) {
948 $_POST['propertyhive_default_country'] = $_POST['propertyhive_countries'][0];
949 }
950
951 update_option( 'propertyhive_default_country', ph_clean($_POST['propertyhive_default_country']) );
952 update_option( 'propertyhive_countries', ph_clean($_POST['propertyhive_countries']) );
953 }
954
955 update_option( 'propertyhive_price_thousand_separator', ph_clean($_POST['propertyhive_price_thousand_separator']) );
956 update_option( 'propertyhive_price_decimal_separator', ph_clean($_POST['propertyhive_price_decimal_separator']) );
957
958 update_option( 'propertyhive_search_form_currency', ph_clean($_POST['propertyhive_search_form_currency']) );
959
960 do_action( 'propertyhive_update_currency_exchange_rates' );
961
962 break;
963 }
964 case 'map':
965 {
966 $settings = $this->get_general_map_setting();
967
968 PH_Admin_Settings::save_fields( $settings );
969 break;
970 }
971 case 'media':
972 {
973 $settings = $this->get_general_media_setting();
974
975 PH_Admin_Settings::save_fields( $settings );
976 break;
977 }
978 case 'gdpr':
979 {
980 $settings = $this->get_general_gdpr_setting();
981
982 PH_Admin_Settings::save_fields( $settings );
983 break;
984 }
985 case 'captcha':
986 {
987 $settings = $this->get_general_captcha_setting();
988
989 PH_Admin_Settings::save_fields( $settings );
990 break;
991 }
992 case 'text-substitution':
993 {
994 $current_settings = get_option( 'propertyhive_template_assistant', array() );
995
996 $text_translations = array();
997 if ( isset($_POST['search']) && is_array($_POST['search']) && !empty($_POST['search']) && isset($_POST['replace']) && is_array($_POST['replace']) && !empty($_POST['replace']) )
998 {
999 foreach ( $_POST['search'] as $i => $search )
1000 {
1001 if ( trim($search) != '' && trim($_POST['replace'][$i]) != '' )
1002 {
1003 $text_translations[] = array(
1004 'search' => sanitize_text_field(wp_unslash($search)),
1005 'replace' => sanitize_text_field(wp_unslash($_POST['replace'][$i])),
1006 );
1007 }
1008 }
1009 }
1010
1011 $propertyhive_template_assistant = array(
1012 'text_translations' => $text_translations,
1013 );
1014
1015 $propertyhive_template_assistant = array_merge($current_settings, $propertyhive_template_assistant);
1016
1017 update_option( 'propertyhive_template_assistant', $propertyhive_template_assistant );
1018 break;
1019 }
1020 case 'misc':
1021 {
1022 $settings = $this->get_general_misc_setting();
1023
1024 PH_Admin_Settings::save_fields( $settings );
1025 break;
1026 }
1027 default: { die("Unknown setting section"); }
1028 }
1029 }
1030 else
1031 {
1032 $settings = $this->get_settings();
1033
1034 PH_Admin_Settings::save_fields( $settings );
1035
1036 $departments = ph_get_departments();
1037
1038 foreach ( $departments as $key => $value )
1039 {
1040 if ( substr($key, 0, 6) == 'phnew-' )
1041 {
1042 // Ignore new departments as we'll deal with them separately
1043 continue;
1044 }
1045
1046 if (
1047 isset($_POST['propertyhive_active_departments_' . str_replace("residential-", "", $key)])
1048 )
1049 {
1050 $option_value = 'yes';
1051 }
1052 else
1053 {
1054 $option_value = 'no';
1055 }
1056
1057 update_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key), $option_value );
1058 }
1059
1060 $custom_departments = array();
1061 if ( isset($_POST['propertyhive_custom_departments']) && !empty($_POST['propertyhive_custom_departments']) )
1062 {
1063 $submitted_custom_departments = explode(",", $_POST['propertyhive_custom_departments']);
1064 $submitted_custom_departments = array_filter($submitted_custom_departments);
1065 if ( !empty($submitted_custom_departments) )
1066 {
1067 foreach ( $submitted_custom_departments as $submitted_custom_department )
1068 {
1069 if (
1070 isset($_POST['propertyhive_active_departments_' . $submitted_custom_department])
1071 )
1072 {
1073 $option_value = 'yes';
1074 }
1075 else
1076 {
1077 $option_value = 'no';
1078 }
1079
1080 $key = $submitted_custom_department;
1081 if ( substr($submitted_custom_department, 0, 6) == 'phnew-' )
1082 {
1083 $key = sanitize_title($_POST['propertyhive_active_departments_name_' . $submitted_custom_department]);
1084 }
1085
1086 $custom_departments[$key] = array(
1087 'name' => ph_clean($_POST['propertyhive_active_departments_name_' . $submitted_custom_department ]),
1088 'based_on' => ph_clean($_POST['propertyhive_active_departments_based_on_' . $submitted_custom_department ])
1089 );
1090
1091 update_option( 'propertyhive_active_departments_' . $key, $option_value );
1092 }
1093 }
1094 }
1095
1096 update_option( 'propertyhive_custom_departments', $custom_departments );
1097
1098 // TO DO: Cater for deleted departments
1099 if ( isset($_POST['propertyhive_custom_departments_original']) && !empty($_POST['propertyhive_custom_departments_original']) )
1100 {
1101 $original_custom_departments = explode(",", $_POST['propertyhive_custom_departments_original']);
1102 $original_custom_departments = array_filter($original_custom_departments);
1103 if ( !empty($original_custom_departments) )
1104 {
1105 $submitted_custom_departments = explode(",", $_POST['propertyhive_custom_departments']);
1106 $submitted_custom_departments = array_filter($submitted_custom_departments);
1107
1108 foreach ( $original_custom_departments as $original_custom_department )
1109 {
1110 if ( !in_array($original_custom_department, $submitted_custom_departments) )
1111 {
1112 // no longer present
1113 delete_option( 'propertyhive_active_departments_' . $original_custom_department );
1114 }
1115 }
1116 }
1117 }
1118
1119 // Update departments in any search forms
1120 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1121
1122 if ( isset($current_settings['search_forms']) && !empty($current_settings['search_forms']) )
1123 {
1124 foreach ( $current_settings['search_forms'] as $id => $form )
1125 {
1126 if ( isset($form['active_fields']) && isset($form['active_fields']['department']) && isset($form['active_fields']['department']['options']) )
1127 {
1128 // We have a department field in this form. Check options match current department settings
1129
1130 $departments = ph_get_departments();
1131
1132 foreach ( $departments as $key => $value )
1133 {
1134 $department_active = get_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key) );
1135
1136 if ( $department_active != 'yes' && isset($form['active_fields']['department']['options'][$key]) )
1137 {
1138 unset($form['active_fields']['department']['options'][$key]);
1139 }
1140
1141 if ( $department_active == 'yes' && !isset($form['active_fields']['department']['options'][$key]) )
1142 {
1143 $form['active_fields']['department']['options'][$key] = $value;
1144 }
1145 }
1146
1147 $current_settings['search_forms'][$id]['active_fields'] = $form['active_fields'];
1148 }
1149 }
1150 }
1151
1152 update_option( 'propertyhive_template_assistant', $current_settings );
1153 }
1154 }
1155
1156 }
1157
1158 endif;
1159
1160 return new PH_Settings_General();
1161