PluginProbe
WPCasa – Real Estate for WordPress / trunk
WPCasa – Real Estate for WordPress vtrunk
1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.1.1 trunk 1.2.0 1.2.1 1.2.10 1.2.10.1 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.2.9.1 1.2.9.2 1.3.0 All 31 releases
wpcasa / includes / class-wpsight-post-types.php

class-wpsight-post-types.php in WPCasa – Real Estate for WordPress trunk, at includes/class-wpsight-post-types.php

1,049 lines 32.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * WPSight_Post_Type_Listing class
8 */
9 class WPSight_Post_Type_Listing {
10
11 /**
12 * Constructor
13 */
14 public function __construct() {
15
16 // Register listing post type
17 add_action( 'init', array( $this, 'register_post_type_listing' ), 0 );
18
19 // Register listing meta fields for the REST API when enabled.
20 add_action( 'init', array( $this, 'register_listing_rest_meta' ), 1 );
21
22 // Hide private listing meta from public REST responses.
23 add_filter( 'rest_prepare_' . wpsight_post_type(), array( $this, 'filter_listing_rest_response_meta' ), 10, 3 );
24
25 // Register custom post statuses
26 add_action( 'init', array( $this, 'register_post_statuses' ), 0 );
27
28 // Manage template for listing archive
29
30 add_action( 'loop_start', array( $this, 'template_listing_archive' ) );
31 add_action( 'loop_end', array( $this, 'template_listing_archive' ) );
32
33 // Manage template for single listing
34
35 add_action( 'loop_start', array( $this, 'template_listing_single' ) );
36 add_action( 'loop_end', array( $this, 'template_listing_single' ) );
37
38 // Optionally create location data from front end
39 // TODO: delete till wpcasa 1.5
40 // add_filter( 'wp', array( $this, 'listing_geolocation' ) );
41
42 // Optionally add default meta data to listing
43 add_action( 'wp_insert_post', array( $this, 'maybe_add_default_meta' ), 10, 2 );
44
45 // Delete old listing previews to clean up
46 add_action( 'wpsight_delete_listing_previews', array( $this, 'delete_listing_previews' ) );
47
48 // Optionally delete listing media files on permanent removal.
49 add_action( 'before_delete_post', array( 'WPSight_Listings', 'maybe_delete_listing_media' ), 10, 2 );
50
51 // Handle custom statuses in publish box
52
53 foreach ( array( 'post', 'post-new' ) as $hook )
54 add_action( "admin_footer-{$hook}.php", array( $this,'custom_statuses_submitdiv' ) );
55
56 // Handle single listing print view
57
58 add_filter( 'query_vars', array( $this, 'wpsight_print_query_vars' ) );
59 add_action( 'template_redirect', array( $this, 'wpsight_print_redirect' ) );
60
61 add_action( 'wpsight_head_print', array( $this, 'wpsight_head_print_css' ) );
62 add_filter( 'wpsight_head_print', array( $this, 'wpsight_head_print_robots' ) );
63
64 // Sanitize CPT
65
66 add_filter( 'wp_insert_post_data', array( $this, 'wpsight_sanitize_post_title' ), 10, 2 );
67
68 }
69
70 /**
71 * register_post_type_listing()
72 *
73 * This functions adds the custom post type listing
74 * and all the corresponding taxonomies.
75 *
76 * @access public
77 * @uses apply_filters()
78 * @uses register_taxonomy()
79 * @uses wpsight_post_type()
80 * @uses register_post_type()
81 *
82 * @since 1.0.0
83 */
84 public function register_post_type_listing() {
85
86 // Custom admin capability
87 $admin_capability = 'edit_listings';
88
89 // Option value show in REST API true/false
90 $show_in_rest = $this->is_rest_api_enabled();
91
92 // Set labels and localize them
93
94 $locations_name = apply_filters( 'wpsight_taxonomy_locations_name', __( 'Locations', 'wpcasa' ) );
95 $locations_singular = apply_filters( 'wpsight_taxonomy_locations_singular', __( 'Location', 'wpcasa' ) );
96
97 $locations_labels = array(
98 'name' => $locations_name,
99 'singular_name' => $locations_singular,
100 'menu_name' => _x( 'Locations', 'taxonomy locations', 'wpcasa' ),
101 'all_items' => _x( 'All Locations', 'taxonomy locations', 'wpcasa' ),
102 'edit_item' => _x( 'Edit Location', 'taxonomy locations', 'wpcasa' ),
103 'view_item' => _x( 'View Location', 'taxonomy locations', 'wpcasa' ),
104 'update_item' => _x( 'Update Location', 'taxonomy locations', 'wpcasa' ),
105 'add_new_item' => _x( 'Add New Location', 'taxonomy locations', 'wpcasa' ),
106 'new_item_name' => _x( 'New Location Name', 'taxonomy locations', 'wpcasa' ),
107 'parent_item' => _x( 'Parent Location', 'taxonomy locations', 'wpcasa' ),
108 'parent_item_colon' => _x( 'Parent Location:', 'taxonomy locations', 'wpcasa' ),
109 'search_items' => _x( 'Search locations', 'taxonomy locations', 'wpcasa' ),
110 'popular_items' => _x( 'Popular Locations', 'taxonomy locations', 'wpcasa' ),
111 'separate_items_with_commas' => _x( 'Separate locations with commas', 'taxonomy locations', 'wpcasa' ),
112 'add_or_remove_items' => _x( 'Add or remove locations', 'taxonomy locations', 'wpcasa' ),
113 'choose_from_most_used' => _x( 'Choose from the most used locations', 'taxonomy locations', 'wpcasa' ),
114 'not_found' => _x( 'No location found', 'taxonomy locations', 'wpcasa' )
115 );
116
117 // Set args and rewrite rules
118
119 $locations_args = array(
120 'labels' => $locations_labels,
121 'hierarchical' => true,
122 'capabilities' => array(
123 'manage_terms' => 'manage_listing_terms',
124 'edit_terms' => 'edit_listing_terms',
125 'delete_terms' => 'delete_listing_terms',
126 'assign_terms' => 'assign_listing_terms'
127 ),
128 'rewrite' => array(
129 'slug' => apply_filters( 'wpsight_rewrite_loctions_slug', 'location' ),
130 'with_front' => false,
131 'hierarchical' => true
132 ),
133 'show_in_rest' => $show_in_rest,
134 'rest_base' => 'wpsight-' . apply_filters( 'wpsight_rewrite_loctions_slug', 'location' ),
135 'rest_controller_class' => 'WP_REST_Terms_Controller'
136 );
137
138 $locations_args = apply_filters( 'wpsight_taxonomy_locations_args', $locations_args );
139
140 // Register taxonomy
141 register_taxonomy( 'location', array( wpsight_post_type() ), $locations_args );
142
143 // Set labels and localize them
144
145 $types_name = apply_filters( 'wpsight_taxonomy_types_name', __( 'Listing Types', 'wpcasa' ) );
146 $types_singular = apply_filters( 'wpsight_taxonomy_types_singular', __( 'Listing Type', 'wpcasa' ) );
147
148 $types_labels = array(
149 'name' => $types_name,
150 'singular_name' => $types_singular,
151 'menu_name' => _x( 'Listing Types', 'taxonomy types', 'wpcasa' ),
152 'all_items' => _x( 'All Listing Types', 'taxonomy types', 'wpcasa' ),
153 'edit_item' => _x( 'Edit Listing Type', 'taxonomy types', 'wpcasa' ),
154 'view_item' => _x( 'View Listing Type', 'taxonomy types', 'wpcasa' ),
155 'update_item' => _x( 'Update Listing Type', 'taxonomy types', 'wpcasa' ),
156 'add_new_item' => _x( 'Add New Listing Type', 'taxonomy types', 'wpcasa' ),
157 'new_item_name' => _x( 'New Listing Type Name', 'taxonomy types', 'wpcasa' ),
158 'parent_item' => _x( 'Parent Listing Type', 'taxonomy types', 'wpcasa' ),
159 'parent_item_colon' => _x( 'Parent Listing Type', 'taxonomy types', 'wpcasa' ).':',
160 'search_items' => _x( 'Search listing types', 'taxonomy types', 'wpcasa' ),
161 'popular_items' => _x( 'Popular Listing Types', 'taxonomy types', 'wpcasa' ),
162 'separate_items_with_commas' => _x( 'Separate listing types with commas', 'taxonomy types', 'wpcasa' ),
163 'add_or_remove_items' => _x( 'Add or remove listing types', 'taxonomy types', 'wpcasa' ),
164 'choose_from_most_used' => _x( 'Choose from the most used listing types', 'taxonomy types', 'wpcasa' ),
165 'not_found' => _x( 'No listing type found', 'taxonomy types', 'wpcasa' )
166 );
167
168 // Set args and rewrite rules
169
170 $types_args = array(
171 'labels' => $types_labels,
172 'hierarchical' => false,
173 'capabilities' => array(
174 'manage_terms' => 'manage_listing_terms',
175 'edit_terms' => 'edit_listing_terms',
176 'delete_terms' => 'delete_listing_terms',
177 'assign_terms' => 'assign_listing_terms'
178 ),
179 'rewrite' => array(
180 'slug' => apply_filters( 'wpsight_rewrite_types_slug', 'type' ),
181 'with_front' => false
182 ),
183 'show_in_rest' => $show_in_rest,
184 'rest_base' => 'wpsight-' . apply_filters( 'wpsight_rewrite_types_slug', 'type' ),
185 'rest_controller_class' => 'WP_REST_Terms_Controller'
186 );
187
188 $types_args = apply_filters( 'wpsight_taxonomy_types_args', $types_args );
189
190 // Register taxonomy
191 register_taxonomy( 'listing-type', array( wpsight_post_type() ), $types_args );
192
193 // Set labels and localize them
194
195 $features_name = apply_filters( 'wpsight_taxonomy_features_name', __( 'Features', 'wpcasa' ) );
196 $features_singular = apply_filters( 'wpsight_taxonomy_features_singular', __( 'Feature', 'wpcasa' ) );
197
198 $features_labels = array(
199 'name' => $features_name,
200 'singular_name' => $features_singular,
201 'menu_name' => _x( 'Features', 'taxonomy features', 'wpcasa' ),
202 'all_items' => _x( 'All Features', 'taxonomy features', 'wpcasa' ),
203 'edit_item' => _x( 'Edit Feature', 'taxonomy features', 'wpcasa' ),
204 'view_item' => _x( 'View Feature', 'taxonomy features', 'wpcasa' ),
205 'update_item' => _x( 'Update Feature', 'taxonomy features', 'wpcasa' ),
206 'add_new_item' => _x( 'Add New Feature', 'taxonomy features', 'wpcasa' ),
207 'new_item_name' => _x( 'New Feature Name', 'taxonomy features', 'wpcasa' ),
208 'parent_item' => _x( 'Parent Feature', 'taxonomy features', 'wpcasa' ),
209 'parent_item_colon' => _x( 'Parent Feature:', 'taxonomy features', 'wpcasa' ),
210 'search_items' => _x( 'Search features', 'taxonomy features', 'wpcasa' ),
211 'popular_items' => _x( 'Popular Features', 'taxonomy features', 'wpcasa' ),
212 'separate_items_with_commas' => _x( 'Separate features with commas', 'taxonomy features', 'wpcasa' ),
213 'add_or_remove_items' => _x( 'Add or remove features', 'taxonomy features', 'wpcasa' ),
214 'choose_from_most_used' => _x( 'Choose from the most used features', 'taxonomy features', 'wpcasa' ),
215 'not_found' => _x( 'No feature found', 'taxonomy features', 'wpcasa' )
216 );
217
218 // Set args and rewrite rules
219
220 $features_args = array(
221 'labels' => $features_labels,
222 'hierarchical' => false,
223 'capabilities' => array(
224 'manage_terms' => 'manage_listing_terms',
225 'edit_terms' => 'edit_listing_terms',
226 'delete_terms' => 'delete_listing_terms',
227 'assign_terms' => 'assign_listing_terms'
228 ),
229 'rewrite' => array(
230 'slug' => apply_filters( 'wpsight_rewrite_features_slug', 'feature' ),
231 'with_front' => false
232 ),
233 'show_in_rest' => $show_in_rest,
234 'rest_base' => 'wpsight-' . apply_filters( 'wpsight_rewrite_features_slug', 'feature' ),
235 'rest_controller_class' => 'WP_REST_Terms_Controller'
236 );
237
238 $features_args = apply_filters( 'wpsight_taxonomy_features_args', $features_args );
239
240 // Register taxonomy
241 register_taxonomy( 'feature', array( wpsight_post_type() ), $features_args );
242
243 // Set labels and localize them
244
245 $categories_name = apply_filters( 'wpsight_taxonomy_categories_name', __( 'Categories', 'wpcasa' ) );
246 $categories_singular = apply_filters( 'wpsight_taxonomy_categories_singular', __( 'Category', 'wpcasa' ) );
247
248 $categories_labels = array(
249 'name' => $categories_name,
250 'singular_name' => $categories_singular
251 );
252
253 // Set args and rewrite rules
254
255 $categories_args = array(
256 'labels' => $categories_labels,
257 'hierarchical' => true,
258 'capabilities' => array(
259 'manage_terms' => 'manage_listing_terms',
260 'edit_terms' => 'edit_listing_terms',
261 'delete_terms' => 'delete_listing_terms',
262 'assign_terms' => 'assign_listing_terms'
263 ),
264 'rewrite' => array(
265 'slug' => apply_filters( 'wpsight_rewrite_categories_slug', 'listing-category' ),
266 'with_front' => false,
267 'hierarchical' => true
268 ),
269 'show_in_rest' => $show_in_rest,
270 'rest_base' => 'wpsight-' . apply_filters( 'wpsight_rewrite_categories_slug', 'listing-category' ),
271 'rest_controller_class' => 'WP_REST_Terms_Controller'
272 );
273
274 $categories_args = apply_filters( 'wpsight_taxonomy_categories_args', $categories_args );
275
276 // Register taxonomy
277 register_taxonomy( 'listing-category', array( wpsight_post_type() ), $categories_args );
278
279 // Set post type labels
280
281 $labels = array(
282 'name' => _x( 'Listings', 'listing', 'wpcasa' ),
283 'singular_name' => _x( 'Listing', 'listing', 'wpcasa' ),
284 'add_new' => _x( 'Add New', 'listing', 'wpcasa' ),
285 'add_new_item' => _x( 'Add New Listing', 'listing', 'wpcasa' ),
286 'edit_item' => _x( 'Edit Listing', 'listing', 'wpcasa' ),
287 'new_item' => _x( 'New Listing', 'listing', 'wpcasa' ),
288 'view_item' => _x( 'View Listing', 'listing', 'wpcasa' ),
289 'search_items' => _x( 'Search Listings', 'listing', 'wpcasa' ),
290 'not_found' => _x( 'No listings found', 'listing', 'wpcasa' ),
291 'not_found_in_trash' => _x( 'No listings found in Trash', 'listing', 'wpcasa' ),
292 'menu_name' => _x( 'Listings', 'listing', 'wpcasa' ),
293 );
294
295 $labels = apply_filters( 'wpsight_post_type_labels_listing', $labels );
296
297 // Set post type arguments
298
299 $args = array(
300 'label' => _x( 'Listings', 'listing', 'wpcasa' ),
301 'description' => _x( 'Searchable listings with detailed information about the corresponding item.', 'listing', 'wpcasa' ),
302 'labels' => $labels,
303 'hierarchical' => false,
304 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'custom-fields', 'revisions', 'excerpt' ),
305 'public' => true,
306 'show_ui' => true,
307 'show_in_menu' => true,
308 'show_in_nav_menus' => true,
309 'menu_position' => 50,
310 'menu_icon' => 'dashicons-location',
311 'publicly_queryable' => true,
312 'exclude_from_search' => false,
313 'has_archive' => true,
314 'query_var' => true,
315 'can_export' => true,
316 'rewrite' => array( 'slug' => apply_filters( 'wpsight_rewrite_listings_slug', 'listing' ), 'with_front' => false ),
317 'capability_type' => array( 'listing', 'listings' ),
318 'map_meta_cap' => true,
319 'show_in_rest' => $show_in_rest,
320 'rest_base' => 'wpsight-' . apply_filters( 'wpsight_rewrite_listings_slug', 'listing' ) ,
321 'rest_controller_class' => 'WP_REST_Posts_Controller',
322 );
323
324 $args = apply_filters( 'wpsight_post_type_args_listing', $args );
325
326 // Register post type
327 register_post_type( 'listing', $args );
328
329 }
330
331 /**
332 * is_rest_api_enabled()
333 *
334 * Check if listings should be exposed in the REST API.
335 *
336 * @access protected
337 * @uses wpsight_get_option()
338 * @uses apply_filters()
339 * @return bool True when listing REST support is enabled.
340 *
341 * @since 1.5.4
342 */
343 protected function is_rest_api_enabled() : bool {
344 return (bool) apply_filters( 'wpsight_show_in_rest', wpsight_get_option( 'listings_rest_api' ) );
345 }
346
347 /**
348 * register_listing_rest_meta()
349 *
350 * Register WPCasa listing meta fields for the REST API.
351 *
352 * @access public
353 * @uses register_post_meta()
354 * @uses wpsight_post_type()
355 * @uses apply_filters()
356 *
357 * @since 1.5.4
358 */
359 public function register_listing_rest_meta() {
360 if ( ! $this->is_rest_api_enabled() ) {
361 return;
362 }
363
364 foreach ( $this->get_listing_rest_meta_fields() as $meta_key => $args ) {
365 register_post_meta(
366 wpsight_post_type(),
367 $meta_key,
368 wp_parse_args(
369 $args,
370 array(
371 'single' => true,
372 'auth_callback' => array( $this, 'listing_rest_meta_auth_callback' ),
373 'show_in_rest' => array(
374 'schema' => array(
375 'type' => 'string',
376 ),
377 ),
378 'sanitize_callback' => 'sanitize_text_field',
379 )
380 )
381 );
382 }
383 }
384
385 /**
386 * get_listing_rest_meta_fields()
387 *
388 * Return WPCasa listing meta fields exposed through the REST API.
389 *
390 * @access protected
391 * @uses wpsight_details()
392 * @uses apply_filters()
393 * @return array REST meta field definitions.
394 *
395 * @since 1.5.4
396 */
397 protected function get_listing_rest_meta_fields() : array {
398 $string_field = array(
399 'type' => 'string',
400 'single' => true,
401 'show_in_rest' => array(
402 'schema' => array(
403 'type' => 'string',
404 ),
405 ),
406 'sanitize_callback' => 'sanitize_text_field',
407 );
408
409 $textarea_field = array(
410 'type' => 'string',
411 'single' => true,
412 'show_in_rest' => array(
413 'schema' => array(
414 'type' => 'string',
415 ),
416 ),
417 'sanitize_callback' => 'sanitize_textarea_field',
418 );
419
420 $boolean_field = array(
421 'type' => 'boolean',
422 'single' => true,
423 'show_in_rest' => array(
424 'schema' => array(
425 'type' => 'boolean',
426 ),
427 ),
428 'sanitize_callback' => 'rest_sanitize_boolean',
429 );
430
431 $integer_field = array(
432 'type' => 'integer',
433 'single' => true,
434 'show_in_rest' => array(
435 'schema' => array(
436 'type' => 'integer',
437 ),
438 ),
439 'sanitize_callback' => 'absint',
440 );
441
442 $url_field = array(
443 'type' => 'string',
444 'single' => true,
445 'show_in_rest' => array(
446 'schema' => array(
447 'type' => 'string',
448 'format' => 'uri',
449 ),
450 ),
451 'sanitize_callback' => 'esc_url_raw',
452 );
453
454 $map_field = array(
455 'single' => true,
456 'type' => 'object',
457 'show_in_rest' => array(
458 'schema' => array(
459 'type' => 'object',
460 'properties' => array(
461 'lat' => array(
462 'type' => 'string',
463 ),
464 'long' => array(
465 'type' => 'string',
466 ),
467 ),
468 'additionalProperties' => array(
469 'type' => 'string',
470 ),
471 ),
472 ),
473 'sanitize_callback' => array( $this, 'sanitize_listing_rest_meta_map' ),
474 );
475
476 $gallery_field = array(
477 'single' => true,
478 'type' => 'object',
479 'show_in_rest' => array(
480 'schema' => array(
481 'type' => 'object',
482 'additionalProperties' => array(
483 'type' => 'string',
484 ),
485 ),
486 ),
487 'sanitize_callback' => array( $this, 'sanitize_listing_rest_meta_gallery' ),
488 );
489
490 $fields = array(
491 '_listing_id' => $string_field,
492 '_listing_not_available' => $boolean_field,
493 '_listing_sticky' => $boolean_field,
494 '_listing_featured' => $boolean_field,
495 '_gallery' => $gallery_field,
496 '_price' => array(
497 'type' => 'string',
498 'single' => true,
499 'show_in_rest' => array(
500 'schema' => array(
501 'type' => 'string',
502 ),
503 ),
504 'sanitize_callback' => array( 'WPSight_Meta_Boxes', 'sanitize_meta_box_listing_price' ),
505 ),
506 '_price_offer' => $string_field,
507 '_price_period' => $string_field,
508 '_map_address' => $string_field,
509 '_map_geolocation' => $map_field,
510 '_map_note' => $string_field,
511 '_map_secret' => $textarea_field,
512 '_map_hide' => $boolean_field,
513 '_map_type' => $string_field,
514 '_map_zoom' => $integer_field,
515 '_map_no_streetview' => $boolean_field,
516 '_geolocation_lat' => $string_field,
517 '_geolocation_long' => $string_field,
518 '_geolocation_elevation' => $string_field,
519 '_geolocation_city' => $string_field,
520 '_geolocation_country_long' => $string_field,
521 '_geolocation_country_short' => $string_field,
522 '_geolocation_formatted_address' => $string_field,
523 '_geolocation_state_long' => $string_field,
524 '_geolocation_state_short' => $string_field,
525 '_geolocation_street' => $string_field,
526 '_geolocation_zipcode' => $string_field,
527 '_geolocation_postcode' => $string_field,
528 '_agent_name' => $string_field,
529 '_agent_company' => $string_field,
530 '_agent_description' => $textarea_field,
531 '_agent_phone' => $string_field,
532 '_agent_website' => $url_field,
533 '_agent_twitter' => $string_field,
534 '_agent_facebook' => $string_field,
535 '_agent_logo' => $url_field,
536 '_agent_logo_id' => $integer_field,
537 );
538
539 foreach ( wpsight_details() as $detail ) {
540 if ( ! empty( $detail['id'] ) ) {
541 $fields[ '_' . $detail['id'] ] = $string_field;
542 }
543 }
544
545 return apply_filters( 'wpsight_listing_rest_meta_fields', $fields );
546 }
547
548 /**
549 * listing_rest_meta_auth_callback()
550 *
551 * Limit protected listing meta access to users who can edit the listing.
552 *
553 * @access public
554 *
555 * @param bool $allowed Whether access is allowed.
556 * @param string $meta_key Meta key being checked.
557 * @param int $object_id Object ID being checked.
558 * @param int $user_id User ID being checked.
559 *
560 * @return bool True when the user may access listing meta.
561 *
562 * @since 1.5.4
563 */
564 public function listing_rest_meta_auth_callback( bool $allowed, string $meta_key, int $object_id, int $user_id ) : bool {
565 if ( ! $this->is_rest_api_enabled() ) {
566 return false;
567 }
568
569 if ( ! empty( $object_id ) ) {
570 return user_can( $user_id, 'edit_post', $object_id );
571 }
572
573 return user_can( $user_id, 'edit_listings' );
574 }
575
576 /**
577 * filter_listing_rest_response_meta()
578 *
579 * Remove private WPCasa meta from REST responses for users who cannot edit the listing.
580 *
581 * @access public
582 *
583 * @param WP_REST_Response $response REST response object.
584 * @param WP_Post $post Listing post object.
585 * @param WP_REST_Request $request REST request object.
586 *
587 * @return WP_REST_Response Filtered REST response object.
588 *
589 * @since 1.5.4
590 */
591 public function filter_listing_rest_response_meta( WP_REST_Response $response, WP_Post $post, $request ) {
592 if ( ! $this->is_rest_api_enabled() || current_user_can( 'edit_post', $post->ID ) ) {
593 return $response;
594 }
595
596 $data = $response->get_data();
597
598 if ( empty( $data['meta'] ) || ! is_array( $data['meta'] ) ) {
599 return $response;
600 }
601
602 foreach ( array_keys( $this->get_listing_rest_meta_fields() ) as $meta_key ) {
603 unset( $data['meta'][ $meta_key ] );
604 }
605
606 $response->set_data( $data );
607
608 return $response;
609 }
610
611 /**
612 * sanitize_listing_rest_meta_map()
613 *
614 * Sanitize map coordinates from REST meta requests.
615 *
616 * @access public
617 * @param mixed $value Submitted meta value.
618 * @return array Sanitized map data.
619 *
620 * @since 1.5.4
621 */
622 public function sanitize_listing_rest_meta_map( $value ) : array {
623 $value = is_array( $value ) ? $value : array();
624 $map = array();
625
626 foreach ( $value as $key => $map_value ) {
627 if ( ! is_scalar( $map_value ) ) {
628 continue;
629 }
630
631 $map[ sanitize_key( $key ) ] = sanitize_text_field( $map_value );
632 }
633
634 return $map;
635 }
636
637 /**
638 * sanitize_listing_rest_meta_gallery()
639 *
640 * Sanitize gallery attachment IDs and URLs from REST meta requests.
641 *
642 * @access public
643 * @param mixed $value Submitted meta value.
644 * @return array Sanitized gallery data.
645 *
646 * @since 1.5.4
647 */
648 public function sanitize_listing_rest_meta_gallery( $value ) : array {
649 $value = is_array( $value ) ? $value : array();
650 $gallery = array();
651
652 foreach ( $value as $attachment_id => $url ) {
653 $attachment_id = absint( $attachment_id );
654
655 if ( ! $attachment_id || ! is_scalar( $url ) ) {
656 continue;
657 }
658
659 $gallery[ $attachment_id ] = esc_url_raw( $url );
660 }
661
662 return $gallery;
663 }
664
665 /**
666 * register_post_statuses()
667 *
668 * Register custom post statuses.
669 *
670 * @access public
671 * @uses wpsight_statuses()
672 * @uses register_post_status()
673 *
674 * @since 1.0.0
675 */
676 public function register_post_statuses() {
677 global $wp_post_statuses;
678
679 foreach( wpsight_statuses() as $status => $args ) {
680
681 if( ! in_array( $status, array_keys( $wp_post_statuses ) ) )
682 register_post_status( $status, $args );
683
684 }
685
686 }
687
688 /**
689 * template_listing_archive()
690 *
691 * Replace default output on listing archive
692 * pages (taxonomies, search or agents) with
693 * our templated output.
694 *
695 * @access public
696 *
697 * @param object $query WP_Query of the corresponding loop
698 *
699 * @uses $query->is_main_query()
700 * @uses wpsight_is_listings_archive()
701 * @uses current_filter()
702 * @uses wpsight_listings()
703 *
704 * @since 1.0.0
705 */
706 public function template_listing_archive( object $query ) {
707
708 // Make sure this is a main query
709
710 if ( ! $query->is_main_query() )
711 return;
712
713 // Only on listing archives
714
715 if( wpsight_is_listings_archive() ) {
716
717 // Remove original output
718
719 if ( 'loop_start' === current_filter() ) {
720 ob_start();
721 } else {
722 ob_end_clean();
723 }
724
725 // Create custom loop output
726
727 // Action before listing archive template is called
728 do_action( 'wpsight_template_listing_archive_before', $query );
729
730 // Get listings for this query
731 wpsight_listings( $query );
732
733 // Action after listing archive template is called
734 do_action( 'wpsight_template_listing_archive_after', $query );
735
736 }
737
738 }
739
740 /**
741 * template_listing_single()
742 *
743 * Replace default output on single listing
744 * pages with our templated output.
745 *
746 * @access public
747 *
748 * @param object $query WP_Query of the corresponding loop
749 *
750 * @uses $query->is_main_query()
751 * @uses wpsight_is_listing_archive()
752 * @uses current_filter()
753 * @uses wpsight_listing()
754 *
755 * @since 1.0.0
756 */
757 public function template_listing_single( object $query ) {
758
759 // Make sure this is a main query
760
761 if ( ! $query->is_main_query() )
762 return;
763
764 // If we have a single-listing.php template and widgets are active, display them
765
766 if( wpsight_locate_template( 'single-listing.php' ) && ( is_active_sidebar( 'listing' ) || is_active_sidebar( 'listing-top' ) || is_active_sidebar( 'listing-bottom' ) ) )
767 return;
768
769 // Only on single listing pages
770
771 if( is_singular( wpsight_post_type() ) ) {
772
773 // Remove original output
774
775 if ( 'loop_start' === current_filter() ) {
776 ob_start();
777 } else {
778 ob_end_clean();
779 }
780
781 // Create custom loop output
782
783 // Action before listing archive template is called
784 do_action( 'wpsight_template_listing_single_before', $query );
785
786 // Get single listing
787 wpsight_listing( $query->post->ID );
788
789 // Action after listing archive template is called
790 do_action( 'wpsight_template_listing_single_after', $query );
791
792 }
793
794 }
795
796 /**
797 * listing_geolocation()
798 *
799 * If a listing is called on the front end,
800 * check if we need to create geolocation data
801 * to ensure backwards compatibiliy with older
802 * WPCasa versions.
803 *
804 * @access public
805 * @uses wpsight_is_listing_single()
806 * @uses get_post_meta()
807 * @uses wpSight_Geocode::has_location_data()
808 * @uses wpSight_Geocode::generate_location_data()
809 *
810 * @since 1.0.0
811 */
812 //TODO: delete till wpcasa 1.5
813 // public function listing_geolocation() {
814 //
815 // if( ! wpsight_is_listing_single() || is_admin() )
816 // return;
817 //
818 // // Update map location information
819 // if ( ! wpSight_Geocode::has_location_data( get_the_id() ) && ( $location = get_post_meta( get_the_id(), '_map_address', true ) ) ) {
820 // wpSight_Geocode::generate_location_data( get_the_id(), $location );
821 // }
822 //
823 // }
824
825 /**
826 * maybe_add_default_meta()
827 *
828 * Optionally create default post meta data
829 * when a post is created or saved.
830 *
831 * @access public
832 *
833 * @param int $post_id Post ID of the corresponding entry
834 * @param object $post WP_Post object
835 *
836 * @uses wpsight_post_type()
837 * @uses add_post_meta()
838 *
839 * @since 1.0.0
840 */
841 public function maybe_add_default_meta( int $post_id, $post = '' ) {
842 if ( empty( $post ) || wpsight_post_type() == $post->post_type ) {
843 add_post_meta( $post_id, '_listing_not_available', 0, true );
844 add_post_meta( $post_id, '_listing_sticky', 0, true );
845 add_post_meta( $post_id, '_listing_featured', 0, true );
846 }
847 }
848
849 /**
850 * delete_listing_previews()
851 *
852 * Delete old listings with preview status when active.
853 *
854 * @access public
855 * @uses wpsight_delete_listing_previews()
856 * @see /functions/wpsight-listings.php
857 *
858 * @since 1.0.0
859 */
860 public function delete_listing_previews() {
861
862 // Delete old listing previews if desired
863 if ( apply_filters( 'wpsight_delete_listing_previews', true ) )
864 wpsight_delete_listing_previews();
865
866 }
867
868 /**
869 * custom_statuses_submitdiv()
870 *
871 * Add custom listing statuses to
872 * publish box on listing edit page.
873 *
874 * @access public
875 * @uses wpsight_post_type()
876 * @uses wpsight_statuses()
877 *
878 * @since 1.0.0
879 */
880 public function custom_statuses_submitdiv() {
881 global $post, $post_type;
882
883 // Only on listing edit pages
884
885 if ( wpsight_post_type() !== $post_type )
886 return;
887
888 // Get custom statuses
889 $statuses = wpsight_statuses();
890
891 // Get all non-builtin post status and add them as <option>
892
893 $options = $display = '';
894
895 foreach ( $statuses as $status => $args ) {
896
897 $selected = selected( $post->post_status, $status, false );
898 $name = $args['label'];
899
900 // If one of our custom post status is selected, remember it
901 $selected AND $display = $name;
902
903 // Build the options
904 $options .= "<option{$selected} value='{$status}'>{$name}</option>";
905
906 }
907 ?>
908 <script type="text/javascript">
909 jQuery( document ).ready( function($) { //#TEST
910
911 postStatus = $('#post_status');
912 status = '<?php echo esc_html( $post->post_status ); ?>';
913
914 save_expired = '<?php echo esc_html_x( 'Save as Expired', 'listing post status', 'wpcasa' ); ?>';
915 save_preview = '<?php echo esc_html_x( 'Save as Preview', 'listing post status', 'wpcasa' ); ?>';
916 save_pending = '<?php echo esc_html_x( 'Save as Pending', 'listing post status', 'wpcasa' ); ?>';
917
918 <?php if ( ! empty( $display ) ) : ?>
919 $( '#post-status-display' ).html( '<?php echo esc_html( $display ) ?>' );
920 <?php endif; ?>
921
922 if ( status == 'pending_payment' )
923 $('#save-post').show().val( save_pending );
924
925 if ( status == 'expired' )
926 $('#save-post').show().val( save_expired );
927
928 if ( status == 'preview' )
929 $('#save-post').show().val( save_preview );
930
931 var select = $( '#post-status-select' ).find( 'select' );
932 $( select ).html( "<?php echo wp_kses( $options, array( 'option' => array(
933 'selected' => array(),
934 'value' => array(),
935 'disabled' => array(),
936 'label' => array(),
937 ) ) ) ?>" );
938
939 $('#post-status-select').find('.save-post-status').click( function( event ) {
940
941 if( $('option:selected', postStatus).val() == 'pending_payment' )
942 $('#save-post').show().val( save_pending );
943
944 if ( $('option:selected', postStatus).val() == 'expired' )
945 $('#save-post').show().val( save_expired );
946
947 if( $('option:selected', postStatus).val() == 'preview' )
948 $('#save-post').show().val( save_preview );
949
950 });
951
952 } );
953 </script>
954 <?php
955 }
956
957 /**
958 * wpsight_print_query_vars()
959 *
960 * Add print to query vars.
961 *
962 * @return array
963 *
964 * @since 1.0.0
965 */
966 public function wpsight_print_query_vars( $vars ) {
967
968 $new_vars = array( 'print' );
969 $vars = array_merge( $new_vars, $vars );
970
971 return $vars;
972 }
973
974 /**
975 * wpsight_print_redirect()
976 *
977 * Redirect to print view template when
978 * query var 'print' is set.
979 *
980 * @uses wpsight_get_template()
981 *
982 * @since 1.0.0
983 */
984 function wpsight_print_redirect() {
985 global $wp, $wp_query;
986
987 if( isset( $wp->query_vars['print'] ) && absint( $wp->query_vars['print'] ) ) {
988 wpsight_get_template( 'listing-print.php' );
989 exit();
990 }
991
992 }
993
994 /**
995 * wpsight_head_print_css()
996 *
997 * Add print styles to print header
998 * using wpsight_head_print action hook.
999 *
1000 * @since 1.0.0
1001 */
1002 function wpsight_head_print_css() {
1003 wp_styles();
1004 wp_enqueue_style( 'wpsight-print', WPSIGHT_PLUGIN_URL . '/assets/css/wpsight-print.css', '', WPSIGHT_VERSION );
1005 wp_print_styles();
1006 }
1007
1008 /**
1009 * wpsight_head_print_robots()
1010 *
1011 * Disallow indexing of print pages
1012 * using robots:noindex.
1013 *
1014 * @since 1.0.0
1015 */
1016 function wpsight_head_print_robots() { ?>
1017 <meta name="robots" content="noindex" />
1018 <?php
1019 }
1020
1021 /**
1022 * wpsight_sanitize_post_title()
1023 *
1024 * This functions sanitizes the custom post type listing
1025 * title to prevent XSS and script in the title
1026 *
1027 * @access public
1028 * @uses wp_kses()
1029 *
1030 * @since 1.3.1
1031 */
1032 public function wpsight_sanitize_post_title( $data, $postarr ) {
1033
1034 if( 'listing' == $data['post_type'] ) {
1035
1036 if( ! empty( $data['post_title'] ) ) {
1037
1038 $data['post_title'] = wp_kses( $data['post_title'], 'post' );
1039
1040 }
1041
1042 }
1043
1044 return $data;
1045 }
1046
1047
1048 }
1049