| @@ -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' ) ) exit; // Exit if accessed directly |
| 4 | 7 | |
| 5 | 8 | /** |
| 6 | 9 | * PH_Shortcodes class. |
| @@ -35,8 +38,9 @@ | ||
| 35 | 38 | 'propertyhive_reset_password_form' => __CLASS__ . '::reset_password_form', |
| 36 | 39 | ); |
| 37 | 40 | |
| 38 | 41 | foreach ( $shortcodes as $shortcode => $function ) { |
| 42 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Public shortcode registration filter; extensions can customize each shortcode tag through this existing dynamic hook contract. | |
| 39 | 43 | add_shortcode( apply_filters( "{$shortcode}_shortcode_tag", $shortcode ), $function ); |
| 40 | 44 | } |
| 41 | 45 | } |
| 42 | 46 | |
| @@ -60,10 +64,12 @@ | ||
| 60 | 64 | |
| 61 | 65 | $before = empty( $wrapper['before'] ) ? '<div class="' . esc_attr( $wrapper['class'] ) . '">' : $wrapper['before']; |
| 62 | 66 | $after = empty( $wrapper['after'] ) ? '</div>' : $wrapper['after']; |
| 63 | 67 | |
| 68 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Wrapper HTML is supplied by PHP callers; the default class is escaped when assembled. | |
| 64 | 69 | echo $before; |
| 65 | 70 | call_user_func( $function, $atts ); |
| 71 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Closing wrapper HTML is supplied by PHP callers. | |
| 66 | 72 | echo $after; |
| 67 | 73 | |
| 68 | 74 | return ob_get_clean(); |
| 69 | 75 | } |
| @@ -99,8 +105,9 @@ | ||
| 99 | 105 | $form_controls = apply_filters( 'propertyhive_search_form_fields_after', $form_controls, $atts ); |
| 100 | 106 | |
| 101 | 107 | if ( |
| 102 | 108 | isset($atts['default_department']) && in_array($atts['default_department'], array_keys( ph_get_departments() )) && |
| 109 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public read-only search form default; no state change. | |
| 103 | 110 | ( !isset($_REQUEST['department']) ) |
| 104 | 111 | ) |
| 105 | 112 | { |
| 106 | 113 | $form_controls['department']['value'] = $atts['default_department']; |
| @@ -126,10 +133,12 @@ | ||
| 126 | 133 | $atts = shortcode_atts( array( |
| 127 | 134 | 'columns' => '2', |
| 128 | 135 | 'orderby' => 'meta_value_num', |
| 129 | 136 | 'order' => 'desc', |
| 137 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- These lines declare shortcode defaults; they do not pass a meta_key/exclude value to WP_Query or get_posts. 131 is the properties shortcode_atts default meta_key; 133/751/1045/1338 are exclude defaults in shortcode_atts. | |
| 130 | 138 | 'meta_key' => '_price_actual', |
| 131 | 139 | 'ids' => '', |
| 140 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- These lines declare shortcode defaults; they do not pass a meta_key/exclude value to WP_Query or get_posts. 131 is the properties shortcode_atts default meta_key; 133/751/1045/1338 are exclude defaults in shortcode_atts. | |
| 132 | 141 | 'exclude' => '', |
| 133 | 142 | 'department' => '', // residential-sales / residential-lettings / commercial / any custom department |
| 134 | 143 | 'minimum_price' => '', |
| 135 | 144 | 'maximum_price' => '', |
| @@ -364,8 +373,9 @@ | ||
| 364 | 373 | if ( isset($atts['keyword']) && $atts['keyword'] != '' ) |
| 365 | 374 | { |
| 366 | 375 | $atts['keyword'] = sanitize_text_field( trim( $atts['keyword'] ) ); |
| 367 | 376 | |
| 377 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Preserve the original request verbatim only to restore it after this shortcode's query; it is not output or persisted. | |
| 368 | 378 | $original_keyword = isset($_REQUEST['keyword']) ? $_REQUEST['keyword'] : ''; |
| 369 | 379 | $_REQUEST['keyword'] = $atts['keyword']; |
| 370 | 380 | |
| 371 | 381 | add_filter( 'posts_where', array( PH()->query, 'keyword_excerpt_where' ), 10, 2 ); |
| @@ -604,8 +614,9 @@ | ||
| 604 | 614 | get_option( 'propertyhive_active_departments_commercial' ) == 'yes' |
| 605 | 615 | ) |
| 606 | 616 | ) |
| 607 | 617 | { |
| 618 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 608 | 619 | $atts['meta_key'] = '_floor_area_from_sqft'; |
| 609 | 620 | } |
| 610 | 621 | |
| 611 | 622 | // Get which page we're currently viewing from the URL |
| @@ -618,13 +629,16 @@ | ||
| 618 | 629 | 'orderby' => $atts['orderby'], |
| 619 | 630 | 'order' => $atts['order'], |
| 620 | 631 | 'posts_per_page' => $atts['posts_per_page'], |
| 621 | 632 | 'paged' => $paged, |
| 633 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Property eligibility and matching fields live in the established metadata schema; retain these filters and the shortcode page limit. | |
| 622 | 634 | 'meta_query' => $meta_query, |
| 635 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Property taxonomy filters are required by this shortcode; WordPress builds the query and the shortcode page limit is retained. | |
| 623 | 636 | 'tax_query' => $tax_query, |
| 624 | 637 | 'has_password' => false, |
| 625 | 638 | ); |
| 626 | 639 | if ( ! empty( $atts['meta_key'] ) ) { |
| 640 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 627 | 641 | $args['meta_key'] = $atts['meta_key']; |
| 628 | 642 | } |
| 629 | 643 | |
| 630 | 644 | if ( ! empty( $atts['ids'] ) ) |
| @@ -640,8 +654,9 @@ | ||
| 640 | 654 | { |
| 641 | 655 | $exclude_ids = array_map( 'absint', explode( ',', $atts['exclude'] ) ); |
| 642 | 656 | $exclude_ids = array_filter( $exclude_ids ); |
| 643 | 657 | if ( ! empty( $exclude_ids ) ) { |
| 658 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Explicit shortcode exclusions are validated as integer IDs above; retain this published selection feature within the shortcode page limit. | |
| 644 | 659 | $args['post__not_in'] = $exclude_ids; |
| 645 | 660 | } |
| 646 | 661 | } |
| 647 | 662 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| @@ -646,8 +661,9 @@ | ||
| 646 | 661 | } |
| 647 | 662 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| 648 | 663 | { |
| 649 | 664 | $args['orderby'] = 'meta_value'; |
| 665 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 650 | 666 | $args['meta_key'] = '_on_market_change_date'; |
| 651 | 667 | } |
| 652 | 668 | |
| 653 | 669 | $args['orderby'] .= ' post_title'; |
| @@ -693,9 +709,10 @@ | ||
| 693 | 709 | if ( isset($atts['carousel']) && !empty($atts['carousel']) ) |
| 694 | 710 | { |
| 695 | 711 | $loop_start = str_replace("class=\"properties", "class=\"properties propertyhive-shortcode-carousel", $loop_start); |
| 696 | 712 | } |
| 697 | - echo $loop_start; | |
| 713 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Buffered loop template HTML; preserve theme overrides and the static carousel class insertion. | |
| 714 | + echo $loop_start; | |
| 698 | 715 | ?> |
| 699 | 716 | |
| 700 | 717 | <?php while ( $properties->have_posts() ) : $properties->the_post(); ?> |
| 701 | 718 | |
| @@ -746,8 +763,9 @@ | ||
| 746 | 763 | 'sale_by_id' => '', |
| 747 | 764 | 'location_id' => '', |
| 748 | 765 | 'commercial_for_sale' => '', |
| 749 | 766 | 'commercial_to_rent' => '', |
| 767 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- These lines declare shortcode defaults; they do not pass a meta_key/exclude value to WP_Query or get_posts. 131 is the properties shortcode_atts default meta_key; 133/751/1045/1338 are exclude defaults in shortcode_atts. | |
| 750 | 768 | 'exclude' => '', |
| 751 | 769 | 'orderby' => 'date', |
| 752 | 770 | 'order' => 'desc', |
| 753 | 771 | 'no_results_output' => '', |
| @@ -937,9 +955,11 @@ | ||
| 937 | 955 | 'posts_per_page' => $atts['per_page'], |
| 938 | 956 | 'paged' => $paged, |
| 939 | 957 | 'orderby' => $atts['orderby'], |
| 940 | 958 | 'order' => $atts['order'], |
| 959 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Property eligibility and matching fields live in the established metadata schema; retain these filters and the shortcode page limit. | |
| 941 | 960 | 'meta_query' => $meta_query, |
| 961 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Property taxonomy filters are required by this shortcode; WordPress builds the query and the shortcode page limit is retained. | |
| 942 | 962 | 'tax_query' => $tax_query, |
| 943 | 963 | 'has_password' => false, |
| 944 | 964 | ); |
| 945 | 965 | |
| @@ -947,8 +967,9 @@ | ||
| 947 | 967 | { |
| 948 | 968 | $exclude_ids = array_map( 'absint', explode( ',', $atts['exclude'] ) ); |
| 949 | 969 | $exclude_ids = array_filter( $exclude_ids ); |
| 950 | 970 | if ( ! empty( $exclude_ids ) ) { |
| 971 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Explicit shortcode exclusions are validated as integer IDs above; retain this published selection feature within the shortcode page limit. | |
| 951 | 972 | $args['post__not_in'] = $exclude_ids; |
| 952 | 973 | } |
| 953 | 974 | } |
| 954 | 975 | |
| @@ -954,8 +975,9 @@ | ||
| 954 | 975 | |
| 955 | 976 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| 956 | 977 | { |
| 957 | 978 | $args['orderby'] = 'meta_value'; |
| 979 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 958 | 980 | $args['meta_key'] = '_on_market_change_date'; |
| 959 | 981 | } |
| 960 | 982 | |
| 961 | 983 | $args['orderby'] .= ' post_title'; |
| @@ -992,9 +1014,10 @@ | ||
| 992 | 1014 | if ( isset($atts['carousel']) && !empty($atts['carousel']) ) |
| 993 | 1015 | { |
| 994 | 1016 | $loop_start = str_replace("class=\"properties", "class=\"properties propertyhive-shortcode-carousel", $loop_start); |
| 995 | 1017 | } |
| 996 | - echo $loop_start; | |
| 1018 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Buffered loop template HTML; preserve theme overrides and the static carousel class insertion. | |
| 1019 | + echo $loop_start; | |
| 997 | 1020 | ?> |
| 998 | 1021 | |
| 999 | 1022 | <?php while ( $properties->have_posts() ) : $properties->the_post(); ?> |
| 1000 | 1023 | |
| @@ -1040,11 +1063,13 @@ | ||
| 1040 | 1063 | 'address_keyword' => '', |
| 1041 | 1064 | 'office_id' => '', |
| 1042 | 1065 | 'negotiator_id' => '', |
| 1043 | 1066 | 'availability_id' => '', |
| 1067 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- These lines declare shortcode defaults; they do not pass a meta_key/exclude value to WP_Query or get_posts. 131 is the properties shortcode_atts default meta_key; 133/751/1045/1338 are exclude defaults in shortcode_atts. | |
| 1044 | 1068 | 'exclude' => '', |
| 1045 | 1069 | 'orderby' => 'rand', |
| 1046 | 1070 | 'order' => 'desc', |
| 1071 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Shortcode default declaration only; no query executes here. | |
| 1047 | 1072 | 'meta_key' => '', |
| 1048 | 1073 | 'no_results_output' => '', |
| 1049 | 1074 | 'pagination' => '', |
| 1050 | 1075 | 'show_order' => '', |
| @@ -1211,11 +1236,13 @@ | ||
| 1211 | 1236 | 'compare' => 'IN', |
| 1212 | 1237 | ); |
| 1213 | 1238 | } |
| 1214 | 1239 | |
| 1240 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Property eligibility and matching fields live in the established metadata schema; retain these filters and the shortcode page limit. | |
| 1215 | 1241 | $args['meta_query'] = $meta_query; |
| 1216 | 1242 | |
| 1217 | 1243 | if ( ! empty( $atts['meta_key'] ) ) { |
| 1244 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 1218 | 1245 | $args['meta_key'] = $atts['meta_key']; |
| 1219 | 1246 | } |
| 1220 | 1247 | |
| 1221 | 1248 | $tax_query = array(); |
| @@ -1229,8 +1256,9 @@ | ||
| 1229 | 1256 | ); |
| 1230 | 1257 | } |
| 1231 | 1258 | |
| 1232 | 1259 | if ( ! empty( $tax_query ) ) { |
| 1260 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Property taxonomy filters are required by this shortcode; WordPress builds the query and the shortcode page limit is retained. | |
| 1233 | 1261 | $args['tax_query'] = $tax_query; |
| 1234 | 1262 | } |
| 1235 | 1263 | |
| 1236 | 1264 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| @@ -1235,8 +1263,9 @@ | ||
| 1235 | 1263 | |
| 1236 | 1264 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| 1237 | 1265 | { |
| 1238 | 1266 | $args['orderby'] = 'meta_value'; |
| 1267 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 1239 | 1268 | $args['meta_key'] = '_on_market_change_date'; |
| 1240 | 1269 | } |
| 1241 | 1270 | |
| 1242 | 1271 | $args['orderby'] .= ' post_title'; |
| @@ -1245,8 +1274,9 @@ | ||
| 1245 | 1274 | { |
| 1246 | 1275 | $exclude_ids = array_map( 'absint', explode( ',', $atts['exclude'] ) ); |
| 1247 | 1276 | $exclude_ids = array_filter( $exclude_ids ); |
| 1248 | 1277 | if ( ! empty( $exclude_ids ) ) { |
| 1278 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Explicit shortcode exclusions are validated as integer IDs above; retain this published selection feature within the shortcode page limit. | |
| 1249 | 1279 | $args['post__not_in'] = $exclude_ids; |
| 1250 | 1280 | } |
| 1251 | 1281 | } |
| 1252 | 1282 | |
| @@ -1282,9 +1312,10 @@ | ||
| 1282 | 1312 | if ( isset($atts['carousel']) && !empty($atts['carousel']) ) |
| 1283 | 1313 | { |
| 1284 | 1314 | $loop_start = str_replace("class=\"properties", "class=\"properties propertyhive-shortcode-carousel", $loop_start); |
| 1285 | 1315 | } |
| 1286 | - echo $loop_start; | |
| 1316 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Buffered loop template HTML; preserve theme overrides and the static carousel class insertion. | |
| 1317 | + echo $loop_start; | |
| 1287 | 1318 | ?> |
| 1288 | 1319 | |
| 1289 | 1320 | <?php while ( $properties->have_posts() ) : $properties->the_post(); ?> |
| 1290 | 1321 | |
| @@ -1333,8 +1364,9 @@ | ||
| 1333 | 1364 | 'property_id' => '', |
| 1334 | 1365 | 'availability_id' => '', |
| 1335 | 1366 | 'property_type_id' => '', |
| 1336 | 1367 | 'match_property_type' => '', |
| 1368 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- These lines declare shortcode defaults; they do not pass a meta_key/exclude value to WP_Query or get_posts. 131 is the properties shortcode_atts default meta_key; 133/751/1045/1338 are exclude defaults in shortcode_atts. | |
| 1337 | 1369 | 'exclude' => '', |
| 1338 | 1370 | 'no_results_output' => '', |
| 1339 | 1371 | 'carousel' => '', |
| 1340 | 1372 | ), $atts, 'similar_properties' ); |
| @@ -1374,8 +1406,9 @@ | ||
| 1374 | 1406 | $department = get_post_meta( $atts['property_id'], '_department', true ); |
| 1375 | 1407 | |
| 1376 | 1408 | $args = array( |
| 1377 | 1409 | 'post_type' => 'property', |
| 1410 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Similar-property results must exclude the one current property; the result count is limited by per_page. | |
| 1378 | 1411 | 'post__not_in' => array($atts['property_id']), |
| 1379 | 1412 | 'post_status' => ( ( is_user_logged_in() && current_user_can( 'manage_propertyhive' ) ) ? array('publish', 'private') : 'publish' ), |
| 1380 | 1413 | 'ignore_sticky_posts' => 1, |
| 1381 | 1414 | 'posts_per_page' => $atts['per_page'], |
| @@ -1604,8 +1637,9 @@ | ||
| 1604 | 1637 | 'value' => $address_field, |
| 1605 | 1638 | ); |
| 1606 | 1639 | } |
| 1607 | 1640 | |
| 1641 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Property eligibility and matching fields live in the established metadata schema; retain these filters and the shortcode page limit. | |
| 1608 | 1642 | $args['meta_query'] = $meta_query; |
| 1609 | 1643 | |
| 1610 | 1644 | $tax_query = array(); |
| 1611 | 1645 | |
| @@ -1671,8 +1705,9 @@ | ||
| 1671 | 1705 | } |
| 1672 | 1706 | } |
| 1673 | 1707 | |
| 1674 | 1708 | if ( ! empty( $tax_query ) ) { |
| 1709 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Property taxonomy filters are required by this shortcode; WordPress builds the query and the shortcode page limit is retained. | |
| 1675 | 1710 | $args['tax_query'] = $tax_query; |
| 1676 | 1711 | } |
| 1677 | 1712 | |
| 1678 | 1713 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| @@ -1677,8 +1712,9 @@ | ||
| 1677 | 1712 | |
| 1678 | 1713 | if ( isset($atts['orderby']) && $atts['orderby'] == 'date' ) |
| 1679 | 1714 | { |
| 1680 | 1715 | $args['orderby'] = 'meta_value'; |
| 1716 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 1681 | 1717 | $args['meta_key'] = '_on_market_change_date'; |
| 1682 | 1718 | } |
| 1683 | 1719 | |
| 1684 | 1720 | $args['orderby'] .= ' post_title'; |
| @@ -1687,8 +1723,9 @@ | ||
| 1687 | 1723 | { |
| 1688 | 1724 | $exclude_ids = array_map( 'absint', explode( ',', $atts['exclude'] ) ); |
| 1689 | 1725 | $exclude_ids = array_filter( $exclude_ids ); |
| 1690 | 1726 | if ( ! empty( $exclude_ids ) ) { |
| 1727 | + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Explicit shortcode exclusions are validated as integer IDs above; retain this published selection feature within the shortcode page limit. | |
| 1691 | 1728 | $args['post__not_in'] = $exclude_ids; |
| 1692 | 1729 | } |
| 1693 | 1730 | } |
| 1694 | 1731 | |
| @@ -1707,9 +1744,10 @@ | ||
| 1707 | 1744 | if ( isset($atts['carousel']) && !empty($atts['carousel']) ) |
| 1708 | 1745 | { |
| 1709 | 1746 | $loop_start = str_replace("class=\"properties", "class=\"properties propertyhive-shortcode-carousel", $loop_start); |
| 1710 | 1747 | } |
| 1711 | - echo $loop_start; | |
| 1748 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Buffered loop template HTML; preserve theme overrides and the static carousel class insertion. | |
| 1749 | + echo $loop_start; | |
| 1712 | 1750 | ?> |
| 1713 | 1751 | |
| 1714 | 1752 | <?php while ( $properties->have_posts() ) : $properties->the_post(); ?> |
| 1715 | 1753 | |
| @@ -1758,9 +1796,9 @@ | ||
| 1758 | 1796 | ), $atts, 'property_map' ); |
| 1759 | 1797 | |
| 1760 | 1798 | ob_start(); |
| 1761 | 1799 | |
| 1762 | - echo get_property_map( $atts ); | |
| 1800 | + get_property_map( $atts ); | |
| 1763 | 1801 | |
| 1764 | 1802 | return ob_get_clean(); |
| 1765 | 1803 | } |
| 1766 | 1804 | |
| @@ -1783,9 +1821,9 @@ | ||
| 1783 | 1821 | ), $atts, 'property_static_map' ); |
| 1784 | 1822 | |
| 1785 | 1823 | ob_start(); |
| 1786 | 1824 | |
| 1787 | - echo get_property_static_map( $atts ); | |
| 1825 | + get_property_static_map( $atts ); | |
| 1788 | 1826 | |
| 1789 | 1827 | return ob_get_clean(); |
| 1790 | 1828 | } |
| 1791 | 1829 | |
| @@ -1807,9 +1845,9 @@ | ||
| 1807 | 1845 | ), $atts, 'property_street_view' ); |
| 1808 | 1846 | |
| 1809 | 1847 | ob_start(); |
| 1810 | 1848 | |
| 1811 | - echo get_property_street_view( $atts ); | |
| 1849 | + get_property_street_view( $atts ); | |
| 1812 | 1850 | |
| 1813 | 1851 | return ob_get_clean(); |
| 1814 | 1852 | } |
| 1815 | 1853 | |
| @@ -1845,9 +1883,9 @@ | ||
| 1845 | 1883 | } |
| 1846 | 1884 | |
| 1847 | 1885 | if ( $property->get_office_address( $atts['address_separator'] ) != '' ) |
| 1848 | 1886 | { |
| 1849 | - echo '<div class="office-address">' . $property->get_office_address( $atts['address_separator'] ) . '</div>'; | |
| 1887 | + echo '<div class="office-address">' . wp_kses_post( $property->get_office_address( $atts['address_separator'] ) ) . '</div>'; | |
| 1850 | 1888 | } |
| 1851 | 1889 | |
| 1852 | 1890 | if ( $property->office_telephone_number != '' ) |
| 1853 | 1891 | { |
| @@ -1910,12 +1948,12 @@ | ||
| 1910 | 1948 | |
| 1911 | 1949 | ob_start(); |
| 1912 | 1950 | |
| 1913 | 1951 | $api_key = get_option('propertyhive_google_maps_api_key', ''); |
| 1914 | - wp_register_script('googlemaps', '//maps.googleapis.com/maps/api/js?' . ( ( $api_key != '' && $api_key !== FALSE ) ? 'key=' . $api_key : '' ), false, '3'); | |
| 1952 | + wp_register_script('googlemaps', '//maps.googleapis.com/maps/api/js?' . ( ( $api_key != '' && $api_key !== FALSE ) ? 'key=' . $api_key : '' ), false, '3', true ); | |
| 1915 | 1953 | wp_enqueue_script('googlemaps'); |
| 1916 | 1954 | |
| 1917 | - echo '<div id="office_map_canvas" style="height:' . str_replace( "px", "", ( ( isset($atts['height']) && !empty($atts['height']) && is_numeric($atts['height']) ) ? (int)$atts['height'] : '400' ) ) . 'px"></div>'; | |
| 1955 | + echo '<div id="office_map_canvas" style="height:' . (int) ( ( isset($atts['height']) && !empty($atts['height']) && is_numeric($atts['height']) ) ? $atts['height'] : 400 ) . 'px"></div>'; | |
| 1918 | 1956 | ?> |
| 1919 | 1957 | <script> |
| 1920 | 1958 | |
| 1921 | 1959 | // We declare vars globally so developers can access them |
| @@ -1936,8 +1974,9 @@ | ||
| 1936 | 1974 | $args['p'] = (int)$atts['office_id']; |
| 1937 | 1975 | } |
| 1938 | 1976 | else |
| 1939 | 1977 | { |
| 1978 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Selects the primary office from the established metadata schema and returns at most one office. | |
| 1940 | 1979 | $args['meta_query'] = array( |
| 1941 | 1980 | array( |
| 1942 | 1981 | 'key' => 'primary', |
| 1943 | 1982 | 'value' => '1' |
| @@ -1977,11 +2016,15 @@ | ||
| 1977 | 2016 | if ( class_exists( 'PH_Map_Search' ) ) |
| 1978 | 2017 | { |
| 1979 | 2018 | $map_add_on_settings = get_option( 'propertyhive_map_search', array() ); |
| 1980 | 2019 | |
| 1981 | - if ( isset($map_add_on_settings['style_js']) && trim($map_add_on_settings['style_js']) != '' ) | |
| 2020 | + if ( isset($map_add_on_settings['style_js']) && is_string($map_add_on_settings['style_js']) && trim($map_add_on_settings['style_js']) != '' ) | |
| 1982 | 2021 | { |
| 1983 | - echo 'map_options.styles = ' . trim($map_add_on_settings['style_js']) . ';'; | |
| 2022 | + // Google Maps styles are JSON arrays, including legacy Snazzy Maps style properties. | |
| 2023 | + $map_styles = json_decode( $map_add_on_settings['style_js'] ); | |
| 2024 | + if ( is_array( $map_styles ) ) { | |
| 2025 | + echo 'map_options.styles = ' . wp_json_encode( $map_styles, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ';'; | |
| 2026 | + } | |
| 1984 | 2027 | } |
| 1985 | 2028 | } |
| 1986 | 2029 | |
| 1987 | 2030 | do_action( 'propertyhive_office_map_options' ); |
| @@ -2192,17 +2235,19 @@ | ||
| 2192 | 2235 | ph_get_template( 'account/invalid-access.php' ); |
| 2193 | 2236 | return ob_get_clean(); |
| 2194 | 2237 | } |
| 2195 | 2238 | |
| 2196 | - // check key provided is valid | |
| 2197 | - if ( !isset($_GET['key']) || empty(ph_clean($_GET['key'])) || !isset($_GET['id']) || empty(absint($_GET['id'])) ) | |
| 2239 | + // Display only: WordPress validates the opaque reset key; the reset action has its own nonce. | |
| 2240 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- An opaque key must remain intact for check_password_reset_key(). | |
| 2241 | + $key = isset( $_GET['key'] ) && is_string( $_GET['key'] ) ? wp_unslash( $_GET['key'] ) : ''; | |
| 2242 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only selects the user whose reset key WordPress verifies below. | |
| 2243 | + $user_id = isset( $_GET['id'] ) && is_string( $_GET['id'] ) ? absint( $_GET['id'] ) : 0; | |
| 2244 | + if ( $key === '' || $user_id === 0 ) | |
| 2198 | 2245 | { |
| 2199 | 2246 | echo esc_html(__( 'Invalid key or id provided. Please try again', 'propertyhive' )); |
| 2200 | 2247 | return ob_get_clean(); |
| 2201 | 2248 | } |
| 2202 | 2249 | |
| 2203 | - $key = ph_clean($_GET['key']); | |
| 2204 | - $user_id = absint($_GET['id']); | |
| 2205 | 2250 | |
| 2206 | 2251 | $userdata = get_userdata( $user_id ); |
| 2207 | 2252 | $user_login = $userdata ? $userdata->user_login : ''; |
| 2208 | 2253 | |
| @@ -2260,9 +2305,10 @@ | ||
| 2260 | 2305 | private static function get_show_order_args( $atts, $args ) |
| 2261 | 2306 | { |
| 2262 | 2307 | $orderby = ''; |
| 2263 | 2308 | |
| 2264 | - if ( isset( $_GET['orderby'] ) && $_GET['orderby'] != '' ) | |
| 2309 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public read-only sort selection; the query helper validates the ordering value. | |
| 2310 | + if ( isset( $_GET['orderby'] ) && is_string( $_GET['orderby'] ) && $_GET['orderby'] != '' ) | |
| 2265 | 2311 | { |
| 2266 | 2312 | $PH_Query = new PH_Query(); |
| 2267 | 2313 | $ordering_args = $PH_Query->get_search_results_ordering_args(); |
| 2268 | 2314 | |
| @@ -2270,8 +2316,9 @@ | ||
| 2270 | 2316 | $args['order'] = $ordering_args['order']; |
| 2271 | 2317 | |
| 2272 | 2318 | if ( isset( $ordering_args['meta_key'] ) ) |
| 2273 | 2319 | { |
| 2320 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Property sorting uses the established price, floor-area or market-date metadata; retain the selected ordering and existing query limits. | |
| 2274 | 2321 | $args['meta_key'] = $ordering_args['meta_key']; |
| 2275 | 2322 | } |
| 2276 | 2323 | else |
| 2277 | 2324 | { |