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-rest-api.php +142 -46 2.2.32.3.1 View file →
@@ -12,8 +12,9 @@
12 12 * @package PropertyHive/Classes/
13 13 * @category Class
14 14 * @author PropertyHive
15 15 */
16 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Legacy public global class PH_Rest_Api; preserving the existing PH_* class name is required for plugin and extension compatibility.
16 17 class PH_Rest_Api {
17 18
18 19 /** @var PH_Rest_Api The single instance of the class */
19 20 protected static $_instance = null;
@@ -18,8 +19,37 @@
18 19 /** @var PH_Rest_Api The single instance of the class */
19 20 protected static $_instance = null;
20 21
21 22 /**
23 + * Download REST media within the site's upload size limit.
24 + *
25 + * @param string $url Remote media URL.
26 + * @return string|WP_Error Temporary filename or an error.
27 + */
28 + private static function download_media( $url ) {
29 + $temporary_file = wp_tempnam( $url );
30 + if ( ! $temporary_file ) {
31 + return new WP_Error( 'propertyhive_media_temp_file', __( 'Unable to create a temporary file.', 'propertyhive' ) );
32 + }
33 + $maximum_size = wp_max_upload_size();
34 + $response = wp_safe_remote_get( $url, array(
35 + 'timeout' => 30,
36 + 'stream' => true,
37 + 'filename' => $temporary_file,
38 + 'limit_response_size' => $maximum_size + 1,
39 + ) );
40 + if ( is_wp_error( $response ) ) {
41 + wp_delete_file( $temporary_file );
42 + return $response;
43 + }
44 + if ( 200 !== wp_remote_retrieve_response_code( $response ) || filesize( $temporary_file ) > $maximum_size ) {
45 + wp_delete_file( $temporary_file );
46 + return new WP_Error( 'propertyhive_media_download', __( 'The media could not be downloaded or exceeds the upload size limit.', 'propertyhive' ) );
47 + }
48 + return $temporary_file;
49 + }
50 +
51 + /**
22 52 * Main PH_Rest_Api Instance.
23 53 *
24 54 * Ensures only one instance of PH_Rest_Api is loaded or can be loaded.
25 55 *
@@ -39,9 +69,9 @@
39 69 *
40 70 * @since 1.0.0
41 71 */
42 72 public function __clone() {
43 - _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
73 + _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
44 74 }
45 75
46 76 /**
47 77 * Unserializing instances of this class is forbidden.
@@ -48,9 +78,9 @@
48 78 *
49 79 * @since 1.0.0
50 80 */
51 81 public function __wakeup() {
52 - _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
82 + _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'propertyhive' ), '1.0.0' );
53 83 }
54 84
55 85 /**
56 86 * Constructor for the licenses class
@@ -97,9 +127,9 @@
97 127 }
98 128
99 129 public function block_enquiry_rest_listing($response, $server, $request)
100 130 {
101 - if ( $request->get_route() === '/wp/v2/enquiry' )
131 + if ( preg_match( '#^/wp/v2/enquiry(?:/|$)#', $request->get_route() ) )
102 132 {
103 133 $current_user = wp_get_current_user();
104 134
105 135 if ( !current_user_can('manage_propertyhive') )
@@ -105,9 +135,9 @@
105 135 if ( !current_user_can('manage_propertyhive') )
106 136 {
107 137 return new WP_Error(
108 138 'rest_forbidden',
109 - __('You are not allowed to list enquiries.', 'propertyhive'),
139 + __( 'You are not allowed to access enquiries.', 'propertyhive' ),
110 140 ['status' => 403]
111 141 );
112 142 }
113 143
@@ -246,22 +276,14 @@
246 276 ),
247 277 ));
248 278 }
249 279
250 - public function enquiry_permission_check()
251 - {
252 - // Check if the user is authenticated
253 - if (is_user_logged_in() || apply_filters('rest_authentication_errors', null) === null) {
254 - // Check if the user has the capability to create enquiries (e.g., 'edit_posts')
255 - if (current_user_can('edit_posts')) {
256 - return true;
257 - } else {
258 - return new WP_Error('rest_forbidden', 'You do not have permissions to create enquiries.', array('status' => 403));
259 - }
260 - } else {
261 - return new WP_Error('rest_forbidden', 'You are not authenticated.', array('status' => 403));
262 - }
263 - }
280 + public function enquiry_permission_check() {
281 + if ( current_user_can( 'manage_propertyhive' ) ) {
282 + return true;
283 + }
284 + return new WP_Error( 'rest_forbidden', __( 'You do not have permission to create enquiries.', 'propertyhive' ), array( 'status' => 403 ) );
285 + }
264 286
265 287 public function handle_enquiry_post(WP_REST_Request $request)
266 288 {
267 289 // Handle the creation of the enquiry post
@@ -534,11 +556,13 @@
534 556
535 557 $PH_Query = new PH_Query();
536 558
537 559 // Meta query
560 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- REST property collection arguments are built from PH_Query filters and are consumed by WordPress REST collection pagination. Meta/tax/date filters and fixed ordering are feature behavior; the REST controller bounds per_page and the source preserves request filters.
538 561 $args['meta_query'] = $PH_Query->get_meta_query();
539 562
540 563 // Tax query
564 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- REST property collection arguments are built from PH_Query filters and are consumed by WordPress REST collection pagination. Meta/tax/date filters and fixed ordering are feature behavior; the REST controller bounds per_page and the source preserves request filters.
541 565 $args['tax_query'] = $PH_Query->get_tax_query();
542 566
543 567 // Date query
544 568 $args['date_query'] = $PH_Query->get_date_query();
@@ -546,8 +570,9 @@
546 570 $ordering = $PH_Query->get_search_results_ordering_args();
547 571 $args['orderby'] = $ordering['orderby'] . ' post_title';
548 572 $args['order'] = $ordering['order'];
549 573 if ( isset( $ordering['meta_key'] ) )
574 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- REST property collection arguments are built from PH_Query filters and are consumed by WordPress REST collection pagination. Meta/tax/date filters and fixed ordering are feature behavior; the REST controller bounds per_page and the source preserves request filters.
550 575 $args['meta_key'] = $ordering['meta_key'];
551 576
552 577 $args = apply_filters( 'propertyhive_rest_api_query_args', $args );
553 578
@@ -613,8 +638,10 @@
613 638 'brochures',
614 639 'epcs',
615 640 'virtual_tours',
616 641 'views_total',
642 + 'views_today',
643 + 'views_yesterday',
617 644 'views_last_7_days',
618 645 'views_last_14_days',
619 646 'views_last_30_days',
620 647 );
@@ -851,8 +878,10 @@
851 878 {
852 879 $return = $property->get_virtual_tours();
853 880 break;
854 881 }
882 + case "views_today":
883 + case "views_yesterday":
855 884 case "views_last_7_days":
856 885 case "views_last_14_days":
857 886 case "views_last_30_days":
858 887 case "views_total":
@@ -857,35 +886,68 @@
857 886 case "views_last_30_days":
858 887 case "views_total":
859 888 {
860 889 $view_statistics = $property->_view_statistics;
861 - if ( !is_array($view_statistics) )
862 - {
863 - $view_statistics = array();
864 - }
890 + if ( !is_array($view_statistics) )
891 + {
892 + $view_statistics = array();
893 + }
865 894
866 - $views = 0;
895 + $views = 0;
867 896
868 - $date_from = '2001-01-01';
869 - switch ($field_name)
870 - {
871 - case "views_last_7_days": { $date_from = date("Y-m-d", strtotime('7 days ago')); break; }
872 - case "views_last_14_days": { $date_from = date("Y-m-d", strtotime('14 days ago')); break; }
873 - case "views_last_30_days": { $date_from = date("Y-m-d", strtotime('30 days ago')); break; }
874 - }
875 - $date_from = strtotime($date_from);
897 + $today = current_datetime()->setTime(0, 0, 0);
876 898
877 - $date_to = date("Y-m-d");
878 - $date_to = strtotime($date_to);
899 + $date_from = new DateTimeImmutable('2001-01-01', wp_timezone());
900 + $date_to = $today;
879 901
880 - for ($i = $date_from; $i <= $date_to; $i += 86400)
881 - {
882 - if ( isset($view_statistics[date("Y-m-d", $i)]) )
883 - {
884 - $views += $view_statistics[date("Y-m-d", $i)];
885 - }
886 - }
902 + switch ($field_name)
903 + {
904 + case 'views_last_7_days':
905 + {
906 + $date_from = $today->modify('-7 days');
907 + $date_to = $today->modify('-1 day');
908 + break;
909 + }
887 910
911 + case 'views_last_14_days':
912 + {
913 + $date_from = $today->modify('-14 days');
914 + $date_to = $today->modify('-1 day');
915 + break;
916 + }
917 +
918 + case 'views_last_30_days':
919 + {
920 + $date_from = $today->modify('-30 days');
921 + $date_to = $today->modify('-1 day');
922 + break;
923 + }
924 +
925 + case 'views_today':
926 + {
927 + $date_from = $today;
928 + $date_to = $today;
929 + break;
930 + }
931 +
932 + case 'views_yesterday':
933 + {
934 + $date_from = $today->modify('-1 day');
935 + $date_to = $date_from;
936 + break;
937 + }
938 + }
939 +
940 + for ( $date = $date_from; $date <= $date_to; $date = $date->modify('+1 day') )
941 + {
942 + $date_key = $date->format('Y-m-d');
943 +
944 + if ( isset($view_statistics[$date_key]) )
945 + {
946 + $views += (int)$view_statistics[$date_key];
947 + }
948 + }
949 +
888 950 $return = $views;
889 951 break;
890 952 }
891 953 default:
@@ -950,13 +1012,48 @@
950 1012 }
951 1013 }
952 1014 break;
953 1015 }
1016 + case "description":
1017 + {
1018 + if ( ! is_string( $value ) ) {
1019 + return new WP_Error( 'propertyhive_rest_description_invalid', __( 'The description must be text.', 'propertyhive' ), array( 'status' => 400 ) );
1020 + }
1021 + $value = propertyhive_sanitize_description( $value );
1022 + $property = new PH_Property($object->ID);
1023 +
1024 + if ( isset($property->_department) && $property->_department == 'commercial' )
1025 + {
1026 + update_post_meta( $object->ID, '_descriptions', '1' );
1027 + update_post_meta( $object->ID, '_description_name_0', '' );
1028 + update_post_meta( $object->ID, '_description_0', wp_slash( $value ) );
1029 + }
1030 + else
1031 + {
1032 + update_post_meta( $object->ID, '_rooms', '1' );
1033 + update_post_meta( $object->ID, '_room_name_0', '' );
1034 + update_post_meta( $object->ID, '_room_dimensions_0', '' );
1035 + update_post_meta( $object->ID, '_room_description_0', wp_slash( $value ) );
1036 + }
1037 + break;
1038 + }
954 1039 case "images":
955 1040 case "floorplans":
956 1041 case "brochures":
957 1042 case "epcs":
958 1043 {
1044 + if ( ! current_user_can( 'upload_files' ) || ! current_user_can( 'edit_post', $object->ID ) ) {
1045 + return new WP_Error( 'propertyhive_rest_media_forbidden', __( 'You do not have permission to update property media.', 'propertyhive' ), array( 'status' => 403 ) );
1046 + }
1047 + if ( ! is_array( $value ) || count( $value ) > 100 ) {
1048 + return new WP_Error( 'propertyhive_rest_media_invalid', __( 'Supply an array containing no more than 100 media items.', 'propertyhive' ), array( 'status' => 400 ) );
1049 + }
1050 + foreach ( $value as $media_item ) {
1051 + if ( ! is_array( $media_item ) || ! isset( $media_item['url'] ) || ! is_string( $media_item['url'] ) || ! preg_match( '~^(https?:)?//~i', $media_item['url'] ) ) {
1052 + return new WP_Error( 'propertyhive_rest_media_invalid', __( 'Each media item must contain an HTTP or HTTPS URL.', 'propertyhive' ), array( 'status' => 400 ) );
1053 + }
1054 + }
1055 +
959 1056 if ( !function_exists('media_handle_upload') ) {
960 1057 require_once(ABSPATH . "wp-admin" . '/includes/image.php');
961 1058 require_once(ABSPATH . "wp-admin" . '/includes/file.php');
962 1059 require_once(ABSPATH . "wp-admin" . '/includes/media.php');
@@ -1030,9 +1127,9 @@
1030 1127 $media_ids[] = $imported_previously_id;
1031 1128 }
1032 1129 else
1033 1130 {
1034 - $tmp = download_url( $url );
1131 + $tmp = self::download_media( $url );
1035 1132 $file_array = array(
1036 1133 'name' => basename( $url ),
1037 1134 'tmp_name' => $tmp
1038 1135 );
@@ -1039,9 +1136,9 @@
1039 1136
1040 1137 // Check for download errors
1041 1138 if ( is_wp_error( $tmp ) )
1042 1139 {
1043 - // ERROR: $tmp->get_error_message();
1140 + return $tmp;
1044 1141 }
1045 1142 else
1046 1143 {
1047 1144 $id = media_handle_sideload( $file_array, $object->ID, $description, array('post_title' => $filename) );
@@ -1048,11 +1145,11 @@
1048 1145
1049 1146 // Check for handle sideload errors.
1050 1147 if ( is_wp_error( $id ) )
1051 1148 {
1052 - @unlink( $file_array['tmp_name'] );
1149 + wp_delete_file( $file_array['tmp_name'] );
1053 1150
1054 - // ERROR: $id->get_error_message();
1151 + return $id;
1055 1152 }
1056 1153 else
1057 1154 {
1058 1155 $media_ids[] = $id;
@@ -1069,9 +1166,9 @@
1069 1166 if ( is_array($previous_media_ids) && !empty($previous_media_ids) )
1070 1167 {
1071 1168 foreach ( $previous_media_ids as $previous_media_id )
1072 1169 {
1073 - if ( !in_array($previous_media_id, $media_ids) )
1170 + if ( ! in_array( $previous_media_id, $media_ids ) && current_user_can( 'delete_post', $previous_media_id ) )
1074 1171 {
1075 1172 if ( wp_delete_attachment( $previous_media_id, TRUE ) !== FALSE )
1076 1173 {
1077 1174
@@ -1211,5 +1308,4 @@
1211 1308 }
1212 1309 }
1213 1310
1214 1311 }
1215 -