PluginProbe
Property Hive / 2.3.1
Property Hive v2.3.1
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 +401 -114 1.4.472.3.1 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,8 +319,32 @@
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 + ),
341 + 'MT' => array(
342 + 'name' => 'Malta',
343 + 'currency_code' => 'EUR',
344 + 'currency_symbol' => '&euro;',
345 + 'currency_prefix' => false
346 + ),
190 347 'MU' => array(
191 348 'name' => 'Mauritius',
192 349 'currency_code' => 'MUR',
193 350 'currency_symbol' => 'Rs',
@@ -192,8 +349,32 @@
192 349 'currency_code' => 'MUR',
193 350 'currency_symbol' => 'Rs',
194 351 'currency_prefix' => false
195 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 + ),
196 377 'NO' => array(
197 378 'name' => 'Norway',
198 379 'currency_code' => 'NOK',
199 380 'currency_symbol' => 'kr',
@@ -198,14 +379,32 @@
198 379 'currency_code' => 'NOK',
199 380 'currency_symbol' => 'kr',
200 381 'currency_prefix' => false
201 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 + ),
202 395 'PT' => array(
203 396 'name' => 'Portugal',
204 397 'currency_code' => 'EUR',
205 398 'currency_symbol' => '&euro;',
206 - 'currency_prefix' => true
399 + 'currency_prefix' => false
207 400 ),
401 + 'QA' => array(
402 + 'name' => 'Qatar',
403 + 'currency_code' => 'QAR',
404 + 'currency_symbol' => 'QR',
405 + 'currency_prefix' => false
406 + ),
208 407 'RU' => array(
209 408 'name' => 'Russia',
210 409 'currency_code' => 'RUB',
211 410 'currency_symbol' => '₽',
@@ -210,8 +409,26 @@
210 409 'currency_code' => 'RUB',
211 410 'currency_symbol' => '₽',
212 411 'currency_prefix' => true
213 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 + ),
214 431 'ZA' => array(
215 432 'name' => 'South Africa',
216 433 'currency_code' => 'ZAR',
217 434 'currency_symbol' => 'R',
@@ -216,14 +433,44 @@
216 433 'currency_code' => 'ZAR',
217 434 'currency_symbol' => 'R',
218 435 'currency_prefix' => true
219 436 ),
437 + 'KR' => array(
438 + 'name' => 'South Korea',
439 + 'currency_code' => 'KRW',
440 + 'currency_symbol' => '₩',
441 + 'currency_prefix' => true
442 + ),
220 443 'ES' => array(
221 444 'name' => 'Spain',
222 445 'currency_code' => 'EUR',
223 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',
224 459 'currency_prefix' => true
225 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 + ),
226 473 'AE' => array(
227 474 'name' => 'United Arab Emirates',
228 475 'currency_code' => 'AED',
229 476 'currency_symbol' => '‎د.إ',
@@ -240,8 +487,14 @@
240 487 'currency_code' => 'USD',
241 488 'currency_symbol' => '$',
242 489 'currency_prefix' => true
243 490 ),
491 + 'VN' => array(
492 + 'name' => 'Vietnam',
493 + 'currency_code' => 'VND',
494 + 'currency_symbol' => '₫',
495 + 'currency_prefix' => true
496 + ),
244 497 );
245 498
246 499 return apply_filters( 'propertyhive_countries', $countries );
247 500 }
@@ -259,9 +512,9 @@
259 512 echo '<option';
260 513 if ( $selected_country == $key || ( $selected_country == '' && $key == 'GB' ) ) {
261 514 echo ' selected="selected"';
262 515 }
263 - 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>';
264 517 }
265 518 }
266 519 }
267 520
@@ -286,9 +539,18 @@
286 539 {
287 540 $countries = $this->countries;
288 541
289 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 +
290 548 $country = get_post_meta( $postID, '_address_country', true );
549 + if ( $country == '' )
550 + {
551 + $country = get_option( 'propertyhive_default_country', 'GB' );
552 + }
291 553
292 554 if (isset($countries[$country]))
293 555 {
294 556 if ( $department == 'residential-sales' )
@@ -293,12 +555,8 @@
293 555 {
294 556 if ( $department == 'residential-sales' )
295 557 {
296 558 $currency = get_post_meta( $postID, '_currency', true );
297 - if ( $country == '' )
298 - {
299 - $country = get_option( 'propertyhive_default_country', 'GB' );
300 - }
301 559 if ( $currency == '' )
302 560 {
303 561 $currency = $this->get_country($country);
304 562 $currency = $currency['currency_code'];
@@ -312,12 +570,8 @@
312 570 }
313 571 elseif ( $department == 'residential-lettings' )
314 572 {
315 573 $currency = get_post_meta( $postID, '_currency', true );
316 - if ( $country == '' )
317 - {
318 - $country = get_option( 'propertyhive_default_country', 'GB' );
319 - }
320 574 if ( $currency == '' )
321 575 {
322 576 $currency = $this->get_country($country);
323 577 $currency = $currency['currency_code'];
@@ -323,34 +577,39 @@
323 577 $currency = $currency['currency_code'];
324 578 }
325 579
326 580 $rent = get_post_meta( $postID, '_rent', true );
327 - $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 + }
328 608
329 - $price = $rent; // Stored in pcm
330 - switch ($rent_frequency)
331 - {
332 - case "pppw":
333 - {
334 - $bedrooms = get_post_meta( $postID, '_bedrooms', true );
335 - if ( ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' ) && apply_filters( 'propertyhive_pppw_to_consider_bedrooms', true ) == true )
336 - {
337 - $price = (($rent * 52) / 12) * $bedrooms;
338 - }
339 - else
340 - {
341 - $price = ($rent * 52) / 12;
342 - }
343 - break;
344 - }
345 - case "pw": { $price = ($rent * 52) / 12; break; }
346 - case "pcm": { $price = $rent; break; }
347 - case "pq": { $price = ($rent * 4) / 12; break; }
348 - case "pa": { $price = ($rent / 12); break; }
609 + $converted_price = $this->convert_price_to_gbp( $price, $currency );
349 610 }
350 611
351 - $converted_price = $this->convert_price_to_gbp( $price, $currency );
352 -
353 612 update_post_meta( $postID, '_price_actual', $converted_price );
354 613 }
355 614 if ( $department == 'commercial' )
356 615 {
@@ -356,12 +615,8 @@
356 615 {
357 616 if ( get_post_meta( $postID, '_for_sale', true ) == 'yes' )
358 617 {
359 618 $currency = get_post_meta( $postID, '_commercial_price_currency', true );
360 - if ( $country == '' )
361 - {
362 - $country = get_option( 'propertyhive_default_country', 'GB' );
363 - }
364 619 if ( $currency == '' )
365 620 {
366 621 $currency = $this->get_country($country);
367 622 $currency = $currency['currency_code'];
@@ -367,8 +622,12 @@
367 622 $currency = $currency['currency_code'];
368 623 }
369 624
370 625 $price = get_post_meta( $postID, '_price_from', true );
626 + if ( $price == '' )
627 + {
628 + $price = get_post_meta( $postID, '_price_to', true );
629 + }
371 630
372 631 $converted_price = $this->convert_price_to_gbp( $price, $currency );
373 632
374 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
@@ -373,8 +632,12 @@
373 632
374 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
375 634
376 635 $price = get_post_meta( $postID, '_price_to', true );
636 + if ( $price == '' )
637 + {
638 + $price = get_post_meta( $postID, '_price_from', true );
639 + }
377 640
378 641 $converted_price = $this->convert_price_to_gbp( $price, $currency );
379 642
380 643 update_post_meta( $postID, '_price_to_actual', $converted_price );
@@ -381,12 +644,8 @@
381 644 }
382 645 if ( get_post_meta( $postID, '_to_rent', true ) == 'yes' )
383 646 {
384 647 $currency = get_post_meta( $postID, '_commercial_rent_currency', true );
385 - if ( $country == '' )
386 - {
387 - $country = get_option( 'propertyhive_default_country', 'GB' );
388 - }
389 648 if ( $currency == '' )
390 649 {
391 650 $currency = $this->get_country($country);
392 651 $currency = $currency['currency_code'];
@@ -394,15 +653,23 @@
394 653
395 654 $rent_units = get_post_meta( $postID, '_rent_units', true );
396 655
397 656 $price = get_post_meta( $postID, '_rent_from', true );
398 - switch ($rent_units)
399 - {
400 - case "pw": { $price = ($price * 52) / 12; break; }
401 - case "pcm": { $price = $price; break; }
402 - case "pq": { $price = ($price * 4) / 52; break; }
403 - case "pa": { $price = ($price / 52); break; }
404 - }
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 + }
405 672
406 673 $converted_price = $this->convert_price_to_gbp( $price, $currency );
407 674
408 675 update_post_meta( $postID, '_rent_from_actual', $converted_price );
@@ -412,15 +679,23 @@
412 679 update_post_meta( $postID, '_price_from_actual', $converted_price );
413 680 }
414 681
415 682 $price = get_post_meta( $postID, '_rent_to', true );
416 - switch ($rent_units)
417 - {
418 - case "pw": { $price = ($price * 52) / 12; break; }
419 - case "pcm": { $price = $price; break; }
420 - case "pq": { $price = ($price * 4) / 52; break; }
421 - case "pa": { $price = ($price / 52); break; }
422 - }
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 + }
423 698
424 699 $converted_price = $this->convert_price_to_gbp( $price, $currency );
425 700
426 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
@@ -426,8 +701,10 @@
426 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
427 702 }
428 703 }
429 704 }
705 +
706 + do_action('propertyhive_property_price_actual_updated', $postID);
430 707 }
431 708
432 709 public function ph_update_currency_exchange_rates()
433 710 {
@@ -436,72 +713,82 @@
436 713 if ( $this->countries )
437 714 {
438 715 $countries = $this->countries;
439 716
440 - $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() );
441 725 $previous_exchange_rates = get_option( 'propertyhive_currency_exchange_rates' );
442 726
443 - $default_country = get_option( 'propertyhive_default_country', 'GB' );
444 - $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 );
445 733
446 - foreach ( $countries as $key => $value )
447 - {
448 - if (!isset($exchange_rates[$value['currency_code']]) && in_array($key, $selected_countries) && $value['currency_code'] != 'GBP')
734 + if ( is_array( $response ) )
449 735 {
450 - // we haven't got this exchange rate
451 - $from = 'GBP';
452 - $to = $value['currency_code'];
736 + $body = wp_remote_retrieve_body( $response );
737 + $json = json_decode($body, true);
453 738
454 - $exchangeRate = '';
455 -
456 - $url = 'https://finance.google.com/finance/converter?a=1&from=' . $from . '&to=' . $to;
457 -
458 - $response = wp_remote_get( $url );
459 -
460 - if ( is_array( $response ) )
739 + // If response is valid JSON and contains the core gbp key
740 + if ( $json !== null && isset( $json['gbp'] ) )
461 741 {
462 - $body = wp_remote_retrieve_body( $response );
742 + $exchange_rates_array = $json['gbp'];
463 743
464 - preg_match("/<span class=bld>(.*)<\/span>/", $body, $converted);
465 -
466 - if ( isset($converted[1]) && $converted[1] != '' )
744 + foreach ( $countries as $country )
467 745 {
468 - $converted = preg_replace("/[^0-9.]/", "", $converted[1]);
746 + $currency_code = $country['currency_code'];
469 747
470 - 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')
471 750 {
472 - $exchangeRate = $converted;
473 - $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 + }
474 756 }
475 757 }
476 758 }
477 - else
478 - {
759 + }
760 + }
479 761
480 - }
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 + }
481 769
482 - if ( $exchangeRate == '' && isset($previous_exchange_rates[$to]) )
483 - {
484 - // if for some reason we get here and don't have an exchange rate
485 - $exchange_rates[$to] = $previous_exchange_rates[$to];
486 - }
487 - }
488 - }
489 - $exchange_rates['GBP'] = "1.0000";
490 - update_option( 'propertyhive_currency_exchange_rates', $exchange_rates );
491 - update_option( 'propertyhive_currency_exchange_rates_updated', date("Y-m-d") );
770 + do_action('propertyhive_exchange_rates_updated', $exchange_rates);
492 771
493 - // 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
494 773 $args = array(
495 774 'post_type' => 'property',
775 + 'fields' => 'ids',
496 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.
497 778 'meta_query' => array(
498 779 array(
499 780 'key' => '_on_market',
500 781 'value' => 'yes',
782 + ),
783 + array(
784 + 'key' => '_address_country',
785 + 'value' => 'GB',
786 + 'compare' => '!=',
501 787 )
502 788 ),
503 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
504 791 );
505 792 $property_query = new WP_Query($args);
506 793
507 794 if ($property_query->have_posts())
@@ -518,5 +805,5 @@
518 805
519 806 }
520 807 }
521 808
522 -}
809 +}