PluginProbe
Property Hive / 2.3.1
Property Hive v2.3.1
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
← All changes | includes/class-ph-post-types.php +81 -12 2.2.22.3.1 View file →
@@ -13,14 +13,52 @@
13 13 * @package PropertyHive/Classes
14 14 * @category Class
15 15 * @author PropertyHive
16 16 */
17 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Legacy public PH_Post_types class; preserve its existing name for plugin and extension compatibility.
17 18 class PH_Post_types {
18 19
20 +
21 + /**
22 + * Keep native CRM screens separate from ordinary WordPress post access.
23 + * Existing post permissions remain required, alongside Property Hive access.
24 + *
25 + * @return array Dedicated primitive capabilities.
26 + */
27 + public static function record_capabilities() {
28 + $capabilities = array();
29 + foreach ( array( 'edit_posts', 'create_posts', 'edit_others_posts', 'edit_private_posts', 'edit_published_posts', 'publish_posts', 'delete_posts', 'delete_others_posts', 'delete_private_posts', 'delete_published_posts', 'read_private_posts' ) as $capability ) {
30 + $capabilities[$capability] = 'propertyhive_' . $capability;
31 + }
32 + return $capabilities;
33 + }
34 +
35 + /**
36 + * Resolve both direct checks and capabilities produced by core's post mapper.
37 + * This preserves custom roles' existing edit/publish/delete restrictions.
38 + *
39 + * @param array $caps Required primitive capabilities.
40 + * @return array Required capabilities.
41 + */
42 + public static function map_record_capabilities( $caps ) {
43 + $mapped = array();
44 + $record_caps = array_flip( self::record_capabilities() );
45 + foreach ( $caps as $capability ) {
46 + if ( isset( $record_caps[$capability] ) ) {
47 + $mapped[] = 'manage_propertyhive';
48 + $mapped[] = 'create_posts' === $record_caps[$capability] ? 'edit_posts' : $record_caps[$capability];
49 + } else {
50 + $mapped[] = $capability;
51 + }
52 + }
53 + return array_values( array_unique( $mapped ) );
54 + }
55 +
19 56 /**
20 57 * Constructor
21 58 */
22 59 public function __construct() {
60 + add_filter( 'map_meta_cap', array( __CLASS__, 'map_record_capabilities' ) );
23 61 add_action( 'init', array( __CLASS__, 'register_taxonomies' ), 5 );
24 62 add_action( 'init', array( __CLASS__, 'register_post_types' ), 5 );
25 63 add_action( 'init', array( __CLASS__, 'register_post_statuses' ), 5 );
26 64
@@ -59,16 +97,24 @@
59 97 }
60 98
61 99 public static function register_post_statuses()
62 100 {
63 - register_post_status('archive', array(
64 - 'label' => _x('Archived', 'post', 'propertyhive'),
65 - 'public' => false,
66 - 'exclude_from_search' => true,
67 - 'show_in_admin_all_list' => false,
68 - 'show_in_admin_status_list' => true,
69 - 'label_count' => _n_noop('Archived <span class="count">(%s)</span>', 'Archived <span class="count">(%s)</span>', 'propertyhive'),
70 - ));
101 + register_post_status(
102 + 'archive',
103 + array(
104 + 'label' => _x('Archived', 'post status label', 'propertyhive'),
105 + 'public' => false,
106 + 'exclude_from_search' => true,
107 + 'show_in_admin_all_list' => false,
108 + 'show_in_admin_status_list' => true,
109 + /* translators: %s: Number of archived posts. */
110 + 'label_count' => _n_noop(
111 + 'Archived <span class="count">(%s)</span>',
112 + 'Archived <span class="count">(%s)</span>',
113 + 'propertyhive'
114 + ),
115 + )
116 + );
71 117 }
72 118
73 119 public static function update_property_indexed_owner_names( $post_id, $post, $update )
74 120 {
@@ -128,8 +174,9 @@
128 174 {
129 175 // Find all properties linked to this contact
130 176 $args = array(
131 177 'post_type' => 'property',
178 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Owner search metadata must be refreshed on properties linked through the existing serialized owner IDs; retain the relationship match.
132 179 'meta_query' => array(
133 180 array(
134 181 'key' => '_owner_contact_id',
135 182 'value' => '"' . $post_id . '"',
@@ -509,8 +556,9 @@
509 556 )
510 557 )
511 558 );
512 559
560 + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Existing public Property Hive extension hook do_action_after_register_taxonomies; changing the established name would detach installed callbacks.
513 561 do_action( 'do_action_after_register_taxonomies' );
514 562 }
515 563
516 564 /**
@@ -548,8 +596,9 @@
548 596 'description' => __( 'This is where you can add new properties to your site.', 'propertyhive' ),
549 597 'public' => true,
550 598 'show_ui' => true,
551 599 'capability_type' => 'post',
600 + 'capabilities' => self::record_capabilities(),
552 601 'map_meta_cap' => true,
553 602 'publicly_queryable' => true,
554 603 'exclude_from_search' => false,
555 604 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -587,8 +636,9 @@
587 636 'description' => __( 'This is where you can add new contacts to your site.', 'propertyhive' ),
588 637 'public' => false,
589 638 'show_ui' => true,
590 639 'capability_type' => 'post',
640 + 'capabilities' => self::record_capabilities(),
591 641 'map_meta_cap' => true,
592 642 'publicly_queryable' => false,
593 643 'exclude_from_search' => true,
594 644 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -621,8 +671,9 @@
621 671 ),
622 672 'public' => true,
623 673 'show_ui' => false,
624 674 'capability_type' => 'post',
675 + 'capabilities' => self::record_capabilities(),
625 676 'map_meta_cap' => true,
626 677 'publicly_queryable' => false,
627 678 'exclude_from_search' => true,
628 679 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -656,8 +707,9 @@
656 707 ),
657 708 'public' => false,
658 709 'show_ui' => true,
659 710 'capability_type' => 'post',
711 + 'capabilities' => self::record_capabilities(),
660 712 'map_meta_cap' => true,
661 713 'publicly_queryable' => false,
662 714 'exclude_from_search' => true,
663 715 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -691,8 +743,9 @@
691 743 ),
692 744 'public' => false,
693 745 'show_ui' => true,
694 746 'capability_type' => 'post',
747 + 'capabilities' => self::record_capabilities(),
695 748 'map_meta_cap' => true,
696 749 'publicly_queryable' => false,
697 750 'exclude_from_search' => true,
698 751 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -725,8 +778,9 @@
725 778 ),
726 779 'public' => false,
727 780 'show_ui' => true,
728 781 'capability_type' => 'post',
782 + 'capabilities' => self::record_capabilities(),
729 783 'map_meta_cap' => true,
730 784 'publicly_queryable' => false,
731 785 'exclude_from_search' => true,
732 786 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -759,8 +813,9 @@
759 813 ),
760 814 'public' => false,
761 815 'show_ui' => true,
762 816 'capability_type' => 'post',
817 + 'capabilities' => self::record_capabilities(),
763 818 'map_meta_cap' => true,
764 819 'publicly_queryable' => false,
765 820 'exclude_from_search' => true,
766 821 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -793,11 +848,11 @@
793 848 ),
794 849 'public' => false,
795 850 'show_ui' => true,
796 851 'capability_type' => 'post',
797 - 'capabilities' => array(
852 + 'capabilities' => array_merge( self::record_capabilities(), array(
798 853 'create_posts' => false
799 - ),
854 + ) ),
800 855 'map_meta_cap' => true,
801 856 'publicly_queryable' => false,
802 857 'exclude_from_search' => true,
803 858 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -830,8 +885,9 @@
830 885 ),
831 886 'public' => false,
832 887 'show_ui' => true,
833 888 'capability_type' => 'post',
889 + 'capabilities' => self::record_capabilities(),
834 890 'map_meta_cap' => true,
835 891 'publicly_queryable' => false,
836 892 'exclude_from_search' => true,
837 893 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
@@ -872,11 +928,11 @@
872 928 'query_var' => true,
873 929 'supports' => false,
874 930 'show_in_nav_menus' => false,
875 931 'show_in_menu' => false,
876 - 'capabilities' => array(
932 + 'capabilities' => array_merge( self::record_capabilities(), array(
877 933 'create_posts' => 'do_not_allow'
878 - ),
934 + ) ),
879 935 )
880 936 )
881 937 );
882 938 do_action( 'propertyhive_after_register_post_types' );
@@ -917,8 +973,9 @@
917 973 $args = array(
918 974 'post_type' => 'enquiry',
919 975 'nopaging' => true,
920 976 'post_status' => array('publish', 'pending', 'private', 'draft', 'auto-draft', 'future', 'trash'),
977 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Both legacy and current property relationship metadata must match when the explicit enquiry-trash option is enabled.
921 978 'meta_query' => array(
922 979 'relation' => 'OR',
923 980 array(
924 981 'key' => '_property_id',
@@ -977,9 +1034,11 @@
977 1034 'post_type' => 'property',
978 1035 'fields' => 'ids',
979 1036 'suppress_filters' => TRUE,
980 1037 'posts_per_page' => 1,
1038 + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Excludes only the property being deleted so its own media reference cannot prevent attachment cleanup.
981 1039 'post__not_in' => array( $post_id ),
1040 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Before deleting an attachment, check all four serialized property media relationships; the query stops at one matching property to preserve shared media.
982 1041 'meta_query' => array(
983 1042 'relation' => 'OR',
984 1043 array(
985 1044 'key' => '_photos',
@@ -1070,8 +1129,9 @@
1070 1129 $args = array(
1071 1130 'post_type' => 'enquiry',
1072 1131 'nopaging' => true,
1073 1132 'post_status' => array('publish', 'pending', 'private', 'draft', 'auto-draft', 'future', 'trash'),
1133 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Both legacy and current property relationship metadata must match when the explicit enquiry-delete option is enabled.
1074 1134 'meta_query' => array(
1075 1135 'relation' => 'OR',
1076 1136 array(
1077 1137 'key' => '_property_id',
@@ -1127,8 +1187,9 @@
1127 1187
1128 1188 $args = array(
1129 1189 'post_type' => 'contact',
1130 1190 'nopaging' => true,
1191 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Remove only contacts linked to the deleted user through their stored user ID.
1131 1192 'meta_query' => array(
1132 1193 array(
1133 1194 'key' => '_user_id',
1134 1195 'value' => (int)$user_id,
@@ -1249,8 +1310,10 @@
1249 1310 $args = array(
1250 1311 'post_type' => 'property',
1251 1312 'fields' => 'ids',
1252 1313 'post_status' => array( 'publish', 'draft'),
1314 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- This maintenance backfill must select records missing the destination metadata; removing the predicate would overwrite existing values.
1315 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Owner search metadata must be refreshed on properties linked through the existing serialized owner IDs; retain the relationship match.
1253 1316 'meta_query' => array(
1254 1317 array(
1255 1318 'key' => '_address_concatenated',
1256 1319 'compare' => 'NOT EXISTS'
@@ -1257,8 +1320,9 @@
1257 1320 )
1258 1321 ),
1259 1322 'nopaging' => true,
1260 1323 'orderby' => 'rand',
1324 + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters -- Maintenance must cover every language; front-end language filters would omit records from this backfill.
1261 1325 'suppress_filters' => true,
1262 1326 );
1263 1327 $property_query = new WP_Query($args);
1264 1328
@@ -1280,8 +1344,10 @@
1280 1344 $args = array(
1281 1345 'post_type' => 'contact',
1282 1346 'fields' => 'ids',
1283 1347 'post_status' => 'publish',
1348 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- This maintenance backfill must select records missing the destination metadata; removing the predicate would overwrite existing values.
1349 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Owner search metadata must be refreshed on properties linked through the existing serialized owner IDs; retain the relationship match.
1284 1350 'meta_query' => array(
1285 1351 array(
1286 1352 'key' => '_address_concatenated',
1287 1353 'compare' => 'NOT EXISTS'
@@ -1288,8 +1354,9 @@
1288 1354 )
1289 1355 ),
1290 1356 'nopaging' => true,
1291 1357 'orderby' => 'rand',
1358 + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters -- Maintenance must cover every language; front-end language filters would omit records from this backfill.
1292 1359 'suppress_filters' => true,
1293 1360 );
1294 1361 $contact_query = new WP_Query($args);
1295 1362
@@ -1351,8 +1418,9 @@
1351 1418 'fields' => 'ids',
1352 1419 'post_type' => 'viewing',
1353 1420 'nopaging' => true,
1354 1421 'post_status' => 'publish',
1422 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Recompute related-viewing metadata only for viewings linked to the changed property or applicant; retain existing relationship and status semantics.
1355 1423 'meta_query' => $meta_query,
1356 1424 'orderby' => 'none'
1357 1425 );
1358 1426
@@ -1385,8 +1453,9 @@
1385 1453 'fields' => 'ids',
1386 1454 'post_type' => 'viewing',
1387 1455 'nopaging' => true,
1388 1456 'post_status' => 'publish',
1457 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Recompute related-viewing metadata only for viewings linked to the changed property or applicant; retain existing relationship and status semantics.
1389 1458 'meta_query' => $meta_query,
1390 1459 'orderby' => 'none'
1391 1460 );
1392 1461