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 +373 -117 1.4.602.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',
@@ -162,36 +241,78 @@
162 241 'currency_code' => 'DKK',
163 242 'currency_symbol' => 'kr',
164 243 'currency_prefix' => false
165 244 ),
245 + 'EG' => array(
246 + 'name' => 'Egypt',
247 + 'currency_code' => 'EGP',
248 + 'currency_symbol' => 'E&pound;',
249 + 'currency_prefix' => true
250 + ),
166 251 'FI' => array(
167 252 'name' => 'Finland',
168 253 'currency_code' => 'EUR',
169 254 'currency_symbol' => '&euro;',
170 - 'currency_prefix' => true
255 + 'currency_prefix' => false
171 256 ),
172 257 'FR' => array(
173 258 'name' => 'France',
174 259 'currency_code' => 'EUR',
175 260 'currency_symbol' => '&euro;',
176 - 'currency_prefix' => true
261 + 'currency_prefix' => false
177 262 ),
178 263 'DE' => array(
179 264 'name' => 'Germany',
180 265 'currency_code' => 'EUR',
181 266 'currency_symbol' => '&euro;',
267 + 'currency_prefix' => false
268 + ),
269 + 'GI' => array(
270 + 'name' => 'Gibraltar',
271 + 'currency_code' => 'GBP',
272 + 'currency_symbol' => '&pound;',
182 273 'currency_prefix' => true
183 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 + ),
184 299 'IE' => array(
185 300 'name' => 'Ireland',
186 301 'currency_code' => 'EUR',
187 302 'currency_symbol' => '&euro;',
188 - 'currency_prefix' => true
303 + 'currency_prefix' => false
189 304 ),
190 305 'IT' => array(
191 306 'name' => 'Italy',
192 307 'currency_code' => 'EUR',
193 308 'currency_symbol' => '&euro;',
309 + 'currency_prefix' => false
310 + ),
311 + 'JM' => array(
312 + 'name' => 'Jamaica',
313 + 'currency_code' => 'JMD',
314 + 'currency_symbol' => '$',
194 315 'currency_prefix' => true
195 316 ),
196 317 'JP' => array(
197 318 'name' => 'Japan',
@@ -198,13 +319,31 @@
198 319 'currency_code' => 'JPY',
199 320 'currency_symbol' => '&yen;',
200 321 'currency_prefix' => true
201 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 + ),
202 341 'MT' => array(
203 342 'name' => 'Malta',
204 343 'currency_code' => 'EUR',
205 344 'currency_symbol' => '&euro;',
206 - 'currency_prefix' => true
345 + 'currency_prefix' => false
207 346 ),
208 347 'MU' => array(
209 348 'name' => 'Mauritius',
210 349 'currency_code' => 'MUR',
@@ -210,8 +349,32 @@
210 349 'currency_code' => 'MUR',
211 350 'currency_symbol' => 'Rs',
212 351 'currency_prefix' => false
213 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 + ),
214 377 'NO' => array(
215 378 'name' => 'Norway',
216 379 'currency_code' => 'NOK',
217 380 'currency_symbol' => 'kr',
@@ -216,14 +379,32 @@
216 379 'currency_code' => 'NOK',
217 380 'currency_symbol' => 'kr',
218 381 'currency_prefix' => false
219 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 + ),
220 395 'PT' => array(
221 396 'name' => 'Portugal',
222 397 'currency_code' => 'EUR',
223 398 'currency_symbol' => '&euro;',
224 - 'currency_prefix' => true
399 + 'currency_prefix' => false
225 400 ),
401 + 'QA' => array(
402 + 'name' => 'Qatar',
403 + 'currency_code' => 'QAR',
404 + 'currency_symbol' => 'QR',
405 + 'currency_prefix' => false
406 + ),
226 407 'RU' => array(
227 408 'name' => 'Russia',
228 409 'currency_code' => 'RUB',
229 410 'currency_symbol' => '₽',
@@ -228,8 +409,26 @@
228 409 'currency_code' => 'RUB',
229 410 'currency_symbol' => '₽',
230 411 'currency_prefix' => true
231 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 + ),
232 431 'ZA' => array(
233 432 'name' => 'South Africa',
234 433 'currency_code' => 'ZAR',
235 434 'currency_symbol' => 'R',
@@ -234,13 +433,19 @@
234 433 'currency_code' => 'ZAR',
235 434 'currency_symbol' => 'R',
236 435 'currency_prefix' => true
237 436 ),
437 + 'KR' => array(
438 + 'name' => 'South Korea',
439 + 'currency_code' => 'KRW',
440 + 'currency_symbol' => 'â‚©',
441 + 'currency_prefix' => true
442 + ),
238 443 'ES' => array(
239 444 'name' => 'Spain',
240 445 'currency_code' => 'EUR',
241 446 'currency_symbol' => '&euro;',
242 - 'currency_prefix' => true
447 + 'currency_prefix' => false
243 448 ),
244 449 'SE' => array(
245 450 'name' => 'Sweden',
246 451 'currency_code' => 'SEK',
@@ -246,8 +451,20 @@
246 451 'currency_code' => 'SEK',
247 452 'currency_symbol' => 'kr',
248 453 'currency_prefix' => false
249 454 ),
455 + 'CH' => array(
456 + 'name' => 'Switzerland',
457 + 'currency_code' => 'CHF',
458 + 'currency_symbol' => 'CHF',
459 + 'currency_prefix' => true
460 + ),
461 + 'TH' => array(
462 + 'name' => 'Thailand',
463 + 'currency_code' => 'THB',
464 + 'currency_symbol' => '฿',
465 + 'currency_prefix' => true
466 + ),
250 467 'TR' => array(
251 468 'name' => 'Turkey',
252 469 'currency_code' => 'TRY',
253 470 'currency_symbol' => '‎₺',
@@ -270,8 +487,14 @@
270 487 'currency_code' => 'USD',
271 488 'currency_symbol' => '$',
272 489 'currency_prefix' => true
273 490 ),
491 + 'VN' => array(
492 + 'name' => 'Vietnam',
493 + 'currency_code' => 'VND',
494 + 'currency_symbol' => 'â‚«',
495 + 'currency_prefix' => true
496 + ),
274 497 );
275 498
276 499 return apply_filters( 'propertyhive_countries', $countries );
277 500 }
@@ -289,9 +512,9 @@
289 512 echo '<option';
290 513 if ( $selected_country == $key || ( $selected_country == '' && $key == 'GB' ) ) {
291 514 echo ' selected="selected"';
292 515 }
293 - 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>';
294 517 }
295 518 }
296 519 }
297 520
@@ -316,9 +539,18 @@
316 539 {
317 540 $countries = $this->countries;
318 541
319 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 +
320 548 $country = get_post_meta( $postID, '_address_country', true );
549 + if ( $country == '' )
550 + {
551 + $country = get_option( 'propertyhive_default_country', 'GB' );
552 + }
321 553
322 554 if (isset($countries[$country]))
323 555 {
324 556 if ( $department == 'residential-sales' )
@@ -323,12 +555,8 @@
323 555 {
324 556 if ( $department == 'residential-sales' )
325 557 {
326 558 $currency = get_post_meta( $postID, '_currency', true );
327 - if ( $country == '' )
328 - {
329 - $country = get_option( 'propertyhive_default_country', 'GB' );
330 - }
331 559 if ( $currency == '' )
332 560 {
333 561 $currency = $this->get_country($country);
334 562 $currency = $currency['currency_code'];
@@ -342,12 +570,8 @@
342 570 }
343 571 elseif ( $department == 'residential-lettings' )
344 572 {
345 573 $currency = get_post_meta( $postID, '_currency', true );
346 - if ( $country == '' )
347 - {
348 - $country = get_option( 'propertyhive_default_country', 'GB' );
349 - }
350 574 if ( $currency == '' )
351 575 {
352 576 $currency = $this->get_country($country);
353 577 $currency = $currency['currency_code'];
@@ -353,34 +577,39 @@
353 577 $currency = $currency['currency_code'];
354 578 }
355 579
356 580 $rent = get_post_meta( $postID, '_rent', true );
357 - $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 + }
358 608
359 - $price = $rent; // Stored in pcm
360 - switch ($rent_frequency)
361 - {
362 - case "pppw":
363 - {
364 - $bedrooms = get_post_meta( $postID, '_bedrooms', true );
365 - if ( ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' ) && apply_filters( 'propertyhive_pppw_to_consider_bedrooms', true ) == true )
366 - {
367 - $price = (($rent * 52) / 12) * $bedrooms;
368 - }
369 - else
370 - {
371 - $price = ($rent * 52) / 12;
372 - }
373 - break;
374 - }
375 - case "pw": { $price = ($rent * 52) / 12; break; }
376 - case "pcm": { $price = $rent; break; }
377 - case "pq": { $price = ($rent * 4) / 12; break; }
378 - case "pa": { $price = ($rent / 12); break; }
609 + $converted_price = $this->convert_price_to_gbp( $price, $currency );
379 610 }
380 611
381 - $converted_price = $this->convert_price_to_gbp( $price, $currency );
382 -
383 612 update_post_meta( $postID, '_price_actual', $converted_price );
384 613 }
385 614 if ( $department == 'commercial' )
386 615 {
@@ -386,12 +615,8 @@
386 615 {
387 616 if ( get_post_meta( $postID, '_for_sale', true ) == 'yes' )
388 617 {
389 618 $currency = get_post_meta( $postID, '_commercial_price_currency', true );
390 - if ( $country == '' )
391 - {
392 - $country = get_option( 'propertyhive_default_country', 'GB' );
393 - }
394 619 if ( $currency == '' )
395 620 {
396 621 $currency = $this->get_country($country);
397 622 $currency = $currency['currency_code'];
@@ -397,8 +622,12 @@
397 622 $currency = $currency['currency_code'];
398 623 }
399 624
400 625 $price = get_post_meta( $postID, '_price_from', true );
626 + if ( $price == '' )
627 + {
628 + $price = get_post_meta( $postID, '_price_to', true );
629 + }
401 630
402 631 $converted_price = $this->convert_price_to_gbp( $price, $currency );
403 632
404 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
@@ -403,8 +632,12 @@
403 632
404 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
405 634
406 635 $price = get_post_meta( $postID, '_price_to', true );
636 + if ( $price == '' )
637 + {
638 + $price = get_post_meta( $postID, '_price_from', true );
639 + }
407 640
408 641 $converted_price = $this->convert_price_to_gbp( $price, $currency );
409 642
410 643 update_post_meta( $postID, '_price_to_actual', $converted_price );
@@ -411,12 +644,8 @@
411 644 }
412 645 if ( get_post_meta( $postID, '_to_rent', true ) == 'yes' )
413 646 {
414 647 $currency = get_post_meta( $postID, '_commercial_rent_currency', true );
415 - if ( $country == '' )
416 - {
417 - $country = get_option( 'propertyhive_default_country', 'GB' );
418 - }
419 648 if ( $currency == '' )
420 649 {
421 650 $currency = $this->get_country($country);
422 651 $currency = $currency['currency_code'];
@@ -424,15 +653,23 @@
424 653
425 654 $rent_units = get_post_meta( $postID, '_rent_units', true );
426 655
427 656 $price = get_post_meta( $postID, '_rent_from', true );
428 - switch ($rent_units)
429 - {
430 - case "pw": { $price = ($price * 52) / 12; break; }
431 - case "pcm": { $price = $price; break; }
432 - case "pq": { $price = ($price * 4) / 52; break; }
433 - case "pa": { $price = ($price / 52); break; }
434 - }
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 + }
435 672
436 673 $converted_price = $this->convert_price_to_gbp( $price, $currency );
437 674
438 675 update_post_meta( $postID, '_rent_from_actual', $converted_price );
@@ -442,15 +679,23 @@
442 679 update_post_meta( $postID, '_price_from_actual', $converted_price );
443 680 }
444 681
445 682 $price = get_post_meta( $postID, '_rent_to', true );
446 - switch ($rent_units)
447 - {
448 - case "pw": { $price = ($price * 52) / 12; break; }
449 - case "pcm": { $price = $price; break; }
450 - case "pq": { $price = ($price * 4) / 52; break; }
451 - case "pa": { $price = ($price / 52); break; }
452 - }
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 + }
453 698
454 699 $converted_price = $this->convert_price_to_gbp( $price, $currency );
455 700
456 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
@@ -456,8 +701,10 @@
456 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
457 702 }
458 703 }
459 704 }
705 +
706 + do_action('propertyhive_property_price_actual_updated', $postID);
460 707 }
461 708
462 709 public function ph_update_currency_exchange_rates()
463 710 {
@@ -466,73 +713,82 @@
466 713 if ( $this->countries )
467 714 {
468 715 $countries = $this->countries;
469 716
470 - $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() );
471 725 $previous_exchange_rates = get_option( 'propertyhive_currency_exchange_rates' );
472 726
473 - $default_country = get_option( 'propertyhive_default_country', 'GB' );
474 - $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 );
475 733
476 - foreach ( $countries as $key => $value )
477 - {
478 - if (!isset($exchange_rates[$value['currency_code']]) && in_array($key, $selected_countries) && $value['currency_code'] != 'GBP')
734 + if ( is_array( $response ) )
479 735 {
480 - // we haven't got this exchange rate
481 - $from = 'GBP';
482 - $to = $value['currency_code'];
736 + $body = wp_remote_retrieve_body( $response );
737 + $json = json_decode($body, true);
483 738
484 - $exchangeRate = '';
485 -
486 - $url = 'https://finance.google.com/finance/converter?a=1&from=' . $from . '&to=' . $to;
487 -
488 - $response = wp_remote_get( $url );
489 -
490 - if ( is_array( $response ) )
739 + // If response is valid JSON and contains the core gbp key
740 + if ( $json !== null && isset( $json['gbp'] ) )
491 741 {
492 - $body = wp_remote_retrieve_body( $response );
742 + $exchange_rates_array = $json['gbp'];
493 743
494 - preg_match("/<span class=bld>(.*)<\/span>/", $body, $converted);
495 -
496 - if ( isset($converted[1]) && $converted[1] != '' )
744 + foreach ( $countries as $country )
497 745 {
498 - $converted = preg_replace("/[^0-9.]/", "", $converted[1]);
746 + $currency_code = $country['currency_code'];
499 747
500 - 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')
501 750 {
502 - $exchangeRate = $converted;
503 - $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 + }
504 756 }
505 757 }
506 758 }
507 - else
508 - {
759 + }
760 + }
509 761
510 - }
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 + }
511 769
512 - if ( $exchangeRate == '' && isset($previous_exchange_rates[$to]) )
513 - {
514 - // if for some reason we get here and don't have an exchange rate
515 - $exchange_rates[$to] = $previous_exchange_rates[$to];
516 - }
517 - }
518 - }
519 - $exchange_rates['GBP'] = "1.0000";
520 - update_option( 'propertyhive_currency_exchange_rates', $exchange_rates );
521 - update_option( 'propertyhive_currency_exchange_rates_updated', date("Y-m-d") );
770 + do_action('propertyhive_exchange_rates_updated', $exchange_rates);
522 771
523 - // 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
524 773 $args = array(
525 774 'post_type' => 'property',
526 775 'fields' => 'ids',
527 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.
528 778 'meta_query' => array(
529 779 array(
530 780 'key' => '_on_market',
531 781 'value' => 'yes',
782 + ),
783 + array(
784 + 'key' => '_address_country',
785 + 'value' => 'GB',
786 + 'compare' => '!=',
532 787 )
533 788 ),
534 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
535 791 );
536 792 $property_query = new WP_Query($args);
537 793
538 794 if ($property_query->have_posts())
@@ -549,5 +805,5 @@
549 805
550 806 }
551 807 }
552 808
553 -}
809 +}