PluginProbe
Property Hive / 2.3.0
Property Hive v2.3.0
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
← All changes | includes/class-ph-countries.php +396 -115 1.4.492.3.0 View file →
@@ -1,6 +1,9 @@
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.
2 4
5 +
3 6 if ( ! defined( 'ABSPATH' ) ) {
4 7 exit; // Exit if accessed directly
5 8 }
6 9
@@ -22,8 +25,9 @@
22 25 add_action( 'template_redirect', array( $this, 'ph_check_currency_change' ) );
23 26
24 27 add_action( 'propertyhive_update_currency_exchange_rates', array( $this, 'ph_update_currency_exchange_rates' ) );
25 28
29 + add_filter( 'propertyhive_search_form_fields_after', array( $this, 'ensure_currency_value_set' ) );
26 30 }
27 31
28 32 /**
29 33 * Auto-load in-accessible properties on demand.
@@ -35,13 +39,59 @@
35 39 return $this->get_countries();
36 40 }
37 41 }
38 42
43 + /**
44 + * Resolve a cookie choice using trusted currency definitions and current rates.
45 + */
46 + public function get_currency_from_cookie() {
47 + if ( ! isset( $_COOKIE['propertyhive_currency'] ) || ! is_string( $_COOKIE['propertyhive_currency'] ) ) {
48 + return false;
49 + }
50 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Decode the JSON envelope, then validate its only accepted field against the server's currency definitions below.
51 + $stored = json_decode( html_entity_decode( wp_unslash( $_COOKIE['propertyhive_currency'] ) ), true );
52 + if ( ! is_array( $stored ) || ! isset( $stored['currency_code'] ) || ! is_string( $stored['currency_code'] ) ) {
53 + return false;
54 + }
55 + $code = sanitize_text_field( $stored['currency_code'] );
56 + $currency = $this->get_currency( $code );
57 + if ( false === $currency ) {
58 + return false;
59 + }
60 + $rates = get_option( 'propertyhive_currency_exchange_rates', array() );
61 + $currency['exchange_rate'] = isset( $rates[ $code ] ) && is_numeric( $rates[ $code ] ) ? (float) $rates[ $code ] : 1;
62 + return $currency;
63 + }
64 +
65 + public function ensure_currency_value_set( $form_controls )
66 + {
67 + if ( isset($form_controls['currency']) )
68 + {
69 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Currency is a read-only display preference.
70 + if ( isset($_GET['currency']) && is_string( $_GET['currency'] ) && $_GET['currency'] != '' )
71 + {
72 +
73 + }
74 + elseif ( false !== ( $currency = $this->get_currency_from_cookie() ) )
75 + {
76 + if ( !empty($currency) && isset($currency['currency_code']) && array_key_exists(ph_clean($currency['currency_code']), $form_controls['currency']['options']) )
77 + {
78 + $form_controls['currency']['value'] = $currency['currency_code'];
79 + }
80 + }
81 + }
82 +
83 + return $form_controls;
84 + }
85 +
39 86 public function ph_check_currency_change()
40 87 {
41 - if ( is_post_type_archive('property') && isset($_GET['currency']) )
88 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public currency choice changes only the visitor's display-preference cookie.
89 + if ( is_post_type_archive('property') && isset($_GET['currency']) && is_string( $_GET['currency'] ) )
42 90 {
43 - if ( $_GET['currency'] == '' )
91 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public currency choice changes only the visitor's display-preference cookie.
92 + $currency_code = sanitize_text_field( wp_unslash( $_GET['currency'] ) );
93 + if ( $currency_code == '' )
44 94 {
45 95 // Set to blank to reset back to properties entered currency
46 96 unset( $_COOKIE['propertyhive_currency'] );
47 97 setcookie( 'propertyhive_currency', '', time() - ( 15 * 60 ) );
@@ -47,12 +97,9 @@
47 97 setcookie( 'propertyhive_currency', '', time() - ( 15 * 60 ) );
48 98 return true;
49 99 }
50 100
51 - // TO DO: Make sure currency passed in is in list of countries they operate in
52 - // so we can get the exchange rate
53 -
54 - $currency = $this->get_currency( sanitize_text_field($_GET['currency']) );
101 + $currency = $this->get_currency( $currency_code );
55 102 if ( $currency === FALSE )
56 103 {
57 104 $default_country = get_option( 'propertyhive_default_country', 'GB' );
58 105 $default_country = $this->get_country( $default_country );
@@ -61,19 +108,17 @@
61 108 }
62 109
63 110 $currency['exchange_rate'] = 1;
64 111 $exchange_rates = get_option( 'propertyhive_currency_exchange_rates', array() );
65 - if ( isset($exchange_rates[$_GET['currency']]) )
112 + if ( isset($exchange_rates[$currency_code]) )
66 113 {
67 - $currency['exchange_rate'] = $exchange_rates[sanitize_text_field($_GET['currency'])];
114 + $currency['exchange_rate'] = $exchange_rates[$currency_code];
68 115 }
69 116
70 - ph_setcookie( 'propertyhive_currency', htmlentities(serialize($currency)), time() + (30 * DAY_IN_SECONDS), is_ssl() );
117 + ph_setcookie( 'propertyhive_currency', htmlentities(json_encode($currency)), time() + (30 * DAY_IN_SECONDS), is_ssl() );
71 118 }
72 119 }
73 120
74 -
75 -
76 121 public function get_country( $country_code ) {
77 122
78 123 $countries = $this->get_countries();
79 124
@@ -92,11 +137,15 @@
92 137 foreach ( $countries as $country )
93 138 {
94 139 if ( $country['currency_code'] == $currency_code )
95 140 {
141 + $currency_symbol = apply_filters( 'propertyhive_currency_symbol', $country['currency_symbol'], $currency_code);
142 + $currency_prefix = apply_filters( 'propertyhive_currency_prefix', $country['currency_prefix'], $currency_code);
143 +
96 144 return array(
97 - 'currency_symbol' => $country['currency_symbol'],
98 - 'currency_prefix' => $country['currency_prefix']
145 + 'currency_code' => $currency_code,
146 + 'currency_symbol' => $currency_symbol,
147 + 'currency_prefix' => $currency_prefix
99 148 );
100 149 }
101 150 }
102 151
@@ -108,8 +157,14 @@
108 157 * @return array
109 158 */
110 159 private function get_countries() {
111 160 $countries = array(
161 + 'AR' => array(
162 + 'name' => 'Argentina',
163 + 'currency_code' => 'ARS',
164 + 'currency_symbol' => '$',
165 + 'currency_prefix' => true
166 + ),
112 167 'AU' => array(
113 168 'name' => 'Australia',
114 169 'currency_code' => 'AUD',
115 170 'currency_symbol' => '$',
@@ -118,8 +173,14 @@
118 173 'AT' => array(
119 174 'name' => 'Austria',
120 175 'currency_code' => 'EUR',
121 176 'currency_symbol' => '&euro;',
177 + 'currency_prefix' => false
178 + ),
179 + 'BB' => array(
180 + 'name' => 'Barbados',
181 + 'currency_code' => 'BBD',
182 + 'currency_symbol' => '$',
122 183 'currency_prefix' => true
123 184 ),
124 185 'BE' => array(
125 186 'name' => 'Belgium',
@@ -124,15 +185,21 @@
124 185 'BE' => array(
125 186 'name' => 'Belgium',
126 187 'currency_code' => 'EUR',
127 188 'currency_symbol' => '&euro;',
128 - 'currency_prefix' => true
189 + 'currency_prefix' => false
129 190 ),
191 + 'BR' => array(
192 + 'name' => 'Brazil',
193 + 'currency_code' => 'BRL',
194 + 'currency_symbol' => 'R$',
195 + 'currency_prefix' => true
196 + ),
130 197 'BG' => array(
131 198 'name' => 'Bulgaria',
132 199 'currency_code' => 'BGN',
133 200 'currency_symbol' => 'лв',
134 - 'currency_prefix' => true
201 + 'currency_prefix' => false
135 202 ),
136 203 'CA' => array(
137 204 'name' => 'Canada',
138 205 'currency_code' => 'CAD',
@@ -138,12 +205,24 @@
138 205 'currency_code' => 'CAD',
139 206 'currency_symbol' => '$',
140 207 'currency_prefix' => true
141 208 ),
209 + 'CN' => array(
210 + 'name' => 'China',
211 + 'currency_code' => 'CNY',
212 + 'currency_symbol' => '¥',
213 + 'currency_prefix' => true
214 + ),
215 + 'CO' => array(
216 + 'name' => 'Colombia',
217 + 'currency_code' => 'COP',
218 + 'currency_symbol' => '$',
219 + 'currency_prefix' => true
220 + ),
142 221 'HR' => array(
143 222 'name' => 'Croatia',
144 - 'currency_code' => 'HRK',
145 - 'currency_symbol' => 'kn',
223 + 'currency_code' => 'EUR',
224 + 'currency_symbol' => '&euro;',
146 225 'currency_prefix' => false
147 226 ),
148 227 'CY' => array(
149 228 'name' => 'Cyprus',
@@ -148,9 +227,9 @@
148 227 'CY' => array(
149 228 'name' => 'Cyprus',
150 229 'currency_code' => 'EUR',
151 230 'currency_symbol' => '&euro;',
152 - 'currency_prefix' => true
231 + 'currency_prefix' => false
153 232 ),
154 233 'CZ' => array(
155 234 'name' => 'Czech Republic',
156 235 'currency_code' => 'CZK',
@@ -156,30 +235,84 @@
156 235 'currency_code' => 'CZK',
157 236 'currency_symbol' => 'Kč',
158 237 'currency_prefix' => false
159 238 ),
239 + 'DK' => array(
240 + 'name' => 'Denmark',
241 + 'currency_code' => 'DKK',
242 + 'currency_symbol' => 'kr',
243 + 'currency_prefix' => false
244 + ),
245 + 'EG' => array(
246 + 'name' => 'Egypt',
247 + 'currency_code' => 'EGP',
248 + 'currency_symbol' => 'E&pound;',
249 + 'currency_prefix' => true
250 + ),
251 + 'FI' => array(
252 + 'name' => 'Finland',
253 + 'currency_code' => 'EUR',
254 + 'currency_symbol' => '&euro;',
255 + 'currency_prefix' => false
256 + ),
160 257 'FR' => array(
161 258 'name' => 'France',
162 259 'currency_code' => 'EUR',
163 260 'currency_symbol' => '&euro;',
164 - 'currency_prefix' => true
261 + 'currency_prefix' => false
165 262 ),
166 263 'DE' => array(
167 264 'name' => 'Germany',
168 265 'currency_code' => 'EUR',
169 266 'currency_symbol' => '&euro;',
267 + 'currency_prefix' => false
268 + ),
269 + 'GI' => array(
270 + 'name' => 'Gibraltar',
271 + 'currency_code' => 'GBP',
272 + 'currency_symbol' => '&pound;',
170 273 'currency_prefix' => true
171 274 ),
275 + 'GR' => array(
276 + 'name' => 'Greece',
277 + 'currency_code' => 'EUR',
278 + 'currency_symbol' => '&euro;',
279 + 'currency_prefix' => false
280 + ),
281 + 'HK' => array(
282 + 'name' => 'Hong Kong',
283 + 'currency_code' => 'HKD',
284 + 'currency_symbol' => '$',
285 + 'currency_prefix' => true
286 + ),
287 + 'IN' => array(
288 + 'name' => 'India',
289 + 'currency_code' => 'INR',
290 + 'currency_symbol' => '₹',
291 + 'currency_prefix' => true
292 + ),
293 + 'ID' => array(
294 + 'name' => 'Indonesia',
295 + 'currency_code' => 'IDR',
296 + 'currency_symbol' => 'Rp',
297 + 'currency_prefix' => true
298 + ),
172 299 'IE' => array(
173 300 'name' => 'Ireland',
174 301 'currency_code' => 'EUR',
175 302 'currency_symbol' => '&euro;',
176 - 'currency_prefix' => true
303 + 'currency_prefix' => false
177 304 ),
178 305 'IT' => array(
179 306 'name' => 'Italy',
180 307 'currency_code' => 'EUR',
181 308 'currency_symbol' => '&euro;',
309 + 'currency_prefix' => false
310 + ),
311 + 'JM' => array(
312 + 'name' => 'Jamaica',
313 + 'currency_code' => 'JMD',
314 + 'currency_symbol' => '$',
182 315 'currency_prefix' => true
183 316 ),
184 317 'JP' => array(
185 318 'name' => 'Japan',
@@ -186,13 +319,31 @@
186 319 'currency_code' => 'JPY',
187 320 'currency_symbol' => '&yen;',
188 321 'currency_prefix' => true
189 322 ),
323 + 'KE' => array(
324 + 'name' => 'Kenya',
325 + 'currency_code' => 'KES',
326 + 'currency_symbol' => 'KSh ',
327 + 'currency_prefix' => true
328 + ),
329 + 'LU' => array(
330 + 'name' => 'Luxembourg',
331 + 'currency_code' => 'EUR',
332 + 'currency_symbol' => '&euro;',
333 + 'currency_prefix' => false
334 + ),
335 + 'MY' => array(
336 + 'name' => 'Malaysia',
337 + 'currency_code' => 'MYR',
338 + 'currency_symbol' => 'RM',
339 + 'currency_prefix' => true
340 + ),
190 341 'MT' => array(
191 342 'name' => 'Malta',
192 343 'currency_code' => 'EUR',
193 344 'currency_symbol' => '&euro;',
194 - 'currency_prefix' => true
345 + 'currency_prefix' => false
195 346 ),
196 347 'MU' => array(
197 348 'name' => 'Mauritius',
198 349 'currency_code' => 'MUR',
@@ -198,8 +349,32 @@
198 349 'currency_code' => 'MUR',
199 350 'currency_symbol' => 'Rs',
200 351 'currency_prefix' => false
201 352 ),
353 + 'MX' => array(
354 + 'name' => 'Mexico',
355 + 'currency_code' => 'MXN',
356 + 'currency_symbol' => '$',
357 + 'currency_prefix' => true
358 + ),
359 + 'MA' => array(
360 + 'name' => 'Morocco',
361 + 'currency_code' => 'MAD',
362 + 'currency_symbol' => 'د.م.',
363 + 'currency_prefix' => false
364 + ),
365 + 'NL' => array(
366 + 'name' => 'Netherlands',
367 + 'currency_code' => 'EUR',
368 + 'currency_symbol' => '&euro;',
369 + 'currency_prefix' => false
370 + ),
371 + 'NZ' => array(
372 + 'name' => 'New Zealand',
373 + 'currency_code' => 'NZD',
374 + 'currency_symbol' => '$',
375 + 'currency_prefix' => true
376 + ),
202 377 'NO' => array(
203 378 'name' => 'Norway',
204 379 'currency_code' => 'NOK',
205 380 'currency_symbol' => 'kr',
@@ -204,14 +379,32 @@
204 379 'currency_code' => 'NOK',
205 380 'currency_symbol' => 'kr',
206 381 'currency_prefix' => false
207 382 ),
383 + 'PK' => array(
384 + 'name' => 'Pakistan',
385 + 'currency_code' => 'PKR',
386 + 'currency_symbol' => 'Rs',
387 + 'currency_prefix' => false
388 + ),
389 + 'PL' => array(
390 + 'name' => 'Poland',
391 + 'currency_code' => 'PLN',
392 + 'currency_symbol' => 'zł',
393 + 'currency_prefix' => false
394 + ),
208 395 'PT' => array(
209 396 'name' => 'Portugal',
210 397 'currency_code' => 'EUR',
211 398 'currency_symbol' => '&euro;',
212 - 'currency_prefix' => true
399 + 'currency_prefix' => false
213 400 ),
401 + 'QA' => array(
402 + 'name' => 'Qatar',
403 + 'currency_code' => 'QAR',
404 + 'currency_symbol' => 'QR',
405 + 'currency_prefix' => false
406 + ),
214 407 'RU' => array(
215 408 'name' => 'Russia',
216 409 'currency_code' => 'RUB',
217 410 'currency_symbol' => '₽',
@@ -216,8 +409,26 @@
216 409 'currency_code' => 'RUB',
217 410 'currency_symbol' => '₽',
218 411 'currency_prefix' => true
219 412 ),
413 + 'VC' => array(
414 + 'name' => 'Saint Vincent and the Grenadines',
415 + 'currency_code' => 'XCD',
416 + 'currency_symbol' => '$',
417 + 'currency_prefix' => true
418 + ),
419 + 'SA' => array(
420 + 'name' => 'Saudi Arabia',
421 + 'currency_code' => 'SAR',
422 + 'currency_symbol' => '﷼',
423 + 'currency_prefix' => false
424 + ),
425 + 'SG' => array(
426 + 'name' => 'Singapore',
427 + 'currency_code' => 'SGD',
428 + 'currency_symbol' => '$',
429 + 'currency_prefix' => true
430 + ),
220 431 'ZA' => array(
221 432 'name' => 'South Africa',
222 433 'currency_code' => 'ZAR',
223 434 'currency_symbol' => 'R',
@@ -222,14 +433,44 @@
222 433 'currency_code' => 'ZAR',
223 434 'currency_symbol' => 'R',
224 435 'currency_prefix' => true
225 436 ),
437 + 'KR' => array(
438 + 'name' => 'South Korea',
439 + 'currency_code' => 'KRW',
440 + 'currency_symbol' => '₩',
441 + 'currency_prefix' => true
442 + ),
226 443 'ES' => array(
227 444 'name' => 'Spain',
228 445 'currency_code' => 'EUR',
229 446 'currency_symbol' => '&euro;',
447 + 'currency_prefix' => false
448 + ),
449 + 'SE' => array(
450 + 'name' => 'Sweden',
451 + 'currency_code' => 'SEK',
452 + 'currency_symbol' => 'kr',
453 + 'currency_prefix' => false
454 + ),
455 + 'CH' => array(
456 + 'name' => 'Switzerland',
457 + 'currency_code' => 'CHF',
458 + 'currency_symbol' => 'CHF',
230 459 'currency_prefix' => true
231 460 ),
461 + 'TH' => array(
462 + 'name' => 'Thailand',
463 + 'currency_code' => 'THB',
464 + 'currency_symbol' => '฿',
465 + 'currency_prefix' => true
466 + ),
467 + 'TR' => array(
468 + 'name' => 'Turkey',
469 + 'currency_code' => 'TRY',
470 + 'currency_symbol' => '‎₺',
471 + 'currency_prefix' => true
472 + ),
232 473 'AE' => array(
233 474 'name' => 'United Arab Emirates',
234 475 'currency_code' => 'AED',
235 476 'currency_symbol' => '‎د.إ',
@@ -246,8 +487,14 @@
246 487 'currency_code' => 'USD',
247 488 'currency_symbol' => '$',
248 489 'currency_prefix' => true
249 490 ),
491 + 'VN' => array(
492 + 'name' => 'Vietnam',
493 + 'currency_code' => 'VND',
494 + 'currency_symbol' => '₫',
495 + 'currency_prefix' => true
496 + ),
250 497 );
251 498
252 499 return apply_filters( 'propertyhive_countries', $countries );
253 500 }
@@ -265,9 +512,9 @@
265 512 echo '<option';
266 513 if ( $selected_country == $key || ( $selected_country == '' && $key == 'GB' ) ) {
267 514 echo ' selected="selected"';
268 515 }
269 - echo ' value="' . esc_attr( $key ) . '">' . ( $escape ? esc_js( $value['name'] ) : $value['name'] ) . '</option>';
516 + echo ' value="' . esc_attr( $key ) . '">' . ( $escape ? esc_js( $value['name'] ) : esc_html( $value['name'] ) ) . '</option>';
270 517 }
271 518 }
272 519 }
273 520
@@ -292,9 +539,18 @@
292 539 {
293 540 $countries = $this->countries;
294 541
295 542 $department = get_post_meta( $postID, '_department', true );
543 + if ( ph_get_custom_department_based_on( $department ) !== false )
544 + {
545 + $department = ph_get_custom_department_based_on( $department );
546 + }
547 +
296 548 $country = get_post_meta( $postID, '_address_country', true );
549 + if ( $country == '' )
550 + {
551 + $country = get_option( 'propertyhive_default_country', 'GB' );
552 + }
297 553
298 554 if (isset($countries[$country]))
299 555 {
300 556 if ( $department == 'residential-sales' )
@@ -299,12 +555,8 @@
299 555 {
300 556 if ( $department == 'residential-sales' )
301 557 {
302 558 $currency = get_post_meta( $postID, '_currency', true );
303 - if ( $country == '' )
304 - {
305 - $country = get_option( 'propertyhive_default_country', 'GB' );
306 - }
307 559 if ( $currency == '' )
308 560 {
309 561 $currency = $this->get_country($country);
310 562 $currency = $currency['currency_code'];
@@ -318,12 +570,8 @@
318 570 }
319 571 elseif ( $department == 'residential-lettings' )
320 572 {
321 573 $currency = get_post_meta( $postID, '_currency', true );
322 - if ( $country == '' )
323 - {
324 - $country = get_option( 'propertyhive_default_country', 'GB' );
325 - }
326 574 if ( $currency == '' )
327 575 {
328 576 $currency = $this->get_country($country);
329 577 $currency = $currency['currency_code'];
@@ -329,34 +577,39 @@
329 577 $currency = $currency['currency_code'];
330 578 }
331 579
332 580 $rent = get_post_meta( $postID, '_rent', true );
333 - $rent_frequency = get_post_meta( $postID, '_rent_frequency', true );
581 +
582 + $converted_price = 0;
583 + if ( !empty($rent) && is_numeric($rent) )
584 + {
585 + $price = $rent; // Stored in pcm
586 + $rent_frequency = get_post_meta( $postID, '_rent_frequency', true );
587 + switch ($rent_frequency)
588 + {
589 + case "pd": { $price = ($rent * 365) / 12; break; }
590 + case "pppw":
591 + {
592 + $bedrooms = get_post_meta( $postID, '_bedrooms', true );
593 + if ( ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' ) && apply_filters( 'propertyhive_pppw_to_consider_bedrooms', true ) == true )
594 + {
595 + $price = (($rent * 52) / 12) * $bedrooms;
596 + }
597 + else
598 + {
599 + $price = ($rent * 52) / 12;
600 + }
601 + break;
602 + }
603 + case "pw": { $price = ($rent * 52) / 12; break; }
604 + case "pcm": { $price = $rent; break; }
605 + case "pq": { $price = ($rent * 4) / 12; break; }
606 + case "pa": { $price = ($rent / 12); break; }
607 + }
334 608
335 - $price = $rent; // Stored in pcm
336 - switch ($rent_frequency)
337 - {
338 - case "pppw":
339 - {
340 - $bedrooms = get_post_meta( $postID, '_bedrooms', true );
341 - if ( ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' ) && apply_filters( 'propertyhive_pppw_to_consider_bedrooms', true ) == true )
342 - {
343 - $price = (($rent * 52) / 12) * $bedrooms;
344 - }
345 - else
346 - {
347 - $price = ($rent * 52) / 12;
348 - }
349 - break;
350 - }
351 - case "pw": { $price = ($rent * 52) / 12; break; }
352 - case "pcm": { $price = $rent; break; }
353 - case "pq": { $price = ($rent * 4) / 12; break; }
354 - case "pa": { $price = ($rent / 12); break; }
609 + $converted_price = $this->convert_price_to_gbp( $price, $currency );
355 610 }
356 611
357 - $converted_price = $this->convert_price_to_gbp( $price, $currency );
358 -
359 612 update_post_meta( $postID, '_price_actual', $converted_price );
360 613 }
361 614 if ( $department == 'commercial' )
362 615 {
@@ -362,12 +615,8 @@
362 615 {
363 616 if ( get_post_meta( $postID, '_for_sale', true ) == 'yes' )
364 617 {
365 618 $currency = get_post_meta( $postID, '_commercial_price_currency', true );
366 - if ( $country == '' )
367 - {
368 - $country = get_option( 'propertyhive_default_country', 'GB' );
369 - }
370 619 if ( $currency == '' )
371 620 {
372 621 $currency = $this->get_country($country);
373 622 $currency = $currency['currency_code'];
@@ -373,8 +622,12 @@
373 622 $currency = $currency['currency_code'];
374 623 }
375 624
376 625 $price = get_post_meta( $postID, '_price_from', true );
626 + if ( $price == '' )
627 + {
628 + $price = get_post_meta( $postID, '_price_to', true );
629 + }
377 630
378 631 $converted_price = $this->convert_price_to_gbp( $price, $currency );
379 632
380 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
@@ -379,8 +632,12 @@
379 632
380 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
381 634
382 635 $price = get_post_meta( $postID, '_price_to', true );
636 + if ( $price == '' )
637 + {
638 + $price = get_post_meta( $postID, '_price_from', true );
639 + }
383 640
384 641 $converted_price = $this->convert_price_to_gbp( $price, $currency );
385 642
386 643 update_post_meta( $postID, '_price_to_actual', $converted_price );
@@ -387,12 +644,8 @@
387 644 }
388 645 if ( get_post_meta( $postID, '_to_rent', true ) == 'yes' )
389 646 {
390 647 $currency = get_post_meta( $postID, '_commercial_rent_currency', true );
391 - if ( $country == '' )
392 - {
393 - $country = get_option( 'propertyhive_default_country', 'GB' );
394 - }
395 648 if ( $currency == '' )
396 649 {
397 650 $currency = $this->get_country($country);
398 651 $currency = $currency['currency_code'];
@@ -400,15 +653,23 @@
400 653
401 654 $rent_units = get_post_meta( $postID, '_rent_units', true );
402 655
403 656 $price = get_post_meta( $postID, '_rent_from', true );
404 - switch ($rent_units)
405 - {
406 - case "pw": { $price = ($price * 52) / 12; break; }
407 - case "pcm": { $price = $price; break; }
408 - case "pq": { $price = ($price * 4) / 52; break; }
409 - case "pa": { $price = ($price / 52); break; }
410 - }
657 + if ( $price == '' )
658 + {
659 + $price = get_post_meta( $postID, '_rent_to', true );
660 + }
661 + if ( is_numeric($price) )
662 + {
663 + switch ($rent_units)
664 + {
665 + case "pd": { $price = ($price * 365) / 12; break; }
666 + case "pw": { $price = ($price * 52) / 12; break; }
667 + case "pcm": { $price = $price; break; }
668 + case "pq": { $price = ($price * 4) / 12; break; }
669 + case "pa": { $price = ($price / 12); break; }
670 + }
671 + }
411 672
412 673 $converted_price = $this->convert_price_to_gbp( $price, $currency );
413 674
414 675 update_post_meta( $postID, '_rent_from_actual', $converted_price );
@@ -418,15 +679,23 @@
418 679 update_post_meta( $postID, '_price_from_actual', $converted_price );
419 680 }
420 681
421 682 $price = get_post_meta( $postID, '_rent_to', true );
422 - switch ($rent_units)
423 - {
424 - case "pw": { $price = ($price * 52) / 12; break; }
425 - case "pcm": { $price = $price; break; }
426 - case "pq": { $price = ($price * 4) / 52; break; }
427 - case "pa": { $price = ($price / 52); break; }
428 - }
683 + if ( $price == '' )
684 + {
685 + $price = get_post_meta( $postID, '_rent_from', true );
686 + }
687 + if ( is_numeric($price) )
688 + {
689 + switch ($rent_units)
690 + {
691 + case "pd": { $price = ($price * 365) / 12; break; }
692 + case "pw": { $price = ($price * 52) / 12; break; }
693 + case "pcm": { $price = $price; break; }
694 + case "pq": { $price = ($price * 4) / 12; break; }
695 + case "pa": { $price = ($price / 12); break; }
696 + }
697 + }
429 698
430 699 $converted_price = $this->convert_price_to_gbp( $price, $currency );
431 700
432 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
@@ -432,8 +701,10 @@
432 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
433 702 }
434 703 }
435 704 }
705 +
706 + do_action('propertyhive_property_price_actual_updated', $postID);
436 707 }
437 708
438 709 public function ph_update_currency_exchange_rates()
439 710 {
@@ -442,72 +713,82 @@
442 713 if ( $this->countries )
443 714 {
444 715 $countries = $this->countries;
445 716
446 - $exchange_rates = array();
717 + // Filter 'propertyhive_new_currency_exchange_rates' allows someone to use their own currency API
718 + // Return should be in format:
719 + // array(
720 + // 'EUR' => x,
721 + // 'USD' => x,
722 + // ... etc
723 + // )
724 + $exchange_rates = apply_filters( 'propertyhive_new_currency_exchange_rates', array() );
447 725 $previous_exchange_rates = get_option( 'propertyhive_currency_exchange_rates' );
448 726
449 - $default_country = get_option( 'propertyhive_default_country', 'GB' );
450 - $selected_countries = get_option( 'propertyhive_countries', array( $default_country ) );
727 + if ( empty($exchange_rates) )
728 + {
729 + // Get all currency exchange rates from GBP
730 + // We're using the API from https://github.com/fawazahmed0/exchange-api
731 + $url = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/gbp.json'; // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent -- Retrieves current exchange-rate data from the configured currency service.
732 + $response = wp_remote_get( $url );
451 733
452 - foreach ( $countries as $key => $value )
453 - {
454 - if (!isset($exchange_rates[$value['currency_code']]) && in_array($key, $selected_countries) && $value['currency_code'] != 'GBP')
734 + if ( is_array( $response ) )
455 735 {
456 - // we haven't got this exchange rate
457 - $from = 'GBP';
458 - $to = $value['currency_code'];
736 + $body = wp_remote_retrieve_body( $response );
737 + $json = json_decode($body, true);
459 738
460 - $exchangeRate = '';
461 -
462 - $url = 'https://finance.google.com/finance/converter?a=1&from=' . $from . '&to=' . $to;
463 -
464 - $response = wp_remote_get( $url );
465 -
466 - if ( is_array( $response ) )
739 + // If response is valid JSON and contains the core gbp key
740 + if ( $json !== null && isset( $json['gbp'] ) )
467 741 {
468 - $body = wp_remote_retrieve_body( $response );
742 + $exchange_rates_array = $json['gbp'];
469 743
470 - preg_match("/<span class=bld>(.*)<\/span>/", $body, $converted);
471 -
472 - if ( isset($converted[1]) && $converted[1] != '' )
744 + foreach ( $countries as $country )
473 745 {
474 - $converted = preg_replace("/[^0-9.]/", "", $converted[1]);
746 + $currency_code = $country['currency_code'];
475 747
476 - if ( $converted != '' )
748 + // If we haven't already got this currency and it's not GBP
749 + if (!isset($exchange_rates[$currency_code]) && $currency_code != 'GBP')
477 750 {
478 - $exchangeRate = $converted;
479 - $exchange_rates[$to] = $exchangeRate;
751 + // If this currency is in the list we received from the API
752 + if ( isset( $exchange_rates_array[strtolower( $currency_code )] ) )
753 + {
754 + $exchange_rates[$currency_code] = (string)$exchange_rates_array[strtolower( $currency_code )];
755 + }
480 756 }
481 757 }
482 758 }
483 - else
484 - {
759 + }
760 + }
485 761
486 - }
762 + // Only update the settings if the API call was successful and we got exchange rates, or if there were none set previously
763 + if ( !empty( $exchange_rates ) || empty( $previous_exchange_rates ) )
764 + {
765 + $exchange_rates['GBP'] = "1.0000";
766 + update_option( 'propertyhive_currency_exchange_rates', $exchange_rates );
767 + update_option( 'propertyhive_currency_exchange_rates_updated', gmdate("Y-m-d") );
768 + }
487 769
488 - if ( $exchangeRate == '' && isset($previous_exchange_rates[$to]) )
489 - {
490 - // if for some reason we get here and don't have an exchange rate
491 - $exchange_rates[$to] = $previous_exchange_rates[$to];
492 - }
493 - }
494 - }
495 - $exchange_rates['GBP'] = "1.0000";
496 - update_option( 'propertyhive_currency_exchange_rates', $exchange_rates );
497 - update_option( 'propertyhive_currency_exchange_rates_updated', date("Y-m-d") );
770 + do_action('propertyhive_exchange_rates_updated', $exchange_rates);
498 771
499 - // Loop through all on market properties and update _actual_price meta value to be price in GBP
772 + // Loop through all on market properties and update _price_actual meta value to be price in GBP
500 773 $args = array(
501 774 'post_type' => 'property',
775 + 'fields' => 'ids',
502 776 'post_status' => 'publish',
777 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Currency recalculation must select all published on-market properties outside GB using their stored market/country metadata.
503 778 'meta_query' => array(
504 779 array(
505 780 'key' => '_on_market',
506 781 'value' => 'yes',
782 + ),
783 + array(
784 + 'key' => '_address_country',
785 + 'value' => 'GB',
786 + 'compare' => '!=',
507 787 )
508 788 ),
509 789 'nopaging' => true,
790 + 'orderby' => 'rand', // order by rand incase there are lots of properties and it times out, at least they should eventually all get processed
510 791 );
511 792 $property_query = new WP_Query($args);
512 793
513 794 if ($property_query->have_posts())
@@ -524,5 +805,5 @@
524 805
525 806 }
526 807 }
527 808
528 -}
809 +}