| @@ -1,5 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | +// phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] ph_clean | |
| 3 | +// ph_clean() recursively sanitizes text; presence, shape and unslashing checks remain separate. | |
| 4 | + | |
| 2 | 5 | /** |
| 3 | 6 | * Setup menus in WP admin. |
| 4 | 7 | * |
| 5 | 8 | * @author PropertyHive |
| @@ -14,8 +17,9 @@ | ||
| 14 | 17 | |
| 15 | 18 | /** |
| 16 | 19 | * PH_Admin_Menus Class |
| 17 | 20 | */ |
| 21 | +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Legacy public global class PH_Admin_Menus; preserving the existing PH_* class name is required for plugin and extension compatibility. | |
| 18 | 22 | class PH_Admin_Menus { |
| 19 | 23 | |
| 20 | 24 | /** |
| 21 | 25 | * Hook in tabs. |
| @@ -22,17 +26,162 @@ | ||
| 22 | 26 | */ |
| 23 | 27 | public function __construct() { |
| 24 | 28 | // Add menus |
| 25 | 29 | add_action( 'admin_menu', array( $this, 'admin_menu' ), 9 ); |
| 30 | + add_action( 'admin_menu', array( $this, 'import_properties_dummy_menu' ), 20 ); | |
| 26 | 31 | add_action( 'admin_menu', array( $this, 'reports_menu' ), 20 ); |
| 27 | 32 | add_action( 'admin_menu', array( $this, 'settings_menu' ), 50 ); |
| 28 | - add_action( 'admin_menu', array( $this, 'add_ons_menu' ), 60 ); | |
| 33 | + add_action( 'admin_menu', array( $this, 'crm_only_mode_menu' ), 99 ); | |
| 29 | 34 | |
| 30 | 35 | add_action( 'admin_head', array( $this, 'menu_highlight' ) ); |
| 31 | - //add_filter( 'menu_order', array( $this, 'menu_order' ) ); | |
| 32 | - //add_filter( 'custom_menu_order', array( $this, 'custom_menu_order' ) ); | |
| 36 | + | |
| 37 | + add_action( 'admin_bar_menu', array( $this, 'remove_from_admin_bar' ), 999); | |
| 38 | + | |
| 39 | + // Handle saving settings earlier than load-{page} hook to avoid race conditions in conditional menus. | |
| 40 | + add_action( 'wp_loaded', array( $this, 'save_settings' ) ); | |
| 33 | 41 | } |
| 34 | 42 | |
| 43 | + public function save_settings() { | |
| 44 | + global $current_tab, $current_section; | |
| 45 | + | |
| 46 | + // We should only save on the settings page. | |
| 47 | + if ( ! is_admin() || ! isset( $_GET['page'] ) || 'ph-settings' !== $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 48 | + return; | |
| 49 | + } | |
| 50 | + | |
| 51 | + // Include settings pages. | |
| 52 | + PH_Admin_Settings::get_settings_pages(); | |
| 53 | + | |
| 54 | + // Get current tab/section. | |
| 55 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound, WordPress.Security.NonceVerification.Recommended -- Read-only settings routing; saved data is separately nonce/capability checked by PH_Admin_Settings::save(). Shared admin settings-view state; this global is intentionally used to control the common settings template and is not an arbitrary application global. | |
| 56 | + $current_tab = empty( $_GET['tab'] ) || ! is_string( $_GET['tab'] ) ? 'general' : sanitize_title( wp_unslash( $_GET['tab'] ) ); // WPCS: input var okay, CSRF ok. | |
| 57 | + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound, WordPress.Security.NonceVerification.Recommended -- Read-only settings routing; saved data is separately nonce/capability checked by PH_Admin_Settings::save(). Shared admin settings-view state; this global is intentionally used to control the common settings template and is not an arbitrary application global. | |
| 58 | + $current_section = empty( $_REQUEST['section'] ) || ! is_string( $_REQUEST['section'] ) ? '' : sanitize_title( wp_unslash( $_REQUEST['section'] ) ); // WPCS: input var okay, CSRF ok. | |
| 59 | + | |
| 60 | + // Save settings if data has been posted. The called save method verifies nonce and capabilities. | |
| 61 | + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Read-only save intent; PH_Admin_Settings::save() validates before changing any settings. | |
| 62 | + $save_requested = ! empty( $_POST['save'] ); | |
| 63 | + if ( '' !== $current_section && apply_filters( "propertyhive_save_settings_{$current_tab}_{$current_section}", $save_requested ) ) { // WPCS: input var okay, CSRF ok. | |
| 64 | + PH_Admin_Settings::save(); | |
| 65 | + } elseif ( '' === $current_section && apply_filters( "propertyhive_save_settings_{$current_tab}", $save_requested ) ) { // WPCS: input var okay, CSRF ok. | |
| 66 | + PH_Admin_Settings::save(); | |
| 67 | + } | |
| 68 | + | |
| 69 | + $redirect_after_save = ''; | |
| 70 | + if ( current_user_can( 'manage_options' ) && isset( $_REQUEST['_wpnonce'] ) && is_string( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'propertyhive-settings' ) ) { | |
| 71 | + $redirect_after_save = isset( $_POST['redirect'] ) && is_string( $_POST['redirect'] ) ? sanitize_url( wp_unslash( $_POST['redirect'] ) ) : ''; | |
| 72 | + } | |
| 73 | + if ( !empty($redirect_after_save) ) | |
| 74 | + { | |
| 75 | + wp_safe_redirect($redirect_after_save . '&ph_message=' . __( 'Your settings have been saved.', 'propertyhive' ) ); | |
| 76 | + die(); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + public function remove_from_admin_bar( $wp_admin_bar ) | |
| 81 | + { | |
| 82 | + $current_user = wp_get_current_user(); | |
| 83 | + | |
| 84 | + $user_id = $current_user->ID; | |
| 85 | + | |
| 86 | + $crm_only_mode = get_user_meta( $user_id, 'crm_only_mode', TRUE ); | |
| 87 | + | |
| 88 | + if ( $crm_only_mode == '1' ) | |
| 89 | + { | |
| 90 | + $wp_admin_bar->remove_node('new-content'); | |
| 91 | + } | |
| 92 | + } | |
| 93 | + | |
| 94 | + public function crm_only_mode_menu() | |
| 95 | + { | |
| 96 | + $current_user = wp_get_current_user(); | |
| 97 | + | |
| 98 | + $user_id = $current_user->ID; | |
| 99 | + | |
| 100 | + $crm_only_mode = get_user_meta( $user_id, 'crm_only_mode', TRUE ); | |
| 101 | + | |
| 102 | + if ( $crm_only_mode == '1' ) | |
| 103 | + { | |
| 104 | + global $menu, $submenu, $wp_filter; | |
| 105 | + | |
| 106 | + // remove all top-level menu items that isn't the Dashboard | |
| 107 | + foreach ( $menu as $i => $menuitem ) | |
| 108 | + { | |
| 109 | + if ( | |
| 110 | + ( !isset($menuitem[2]) || ( isset($menuitem[2]) && $menuitem[2] != 'index.php' ) ) | |
| 111 | + && | |
| 112 | + apply_filters( 'propertyhive_remove_menu_item_in_crm_only_mode', true, $menuitem ) === true | |
| 113 | + ) | |
| 114 | + { | |
| 115 | + unset($menu[$i]); | |
| 116 | + } | |
| 117 | + } | |
| 118 | + if ( isset($submenu['propertyhive']) ) | |
| 119 | + { | |
| 120 | + unset($submenu['propertyhive'][0]); | |
| 121 | + $position = 5; | |
| 122 | + foreach ( $submenu['propertyhive'] as $submenuitem ) | |
| 123 | + { | |
| 124 | + $callback = ''; | |
| 125 | + if ( substr($submenuitem[2], 0, 3) == 'ph-' ) | |
| 126 | + { | |
| 127 | + $callback = array( $this, substr($submenuitem[2], 3) . '_page' ); | |
| 128 | + } | |
| 129 | + elseif ( isset($wp_filter[sanitize_title(__( 'Property Hive', 'propertyhive' )) . '_page_' . $submenuitem[2]]) ) | |
| 130 | + { | |
| 131 | + // get class name from callbacks then convert it to class name | |
| 132 | + // i.e. convert PH_Property_Import to PHPI() | |
| 133 | + $class_name = ''; | |
| 134 | + $function_name = ''; | |
| 135 | + if ( isset($wp_filter[sanitize_title(__( 'Property Hive', 'propertyhive' )) . '_page_' . $submenuitem[2]]->callbacks) ) | |
| 136 | + { | |
| 137 | + foreach ( $wp_filter[sanitize_title(__( 'Property Hive', 'propertyhive' )) . '_page_' . $submenuitem[2]]->callbacks as $priority => $filter_callbacks ) | |
| 138 | + { | |
| 139 | + foreach ( $filter_callbacks as $oddkey => $filter_callback ) | |
| 140 | + { | |
| 141 | + if ( isset($filter_callback['function']) && count($filter_callback['function']) >= 2 ) | |
| 142 | + { | |
| 143 | + $class_name = get_class($filter_callback['function'][0]); | |
| 144 | + $explode_class_name = explode("_", $class_name); | |
| 145 | + | |
| 146 | + $class_name_bits = array(); | |
| 147 | + foreach ( $explode_class_name as $exploded_class_name_bit ) | |
| 148 | + { | |
| 149 | + if ( $exploded_class_name_bit == 'PH' ) | |
| 150 | + { | |
| 151 | + $class_name_bits[] = $exploded_class_name_bit; | |
| 152 | + } | |
| 153 | + else | |
| 154 | + { | |
| 155 | + $class_name_bits[] = strtoupper(substr($exploded_class_name_bit, 0, 1)); | |
| 156 | + } | |
| 157 | + } | |
| 158 | + | |
| 159 | + $class_name = implode("", $class_name_bits); | |
| 160 | + $function_name = $filter_callback['function'][1]; | |
| 161 | + } | |
| 162 | + } | |
| 163 | + } | |
| 164 | + } | |
| 165 | + | |
| 166 | + if ( class_exists($class_name) && $class_name != '' && $function_name != '' ) | |
| 167 | + { | |
| 168 | + $callback = array( $class_name(), $function_name ); | |
| 169 | + } | |
| 170 | + elseif ( function_exists($class_name) && $class_name != '' && $function_name != '' ) | |
| 171 | + { | |
| 172 | + $callback = array( $class_name(), $function_name ); | |
| 173 | + } | |
| 174 | + } | |
| 175 | + | |
| 176 | + add_menu_page( $submenuitem[3], $submenuitem[0], $submenuitem[1], $submenuitem[2], $callback, $this->get_menu_icon($submenuitem[2]), $position ); | |
| 177 | + $position += 5; | |
| 178 | + } | |
| 179 | + unset($submenu['propertyhive']); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + } | |
| 183 | + | |
| 35 | 184 | /** |
| 36 | 185 | * Add menu items |
| 37 | 186 | */ |
| 38 | 187 | public function admin_menu() { |
| @@ -40,9 +189,9 @@ | ||
| 40 | 189 | |
| 41 | 190 | //if ( current_user_can( 'manage_propertyhive' ) ) |
| 42 | 191 | $menu[] = array( '', 'read', 'separator-propertyhive', '', 'wp-menu-separator propertyhive' ); |
| 43 | 192 | |
| 44 | - add_menu_page( __( 'Property Hive', 'propertyhive' ), __( 'Property Hive', 'propertyhive' ), 'manage_propertyhive', 'propertyhive' , array( $this, 'settings_page' ), PH()->plugin_url() . '/assets/images/menu-icon.png', '54.5' ); | |
| 193 | + add_menu_page( __( 'Property Hive', 'propertyhive' ), __( 'Property Hive', 'propertyhive' ), 'manage_propertyhive', 'propertyhive' , array( $this, 'settings_page' ), $this->get_menu_icon(), '54.5' ); | |
| 45 | 194 | |
| 46 | 195 | add_submenu_page( 'propertyhive', __( 'Properties', 'propertyhive' ), __( 'Properties', 'propertyhive' ), 'manage_propertyhive', 'edit.php?post_type=property'/*, array( $this, 'attributes_page' )*/ ); |
| 47 | 196 | |
| 48 | 197 | if ( get_option('propertyhive_module_disabled_contacts', '') != 'yes' ) |
| @@ -54,28 +203,34 @@ | ||
| 54 | 203 | |
| 55 | 204 | if ( get_option('propertyhive_module_disabled_enquiries', '') != 'yes' ) |
| 56 | 205 | { |
| 57 | 206 | $count = ''; |
| 58 | - $args = array( | |
| 59 | - 'post_type' => 'enquiry', | |
| 60 | - 'nopaging' => true, | |
| 61 | - 'fields' => 'ids', | |
| 62 | - 'meta_query' => array( | |
| 63 | - array( | |
| 64 | - 'key' => '_status', | |
| 65 | - 'value' => 'open' | |
| 66 | - ), | |
| 67 | - array( | |
| 68 | - 'key' => '_negotiator_id', | |
| 69 | - 'value' => '' | |
| 70 | - ), | |
| 71 | - ), | |
| 72 | - ); | |
| 73 | - $enquiry_query = new WP_Query( $args ); | |
| 74 | - if ( $enquiry_query->have_posts() ) | |
| 207 | + if ( apply_filters( 'propertyhive_show_admin_menu_enquiry_count', TRUE ) === TRUE ) | |
| 75 | 208 | { |
| 76 | - $count = ' <span class="update-plugins count-' . $enquiry_query->found_posts . '"><span class="plugin-count">' . $enquiry_query->found_posts . '</span></span>'; | |
| 77 | - } | |
| 209 | + $args = array( | |
| 210 | + 'post_type' => 'enquiry', | |
| 211 | + 'posts_per_page' => 1, | |
| 212 | + 'no_found_rows' => false, | |
| 213 | + 'fields' => 'ids', | |
| 214 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Count-only menu query fetches one ID while retaining found_rows for the complete total. | |
| 215 | + 'meta_query' => array( | |
| 216 | + array( | |
| 217 | + 'key' => '_status', | |
| 218 | + 'value' => 'open' | |
| 219 | + ), | |
| 220 | + array( | |
| 221 | + 'key' => '_negotiator_id', | |
| 222 | + 'value' => '' | |
| 223 | + ), | |
| 224 | + ), | |
| 225 | + ); | |
| 226 | + $args = apply_filters( 'propertyhive_admin_menu_enquiry_count_args', $args ); | |
| 227 | + $enquiry_query = new WP_Query( $args ); | |
| 228 | + if ( $enquiry_query->have_posts() ) | |
| 229 | + { | |
| 230 | + $count = ' <span class="update-plugins count-' . $enquiry_query->found_posts . '"><span class="plugin-count">' . $enquiry_query->found_posts . '</span></span>'; | |
| 231 | + } | |
| 232 | + } | |
| 78 | 233 | add_submenu_page( 'propertyhive', __( 'Enquiries', 'propertyhive' ), __( 'Enquiries', 'propertyhive' ) . $count, 'manage_propertyhive', 'edit.php?post_type=enquiry'/*, array( $this, 'attributes_page' )*/ ); |
| 79 | 234 | } |
| 80 | 235 | |
| 81 | 236 | if ( get_option('propertyhive_module_disabled_appraisals', '') != 'yes' ) |
| @@ -93,16 +248,143 @@ | ||
| 93 | 248 | add_submenu_page( 'propertyhive', __( 'Offers', 'propertyhive' ), __( 'Offers', 'propertyhive' ), 'manage_propertyhive', 'edit.php?post_type=offer'/*, array( $this, 'attributes_page' )*/ ); |
| 94 | 249 | add_submenu_page( 'propertyhive', __( 'Sales', 'propertyhive' ), __( 'Sales', 'propertyhive' ), 'manage_propertyhive', 'edit.php?post_type=sale'/*, array( $this, 'attributes_page' )*/ ); |
| 95 | 250 | } |
| 96 | 251 | |
| 252 | + if ( get_option( 'propertyhive_active_departments_lettings' ) == 'yes' && get_option('propertyhive_module_disabled_tenancies', '') != 'yes' ) | |
| 253 | + { | |
| 254 | + add_submenu_page( 'propertyhive', __( 'Tenancies', 'propertyhive' ), __( 'Tenancies', 'propertyhive' ), 'manage_propertyhive', 'edit.php?post_type=tenancy'/*, array( $this, 'attributes_page' )*/ ); | |
| 255 | + | |
| 256 | + $count = ''; | |
| 257 | + if ( apply_filters( 'propertyhive_show_admin_menu_key_date_count', TRUE ) === TRUE ) | |
| 258 | + { | |
| 259 | + $args = array( | |
| 260 | + 'post_type' => 'key_date', | |
| 261 | + 'posts_per_page' => 1, | |
| 262 | + 'no_found_rows' => false, | |
| 263 | + 'fields' => 'ids', | |
| 264 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Count-only menu query fetches one ID while retaining found_rows for the complete total. | |
| 265 | + 'meta_query' => array( | |
| 266 | + array( | |
| 267 | + 'key' => '_key_date_status', | |
| 268 | + 'value' => 'pending' | |
| 269 | + ), | |
| 270 | + array( | |
| 271 | + 'key' => '_date_due', | |
| 272 | + 'value' => gmdate('Y-m-d'), | |
| 273 | + 'type' => 'date', | |
| 274 | + 'compare' => '<=', | |
| 275 | + ), | |
| 276 | + ), | |
| 277 | + ); | |
| 278 | + $args = apply_filters( 'propertyhive_admin_menu_key_date_count_args', $args ); | |
| 279 | + $key_date_query = new WP_Query( $args ); | |
| 280 | + if ( $key_date_query->have_posts() ) | |
| 281 | + { | |
| 282 | + $count = ' <span class="update-plugins count-' . $key_date_query->found_posts . '"><span class="plugin-count">' . $key_date_query->found_posts . '</span></span>'; | |
| 283 | + } | |
| 284 | + } | |
| 285 | + add_submenu_page( 'propertyhive', __( 'Management', 'propertyhive' ), __( 'Management', 'propertyhive' ) . $count, 'manage_propertyhive', 'edit.php?post_type=key_date&orderby=date_due&order=asc&status=upcoming_and_overdue&filter_action=Filter' ); | |
| 286 | + } | |
| 287 | + | |
| 97 | 288 | if ( get_option('propertyhive_module_disabled_contacts', '') != 'yes' ) |
| 98 | 289 | { |
| 99 | - add_submenu_page( null, __( 'Applicant Matching Properties', 'propertyhive'), __( 'Applicant Matching Properties', 'propertyhive' ), 'manage_propertyhive', 'ph-matching-properties', array($this, 'matching_properties_page')); | |
| 100 | - add_submenu_page( null, __( 'Generate Applicant List', 'propertyhive'), __( 'Generate Applicant List', 'propertyhive' ), 'manage_propertyhive', 'ph-generate-applicant-list', array($this, 'generate_applicant_list_page')); | |
| 101 | - add_submenu_page( null, __( 'Applicant Matching Applicants', 'propertyhive'), __( 'Applicant Matching Properties', 'propertyhive' ), 'manage_propertyhive', 'ph-matching-applicants', array($this, 'matching_applicants_page')); | |
| 290 | + add_submenu_page( '', __( 'Applicant Matching Properties', 'propertyhive'), __( 'Applicant Matching Properties', 'propertyhive' ), 'manage_propertyhive', 'ph-matching-properties', array($this, 'matching_properties_page')); | |
| 291 | + add_submenu_page( '', __( 'Generate Applicant List', 'propertyhive'), __( 'Generate Applicant List', 'propertyhive' ), 'manage_propertyhive', 'ph-generate-applicant-list', array($this, 'generate_applicant_list_page')); | |
| 292 | + add_submenu_page( '', __( 'Applicant Matching Applicants', 'propertyhive'), __( 'Applicant Matching Properties', 'propertyhive' ), 'manage_propertyhive', 'ph-matching-applicants', array($this, 'matching_applicants_page')); | |
| 293 | + add_submenu_page( '', __( 'Merge Duplicate Contacts', 'propertyhive'), __( 'Merge Duplicate Contacts', 'propertyhive' ), 'manage_propertyhive', 'ph-merge-duplicate-contacts', array($this, 'generate_merge_duplicate_contacts_page')); | |
| 102 | 294 | } |
| 103 | 295 | } |
| 104 | 296 | |
| 297 | + /** | |
| 298 | + * Add menu item | |
| 299 | + */ | |
| 300 | + public function import_properties_dummy_menu() | |
| 301 | + { | |
| 302 | + // check clauses | |
| 303 | + if ( !current_user_can( 'manage_options' ) ) | |
| 304 | + { | |
| 305 | + // Not an administrator | |
| 306 | + return; | |
| 307 | + } | |
| 308 | + | |
| 309 | + if ( apply_filters( 'propertyhive_admin_menu_property_import_button', true ) !== true ) | |
| 310 | + { | |
| 311 | + // Manually turned off by filter | |
| 312 | + return; | |
| 313 | + } | |
| 314 | + | |
| 315 | + if ( class_exists('PH_Property_Import') ) | |
| 316 | + { | |
| 317 | + // Already activated. Check can be used | |
| 318 | + if ( apply_filters( 'propertyhive_add_on_can_be_used', true, 'propertyhive-property-import' ) === true ) | |
| 319 | + { | |
| 320 | + // Yes. Import add on is fine to use | |
| 321 | + return; | |
| 322 | + } | |
| 323 | + } | |
| 324 | + | |
| 325 | + // check date installed more than when PRO went live | |
| 326 | + $propertyhive_install_timestamp = get_option( 'propertyhive_install_timestamp', '' ); | |
| 327 | + if ( !empty($propertyhive_install_timestamp) ) | |
| 328 | + { | |
| 329 | + $november_first_2023 = strtotime('2023-11-01 00:00:00'); | |
| 330 | + if ( $propertyhive_install_timestamp < $november_first_2023 ) | |
| 331 | + { | |
| 332 | + // Installed before 1st Nov 2023. Don't show anything | |
| 333 | + return; | |
| 334 | + } | |
| 335 | + } | |
| 336 | + | |
| 337 | + $show_dummy_link = false; | |
| 338 | + | |
| 339 | + $license_type = get_option( 'propertyhive_license_type', '' ); | |
| 340 | + if ( $license_type == '' ) | |
| 341 | + { | |
| 342 | + $show_dummy_link = true; | |
| 343 | + } | |
| 344 | + | |
| 345 | + if ( !$show_dummy_link ) | |
| 346 | + { | |
| 347 | + if ( $license_type == 'old' ) | |
| 348 | + { | |
| 349 | + // Old user. Don't do anything | |
| 350 | + return; | |
| 351 | + } | |
| 352 | + | |
| 353 | + if ( $license_type == 'pro' ) | |
| 354 | + { | |
| 355 | + $license_key = get_option( 'propertyhive_pro_license_key', '' ); | |
| 356 | + if ( empty($license_key) ) | |
| 357 | + { | |
| 358 | + // No license key entered | |
| 359 | + $show_dummy_link = true; | |
| 360 | + } | |
| 361 | + else | |
| 362 | + { | |
| 363 | + if ( PH()->license->is_valid_pro_license_key() ) | |
| 364 | + { | |
| 365 | + // valid license key. | |
| 366 | + return; | |
| 367 | + } | |
| 368 | + else | |
| 369 | + { | |
| 370 | + $show_dummy_link = true; | |
| 371 | + } | |
| 372 | + } | |
| 373 | + } | |
| 374 | + } | |
| 375 | + | |
| 376 | + if ( $show_dummy_link === true ) | |
| 377 | + { | |
| 378 | + add_submenu_page( 'propertyhive', __( 'Import Properties', 'propertyhive' ), __( 'Import Properties', 'propertyhive' ) . '<span class="update-plugins" style="padding:0 3px;"><span class="plugin-count">PRO</span></span>', 'manage_options', 'ph-import_properties_dummy', array( $this, 'import_properties_dummy_page' ) ); | |
| 379 | + } | |
| 380 | + } | |
| 381 | + | |
| 382 | + public function import_properties_dummy_page() | |
| 383 | + { | |
| 384 | + include_once( 'views/html-import-properties-dummy.php' ); | |
| 385 | + } | |
| 386 | + | |
| 105 | 387 | /** |
| 106 | 388 | * Add menu item |
| 107 | 389 | */ |
| 108 | 390 | public function reports_menu() { |
| @@ -118,15 +400,8 @@ | ||
| 118 | 400 | //add_action( 'load-' . $settings_page, array( $this, 'settings_page_init' ) ); |
| 119 | 401 | } |
| 120 | 402 | |
| 121 | 403 | /** |
| 122 | - * Add menu item | |
| 123 | - */ | |
| 124 | - public function add_ons_menu() { | |
| 125 | - $settings_page = add_submenu_page( 'propertyhive', __( 'Add Ons', 'propertyhive' ), __( 'Add Ons', 'propertyhive' ) , 'manage_options', 'admin.php?page=ph-settings&tab=addons'/*, array( $this, 'settings_page' )*/ ); | |
| 126 | - } | |
| 127 | - | |
| 128 | - /** | |
| 129 | 404 | * Loads gateways and shipping methods into memory for use within settings. |
| 130 | 405 | */ |
| 131 | 406 | public function settings_page_init() { |
| 132 | 407 | |
| @@ -141,71 +416,42 @@ | ||
| 141 | 416 | public function menu_highlight() { |
| 142 | 417 | |
| 143 | 418 | global $menu, $submenu, $parent_file, $submenu_file, $self, $post_type, $taxonomy; |
| 144 | 419 | |
| 145 | - $to_highlight_types = array( 'property', 'contact', 'enquiry', 'appraisal', 'viewing', 'offer', 'sale' ); | |
| 420 | + $current_user = wp_get_current_user(); | |
| 146 | 421 | |
| 147 | - if ( isset( $post_type ) ) { | |
| 148 | - if ( in_array( $post_type, $to_highlight_types ) ) { | |
| 149 | - $submenu_file = 'edit.php?post_type=' . esc_attr( $post_type ); | |
| 150 | - $parent_file = 'propertyhive'; | |
| 422 | + $user_id = $current_user->ID; | |
| 423 | + | |
| 424 | + $crm_only_mode = get_user_meta( $user_id, 'crm_only_mode', TRUE ); | |
| 425 | + | |
| 426 | + if ( $crm_only_mode == '1' ) | |
| 427 | + { | |
| 428 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only CRM navigation highlighting, not a data mutation. | |
| 429 | + $contact_type = isset( $_GET['_contact_type'] ) && is_string( $_GET['_contact_type'] ) ? sanitize_text_field( wp_unslash( $_GET['_contact_type'] ) ) : ''; | |
| 430 | + if ( $post_type == 'contact' && '' !== $contact_type ) | |
| 431 | + { | |
| 432 | + $parent_file = 'edit.php?post_type=contact&_contact_type=' . rawurlencode( $contact_type ); | |
| 151 | 433 | } |
| 152 | 434 | } |
| 435 | + else | |
| 436 | + { | |
| 437 | + $to_highlight_types = array( 'property', 'contact', 'enquiry', 'appraisal', 'viewing', 'offer', 'sale', 'tenancy', 'key_date' ); | |
| 153 | 438 | |
| 154 | - if ( isset( $submenu['propertyhive'] ) && isset( $submenu['propertyhive'][1] ) ) { | |
| 155 | - $submenu['propertyhive'][0] = $submenu['propertyhive'][1]; | |
| 156 | - unset( $submenu['propertyhive'][1] ); | |
| 439 | + if ( isset( $post_type ) ) { | |
| 440 | + if ( in_array( $post_type, $to_highlight_types ) ) { | |
| 441 | + $submenu_file = 'edit.php?post_type=' . esc_attr( $post_type ); | |
| 442 | + $parent_file = 'propertyhive'; | |
| 443 | + } | |
| 444 | + } | |
| 445 | + | |
| 446 | + if ( isset( $submenu['propertyhive'] ) && isset( $submenu['propertyhive'][1] ) ) { | |
| 447 | + $submenu['propertyhive'][0] = $submenu['propertyhive'][1]; | |
| 448 | + unset( $submenu['propertyhive'][1] ); | |
| 449 | + } | |
| 157 | 450 | } |
| 158 | 451 | } |
| 159 | 452 | |
| 160 | 453 | /** |
| 161 | - * Reorder the PH menu items in admin. | |
| 162 | - * | |
| 163 | - * @param mixed $menu_order | |
| 164 | - * @return array | |
| 165 | - */ | |
| 166 | - public function menu_order( $menu_order ) { | |
| 167 | - | |
| 168 | - | |
| 169 | - // Initialize our custom order array | |
| 170 | - $propertyhive_menu_order = array(); | |
| 171 | - | |
| 172 | - // Get the index of our custom separator | |
| 173 | - $propertyhive_separator = array_search( 'separator-propertyhive', $menu_order ); | |
| 174 | - | |
| 175 | - // Get index of product menu | |
| 176 | - $propertyhive_property = array_search( 'edit.php?post_type=property', $menu_order ); | |
| 177 | - | |
| 178 | - // Loop through menu order and do some rearranging | |
| 179 | - foreach ( $menu_order as $index => $item ) : | |
| 180 | - | |
| 181 | - if ( ( ( 'propertyhive' ) == $item ) ) : | |
| 182 | - $propertyhive_menu_order[] = 'separator-propertyhive'; | |
| 183 | - $propertyhive_menu_order[] = $item; | |
| 184 | - $propertyhive_menu_order[] = 'edit.php?post_type=property'; | |
| 185 | - unset( $menu_order[$propertyhive_separator] ); | |
| 186 | - unset( $menu_order[$propertyhive_property] ); | |
| 187 | - elseif ( !in_array( $item, array( 'separator-propertyhive' ) ) ) : | |
| 188 | - $propertyhive_menu_order[] = $item; | |
| 189 | - endif; | |
| 190 | - | |
| 191 | - endforeach; | |
| 192 | - | |
| 193 | - // Return order | |
| 194 | - return $propertyhive_menu_order; | |
| 195 | - } | |
| 196 | - | |
| 197 | - /** | |
| 198 | - * custom_menu_order | |
| 199 | - * @return bool | |
| 200 | - */ | |
| 201 | - public function custom_menu_order() { | |
| 202 | - if ( ! current_user_can( 'manage_propertyhive' ) ) | |
| 203 | - return false; | |
| 204 | - return true; | |
| 205 | - } | |
| 206 | - | |
| 207 | - /** | |
| 208 | 454 | * Init the reports page |
| 209 | 455 | */ |
| 210 | 456 | public function reports_page() { |
| 211 | 457 | include_once( 'class-ph-admin-reports.php' ); |
| @@ -233,9 +479,10 @@ | ||
| 233 | 479 | * Init the applicant list page |
| 234 | 480 | */ |
| 235 | 481 | public function generate_applicant_list_page() { |
| 236 | 482 | include_once( 'class-ph-admin-applicant-list.php' ); |
| 237 | - PH_Admin_Applicant_List::output(); | |
| 483 | + $ph_admin_applicant_list = new PH_Admin_Applicant_List(); | |
| 484 | + $ph_admin_applicant_list->output(); | |
| 238 | 485 | } |
| 239 | 486 | |
| 240 | 487 | /** |
| 241 | 488 | * Init the property matching applicants page |
| @@ -246,13 +493,100 @@ | ||
| 246 | 493 | $ph_admin_matching_applicants->output(); |
| 247 | 494 | } |
| 248 | 495 | |
| 249 | 496 | /** |
| 250 | - * Init the status page | |
| 497 | + * Init the merge contacts page | |
| 251 | 498 | */ |
| 252 | - public function status_page() { | |
| 253 | - $page = include( 'class-ph-admin-status.php' ); | |
| 254 | - $page->output(); | |
| 499 | + public function generate_merge_duplicate_contacts_page() { | |
| 500 | + include_once( 'class-ph-admin-merge-contacts.php' ); | |
| 501 | + $ph_admin_merge_contacts = new PH_Admin_Merge_Contacts(); | |
| 502 | + $ph_admin_merge_contacts->output(); | |
| 503 | + } | |
| 504 | + | |
| 505 | + private function get_menu_icon( $section = '' ) | |
| 506 | + { | |
| 507 | + // extract post type | |
| 508 | + $explode_section = explode("?", $section, 2); | |
| 509 | + $tab = ''; | |
| 510 | + if ( count($explode_section) == 2 ) | |
| 511 | + { | |
| 512 | + parse_str( $explode_section[1], $array ); | |
| 513 | + | |
| 514 | + if ( isset($array['post_type']) ) | |
| 515 | + { | |
| 516 | + $section = $array['post_type']; | |
| 517 | + } | |
| 518 | + elseif ( isset($array['page']) ) | |
| 519 | + { | |
| 520 | + $section = $array['page']; | |
| 521 | + if ( isset($array['tab']) ) | |
| 522 | + { | |
| 523 | + $tab = $array['tab']; | |
| 524 | + } | |
| 525 | + } | |
| 526 | + } | |
| 527 | + | |
| 528 | + $icon = PH()->plugin_url() . '/assets/images/menu-icon.png'; | |
| 529 | + switch ( $section ) | |
| 530 | + { | |
| 531 | + case "contact": | |
| 532 | + { | |
| 533 | + $icon = "dashicons-admin-users"; | |
| 534 | + break; | |
| 535 | + } | |
| 536 | + case "property": | |
| 537 | + { | |
| 538 | + $icon = "dashicons-admin-home"; | |
| 539 | + break; | |
| 540 | + } | |
| 541 | + case "appraisal": | |
| 542 | + { | |
| 543 | + $icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzgwIiBoZWlnaHQ9IjM5MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnPgogIDx0aXRsZT5MYXllciAxPC90aXRsZT4KICA8cGF0aCBmaWxsPSIjZjBmMGYxIiBpZD0ic3ZnXzEiIGQ9Im0xOTAuMjA5MDU3LDYuMjExNDA4Yy0xMDMuNzU0LDAgLTE4OC4xNjEsODQuNDEzIC0xODguMTYxLDE4OC4xNjdzODQuNDA3LDE4OC4xNTUgMTg4LjE2MSwxODguMTU1YzEwMy43NiwwIDE4OC4xNjcsLTg0LjQwMSAxODguMTY3LC0xODguMTU1cy04NC40MDcsLTE4OC4xNjcgLTE4OC4xNjcsLTE4OC4xNjd6bTAsMzQ2LjY0MmMtODcuMzgzLDAgLTE1OC40NzYsLTcxLjA5MyAtMTU4LjQ3NiwtMTU4LjQ3NmMwLC04Ny4zOTUgNzEuMDkyLC0xNTguNDg3IDE1OC40NzYsLTE1OC40ODdjODcuMzg5LDAgMTU4LjQ4Nyw3MS4wOTMgMTU4LjQ4NywxNTguNDg3YzAuMDAxLDg3LjM4MyAtNzEuMDk4LDE1OC40NzYgLTE1OC40ODcsMTU4LjQ3NnoiLz4KICA8cGF0aCBmaWxsPSIjZjBmMGYxIiBpZD0ic3ZnXzIiIGQ9Im0yMTcuMjIxMDYsMTE1LjY4MjRjMTQuODA2LDAgMTguODY3LDEwLjczOSAyMi45MjksMjMuNTIybDEzLjkzOCwtMTcuNzA3Yy00LjY0NSwtMTguNTg3IC0xNy40MjIsLTI5LjYxMSAtNDIuOTY3LC0yOS42MTFjLTQzLjg0NSwwIC00OS4wNjYsMzEuOTMxIC00OS4wNjYsNTkuNzk0bDAsMzAuMjA1bC0yMS40OSwwbC01LjgwMywyNC4zOTFsMjUuODM1LDBjLTMuMTkzLDMyLjgxMSAtMTEuNjEyLDYzLjU3NSAtMzQuMjYxLDkwLjU4MmwxMjUuMTQ2LDBsMCwtMzAuMTk1bC03MC41NjcsMGM5LjAwMiwtMjAuNjIxIDEyLjQ5OCwtMzguNjE0IDEzLjk0OCwtNjAuMzg5bDQ4LjQ3OSwwbDUuODEsLTI0LjM5MWwtNTMuMTM0LDBsMCwtMjQuMzkxYzAsLTIyLjY0MSAxLjE2NiwtNDEuODEgMjEuMjAzLC00MS44MXoiLz4KIDwvZz4KPC9zdmc+"; | |
| 544 | + break; | |
| 545 | + } | |
| 546 | + case "viewing": | |
| 547 | + { | |
| 548 | + $icon = "dashicons-visibility"; | |
| 549 | + break; | |
| 550 | + } | |
| 551 | + case "enquiry": | |
| 552 | + { | |
| 553 | + $icon = "dashicons-admin-comments"; | |
| 554 | + break; | |
| 555 | + } | |
| 556 | + case "offer": | |
| 557 | + case "sale": | |
| 558 | + { | |
| 559 | + $icon = "dashicons-tag"; | |
| 560 | + break; | |
| 561 | + } | |
| 562 | + case "tenancy": | |
| 563 | + { | |
| 564 | + $icon = "dashicons-admin-network"; | |
| 565 | + break; | |
| 566 | + } | |
| 567 | + case "key_date": | |
| 568 | + { | |
| 569 | + $icon = "dashicons-admin-network"; | |
| 570 | + break; | |
| 571 | + } | |
| 572 | + case "ph-reports": | |
| 573 | + { | |
| 574 | + $icon = "dashicons-chart-bar"; | |
| 575 | + break; | |
| 576 | + } | |
| 577 | + case "ph-settings": | |
| 578 | + { | |
| 579 | + $icon = "dashicons-admin-settings"; | |
| 580 | + if ( $tab == 'addons' ) | |
| 581 | + { | |
| 582 | + $icon = "dashicons-insert"; | |
| 583 | + } | |
| 584 | + break; | |
| 585 | + } | |
| 586 | + } | |
| 587 | + $icon = apply_filters( 'propertyhive_menu_icon', $icon, $section ); | |
| 588 | + return $icon; | |
| 255 | 589 | } |
| 256 | 590 | |
| 257 | 591 | } |
| 258 | 592 | |