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 +435 -107 1.4.62.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( $_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[$_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' => '$',
@@ -114,12 +169,18 @@
114 169 'currency_code' => 'AUD',
115 170 'currency_symbol' => '$',
116 171 'currency_prefix' => true
117 172 ),
118 - 'AU' => array(
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,24 +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 + ),
299 + 'IE' => array(
300 + 'name' => 'Ireland',
301 + 'currency_code' => 'EUR',
302 + 'currency_symbol' => '&euro;',
303 + 'currency_prefix' => false
304 + ),
172 305 'IT' => array(
173 306 'name' => 'Italy',
174 307 'currency_code' => 'EUR',
175 308 'currency_symbol' => '&euro;',
309 + 'currency_prefix' => false
310 + ),
311 + 'JM' => array(
312 + 'name' => 'Jamaica',
313 + 'currency_code' => 'JMD',
314 + 'currency_symbol' => '$',
176 315 'currency_prefix' => true
177 316 ),
178 317 'JP' => array(
179 318 'name' => 'Japan',
@@ -180,14 +319,92 @@
180 319 'currency_code' => 'JPY',
181 320 'currency_symbol' => '&yen;',
182 321 'currency_prefix' => true
183 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 + ),
347 + 'MU' => array(
348 + 'name' => 'Mauritius',
349 + 'currency_code' => 'MUR',
350 + 'currency_symbol' => 'Rs',
351 + 'currency_prefix' => false
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 + ),
377 + 'NO' => array(
378 + 'name' => 'Norway',
379 + 'currency_code' => 'NOK',
380 + 'currency_symbol' => 'kr',
381 + 'currency_prefix' => false
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 + ),
184 395 'PT' => array(
185 396 'name' => 'Portugal',
186 397 'currency_code' => 'EUR',
187 398 'currency_symbol' => '&euro;',
188 - 'currency_prefix' => true
399 + 'currency_prefix' => false
189 400 ),
401 + 'QA' => array(
402 + 'name' => 'Qatar',
403 + 'currency_code' => 'QAR',
404 + 'currency_symbol' => 'QR',
405 + 'currency_prefix' => false
406 + ),
190 407 'RU' => array(
191 408 'name' => 'Russia',
192 409 'currency_code' => 'RUB',
193 410 'currency_symbol' => '₽',
@@ -192,8 +409,26 @@
192 409 'currency_code' => 'RUB',
193 410 'currency_symbol' => '₽',
194 411 'currency_prefix' => true
195 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 + ),
196 431 'ZA' => array(
197 432 'name' => 'South Africa',
198 433 'currency_code' => 'ZAR',
199 434 'currency_symbol' => 'R',
@@ -198,14 +433,44 @@
198 433 'currency_code' => 'ZAR',
199 434 'currency_symbol' => 'R',
200 435 'currency_prefix' => true
201 436 ),
437 + 'KR' => array(
438 + 'name' => 'South Korea',
439 + 'currency_code' => 'KRW',
440 + 'currency_symbol' => '₩',
441 + 'currency_prefix' => true
442 + ),
202 443 'ES' => array(
203 444 'name' => 'Spain',
204 445 'currency_code' => 'EUR',
205 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',
206 459 'currency_prefix' => true
207 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 + ),
208 473 'AE' => array(
209 474 'name' => 'United Arab Emirates',
210 475 'currency_code' => 'AED',
211 476 'currency_symbol' => '‎د.إ',
@@ -222,8 +487,14 @@
222 487 'currency_code' => 'USD',
223 488 'currency_symbol' => '$',
224 489 'currency_prefix' => true
225 490 ),
491 + 'VN' => array(
492 + 'name' => 'Vietnam',
493 + 'currency_code' => 'VND',
494 + 'currency_symbol' => '₫',
495 + 'currency_prefix' => true
496 + ),
226 497 );
227 498
228 499 return apply_filters( 'propertyhive_countries', $countries );
229 500 }
@@ -241,9 +512,9 @@
241 512 echo '<option';
242 513 if ( $selected_country == $key || ( $selected_country == '' && $key == 'GB' ) ) {
243 514 echo ' selected="selected"';
244 515 }
245 - 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>';
246 517 }
247 518 }
248 519 }
249 520
@@ -268,9 +539,18 @@
268 539 {
269 540 $countries = $this->countries;
270 541
271 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 +
272 548 $country = get_post_meta( $postID, '_address_country', true );
549 + if ( $country == '' )
550 + {
551 + $country = get_option( 'propertyhive_default_country', 'GB' );
552 + }
273 553
274 554 if (isset($countries[$country]))
275 555 {
276 556 if ( $department == 'residential-sales' )
@@ -275,12 +555,8 @@
275 555 {
276 556 if ( $department == 'residential-sales' )
277 557 {
278 558 $currency = get_post_meta( $postID, '_currency', true );
279 - if ( $country == '' )
280 - {
281 - $country = get_option( 'propertyhive_default_country', 'GB' );
282 - }
283 559 if ( $currency == '' )
284 560 {
285 561 $currency = $this->get_country($country);
286 562 $currency = $currency['currency_code'];
@@ -294,12 +570,8 @@
294 570 }
295 571 elseif ( $department == 'residential-lettings' )
296 572 {
297 573 $currency = get_post_meta( $postID, '_currency', true );
298 - if ( $country == '' )
299 - {
300 - $country = get_option( 'propertyhive_default_country', 'GB' );
301 - }
302 574 if ( $currency == '' )
303 575 {
304 576 $currency = $this->get_country($country);
305 577 $currency = $currency['currency_code'];
@@ -305,34 +577,39 @@
305 577 $currency = $currency['currency_code'];
306 578 }
307 579
308 580 $rent = get_post_meta( $postID, '_rent', true );
309 - $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 + }
310 608
311 - $price = $rent; // Stored in pcm
312 - switch ($rent_frequency)
313 - {
314 - case "pppw":
315 - {
316 - $bedrooms = get_post_meta( $postID, '_bedrooms', true );
317 - if ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' )
318 - {
319 - $price = (($rent * 52) / 12) * $bedrooms;
320 - }
321 - else
322 - {
323 - $price = ($rent * 52) / 12;
324 - }
325 - break;
326 - }
327 - case "pw": { $price = ($rent * 52) / 12; break; }
328 - case "pcm": { $price = $rent; break; }
329 - case "pq": { $price = ($rent * 4) / 12; break; }
330 - case "pa": { $price = ($rent / 12); break; }
609 + $converted_price = $this->convert_price_to_gbp( $price, $currency );
331 610 }
332 611
333 - $converted_price = $this->convert_price_to_gbp( $price, $currency );
334 -
335 612 update_post_meta( $postID, '_price_actual', $converted_price );
336 613 }
337 614 if ( $department == 'commercial' )
338 615 {
@@ -338,12 +615,8 @@
338 615 {
339 616 if ( get_post_meta( $postID, '_for_sale', true ) == 'yes' )
340 617 {
341 618 $currency = get_post_meta( $postID, '_commercial_price_currency', true );
342 - if ( $country == '' )
343 - {
344 - $country = get_option( 'propertyhive_default_country', 'GB' );
345 - }
346 619 if ( $currency == '' )
347 620 {
348 621 $currency = $this->get_country($country);
349 622 $currency = $currency['currency_code'];
@@ -349,8 +622,12 @@
349 622 $currency = $currency['currency_code'];
350 623 }
351 624
352 625 $price = get_post_meta( $postID, '_price_from', true );
626 + if ( $price == '' )
627 + {
628 + $price = get_post_meta( $postID, '_price_to', true );
629 + }
353 630
354 631 $converted_price = $this->convert_price_to_gbp( $price, $currency );
355 632
356 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
@@ -355,8 +632,12 @@
355 632
356 633 update_post_meta( $postID, '_price_from_actual', $converted_price );
357 634
358 635 $price = get_post_meta( $postID, '_price_to', true );
636 + if ( $price == '' )
637 + {
638 + $price = get_post_meta( $postID, '_price_from', true );
639 + }
359 640
360 641 $converted_price = $this->convert_price_to_gbp( $price, $currency );
361 642
362 643 update_post_meta( $postID, '_price_to_actual', $converted_price );
@@ -363,12 +644,8 @@
363 644 }
364 645 if ( get_post_meta( $postID, '_to_rent', true ) == 'yes' )
365 646 {
366 647 $currency = get_post_meta( $postID, '_commercial_rent_currency', true );
367 - if ( $country == '' )
368 - {
369 - $country = get_option( 'propertyhive_default_country', 'GB' );
370 - }
371 648 if ( $currency == '' )
372 649 {
373 650 $currency = $this->get_country($country);
374 651 $currency = $currency['currency_code'];
@@ -376,28 +653,49 @@
376 653
377 654 $rent_units = get_post_meta( $postID, '_rent_units', true );
378 655
379 656 $price = get_post_meta( $postID, '_rent_from', true );
380 - switch ($rent_units)
381 - {
382 - case "pw": { $price = ($price * 52) / 12; break; }
383 - case "pcm": { $price = $price; break; }
384 - case "pq": { $price = ($price * 4) / 52; break; }
385 - case "pa": { $price = ($price / 52); break; }
386 - }
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 + }
387 672
388 673 $converted_price = $this->convert_price_to_gbp( $price, $currency );
389 674
390 675 update_post_meta( $postID, '_rent_from_actual', $converted_price );
391 676
677 + if ( get_post_meta( $postID, '_for_sale', true ) != 'yes' )
678 + {
679 + update_post_meta( $postID, '_price_from_actual', $converted_price );
680 + }
681 +
392 682 $price = get_post_meta( $postID, '_rent_to', true );
393 - switch ($rent_units)
394 - {
395 - case "pw": { $price = ($price * 52) / 12; break; }
396 - case "pcm": { $price = $price; break; }
397 - case "pq": { $price = ($price * 4) / 52; break; }
398 - case "pa": { $price = ($price / 52); break; }
399 - }
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 + }
400 698
401 699 $converted_price = $this->convert_price_to_gbp( $price, $currency );
402 700
403 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
@@ -403,8 +701,10 @@
403 701 update_post_meta( $postID, '_rent_to_actual', $converted_price );
404 702 }
405 703 }
406 704 }
705 +
706 + do_action('propertyhive_property_price_actual_updated', $postID);
407 707 }
408 708
409 709 public function ph_update_currency_exchange_rates()
410 710 {
@@ -413,54 +713,82 @@
413 713 if ( $this->countries )
414 714 {
415 715 $countries = $this->countries;
416 716
417 - $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() );
418 725 $previous_exchange_rates = get_option( 'propertyhive_currency_exchange_rates' );
419 726
420 - $default_country = get_option( 'propertyhive_default_country', 'GB' );
421 - $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 );
422 733
423 - foreach ( $countries as $key => $value )
424 - {
425 - if (!isset($exchange_rates[$value['currency_code']]) && in_array($key, $selected_countries))
734 + if ( is_array( $response ) )
426 735 {
427 - // we haven't got this exchange rate
428 - $from = 'GBP';
429 - $to = $value['currency_code'];
430 - $url = 'http://finance.yahoo.com/d/quotes.csv?e=.csv&f=sl1d1t1&s='. $from . $to .'=X';
736 + $body = wp_remote_retrieve_body( $response );
737 + $json = json_decode($body, true);
431 738
432 - $filehandler = @fopen( $url, 'r' );
433 -
434 - $exchangeRate = '';
435 -
436 - if ( $filehandler )
739 + // If response is valid JSON and contains the core gbp key
740 + if ( $json !== null && isset( $json['gbp'] ) )
437 741 {
438 - $data = fgets($filehandler, 4096);
439 - fclose($filehandler);
742 + $exchange_rates_array = $json['gbp'];
440 743
441 - $InfoData = explode(',',$data);
744 + foreach ( $countries as $country )
745 + {
746 + $currency_code = $country['currency_code'];
442 747
443 - if ( isset($InfoData[1]) )
444 - {
445 - $exchangeRate = $InfoData[1];
446 - $exchange_rates[$to] = $exchangeRate;
748 + // If we haven't already got this currency and it's not GBP
749 + if (!isset($exchange_rates[$currency_code]) && $currency_code != 'GBP')
750 + {
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 + }
756 + }
447 757 }
448 758 }
759 + }
760 + }
449 761
450 - if ( $exchangeRate == '' && isset($previous_exchange_rates[$to]) )
451 - {
452 - // if for some reason we get here and don't have an exchange rate
453 - $exchange_rates[$to] = $previous_exchange_rates[$to];
454 - }
455 - }
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") );
456 768 }
457 - update_option( 'propertyhive_currency_exchange_rates', $exchange_rates );
458 769
459 - // Loop through all properties and update _actual_price meta value to be price in GBP
770 + do_action('propertyhive_exchange_rates_updated', $exchange_rates);
771 +
772 + // Loop through all on market properties and update _price_actual meta value to be price in GBP
460 773 $args = array(
461 774 'post_type' => 'property',
462 - 'nopaging' => true
775 + 'fields' => 'ids',
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.
778 + 'meta_query' => array(
779 + array(
780 + 'key' => '_on_market',
781 + 'value' => 'yes',
782 + ),
783 + array(
784 + 'key' => '_address_country',
785 + 'value' => 'GB',
786 + 'compare' => '!=',
787 + )
788 + ),
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
463 791 );
464 792 $property_query = new WP_Query($args);
465 793
466 794 if ($property_query->have_posts())
@@ -477,5 +805,5 @@
477 805
478 806 }
479 807 }
480 808
481 -}
809 +}