PluginProbe
Property Hive / 2.2.6
Property Hive v2.2.6
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 1.4.62 All 260 releases
propertyhive / includes / admin / class-ph-admin-post-types.php

class-ph-admin-post-types.php in Property Hive 2.2.6, at includes/admin/class-ph-admin-post-types.php

1,936 lines 71.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Post Types Admin
4 *
5 * @author PropertyHive
6 * @category Admin
7 * @package PropertyHive/Admin
8 * @version 1.0.0
9 */
10
11 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
12
13 if ( ! class_exists( 'PH_Admin_Post_Types' ) ) :
14
15 /**
16 * PH_Admin_Post_Types Class
17 */
18 class PH_Admin_Post_Types {
19
20 /**
21 * Constructor
22 */
23 public function __construct() {
24 add_action( 'admin_init', array( $this, 'include_post_type_handlers' ) );
25 add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
26 add_action( 'pre_get_posts', array( $this, 'refresh_property_office_filtering' ));
27 add_action( 'admin_print_scripts', array( $this, 'remove_month_filter' ) );
28 add_action( 'admin_print_scripts', array( $this, 'disable_autosave' ) );
29
30 // Filters
31 add_action( 'restrict_manage_posts', array( $this, 'restrict_manage_posts' ) );
32 add_filter( 'request', array( $this, 'request_query' ) );
33 add_filter( 'posts_join', array( $this, 'posts_join' ), 10, 2 );
34 add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 );
35
36 // Status transitions
37 add_action( 'delete_post', array( $this, 'delete_post' ) );
38 add_action( 'wp_trash_post', array( $this, 'trash_post' ) );
39 add_action( 'untrash_post', array( $this, 'untrash_post' ) );
40
41 add_action( 'admin_init', array( $this, 'handle_archive_action' ) );
42 add_action( 'admin_init', array( $this, 'handle_unarchive_action' ) );
43
44 $post_types = array('property', 'contact', 'appraisal', 'viewing', 'offer', 'sale', 'tenancy', 'key_date');
45 $post_types = apply_filters( 'propertyhive_post_types_with_archive', $post_types );
46
47 foreach ( $post_types as $post_type )
48 {
49 add_filter( 'views_edit-' . $post_type, array( $this, 'adjust_post_status_views' ) );
50 add_filter( "bulk_actions-edit-$post_type", array( $this, 'register_bulk_action_move_to_archive' ) );
51 add_filter( "handle_bulk_actions-edit-$post_type", array( $this, 'handle_bulk_action_archive_and_unarchive' ), 10, 3 );
52 }
53
54 add_filter( 'post_row_actions', array( $this, 'modify_post_row_actions_for_archived' ), 10, 2 );
55 }
56
57 public function handle_bulk_action_archive_and_unarchive($redirect_to, $doaction, $post_ids)
58 {
59 if ($doaction === 'move_to_archive')
60 {
61 foreach ($post_ids as $post_id)
62 {
63 // Check permissions
64 if (!current_user_can('edit_post', $post_id)) {
65 continue;
66 }
67
68 // Update the post status to 'archive'
69 $updated_post = array(
70 'ID' => $post_id,
71 'post_status' => 'archive',
72 );
73
74 wp_update_post($updated_post);
75 }
76
77 $redirect_to = add_query_arg('bulk_archived_posts', count($post_ids), $redirect_to);
78 }
79 elseif ($doaction === 'unarchive')
80 {
81 foreach ($post_ids as $post_id)
82 {
83 // Check permissions
84 if (!current_user_can('edit_post', $post_id)) {
85 continue;
86 }
87
88 // Update the post status to 'publish' (or whatever the original status should be)
89 $updated_post = array(
90 'ID' => $post_id,
91 'post_status' => 'publish',
92 );
93
94 wp_update_post($updated_post);
95 }
96
97 $redirect_to = add_query_arg('bulk_unarchived_posts', count($post_ids), $redirect_to);
98 }
99
100 return $redirect_to;
101 }
102
103 public function register_bulk_action_move_to_archive( $bulk_actions )
104 {
105 global $post_status;
106
107 // Define our custom actions
108 $custom_actions = array();
109
110 if ($post_status === 'archive') {
111 $custom_actions['unarchive'] = __('Unarchive', 'propertyhive');
112 } else {
113 $custom_actions['move_to_archive'] = __('Move to Archive', 'propertyhive');
114 }
115
116 // Check if 'trash' exists and insert custom actions before it
117 if (isset($bulk_actions['trash']))
118 {
119 $new_actions = array();
120 foreach ($bulk_actions as $key => $value) {
121 if ($key === 'trash') {
122 $new_actions = array_merge($new_actions, $custom_actions);
123 }
124 $new_actions[$key] = $value;
125 }
126 return $new_actions;
127 }
128 elseif (isset($bulk_actions['untrash']))
129 {
130 $new_actions = array();
131 foreach ($bulk_actions as $key => $value) {
132 if ($key === 'untrash') {
133 $new_actions = array_merge($new_actions, $custom_actions);
134 }
135 $new_actions[$key] = $value;
136 }
137 return $new_actions;
138 }
139 else
140 {
141 // If 'trash' doesn't exist, append custom actions at the end
142 return array_merge($bulk_actions, $custom_actions);
143 }
144 }
145
146 public function modify_post_row_actions_for_archived( $actions, $post )
147 {
148 // Define the post types that can be archived
149 $post_types = array('property', 'contact', 'appraisal', 'viewing', 'offer', 'sale', 'tenancy', 'key_date');
150 $post_types = apply_filters('propertyhive_post_types_with_archive', $post_types);
151
152 // Check if the current post type is in the allowed post types and if the post is archived
153 if ( in_array($post->post_type, $post_types) && $post->post_status == 'archive' )
154 {
155 // Remove the "View" link
156 if (isset($actions['view'])) {
157 unset($actions['view']);
158 }
159
160 // Add the "Unarchive" link
161 $unarchive_url = wp_nonce_url(admin_url('post.php?post=' . $post->ID . '&action=unarchive&return=archive'), 'unarchive-post_' . $post->ID);
162 $actions['unarchive'] = '<a href="' . esc_url($unarchive_url) . '">' . __('Unarchive', 'propertyhive') . '</a>';
163 }
164
165 return $actions;
166 }
167
168 public function adjust_post_status_views( $views )
169 {
170 if (isset($views['archive']))
171 {
172 $archive = $views['archive'];
173 unset($views['archive']);
174
175 $new_views = array();
176 $bin_exists = false;
177
178 foreach ($views as $key => $view) {
179 if ($key === 'trash') {
180 $bin_exists = true;
181 $new_views['archive'] = $archive;
182 }
183 $new_views[$key] = $view;
184 }
185
186 // Ensure 'archive' is added to the end if 'trash' is not present
187 if (!$bin_exists) {
188 $new_views['archive'] = $archive;
189 }
190
191 return $new_views;
192 }
193
194 return $views;
195 }
196
197 public function handle_archive_action()
198 {
199 // Check if the action and nonce are set and valid
200 if ( !isset($_GET['action']) || $_GET['action'] !== 'archive_single' )
201 return;
202
203 $post_id = isset($_GET['post']) ? intval($_GET['post']) : 0;
204 $post_type = get_post_type($post_id);
205
206 if ( !wp_verify_nonce($_GET['_wpnonce'], 'archive-post_' . $post_id) )
207 {
208 wp_die(esc_html(__('Security check failed.', 'propertyhive')));
209 }
210
211 if ( !current_user_can('edit_post', $post_id) )
212 {
213 wp_die(esc_html(__('You do not have permission to edit this post.', 'propertyhive')));
214 }
215
216 // Update the post status to 'archive'
217 $updated_post = array(
218 'ID' => $post_id,
219 'post_status' => 'archive',
220 );
221
222 $result = wp_update_post($updated_post, true);
223
224 if ( is_wp_error($result) )
225 {
226 wp_die(esc_html(__('An error occurred while archiving the post.', 'propertyhive')));
227 }
228
229 // Redirect to the main list of contacts
230 wp_redirect(admin_url('edit.php?post_type=' . $post_type));
231 exit;
232 }
233
234 public function handle_unarchive_action()
235 {
236 // Check if the action and nonce are set and valid
237 if ( !isset($_GET['action']) || $_GET['action'] !== 'unarchive_single' )
238 return;
239
240 $post_id = isset($_GET['post']) ? intval($_GET['post']) : 0;
241 $post_type = get_post_type($post_id);
242
243 if ( !wp_verify_nonce($_GET['_wpnonce'], 'unarchive-post_' . $post_id) )
244 {
245 wp_die(esc_html(__('Security check failed.', 'propertyhive')));
246 }
247
248 if ( !current_user_can('edit_post', $post_id) )
249 {
250 wp_die(esc_html(__('You do not have permission to edit this post.', 'propertyhive')));
251 }
252
253 // Update the post status to 'publish'
254 $updated_post = array(
255 'ID' => $post_id,
256 'post_status' => 'publish',
257 );
258
259 $result = wp_update_post($updated_post, true);
260
261 if ( is_wp_error($result) )
262 {
263 wp_die(esc_html(__('An error occurred while unarchiving the post.', 'propertyhive')));
264 }
265
266 // Redirect to the main list of contacts
267 if ( isset($_GET['return']) && $_GET['return'] === 'archive' )
268 {
269 wp_redirect(admin_url('edit.php?post_status=archive&post_type=' . get_post_type($post_id)));
270 }
271 else
272 {
273 wp_redirect(admin_url('edit.php?post_type=' . get_post_type($post_id)));
274 }
275 exit;
276 }
277
278 /**
279 * Conditonally load classes and functions only needed when viewing a post type.
280 */
281 public function include_post_type_handlers() {
282 include( 'post-types/class-ph-admin-header-stripes.php' );
283 include( 'post-types/class-ph-admin-meta-boxes.php' );
284
285 include( 'post-types/class-ph-admin-cpt-property.php' );
286 include( 'post-types/class-ph-admin-cpt-contact.php' );
287 include( 'post-types/class-ph-admin-cpt-enquiry.php' );
288 include( 'post-types/class-ph-admin-cpt-office.php' );
289 include( 'post-types/class-ph-admin-cpt-appraisal.php' );
290 include( 'post-types/class-ph-admin-cpt-viewing.php' );
291 include( 'post-types/class-ph-admin-cpt-offer.php' );
292 include( 'post-types/class-ph-admin-cpt-sale.php' );
293 include( 'post-types/class-ph-admin-cpt-tenancy.php' );
294 include( 'post-types/class-ph-admin-cpt-key-date.php' );
295 }
296
297 /**
298 * Change messages when a post type is updated.
299 *
300 * @param array $messages
301 * @return array
302 */
303 public function post_updated_messages( $messages ) {
304 global $post, $post_ID;
305
306 $messages['property'] = array(
307 0 => '', // Unused. Messages start at index 1.
308 /* translators: %s: URL to view the property */
309 1 => sprintf( __( 'Property updated. <a href="%s">View property</a>', 'propertyhive' ), esc_url( get_permalink($post_ID) ) ),
310 2 => __( 'Custom field updated.', 'propertyhive' ),
311 3 => __( 'Custom field deleted.', 'propertyhive' ),
312 4 => __( 'Property updated.', 'propertyhive' ),
313 5 => __( 'Revision restored.', 'propertyhive' ),
314 /* translators: %s: URL to view the property */
315 6 => sprintf( __( 'Property published. <a href="%s">View property</a>', 'propertyhive' ), esc_url( get_permalink($post_ID) ) ),
316 7 => __( 'Property saved.', 'propertyhive' ),
317 /* translators: %s: URL to preview the property */
318 8 => sprintf( __( 'Property submitted. <a target="_blank" href="%s">Preview property</a>', 'propertyhive' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
319 /* translators: 1: formatted date, 2: URL to preview the property */
320 9 => sprintf( __( 'Property scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview property</a>', 'propertyhive' ),
321 date_i18n( __( 'M j, Y @ G:i', 'propertyhive' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
322 /* translators: %s: URL to preview the property */
323 10 => sprintf( __( 'Property draft updated. <a target="_blank" href="%s">Preview property</a>', 'propertyhive' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
324 );
325
326 $messages['contact'] = array(
327 0 => '', // Unused. Messages start at index 1.
328 1 => __( 'Contact updated.', 'propertyhive' ),
329 2 => __( 'Custom field updated.', 'propertyhive' ),
330 3 => __( 'Custom field deleted.', 'propertyhive' ),
331 4 => __( 'Contact updated.', 'propertyhive' ),
332 5 => __( 'Revision restored.', 'propertyhive' ),
333 6 => __( 'Contact published.', 'propertyhive' ),
334 7 => __( 'Contact saved.', 'propertyhive' ),
335 8 => __( 'Contact submitted.', 'propertyhive' ),
336 /* translators: 1: formatted date */
337 9 => sprintf( __( 'Contact scheduled for: <strong>%1$s</strong>.', 'propertyhive' ), date_i18n( __( 'M j, Y @ G:i', 'propertyhive' ), strtotime( $post->post_date ) )),
338 10 => __( 'Contact draft updated.', 'propertyhive' ),
339 );
340
341 $messages['office'] = array(
342 0 => '', // Unused. Messages start at index 1.
343 1 => __( 'Office updated.', 'propertyhive' ),
344 2 => __( 'Custom field updated.', 'propertyhive' ),
345 3 => __( 'Custom field deleted.', 'propertyhive' ),
346 4 => __( 'Office updated.', 'propertyhive' ),
347 5 => __( 'Revision restored.', 'propertyhive' ),
348 6 => sprintf( __( 'Office published.', 'propertyhive' ), esc_url( get_permalink($post_ID) ) ),
349 7 => __( 'Office saved.', 'propertyhive' ),
350 8 => sprintf( __( 'Office submitted.', 'propertyhive' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
351 /* translators: 1: formatted date */
352 9 => sprintf( __( 'Office scheduled for: <strong>%1$s</strong>.', 'propertyhive' ),
353 date_i18n( __( 'M j, Y @ G:i', 'propertyhive' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
354 10 => sprintf( __( 'Office draft updated. ', 'propertyhive' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
355 );
356
357 $messages['enquiry'] = array(
358 0 => '', // Unused. Messages start at index 1.
359 1 => sprintf( __( 'Enquiry updated.', 'propertyhive' ), esc_url( get_permalink($post_ID) ) ),
360 2 => __( 'Custom field updated.', 'propertyhive' ),
361 3 => __( 'Custom field deleted.', 'propertyhive' ),
362 4 => __( 'Enquiry updated.', 'propertyhive' ),
363 5 => __( 'Revision restored.', 'propertyhive' ),
364 6 => sprintf( __( 'Enquiry published.', 'propertyhive' ), esc_url( get_permalink($post_ID) ) ),
365 7 => __( 'Enquiry saved.', 'propertyhive' ),
366 8 => sprintf( __( 'Enquiry submitted.', 'propertyhive' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
367 /* translators: 1: formatted date */
368 9 => sprintf( __( 'Enquiry scheduled for: <strong>%1$s</strong>.', 'propertyhive' ),
369 date_i18n( __( 'M j, Y @ G:i', 'propertyhive' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
370 10 => sprintf( __( 'Enquiry draft updated.', 'propertyhive' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
371 );
372
373 return $messages;
374 }
375
376 /**
377 * Remove month filter from some property hive pages
378 */
379 public function remove_month_filter() {
380 global $typenow;
381
382 $post_types_to_hide_months_dropdown = array('property', 'contact', 'enquiry', 'appraisal', 'viewing', 'offer', 'sale', 'tenancy', 'key_date');
383 $post_types_to_hide_months_dropdown = apply_filters( 'propertyhive_post_types_to_hide_months_dropdown', $post_types_to_hide_months_dropdown );
384
385 if ( in_array($typenow, $post_types_to_hide_months_dropdown) )
386 {
387 add_filter('months_dropdown_results', '__return_empty_array');
388 }
389 }
390
391 /**
392 * Disable the auto-save functionality for certain CPT's.
393 *
394 * @access public
395 * @return void
396 */
397 public function disable_autosave(){
398 /*global $post;
399
400 if ( $post && get_post_type( $post->ID ) === 'enquiry' ) {
401 wp_dequeue_script( 'autosave' );
402 }*/
403 }
404
405 /**
406 * Filters for post types
407 */
408 public function restrict_manage_posts() {
409 global $typenow, $wp_query;
410
411 switch ( $typenow ) {
412 case 'property' :
413 $this->property_filters();
414 break;
415 case 'contact' :
416 $this->contact_filters();
417 break;
418 case 'enquiry' :
419 $this->enquiry_filters();
420 break;
421 case 'appraisal' :
422 $this->appraisal_filters();
423 break;
424 case 'viewing' :
425 $this->viewing_filters();
426 break;
427 case 'offer' :
428 $this->offer_filters();
429 break;
430 case 'sale' :
431 $this->sale_filters();
432 break;
433 case 'tenancy' :
434 $this->tenancy_filters();
435 break;
436 case 'key_date' :
437 $this->key_date_filters();
438 break;
439 default :
440 break;
441 }
442 }
443
444 /**
445 * Show a property filter box
446 */
447 public function property_filters() {
448 global $wp_query;
449
450 // Department filtering
451 $output = '';
452
453 $output .= $this->property_department_filter();
454 $output .= $this->property_marketing_filter();
455 $output .= $this->property_availability_filter();
456 $output .= $this->property_location_filter();
457 $output .= $this->property_office_filter();
458 $output .= $this->negotiator_filter();
459
460 echo apply_filters( 'propertyhive_property_filters', $output );
461 }
462
463 /**
464 * Show a property department filter box
465 */
466 public function property_department_filter() {
467 global $wp_query;
468
469 $departments = ph_get_departments();
470
471 $selected_department = isset( $_GET['_department'] ) && in_array( $_GET['_department'], array_keys($departments) ) ? $_GET['_department'] : '';
472
473 // Department filtering
474 $output = '<select name="_department" id="dropdown_property_department">';
475
476 $output .= '<option value="">' . __( 'All Departments', 'propertyhive' ) . '</option>';
477
478 foreach ( $departments as $key => $value )
479 {
480 if ( get_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key) ) == 'yes' )
481 {
482 $output .= '<option value="' . esc_attr($key) . '"';
483 $output .= selected( $key, $selected_department, false );
484 $output .= '>' . esc_html($value) . '</option>';
485 }
486 }
487
488 $output .= '</select>';
489
490 return $output;
491 }
492
493 /**
494 * Show a property office filter box
495 */
496 public function property_office_filter() {
497 global $wp_query, $post;
498
499 // Department filtering
500 $output = '<select name="_office_id" id="dropdown_property_office_id">';
501
502 $output .= '<option value="">' . __( 'All Offices', 'propertyhive' ) . '</option>';
503
504 $args = array(
505 'post_type' => 'office',
506 'nopaging' => true,
507 'orderby' => 'title',
508 'order' => 'ASC'
509 );
510 $office_query = new WP_Query($args);
511
512 if ($office_query->have_posts())
513 {
514 while ($office_query->have_posts())
515 {
516 $office_query->the_post();
517
518 $output .= '<option value="' . esc_attr($post->ID) . '"';
519 if ( isset( $_GET['_office_id'] ) && ! empty( $_GET['_office_id'] ) )
520 {
521 $output .= selected( $post->ID, (int)$_GET['_office_id'], false );
522 }
523 $output .= '>' . esc_html(get_the_title()) . '</option>';
524 }
525 }
526
527 wp_reset_postdata();
528
529 $output .= '</select>';
530
531 return $output;
532 }
533
534 /**
535 * Show a negotiator filter box
536 */
537 public function negotiator_filter() {
538
539 return wp_dropdown_users(array(
540 'name' => '_negotiator_id',
541 'id' => 'dropdown_property_negotiator_id',
542 'show_option_all' => __( 'All Negotiators', 'propertyhive' ),
543 'selected' => empty( $_GET['_negotiator_id'] ) ? '' : (int)$_GET['_negotiator_id'],
544 'echo' => false,
545 'role__not_in' => apply_filters( 'property_negotiator_exclude_roles', array('property_hive_contact', 'subscriber') )
546 ));
547 }
548
549 /**
550 * Show a date range selector
551 */
552 public function date_range_filter() {
553
554 $date_range_label = empty( $_GET['_date_range_label'] ) ? __( 'Any Time', 'propertyhive' ) : $_GET['_date_range_label'];
555
556 // The date picker doesn't have a concept of 'Any Time', so valid dates must be used
557 // I've used the last and first date of the month (reversed) as it's a range that is not selectable, but is within the current month
558 // If I used an already labelled date range (e.g. 'Today'), it would show as 'Today' when selected
559 // If I use a nearby date range (e.g. 'Yesterday'), if someone actually selected that range it would show as 'Any Time'
560 // If I use a unlikely date range (e.g. 01-01-1970 - 31-12-2070), the custom date range picker would open showing Jan 1970.
561 $date_range_from = empty( $_GET['_date_range_from'] ) ? date('Y-m-d', strtotime('last day of this month')) : $_GET['_date_range_from'];
562 $date_range_to = empty( $_GET['_date_range_to'] ) ? date('Y-m-d', strtotime('first day of this month')) : $_GET['_date_range_to'];
563
564 return "
565 <select name='_date_range_label' id='date_range' style='max-width:25rem;'>
566 <option selected>" . esc_html($date_range_label) . "</option>
567 <select/>
568 <input type='hidden' name='_date_range_from' id='date_range_from' value='" . esc_attr($date_range_from) . "'>
569 <input type='hidden' name='_date_range_to' id='date_range_to' value='" . esc_attr($date_range_to) . "'>
570 ";
571 }
572
573 /**
574 * Show a property location filter box
575 */
576 public function property_location_filter() {
577 global $wp_query, $post;
578
579 // Department filtering
580 $output = '<select name="_location_id" id="dropdown_property_location_id">';
581
582 $options = array( );
583 $args = array(
584 'hide_empty' => false,
585 'parent' => 0
586 );
587 $terms = get_terms( 'location', $args );
588
589 if ( !empty( $terms ) && !is_wp_error( $terms ) )
590 {
591 foreach ($terms as $term)
592 {
593 $options[$term->term_id] = $term->name;
594
595 $args = array(
596 'hide_empty' => false,
597 'parent' => $term->term_id
598 );
599 $subterms = get_terms( 'location', $args );
600
601 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
602 {
603 foreach ($subterms as $term)
604 {
605 $options[$term->term_id] = '- ' . $term->name;
606
607 $args = array(
608 'hide_empty' => false,
609 'parent' => $term->term_id
610 );
611 $subsubterms = get_terms( 'location', $args );
612
613 if ( !empty( $subsubterms ) && !is_wp_error( $subsubterms ) )
614 {
615 foreach ($subsubterms as $term)
616 {
617 $options[$term->term_id] = '- ' . $term->name;
618 }
619 }
620 }
621 }
622 }
623 }
624
625 $output .= '<option value="">' . esc_html(__( 'All Locations', 'propertyhive' )) . '</option>';
626
627 if ( !empty($options) )
628 {
629 foreach ( $options as $value => $label )
630 {
631 $output .= '<option value="' . esc_attr($value) . '"';
632 if ( isset( $_GET['_location_id'] ) && ! empty( $_GET['_location_id'] ) )
633 {
634 $output .= selected( $value, (int)$_GET['_location_id'], false );
635 }
636 $output .= '>' . esc_html($label) . '</option>';
637 }
638 }
639
640 $output .= '</select>';
641
642 return $output;
643 }
644
645 /**
646 * Show a property availability filter box
647 */
648 public function property_availability_filter() {
649 global $wp_query, $post;
650
651 // Availability filtering
652 $output = '<select name="_availability_id" id="dropdown_property_availability_id">';
653
654 $options = array( );
655 $args = array(
656 'hide_empty' => false,
657 'parent' => 0
658 );
659 $terms = get_terms( 'availability', $args );
660
661 if ( !empty( $terms ) && !is_wp_error( $terms ) )
662 {
663 foreach ($terms as $term)
664 {
665 $options[$term->term_id] = $term->name;
666 }
667 }
668
669 $output .= '<option value="">' . esc_html(__( 'All Availabilities', 'propertyhive' )) . '</option>';
670
671 if ( !empty($options) )
672 {
673 foreach ( $options as $value => $label )
674 {
675 $output .= '<option value="' . esc_attr($value) . '"';
676 if ( isset( $_GET['_availability_id'] ) && ! empty( $_GET['_availability_id'] ) )
677 {
678 $output .= selected( $value, (int)$_GET['_availability_id'], false );
679 }
680 $output .= '>' . esc_html($label) . '</option>';
681 }
682 }
683
684 $output .= '</select>';
685
686 return $output;
687 }
688
689 /**
690 * Show a property marketing filter box
691 */
692 public function property_marketing_filter() {
693 global $wp_query, $post;
694
695 // Availability filtering
696 $output = '<select name="_marketing" id="dropdown_property_marketing">';
697
698 $output .= '<option value="">' . __( 'All Marketing Statuses', 'propertyhive' ) . '</option>';
699
700 $options = array(
701 'on_market' => __( 'On Market Only', 'propertyhive' ),
702 'off_market' => __( 'Not On Market Only', 'propertyhive' ),
703 'featured' => __( 'Featured Only', 'propertyhive' ),
704 );
705
706 $args = array(
707 'hide_empty' => false,
708 'parent' => 0
709 );
710 $terms = get_terms( 'marketing_flag', $args );
711
712 if ( !empty( $terms ) && !is_wp_error( $terms ) )
713 {
714 foreach ($terms as $term)
715 {
716 $options['marketing_flag_' . $term->term_id] = __( 'Has Marketing Flag', 'propertyhive') . ' - ' . $term->name;
717 }
718 }
719
720 $options = apply_filters( 'propertyhive_property_filter_marketing_options', $options );
721
722 foreach ( $options as $key => $value )
723 {
724 $output .= '<option value="' . esc_attr($key) . '"';
725 if ( isset( $_GET['_marketing'] ) && ! empty( $_GET['_marketing'] ) )
726 {
727 $output .= selected( $key, sanitize_text_field($_GET['_marketing']), false );
728 }
729 $output .= '>' . esc_html($value) . '</option>';
730 }
731
732 $output .= '</select>';
733
734 return $output;
735 }
736
737 /**
738 * Show a contact filter box
739 */
740 public function contact_filters() {
741 global $wp_query;
742
743 $selected_contact_type = isset( $_GET['_contact_type'] ) && in_array( $_GET['_contact_type'], array( 'owner', 'potentialowner', 'applicant', 'hotapplicant', 'thirdparty' ) ) ? ph_clean($_GET['_contact_type']) : '';
744
745 // Type filtering
746 $options = array();
747
748 // Owners
749 $option = '<option value="owner"';
750 $option .= selected( 'owner', $selected_contact_type, false );
751 $option .= '>' . esc_html(__( 'Owners and Landlords', 'propertyhive' )) . '</option>';
752
753 $options[] = $option;
754
755 // Potential Owners
756 $option = '<option value="potentialowner"';
757 $option .= selected( 'potentialowner', $selected_contact_type, false );
758 $option .= '>' . esc_html(__( 'Potential Owners and Landlords', 'propertyhive' )) . '</option>';
759
760 $options[] = $option;
761
762 // Applicants
763 $option = '<option value="applicant"';
764 $option .= selected( 'applicant', $selected_contact_type, false );
765 $option .= '>' . esc_html(__( 'Applicants', 'propertyhive' )) . '</option>';
766
767 $options[] = $option;
768
769 // Hot Applicants
770 $option = '<option value="hotapplicant"';
771 $option .= selected( 'hotapplicant', $selected_contact_type, false );
772 $option .= '>- ' . esc_html(__( 'Hot Applicants', 'propertyhive' )) . '</option>';
773
774 $options[] = $option;
775
776 // Third Parties
777 $option = '<option value="thirdparty"';
778 $option .= selected( 'thirdparty', $selected_contact_type, false );
779 $option .= '>' . esc_html(__( 'Third Party Contacts', 'propertyhive' )) . '</option>';
780
781 $options[] = $option;
782
783 $options = apply_filters( 'propertyhive_contact_filter_options', $options );
784
785 $output = '';
786 if (count($options) > 1)
787 {
788 $output = '<select name="_contact_type" id="dropdown_contact_type">';
789
790 $output .= '<option value="">' . esc_html(__( 'Show all contact types', 'propertyhive' )) . '</option>';
791
792 $output .= implode("", $options);
793
794 $output .= '</select>';
795 }
796
797 $output .= $this->date_range_filter('Date Created');
798
799 echo apply_filters( 'propertyhive_contact_filters', $output );
800 }
801
802 /**
803 * Show an enquiry filter box
804 */
805 public function enquiry_filters() {
806 global $wp_query;
807
808 // Department filtering
809 $output = '';
810
811 $output .= $this->date_range_filter();
812 $output .= $this->enquiry_status_filter();
813 $output .= $this->enquiry_source_filter();
814 $output .= $this->enquiry_office_filter();
815 $output .= $this->enquiry_negotiator_filter();
816
817 echo apply_filters( 'propertyhive_enquiry_filters', $output );
818 }
819
820 /**
821 * Show an enquiry status filter box
822 */
823 public function enquiry_status_filter() {
824 global $wp_query;
825
826 $selected_status = isset( $_GET['_status'] ) && in_array( $_GET['_status'], array( 'all', 'open', 'closed' ) ) ? $_GET['_status'] : '';
827
828 // Status filtering
829 $output = '<select name="_status" id="dropdown_enquiry_status">
830 <option value="all"' . selected( 'all', $selected_status, false ) . '>All</option>';
831
832 $enquiry_statuses = ph_get_enquiry_statuses();
833
834 foreach ( $enquiry_statuses as $status => $display_status )
835 {
836 $output .= '<option value="' . esc_attr($status) . '"';
837 if ( $status == $selected_status || ( $status == 'open' && ( !isset($_GET['_status']) || empty($_GET['_status']) ) ) )
838 {
839 $output .= ' selected';
840 }
841 $output .= selected( $status, $selected_status, false );
842 $output .= '>' . esc_html($display_status) . '</option>';
843 }
844
845 $output .= '</select>';
846
847 return $output;
848 }
849
850 /**
851 * Show an enquiry source filter box
852 */
853 public function enquiry_source_filter() {
854 global $wp_query;
855
856 $sources = array(
857 'office' => __( 'Office', 'propertyhive' ),
858 'website' => __( 'Website', 'propertyhive' )
859 );
860
861 $sources = apply_filters( 'propertyhive_enquiry_sources', $sources );
862
863 asort($sources);
864
865 // Status filtering
866 $output = '<select name="_source" id="dropdown_enquiry_source">';
867
868 $output .= '<option value="">' . __( 'Show all sources', 'propertyhive' ) . '</option>';
869
870 foreach ( $sources as $key => $value )
871 {
872 $output .= '<option value="' . esc_attr($key) . '"';
873 if ( isset( $_GET['_source'] ) && ! empty( $_GET['_source'] ) )
874 {
875 $output .= selected( $key, sanitize_text_field($_GET['_source']), false );
876 }
877 $output .= '>' . esc_html(__( $value, 'propertyhive' )) . '</option>';
878 }
879
880 $output .= '</select>';
881
882 return $output;
883 }
884
885 /**
886 * Show an enquiry office filter box
887 */
888 public function enquiry_office_filter() {
889 global $wp_query, $post;
890
891 // Department filtering
892 $output = '<select name="_office_id" id="dropdown_enquiry_office_id">';
893
894 $output .= '<option value="">' . __( 'All Offices', 'propertyhive' ) . '</option>';
895
896 $args = array(
897 'post_type' => 'office',
898 'nopaging' => true,
899 'orderby' => 'title',
900 'order' => 'ASC'
901 );
902 $office_query = new WP_Query($args);
903
904 if ($office_query->have_posts())
905 {
906 while ($office_query->have_posts())
907 {
908 $office_query->the_post();
909
910 $output .= '<option value="' . esc_attr($post->ID) . '"';
911 if ( isset( $_GET['_office_id'] ) && ! empty( $_GET['_office_id'] ) )
912 {
913 $output .= selected( $post->ID, (int)$_GET['_office_id'], false );
914 }
915 $output .= '>' . esc_html(get_the_title()) . '</option>';
916 }
917 }
918
919 wp_reset_postdata();
920
921 $output .= '</select>';
922
923 return $output;
924 }
925
926 /**
927 * Show an enquiry negotiator filter box
928 */
929 public function enquiry_negotiator_filter() {
930 return wp_dropdown_users(array(
931 'name' => '_negotiator_id',
932 'id' => 'dropdown_enquiry_negotiator_id',
933 'show_option_all' => __( 'All Negotiators', 'propertyhive' ),
934 'selected' => empty( $_GET['_negotiator_id'] ) ? '' : (int)$_GET['_negotiator_id'],
935 'echo' => false,
936 'role__not_in' => apply_filters( 'property_negotiator_exclude_roles', array('property_hive_contact', 'subscriber') )
937 ));
938 }
939
940 /**
941 * Show am appraisal filter box
942 */
943 public function appraisal_filters() {
944 global $wp_query;
945
946 $output = '';
947
948 $output .= $this->appraisal_status_filter();
949 $output .= $this->negotiator_filter();
950 $output .= $this->date_range_filter();
951
952 echo apply_filters( 'propertyhive_appraisal_filters', $output );
953 }
954
955 /**
956 * Show an appraisal status filter box
957 */
958 public function appraisal_status_filter() {
959 global $wp_query;
960
961 $selected_status = isset( $_GET['_status'] ) && in_array( $_GET['_status'], array( 'pending', 'carried_out', 'won', 'lost', 'instructed', 'cancelled' ) ) ? ph_clean($_GET['_status']) : '';
962
963 // Status filtering
964 $output = '<select name="_status" id="dropdown_appraisal_status">';
965
966 $output .= '<option value="">' . __( 'All Statuses', 'propertyhive' ) . '</option>';
967
968 $output .= '<option value="pending"';
969 $output .= selected( 'pending', $selected_status, false );
970 $output .= '>' . esc_html(__( 'Pending', 'propertyhive' )) . '</option>';
971
972 $output .= '<option value="carried_out"';
973 $output .= selected( 'carried_out', $selected_status, false );
974 $output .= '>' . esc_html(__( 'Carried Out', 'propertyhive' )) . '</option>';
975
976 $output .= '<option value="won"';
977 $output .= selected( 'won', $selected_status, false );
978 $output .= '>- ' . esc_html(__( 'Won', 'propertyhive' )) . '</option>';
979
980 $output .= '<option value="lost"';
981 $output .= selected( 'lost', $selected_status, false );
982 $output .= '>- ' . esc_html(__( 'Lost', 'propertyhive' )) . '</option>';
983
984 $output .= '<option value="instructed"';
985 $output .= selected( 'instructed', $selected_status, false );
986 $output .= '>- ' . esc_html(__( 'Instructed', 'propertyhive' )) . '</option>';
987
988 $output .= '<option value="cancelled"';
989 $output .= selected( 'cancelled', $selected_status, false );
990 $output .= '>' . esc_html(__( 'Cancelled', 'propertyhive' )) . '</option>';
991
992 $output .= '</select>';
993
994 return $output;
995 }
996
997 /**
998 * Show a viewing filter box
999 */
1000 public function viewing_filters() {
1001 global $wp_query;
1002
1003 // Department filtering
1004 $output = '';
1005
1006 $output .= $this->viewing_status_filter();
1007 $output .= $this->property_office_filter();
1008 $output .= $this->negotiator_filter();
1009 $output .= $this->date_range_filter();
1010
1011 echo apply_filters( 'propertyhive_viewing_filters', $output );
1012 }
1013
1014 /**
1015 * Show a viewing status filter box
1016 */
1017 public function viewing_status_filter() {
1018 global $wp_query;
1019
1020 $selected_status = isset( $_GET['_status'] ) && in_array( $_GET['_status'], array( 'pending', 'confirmed', 'unconfirmed', 'carried_out', 'awaiting_feedback', 'feedback_passed_on', 'feedback_not_passed_on', 'cancelled', 'no_show' ) ) ? ph_clean($_GET['_status']) : '';
1021
1022 // Status filtering
1023 $output = '<select name="_status" id="dropdown_viewing_status">';
1024
1025 $output .= '<option value="">' . __( 'All Statuses', 'propertyhive' ) . '</option>';
1026
1027 $viewing_statuses = ph_get_viewing_statuses();
1028
1029 foreach ( $viewing_statuses as $status => $display_status )
1030 {
1031 $output .= '<option value="' . esc_attr($status) . '"';
1032 $output .= selected( $status, $selected_status, false );
1033 $output .= '>' . esc_html($display_status) . '</option>';
1034 }
1035
1036 $output .= '</select>';
1037
1038 return $output;
1039 }
1040
1041
1042 public function refresh_property_office_filtering( $query ) {
1043 remove_filter('posts_join', array( $this, 'filter_by_property_office') );
1044
1045 if ( ! empty( $_GET['_office_id'] ) && in_array( $query->query['post_type'], array(
1046 'viewing',
1047 'offer',
1048 'sale',
1049 ))) {
1050 add_filter('posts_join', array( $this, 'filter_by_property_office' ) );
1051 };
1052 }
1053
1054
1055 public function filter_by_property_office($query) {
1056 global $wpdb;
1057
1058 return $query . '
1059 INNER JOIN ' . $wpdb->postmeta . ' AS property_meta ON property_meta.post_id = ' . $wpdb->posts . '.ID AND property_meta.meta_key = "_property_id"
1060 INNER JOIN ' . $wpdb->postmeta . ' AS property_office_meta ON property_office_meta.post_id = property_meta.meta_value AND property_office_meta.meta_key = "_office_id"
1061 AND property_office_meta.meta_value = ' . (int)$_GET['_office_id'];
1062 }
1063
1064 /**
1065 * Show an offer filter box
1066 */
1067 public function offer_filters() {
1068 global $wp_query;
1069
1070 $output = '';
1071
1072 $output .= $this->offer_status_filter();
1073 $output .= $this->property_office_filter();
1074 $output .= $this->date_range_filter();
1075
1076 echo apply_filters( 'propertyhive_offer_filters', $output );
1077 }
1078
1079 /**
1080 * Show an offer status filter box
1081 */
1082 public function offer_status_filter() {
1083 global $wp_query;
1084
1085 $selected_status = isset( $_GET['_status'] ) && in_array( $_GET['_status'], array( 'pending', 'accepted', 'declined' ) ) ? ph_clean($_GET['_status']) : '';
1086
1087 // Status filtering
1088 $output = '<select name="_status" id="dropdown_offer_status">';
1089
1090 $output .= '<option value="">' . esc_html(__( 'All Statuses', 'propertyhive' )) . '</option>';
1091
1092 $offer_statuses = ph_get_offer_statuses();
1093
1094 foreach ( $offer_statuses as $status => $display_status )
1095 {
1096 $output .= '<option value="' . esc_attr($status) . '"';
1097 $output .= selected( $status, $selected_status, false );
1098 $output .= '>' . esc_html($display_status) . '</option>';
1099 }
1100
1101 $output .= '</select>';
1102
1103 return $output;
1104 }
1105
1106 /**
1107 * Show an sale filter box
1108 */
1109 public function sale_filters() {
1110 global $wp_query;
1111
1112 $output = '';
1113
1114 $output .= $this->sale_status_filter();
1115 $output .= $this->property_office_filter();
1116 $output .= $this->date_range_filter();
1117
1118 echo apply_filters( 'propertyhive_sale_filters', $output );
1119 }
1120
1121 /**
1122 * Show an sale status filter box
1123 */
1124 public function sale_status_filter() {
1125 global $wp_query;
1126
1127 $selected_status = isset( $_GET['_status'] ) && in_array( $_GET['_status'], array( 'current', 'exchanged', 'completed', 'fallen_through' ) ) ? ph_clean($_GET['_status']) : '';
1128
1129 // Status filtering
1130 $output = '<select name="_status" id="dropdown_sale_status">';
1131
1132 $output .= '<option value="">' . __( 'All Statuses', 'propertyhive' ) . '</option>';
1133
1134 $sale_statuses = ph_get_sale_statuses();
1135
1136 foreach ( $sale_statuses as $status => $display_status )
1137 {
1138 $output .= '<option value="' . esc_attr($status) . '"';
1139 $output .= selected( $status, $selected_status, false );
1140 $output .= '>' . esc_html($display_status) . '</option>';
1141 }
1142
1143 $output .= '</select>';
1144
1145 return $output;
1146 }
1147
1148 /**
1149 * Show an tenancy filter box
1150 */
1151 public function tenancy_filters() {
1152 global $wp_query;
1153
1154 $output = '';
1155
1156 $output .= $this->tenancy_status_filter();
1157 $output .= $this->tenancy_management_type_filter();
1158
1159 echo apply_filters( 'propertyhive_tenancy_filters', $output );
1160 }
1161
1162 /**
1163 * Show an tenancy status filter box
1164 */
1165 public function tenancy_status_filter() {
1166 global $wp_query;
1167
1168 $selected_status = isset( $_GET['_status'] ) && in_array( $_GET['_status'], array( 'pending', 'current', 'finished') ) ? ph_clean($_GET['_status']) : '';
1169
1170 // Status filtering
1171 $output = '<select name="_status" id="dropdown_tenancy_status">';
1172
1173 $output .= '<option value="">' . esc_html(__( 'All Statuses', 'propertyhive' )) . '</option>';
1174
1175 $output .= '<option value="pending"';
1176 $output .= selected( 'pending', $selected_status, false );
1177 $output .= '>' . esc_html(__( 'Pending', 'propertyhive' )) . '</option>';
1178
1179 $output .= '<option value="current"';
1180 $output .= selected( 'current', $selected_status, false );
1181 $output .= '> ' . esc_html(__( 'Current', 'propertyhive' )) . '</option>';
1182
1183 $output .= '<option value="finished"';
1184 $output .= selected( 'finished', $selected_status, false );
1185 $output .= '> ' . esc_html(__( 'Finished', 'propertyhive' )) . '</option>';
1186
1187 $output .= '</select>';
1188
1189 return $output;
1190 }
1191
1192 /**
1193 * Show an tenancy management type filter box
1194 */
1195 public function tenancy_management_type_filter() {
1196 global $wp_query;
1197
1198 $management_types = apply_filters( 'propertyhive_tenancy_management_types', array(
1199 'let_only' => 'Let Only',
1200 'fully_managed' => 'Fully Managed'
1201 ) );
1202
1203 $selected_management_type = isset( $_GET['_management_type'] ) && in_array( $_GET['_management_type'], array_keys($management_types) ) ? ph_clean($_GET['_management_type']) : '';
1204
1205 // Status filtering
1206 $output = '<select name="_management_type" id="dropdown_tenancy_management_type">';
1207
1208 $output .= '<option value="">' . esc_html(__( 'All Management Types', 'propertyhive' )) . '</option>';
1209
1210 foreach ( $management_types as $key => $value )
1211 {
1212 $output .= '<option value="' . esc_attr($key) . '"';
1213 $output .= selected( $key, $selected_management_type, false );
1214 $output .= '>' . esc_html(__( $value, 'propertyhive' )) . '</option>';
1215 }
1216
1217 $output .= '</select>';
1218
1219 return $output;
1220 }
1221
1222 public function key_date_filters() {
1223 global $wp_query;
1224
1225 $output = '';
1226
1227 $output .= $this->key_date_type_filter();
1228 $output .= $this->key_date_status_filter();
1229 $output .= $this->date_range_filter();
1230
1231 echo apply_filters( 'propertyhive_tenancy_filters', $output );
1232 }
1233
1234 public function key_date_type_filter() {
1235
1236 $selected_value = ! empty($_GET['_key_date_type_id']) ? (int)$_GET['_key_date_type_id'] : '';
1237 $terms = get_terms( 'management_key_date_type', array(
1238 'hide_empty' => false,
1239 'parent' => 0
1240 ) );
1241
1242 $output = '<select name="_key_date_type_id">';
1243 $output .= '<option value="">' . esc_html(__( 'All Types', 'propertyhive' )) . '</option>';
1244
1245 if ( !empty( $terms ) && !is_wp_error( $terms ) )
1246 {
1247 foreach ($terms as $term)
1248 {
1249 $output .= '<option value="' . esc_attr($term->term_id) . '"';
1250 $output .= selected($term->term_id, $selected_value, false );
1251 $output .= '>' . esc_html($term->name) . '</option>';
1252 }
1253 }
1254
1255 $output .= '</select>';
1256
1257 return $output;
1258 }
1259
1260
1261 public function key_date_status_filter() {
1262
1263 $selected_status = isset( $_GET['status'] ) && in_array( $_GET['status'], array( 'upcoming_and_overdue', 'overdue', 'booked', 'complete', 'pending', 'on_hold', 'cancelled') ) ? ph_clean($_GET['status']) : '';
1264
1265 $output = '<select name="status" id="dropdown_key_date_status">';
1266
1267 $output .= '<option value="">' . esc_html(__( 'All Statuses', 'propertyhive' )) . '</option>';
1268
1269 $output .= '<option value="upcoming_and_overdue"';
1270 $output .= selected( 'upcoming_and_overdue', $selected_status, false );
1271 $output .= '>' . esc_html(__( 'Upcoming & Overdue', 'propertyhive' )) . '</option>';
1272
1273 $output .= '<option value="overdue"';
1274 $output .= selected( 'overdue', $selected_status, false );
1275 $output .= '>' . esc_html(__( 'Overdue', 'propertyhive' )) . '</option>';
1276
1277 $output .= '<option value="booked"';
1278 $output .= selected( 'booked', $selected_status, false );
1279 $output .= '> ' . esc_html(__( 'Booked', 'propertyhive' )) . '</option>';
1280
1281 $output .= '<option value="complete"';
1282 $output .= selected( 'complete', $selected_status, false );
1283 $output .= '> ' . esc_html(__( 'Complete', 'propertyhive' )) . '</option>';
1284
1285 $output .= '<option value="pending"';
1286 $output .= selected( 'pending', $selected_status, false );
1287 $output .= '> ' . esc_html(__( 'Pending', 'propertyhive' )) . '</option>';
1288
1289 $output .= '<option value="on_hold"';
1290 $output .= selected( 'on_hold', $selected_status, false );
1291 $output .= '> ' . esc_html(__( 'On Hold', 'propertyhive' )) . '</option>';
1292
1293 $output .= '<option value="cancelled"';
1294 $output .= selected( 'cancelled', $selected_status, false );
1295 $output .= '> ' . esc_html(__( 'Cancelled', 'propertyhive' )) . '</option>';
1296
1297 $output .= '</select>';
1298
1299 return $output;
1300 }
1301
1302 /**
1303 * Filters and sorting handler
1304 * @param array $vars
1305 * @return array
1306 */
1307 public function request_query( $vars ) {
1308 global $typenow, $wp_query;
1309
1310 if ( !isset($vars['meta_query']) ) { $vars['meta_query'] = array(); }
1311 if ( !isset($vars['tax_query']) ) { $vars['tax_query'] = array(); }
1312
1313 if ( 'property' === $typenow )
1314 {
1315 if ( ! empty( $_GET['_department'] ) ) {
1316 $vars['meta_query'][] = array(
1317 'key' => '_department',
1318 'value' => sanitize_text_field( $_GET['_department'] ),
1319 );
1320 }
1321 if ( ! empty( $_GET['_office_id'] ) ) {
1322 $vars['meta_query'][] = array(
1323 'key' => '_office_id',
1324 'value' => (int)$_GET['_office_id'],
1325 );
1326 }
1327 if ( ! empty( $_GET['_negotiator_id'] ) ) {
1328 $vars['meta_query'][] = array(
1329 'key' => '_negotiator_id',
1330 'value' => (int)$_GET['_negotiator_id'],
1331 );
1332 }
1333 if ( ! empty( $_GET['_location_id'] ) ) {
1334 $vars['tax_query'][] = array(
1335 'taxonomy' => 'location',
1336 'terms' => ( (is_array($_GET['_location_id'])) ? (int)$_GET['_location_id'] : array( (int)$_GET['_location_id'] ) )
1337 );
1338 }
1339 if ( ! empty( $_GET['_availability_id'] ) ) {
1340 $vars['tax_query'][] = array(
1341 'taxonomy' => 'availability',
1342 'terms' => ( (is_array($_GET['_availability_id'])) ? (int)$_GET['_availability_id'] : array( (int)$_GET['_availability_id'] ) )
1343 );
1344 }
1345 if ( ! empty( $_GET['_marketing'] ) && $_GET['_marketing'] == 'on_market' ) {
1346 $vars['meta_query'][] = array(
1347 'key' => '_on_market',
1348 'value' => 'yes',
1349 );
1350 }
1351 if ( ! empty( $_GET['_marketing'] ) && $_GET['_marketing'] == 'off_market' ) {
1352 $vars['meta_query'][] = array(
1353 'key' => '_on_market',
1354 'value' => 'yes',
1355 'compare' => '!=',
1356 );
1357 }
1358 if ( ! empty( $_GET['_marketing'] ) && $_GET['_marketing'] == 'featured' ) {
1359 $vars['meta_query'][] = array(
1360 'key' => '_featured',
1361 'value' => 'yes',
1362 );
1363 }
1364 if ( ! empty( $_GET['_marketing'] ) && substr($_GET['_marketing'], 0, 15) == 'marketing_flag_' ) {
1365 $marketing_flag_id = sanitize_text_field( str_replace("marketing_flag_", "", $_GET['_marketing']) );
1366 $vars['tax_query'][] = array(
1367 'taxonomy' => 'marketing_flag',
1368 'terms' => ( (is_array($marketing_flag_id)) ? $marketing_flag_id : array( $marketing_flag_id ) )
1369 );
1370 }
1371 }
1372 elseif ( 'contact' === $typenow )
1373 {
1374 if ( ! empty( $_GET['_contact_type'] ) )
1375 {
1376 $contact_type = ph_clean($_GET['_contact_type']);
1377 if ( $contact_type == 'hotapplicant' )
1378 {
1379 $contact_type = 'applicant';
1380
1381 $vars['meta_query'][] = array(
1382 'key' => '_hot_applicant',
1383 'value' => 'yes',
1384 );
1385 }
1386 $vars['meta_query'][] = array(
1387 'key' => '_contact_types',
1388 'value' => $contact_type,
1389 'compare' => 'LIKE'
1390 );
1391 }
1392
1393 $vars = $this->filter_by_date_range($vars, 'date_query');
1394 }
1395 elseif ( 'enquiry' === $typenow )
1396 {
1397 if ( ! empty( $_GET['_status'] ) && ph_clean($_GET['_status']) != 'all' ) {
1398
1399 $vars['meta_query'][] = array(
1400 'key' => '_status',
1401 'value' => sanitize_text_field( $_GET['_status'] ),
1402 );
1403 }
1404 else
1405 {
1406 if ( empty( $_GET['_status'] ) )
1407 {
1408 $vars['meta_query'][] = array(
1409 'key' => '_status',
1410 'value' => 'open',
1411 );
1412 }
1413 }
1414 if ( ! empty( $_GET['_source'] ) ) {
1415 $vars['meta_query'][] = array(
1416 'key' => '_source',
1417 'value' => sanitize_text_field( $_GET['_source'] ),
1418 );
1419 }
1420 if ( ! empty( $_GET['_office_id'] ) ) {
1421 $vars['meta_query'][] = array(
1422 'key' => '_office_id',
1423 'value' => (int)$_GET['_office_id'],
1424 );
1425 }
1426 if ( ! empty( $_GET['_negotiator_id'] ) ) {
1427 $vars['meta_query'][] = array(
1428 'key' => '_negotiator_id',
1429 'value' => (int)$_GET['_negotiator_id'],
1430 );
1431 }
1432
1433 $vars = $this->filter_by_date_range($vars, 'date_query');
1434 }
1435 elseif ( 'appraisal' === $typenow )
1436 {
1437 if ( ! empty( $_GET['_status'] ) ) {
1438 switch ( sanitize_text_field( $_GET['_status'] ) )
1439 {
1440 case "confirmed":
1441 {
1442 $vars['meta_query'][] = array(
1443 'key' => '_status',
1444 'value' => 'pending',
1445 );
1446 $vars['meta_query'][] = array(
1447 'key' => '_all_confirmed',
1448 'value' => 'yes',
1449 );
1450 break;
1451 }
1452 case "unconfirmed":
1453 {
1454 $vars['meta_query'][] = array(
1455 'key' => '_status',
1456 'value' => 'pending',
1457 );
1458 $vars['meta_query'][] = array(
1459 'key' => '_all_confirmed',
1460 'value' => '',
1461 );
1462 break;
1463 }
1464 default:
1465 {
1466 $vars['meta_query'][] = array(
1467 'key' => '_status',
1468 'value' => sanitize_text_field( $_GET['_status'] ),
1469 );
1470 }
1471 }
1472 }
1473 if ( ! empty( $_GET['_negotiator_id'] ) )
1474 {
1475 $vars['meta_query'][] = array(
1476 'key' => '_negotiator_id',
1477 'value' => (int)$_GET['_negotiator_id'],
1478 );
1479 }
1480
1481 $vars = $this->filter_by_date_range($vars);
1482 }
1483 elseif ( 'viewing' === $typenow )
1484 {
1485 if ( ! empty( $_GET['_status'] ) ) {
1486
1487 $vars['meta_query'] = add_viewing_status_meta_query( $vars['meta_query'], sanitize_text_field( $_GET['_status'] ) );
1488
1489 }
1490 if ( ! empty( $_GET['_negotiator_id'] ) )
1491 {
1492 $vars['meta_query'][] = array(
1493 'key' => '_negotiator_id',
1494 'value' => (int)$_GET['_negotiator_id'],
1495 );
1496 }
1497
1498 $vars = $this->filter_by_date_range($vars);
1499 }
1500 elseif ( 'offer' === $typenow )
1501 {
1502 if ( ! empty( $_GET['_status'] ) ) {
1503 $vars['meta_query'][] = array(
1504 'key' => '_status',
1505 'value' => sanitize_text_field( $_GET['_status'] ),
1506 );
1507 }
1508
1509 $vars = $this->filter_by_date_range($vars, '_offer_date_time');
1510 }
1511 elseif ( 'sale' === $typenow )
1512 {
1513 if ( ! empty( $_GET['_status'] ) ) {
1514 $vars['meta_query'][] = array(
1515 'key' => '_status',
1516 'value' => sanitize_text_field( $_GET['_status'] ),
1517 );
1518 }
1519
1520 $vars = $this->filter_by_date_range($vars, '_sale_date_time');
1521 }
1522 elseif ( 'tenancy' === $typenow )
1523 {
1524 if ( ! empty( $_GET['_status'] ) )
1525 {
1526 switch ( $_GET['_status'] )
1527 {
1528 case 'pending' :
1529 $vars['meta_query'][] = array(
1530 'key' => '_start_date',
1531 'value' => date('Y-m-d'),
1532 'type' => 'date',
1533 'compare' => '>',
1534 );
1535 break;
1536
1537 case 'current' :
1538 $vars['meta_query'][] = array(
1539 'relation' => 'OR',
1540 array(
1541 array(
1542 'key' => '_start_date',
1543 'value' => date('Y-m-d'),
1544 'type' => 'date',
1545 'compare' => '<=',
1546 ),
1547 array(
1548 'key' => '_end_date',
1549 'value' => date('Y-m-d'),
1550 'type' => 'date',
1551 'compare' => '>=',
1552 )
1553 ),
1554 array(
1555 array(
1556 'key' => '_start_date',
1557 'value' => date('Y-m-d'),
1558 'type' => 'date',
1559 'compare' => '<=',
1560 ),
1561 array(
1562 'key' => '_end_date',
1563 'value' => '',
1564 'compare' => '=',
1565 )
1566 )
1567 );
1568 break;
1569
1570 case 'finished':
1571 $vars['meta_query'][] = array(
1572 'key' => '_end_date',
1573 'value' => date('Y-m-d'),
1574 'type' => 'date',
1575 'compare' => '<',
1576 );
1577 break;
1578 }
1579 }
1580
1581 if ( ! empty( $_GET['_management_type'] ) ) {
1582 $vars['meta_query'][] = array(
1583 'key' => '_management_type',
1584 'value' => sanitize_text_field( $_GET['_management_type'] ),
1585 );
1586 }
1587 }
1588 elseif ( 'key_date' === $typenow )
1589 {
1590 if ( ! empty( $_GET['status'] ) ) {
1591
1592 $value = sanitize_text_field( $_GET['status'] );
1593
1594 switch ($value) {
1595 case 'booked':
1596 case 'complete':
1597 case 'on_hold':
1598 case 'cancelled':
1599 $vars['meta_query'][] = array(
1600 'key' => '_key_date_status',
1601 'value' => $value,
1602 );
1603 break;
1604 case 'pending':
1605 $vars['meta_query'][] = array(
1606 'key' => '_key_date_status',
1607 'value' => 'pending',
1608 );
1609 break;
1610 case 'overdue':
1611 $vars['meta_query'][] = array(
1612 'key' => '_key_date_status',
1613 'value' => array('pending', 'booked'),
1614 'compare' => 'IN'
1615 );
1616 $vars['meta_query'][] = array(
1617 'key' => '_date_due',
1618 'value' => date("Y-m-d"),
1619 'type' => 'date',
1620 'compare' => '<',
1621 );
1622 break;
1623 case 'upcoming_and_overdue':
1624 $vars['meta_query'][] = array(
1625 'key' => '_key_date_status',
1626 'value' => array('pending', 'booked'),
1627 'compare' => 'IN'
1628 );
1629 $upcoming_threshold = new DateTime('+ ' . apply_filters( 'propertyhive_key_date_upcoming_days', 7 ) . ' DAYS');
1630 $vars['meta_query'][] = array(
1631 'key' => '_date_due',
1632 'value' => $upcoming_threshold->format('Y-m-d'),
1633 'type' => 'date',
1634 'compare' => '<=',
1635 );
1636 break;
1637 }
1638 }
1639
1640 if ( !empty( $_GET['_key_date_type_id'] ) )
1641 {
1642 $vars['meta_query'][] = array(
1643 'key' => '_key_date_type_id',
1644 'value' => (int)$_GET['_key_date_type_id'],
1645 );
1646 }
1647
1648 $vars = $this->filter_by_date_range($vars, '_date_due');
1649 }
1650
1651 $vars = apply_filters( 'propertyhive_property_filter_query', $vars, $typenow );
1652
1653 return $vars;
1654 }
1655
1656 private function filter_by_date_range($vars, $meta_key = '_start_date_time')
1657 {
1658 if (
1659 ! empty( $_GET['_date_range_label'] )
1660 && ! empty( $_GET['_date_range_from'] )
1661 && ! empty( $_GET['_date_range_to'] )
1662 && $_GET['_date_range_label'] !== 'Any Time'
1663 && DateTime::createFromFormat('Y-m-d', $_GET['_date_range_from']) !== false
1664 && DateTime::createFromFormat('Y-m-d', $_GET['_date_range_to']) !== false
1665 )
1666 {
1667 if ( $meta_key == 'date_query' )
1668 {
1669 $vars['date_query'] = array(
1670 'after' => $_GET['_date_range_from'] . ' 00:00:00',
1671 'before' => $_GET['_date_range_to'] . ' 23:59:59',
1672 );
1673 }
1674 else
1675 {
1676 $vars['meta_query'] = array_merge($vars['meta_query'], array (
1677 array(
1678 'key' => $meta_key,
1679 'value' => ph_clean($_GET['_date_range_from']),
1680 'type' => 'date',
1681 'compare' => '>='
1682 ),
1683 array(
1684 'key' => $meta_key,
1685 'value' => ph_clean($_GET['_date_range_to']),
1686 'type' => 'date',
1687 'compare' => '<='
1688 ),
1689 ));
1690 }
1691 }
1692
1693 return $vars;
1694 }
1695
1696 public function posts_join( $join, $q ) {
1697 global $typenow, $wp_query, $wpdb;
1698
1699 if ( !$q->is_main_query() )
1700 return $join;
1701
1702 if ( !isset($_GET['s']) || ( isset($_GET['s']) && ph_clean($_GET['s']) == '' ) )
1703 return $join;
1704
1705 if ( 'property' === $typenow )
1706 {
1707 $join .= "
1708 LEFT JOIN " . $wpdb->postmeta . " AS ph_property_filter_meta_address_concatenated ON " . $wpdb->posts . ".ID = ph_property_filter_meta_address_concatenated.post_id AND ph_property_filter_meta_address_concatenated.meta_key = '_address_concatenated'
1709 LEFT JOIN " . $wpdb->postmeta . " AS ph_property_filter_meta_reference_number ON " . $wpdb->posts . ".ID = ph_property_filter_meta_reference_number.post_id AND ph_property_filter_meta_reference_number.meta_key = '_reference_number'
1710 LEFT JOIN " . $wpdb->postmeta . " AS ph_property_filter_meta_owner_details ON " . $wpdb->posts . ".ID = ph_property_filter_meta_owner_details.post_id AND ph_property_filter_meta_owner_details.meta_key = '_owner_details'
1711 ";
1712 }
1713 elseif ( 'contact' === $typenow )
1714 {
1715 $phone_number = '';
1716 if ( is_numeric(substr(ph_clean($_GET['s']), 0, 1)) )
1717 {
1718 $phone_number = preg_replace( "/[^0-9,]/", "", ph_clean($_GET['s']) );
1719 }
1720
1721 $join .= "
1722 LEFT JOIN " . $wpdb->postmeta . " AS ph_contact_filter_meta_address_concatenated ON " . $wpdb->posts . ".ID = ph_contact_filter_meta_address_concatenated.post_id AND ph_contact_filter_meta_address_concatenated.meta_key = '_address_concatenated'
1723 LEFT JOIN " . $wpdb->postmeta . " AS ph_contact_filter_meta_email_address ON " . $wpdb->posts . ".ID = ph_contact_filter_meta_email_address.post_id AND ph_contact_filter_meta_email_address.meta_key = '_email_address' ";
1724
1725 if ( $phone_number != '' )
1726 {
1727 $join .= " LEFT JOIN " . $wpdb->postmeta . " AS ph_contact_filter_meta_telephone_number ON " . $wpdb->posts . ".ID = ph_contact_filter_meta_telephone_number.post_id AND ph_contact_filter_meta_telephone_number.meta_key = '_telephone_number_clean'
1728 ";
1729 }
1730 }
1731 elseif ( 'appraisal' === $typenow )
1732 {
1733 $join .= "
1734 LEFT JOIN " . $wpdb->postmeta . " AS ph_appraisal_filter_meta_name_number ON " . $wpdb->posts . ".ID = ph_appraisal_filter_meta_name_number.post_id AND ph_appraisal_filter_meta_name_number.meta_key = '_address_name_number'
1735 LEFT JOIN " . $wpdb->postmeta . " AS ph_appraisal_filter_meta_street ON " . $wpdb->posts . ".ID = ph_appraisal_filter_meta_street.post_id AND ph_appraisal_filter_meta_street.meta_key = '_address_street'
1736 LEFT JOIN " . $wpdb->postmeta . " AS ph_appraisal_filter_meta_2 ON " . $wpdb->posts . ".ID = ph_appraisal_filter_meta_2.post_id AND ph_appraisal_filter_meta_2.meta_key = '_address_two'
1737 LEFT JOIN " . $wpdb->postmeta . " AS ph_appraisal_filter_meta_3 ON " . $wpdb->posts . ".ID = ph_appraisal_filter_meta_3.post_id AND ph_appraisal_filter_meta_3.meta_key = '_address_three'
1738 LEFT JOIN " . $wpdb->postmeta . " AS ph_appraisal_filter_meta_4 ON " . $wpdb->posts . ".ID = ph_appraisal_filter_meta_4.post_id AND ph_appraisal_filter_meta_4.meta_key = '_address_four'
1739 LEFT JOIN " . $wpdb->postmeta . " AS ph_appraisal_filter_meta_postcode ON " . $wpdb->posts . ".ID = ph_appraisal_filter_meta_postcode.post_id AND ph_appraisal_filter_meta_postcode.meta_key = '_address_postcode'
1740 ";
1741 }
1742 elseif ( 'viewing' === $typenow || 'offer' === $typenow || 'sale' === $typenow || 'tenancy' === $typenow )
1743 {
1744 $join .= "
1745 LEFT JOIN " . $wpdb->postmeta . " AS ph_property_filter_meta ON " . $wpdb->posts . ".ID = ph_property_filter_meta.post_id AND ph_property_filter_meta.meta_key = '_property_id'
1746 LEFT JOIN " . $wpdb->posts . " AS ph_property_filter_posts ON ph_property_filter_posts.ID = ph_property_filter_meta.meta_value
1747 LEFT JOIN " . $wpdb->postmeta . " AS ph_property_filter_meta_address_concatenated ON ph_property_filter_posts.ID = ph_property_filter_meta_address_concatenated.post_id AND ph_property_filter_meta_address_concatenated.meta_key = '_address_concatenated'
1748 LEFT JOIN " . $wpdb->postmeta . " AS ph_property_filter_meta_reference_number ON ph_property_filter_posts.ID = ph_property_filter_meta_reference_number.post_id AND ph_property_filter_meta_reference_number.meta_key = '_reference_number'
1749 LEFT JOIN " . $wpdb->postmeta . " AS ph_applicant_filter_meta ON " . $wpdb->posts . ".ID = ph_applicant_filter_meta.post_id AND ph_applicant_filter_meta.meta_key = '_applicant_contact_id'
1750 LEFT JOIN " . $wpdb->posts . " AS ph_applicant_filter_posts ON ph_applicant_filter_posts.ID = ph_applicant_filter_meta.meta_value
1751 ";
1752 }
1753
1754 return $join;
1755 }
1756
1757 public function posts_where( $where, $q ) {
1758 global $typenow, $wp_query, $wpdb;
1759
1760 if ( !$q->is_main_query() )
1761 return $where;
1762
1763 if ( !isset($_GET['s']) || ( isset($_GET['s']) && ph_clean($_GET['s']) == '' ) )
1764 return $where;
1765
1766 if ( 'property' === $typenow )
1767 {
1768 $where = preg_replace(
1769 "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
1770 "(
1771 (" . $wpdb->posts . ".post_title LIKE $1)
1772 OR
1773 (ph_property_filter_meta_address_concatenated.meta_value LIKE $1)
1774 OR
1775 (ph_property_filter_meta_reference_number.meta_value LIKE '" . esc_sql($_GET['s']) . "%')
1776 OR
1777 (ph_property_filter_meta_owner_details.meta_value LIKE $1)
1778 )",
1779 $where
1780 );
1781
1782 $where = preg_replace(
1783 "/\s+OR\s+\(\s*" . $wpdb->posts . ".post_excerpt\s+LIKE\s*(\'[^\']+\')\s*\)/",
1784 "",
1785 $where
1786 );
1787
1788 $where = preg_replace(
1789 "/\s+OR\s+\(\s*" . $wpdb->posts . ".post_content\s+LIKE\s*(\'[^\']+\')\s*\)/",
1790 "",
1791 $where
1792 );
1793 }
1794 elseif ( 'contact' === $typenow )
1795 {
1796 $phone_number = '';
1797 if ( is_numeric(substr(ph_clean($_GET['s']), 0, 1)) )
1798 {
1799 $phone_number = preg_replace( "/[^0-9,]/", "", ph_clean($_GET['s']) );
1800 }
1801
1802 $where = preg_replace(
1803 "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
1804 "(
1805 (" . $wpdb->posts . ".post_title LIKE $1)
1806 OR
1807 (ph_contact_filter_meta_address_concatenated.meta_value LIKE $1)
1808 OR
1809 (ph_contact_filter_meta_email_address.meta_value LIKE $1)
1810 " . ( $phone_number != '' ? "OR (ph_contact_filter_meta_telephone_number.meta_value LIKE '%" . $phone_number . "%')" : '' ) . "
1811 )",
1812 $where
1813 );
1814
1815 $where = preg_replace(
1816 "/\s+OR\s+\(\s*" . $wpdb->posts . ".post_excerpt\s+LIKE\s*(\'[^\']+\')\s*\)/",
1817 "",
1818 $where
1819 );
1820
1821 $where = preg_replace(
1822 "/\s+OR\s+\(\s*" . $wpdb->posts . ".post_content\s+LIKE\s*(\'[^\']+\')\s*\)/",
1823 "",
1824 $where
1825 );
1826 }
1827 elseif ( 'appraisal' === $typenow )
1828 {
1829 $where = preg_replace(
1830 "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
1831 "(
1832 (" . $wpdb->posts . ".post_title LIKE $1)
1833 OR
1834 (ph_appraisal_filter_meta_name_number.meta_value LIKE $1)
1835 OR
1836 (ph_appraisal_filter_meta_street.meta_value LIKE $1)
1837 OR
1838 (ph_appraisal_filter_meta_2.meta_value LIKE $1)
1839 OR
1840 (ph_appraisal_filter_meta_3.meta_value LIKE $1)
1841 OR
1842 (ph_appraisal_filter_meta_4.meta_value LIKE $1)
1843 OR
1844 (ph_appraisal_filter_meta_postcode.meta_value LIKE $1)
1845 )",
1846 $where
1847 );
1848 }
1849 elseif ( 'viewing' === $typenow || 'offer' === $typenow || 'sale' === $typenow || 'tenancy' === $typenow )
1850 {
1851 $where = preg_replace(
1852 "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
1853 "(
1854 (" . $wpdb->posts . ".post_title LIKE $1)
1855 OR
1856 (ph_property_filter_posts.post_title LIKE $1)
1857 OR
1858 (ph_property_filter_meta_address_concatenated.meta_value LIKE $1)
1859 OR
1860 (ph_property_filter_meta_reference_number.meta_value = '" . esc_sql($_GET['s']) . "')
1861 OR
1862 (ph_applicant_filter_posts.post_title LIKE $1)
1863 )",
1864 $where
1865 );
1866 }
1867
1868 return $where;
1869 }
1870
1871 /**
1872 * Removes variations etc belonging to a deleted post, and clears transients
1873 *
1874 * @access public
1875 * @param mixed $id ID of post being deleted
1876 * @return void
1877 */
1878 public function delete_post( $id ) {
1879 /*global $propertyhive, $wpdb;
1880
1881 if ( ! current_user_can( 'delete_posts' ) )
1882 return;
1883
1884 if ( $id > 0 ) {
1885
1886 $post_type = get_post_type( $id );
1887
1888 switch( $post_type ) {
1889 case 'property' :
1890 ph_delete_property_transients();
1891 break;
1892 case 'contact' :
1893 ph_delete_contact_transients();
1894 break;
1895 case 'enquiry' :
1896 ph_delete_enquiry_transients();
1897 break;
1898 }
1899 }*/
1900 }
1901
1902 /**
1903 * propertyhive_trash_post function.
1904 *
1905 * @access public
1906 * @param mixed $id
1907 * @return void
1908 */
1909 public function trash_post( $id ) {
1910 /*if ( $id > 0 ) {
1911
1912 $post_type = get_post_type( $id );
1913
1914
1915 }*/
1916 }
1917
1918 /**
1919 * propertyhive_untrash_post function.
1920 *
1921 * @access public
1922 * @param mixed $id
1923 * @return void
1924 */
1925 public function untrash_post( $id ) {
1926 /*if ( $id > 0 ) {
1927
1928 $post_type = get_post_type( $id );
1929
1930 }*/
1931 }
1932 }
1933
1934 endif;
1935
1936 return new PH_Admin_Post_Types();