* @package View_Admin_As */ if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { die(); } /** * Compatibility class. * * @author Jory Hogeveen * @package View_Admin_As * @since 1.6 * @version 1.8 * @uses \VAA_View_Admin_As_Base Extends class */ final class VAA_View_Admin_As_Compat extends VAA_View_Admin_As_Base { /** * The single instance of the class. * * @since 1.6 * @static * @var \VAA_View_Admin_As_Compat */ private static $_instance = null; /** * Populate the instance. * * @since 1.6 * @since 1.6.1 $vaa param. * @access protected * @param \VAA_View_Admin_As $vaa The main VAA object. */ protected function __construct( $vaa ) { self::$_instance = $this; parent::__construct( $vaa ); } /** * Fix compatibility issues. * * @since 0.1 * @since 1.6 Moved third_party_compatibility() to this class from main class. * @access public * @return void */ public function init() { $this->add_action( 'vaa_view_admin_as_init', array( $this, 'init_after' ) ); /** * Add our caps to the members plugin. * Hook `members_get_capabilities` also used by: * - User Role Editor (URE) >> Own filter: `ure_full_capabilites` * - WPFront User Role Editor * - Capability Manager Enhanced >> Own filter: `capsman_get_capabilities` * - Pods * - Yoast SEO 5.8+ * * @since 1.6 */ $this->add_filter( 'members_get_capabilities', array( $this, 'get_vaa_capabilities' ) ); $this->add_action( 'members_register_cap_groups', array( $this, 'action_members_register_cap_group' ) ); /** * Add our caps to the User Role Editor plugin (URE). * @since 1.6.4 */ $this->add_filter( 'ure_capabilities_groups_tree', array( $this, 'filter_ure_capabilities_groups_tree' ) ); $this->add_filter( 'ure_custom_capability_groups', array( $this, 'filter_ure_custom_capability_groups' ), 10, 2 ); /** * Get all capabilities. * @since 1.5 */ $this->add_filter( 'view_admin_as_get_capabilities', array( $this, 'get_capabilities' ), 10, 2 ); /** * WP Admin UI Customize 1.5.11+. * @since 1.7.4 */ // wauc_admin_bar_default_load $this->add_filter( 'wauc_admin_bar_menu_add_nodes', array( $this, 'filter_wauc_admin_bar_menu_add_nodes' ), 10, 2 ); $this->add_filter( 'wauc_admin_bar_filter_load', array( $this, 'filter_wauc_admin_bar_filter_load' ) ); $this->add_filter( 'wauc_admin_bar_menu_widget_no_submenu', array( $this, 'filter_wauc_admin_bar_menu_widget_no_submenu' ) ); $this->add_filter( 'wauc_admin_bar_menu_widget_title_readonly_vaa', '__return_true' ); $this->add_filter( 'wauc_admin_bar_menu_widget_disable_target_vaa', '__return_true' ); } /** * Fix compatibility issues on load. * Called from 'vaa_view_admin_as_init' hook (after loading all data). * * @since 1.6.1 * @access public * @return void */ public function init_after() { if ( $this->store->get_view() && (int) $this->store->get_curUser()->ID === (int) $this->store->get_selectedUser()->ID ) { // Only apply the filter if the current user is modified. $this->add_filter( 'pods_is_admin', array( $this, 'filter_pods_caps_check' ), 99, 2 ); } } /** * Get's current capabilities and merges with capabilities from other plugins. * * @since 1.6 * @access public * @see \VAA_View_Admin_As_Compat::init() * * @param array $caps The capabilities. * @param bool[] $args Pass arguments to get only certain capabilities. * @return array Both key and values are the capabilities. */ public function get_capabilities( $caps = array(), $args = array() ) { $args = wp_parse_args( $args, array( 'vaa' => true, // Get VAA related capabilities? 'wp' => true, // Get WP core related capabilities? 'plugins' => true, // Get capabilities from plugin hooks and filters? ) ); if ( $args['vaa'] ) { $caps = $this->get_vaa_capabilities( $caps ); } if ( $args['wp'] ) { $caps = $this->get_wordpress_capabilities( $caps ); } if ( $args['plugins'] ) { $caps = $this->get_plugin_capabilities( $caps ); } // @since 1.8 Make sure both keys and values are capabilities. $all_caps = array(); foreach ( $caps as $cap_key => $cap ) { if ( is_string( $cap ) && ! is_numeric( $cap ) ) { $all_caps[ $cap ] = $cap; } else { $all_caps[ $cap_key ] = $cap_key; } } return $all_caps; } /** * Add our capabilities to an existing list of capabilities. * * @since 1.6 * @since 1.7.3 Renamed from add_capabilities(). * @access public * @see \VAA_View_Admin_As_Compat::init() * * @param array $caps The capabilities. * @return array */ public function get_vaa_capabilities( $caps = array() ) { // Allow VAA modules to add their capabilities. foreach ( (array) apply_filters( 'view_admin_as_add_capabilities', array( 'view_admin_as' ) ) as $cap ) { $caps[ $cap ] = $cap; } return $caps; } /** * Get all capabilities from WP core or WP objects. * * @since 1.7.1 * @param array $caps The capabilities. * @return array */ public function get_wordpress_capabilities( $caps = array() ) { // @since 1.7.1 Store available capabilities existing in roles. foreach ( $this->store->get_roles() as $key => $role ) { if ( is_array( $role->capabilities ) ) { foreach ( $role->capabilities as $cap => $grant ) { $caps[ (string) $cap ] = $cap; } } } /** * @since 1.7.1 Add post type and taxonomy caps. * @since 1.7.3 Prevent duplicate array keys. */ $wp_objects = array_merge( array_values( (array) get_post_types( array(), 'objects' ) ), array_values( (array) get_taxonomies( array(), 'objects' ) ) ); foreach ( $wp_objects as $obj ) { if ( isset( $obj->cap ) ) { // WP stores the object caps as general_cap_name => actual_cap. $caps = array_merge( array_combine( (array) $obj->cap, (array) $obj->cap ), $caps ); } } /** * Other WordPress capabilities. * @since 1.7.4 */ $caps = array_merge( array( // @since 4.9 'activate_plugin', 'deactivate_plugin', 'deactivate_plugins', 'install_languages', 'update_languages', ), $caps ); /** * Network capabilities. * @since 1.5.3 * @since 1.7.2 Added new WP 4.8 caps. * https://make.wordpress.org/core/2017/05/22/multisite-focused-changes-in-4-8/ * @see https://codex.wordpress.org/Roles_and_Capabilities */ if ( is_multisite() ) { $network_caps = array( 'manage_network', 'manage_sites', 'manage_network_users', 'manage_network_plugins', 'manage_network_themes', 'manage_network_options', ); if ( VAA_API::validate_wp_version( '4.8' ) ) { $network_caps[] = 'upgrade_network'; $network_caps[] = 'setup_network'; } $caps = array_merge( array_combine( $network_caps, $network_caps ), $caps ); } return $caps; } /** * Get all capabilities from other plugins. * * Disable some PHPMD checks for this method. * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @todo Refactor to enable above checks? * * @since 1.7.1 * @param array $caps The capabilities. * @return array */ public function get_plugin_capabilities( $caps = array() ) { // WooCommerce caps are not accessible but are assigned to roles on install. // get_wordpress_capabilities() will find them. // @since 1.7.1 Gravity Forms. if ( VAA_API::exists_callable( array( 'GFCommon', 'all_caps' ) ) ) { $caps = array_merge( (array) GFCommon::all_caps(), $caps ); } // @since 1.7.1 User Role Editor. if ( VAA_API::exists_callable( array( 'URE_Own_Capabilities', 'get_caps' ) ) ) { $caps = array_merge( (array) URE_Own_Capabilities::get_caps(), $caps ); } $caps = apply_filters( 'ure_full_capabilites', $caps ); // @since 1.7.1 WPFront User Role Editor. if ( class_exists( 'WPFront_User_Role_Editor' ) && ! empty( WPFront_User_Role_Editor::$ROLE_CAPS ) ) { $caps = array_merge( (array) WPFront_User_Role_Editor::$ROLE_CAPS, $caps ); } // @since 1.7.1 User Roles and Capabilities. if ( VAA_API::exists_callable( array( 'Solvease_Roles_Capabilities_User_Caps', 'solvease_roles_capabilities_caps' ) ) ) { $caps = array_merge( (array) Solvease_Roles_Capabilities_User_Caps::solvease_roles_capabilities_caps(), $caps ); } // @since 1.7.1 bbPress. if ( function_exists( 'bbp_get_caps_for_role' ) ) { if ( function_exists( 'bbp_get_keymaster_role' ) ) { $bbp_keymaster_role = bbp_get_keymaster_role(); } else { $bbp_keymaster_role = apply_filters( 'bbp_get_keymaster_role', 'bbp_keymaster' ); } $caps = array_merge( (array) bbp_get_caps_for_role( $bbp_keymaster_role ), $caps ); } // @since 1.7.1 BuddyPress. if ( class_exists( 'BuddyPress' ) ) { $caps = array_merge( array( 'bp_moderate', 'bp_xprofile_change_field_visibility', // @todo Check usage of capabilities below. /* 'throttle', 'keep_gate', 'moderate_comments', 'edit_cover_image', 'edit_avatar', 'edit_favorites', 'edit_favorites_of', 'add_tag_to', 'edit_tag_by_on', 'change_user_password', 'moderate', 'browse_deleted', 'view_by_ip', 'write_posts', 'write_topic', 'write_topics', 'move_topic', 'stick_topic', 'close_topic', 'edit_topic', 'delete_topic', 'delete_forum', 'manage_forums', 'manage_tags', */ ), // @see bp_get_community_caps() >> bp-core-caps.php. apply_filters( 'bp_get_community_caps', array() ), $caps ); } // End if(). // @since 1.7.4 Yoast SEO 5.5+ Load integration on front end. if ( ! is_admin() ) { /** * @since 1.8 Yoast SEO - Check for API function. * @link https://github.com/Yoast/wordpress-seo/pull/9365 */ if ( function_exists( 'wpseo_get_capabilities' ) ) { $caps = array_merge( (array) wpseo_get_capabilities(), $caps ); } elseif ( defined( 'WPSEO_VERSION' ) ) { $yoast_seo_caps = array( 'wpseo_bulk_edit', 'wpseo_edit_advanced_metadata', 'wpseo_manage_options', ); $caps = array_merge( $yoast_seo_caps, $caps ); } } // Members. if ( function_exists( 'members_get_plugin_capabilities' ) ) { $caps = array_merge( (array) members_get_plugin_capabilities(), $caps ); } // Get caps from multiple plugins through the Members filter. $caps = apply_filters( 'members_get_capabilities', $caps ); // Pods. $caps = apply_filters( 'pods_roles_get_capabilities', $caps ); return $caps; } /** * Fix compatibility issues Pods Framework 2.0+. * * @since 1.0.1 * @since 1.6 Moved to this class from main class. * @since 1.6.2 Check for all provided capabilities. * @access public * @see \VAA_View_Admin_As_Compat::init() * * @param bool $bool Boolean provided by the pods_is_admin hook (not used). * @param array $caps String or Array provided by the pods_is_admin hook. * @return bool */ public function filter_pods_caps_check( $bool, $caps ) { foreach ( (array) $caps as $capability ) { if ( $this->vaa->view()->current_view_can( $capability ) ) { return true; } } return false; } /** * Add our capabilities to our own group in the Members plugin. * * @see members_register_cap_group() * * @since 1.6 * @access public * @see \VAA_View_Admin_As_Compat::init() */ public function action_members_register_cap_group() { if ( ! function_exists( 'members_register_cap_group' ) ) { return; } // Register the vaa group. members_register_cap_group( 'view_admin_as', array( 'label' => esc_html__( 'View Admin As', VIEW_ADMIN_AS_DOMAIN ), 'caps' => $this->get_vaa_capabilities(), 'icon' => 'dashicons-visibility', 'diff_added' => true, ) ); } /** * Add our our own capability group in the URE plugin. * * @since 1.6.4 * @access public * @see \VAA_View_Admin_As_Compat::init() * @see \URE_Capabilities_Groups_Manager::get_groups_tree() * @param array $groups Current groups * @return array */ public function filter_ure_capabilities_groups_tree( $groups ) { $groups = (array) $groups; $groups['view_admin_as'] = array( 'caption' => esc_html__( 'View Admin As', VIEW_ADMIN_AS_DOMAIN ), 'parent' => 'custom', 'level' => 3, ); return $groups; } /** * Add our capabilities to our own group in the URE plugin. * * @since 1.6.4 * @access public * @see \VAA_View_Admin_As_Compat::init() * @see \URE_Capabilities_Groups_Manager::get_cap_groups() * @param array $groups Current capability groups * @param string $cap_id Capability identifier * @return array */ public function filter_ure_custom_capability_groups( $groups, $cap_id ) { if ( in_array( $cap_id, $this->get_vaa_capabilities(), true ) ) { $groups = (array) $groups; $groups[] = 'view_admin_as'; } return $groups; } /** * Force user setting location when WAUC is active. * * Disable some PHPMD checks for this method. * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @todo Refactor to enable above checks? * * @since 1.7.4 * @access public * @see \WP_Admin_UI_Customize::admin_bar_menu() * @param array $wauc_nodes * @param array $all_nodes * @return array */ public function filter_wauc_admin_bar_menu_add_nodes( $wauc_nodes, $all_nodes ) { $admin_menu_location = $this->store->get_userSettings( 'admin_menu_location' ); $vaa_root = VAA_View_Admin_As_Admin_Bar::$root; $check = array( 'depth' => 'main', ); if ( 'my-account' === $admin_menu_location ) { $check['depth'] = 'sub'; $check['location'] = 'right'; $check['parent'] = $admin_menu_location; } // Compat when this node is added twice. foreach ( $wauc_nodes as $location => $levels ) { foreach ( $levels as $depth => $nodes ) { foreach ( $nodes as $id => $node ) { if ( isset( $node['id'] ) && $vaa_root === $node['id'] ) { $current = array( 'depth' => $depth, 'location' => $location, 'parent' => $node['parent'], ); foreach ( $check as $key => $val ) { if ( $val !== $current[ $key ] ) { unset( $wauc_nodes[ $location ][ $depth ][ $id ] ); break; } } } } } } // Make sure all VAA nodes will be added. $wauc_nodes['vaa'] = array( 'sub' => array() ); foreach ( $all_nodes as $node ) { $id = ( ! empty( $node->id ) ) ? $node->id : null; if ( $vaa_root !== $id && 0 === strpos( $id, $vaa_root ) ) { $wauc_nodes['vaa']['sub'][] = (array) $node; } } return $wauc_nodes; } /** * Remove our nodes from the WAUC admin bar editor. * @since 1.7.4 * @access public * @see \WP_Admin_UI_Customize::admin_bar_filter_load() * @param array $all_nodes * @return array */ public function filter_wauc_admin_bar_filter_load( $all_nodes ) { if ( empty( $all_nodes['right'] ) ) { return $all_nodes; } $slug = VAA_View_Admin_As_Admin_Bar::$root; foreach ( (array) $all_nodes['right'] as $location => $nodes ) { if ( 0 !== strpos( $location, 'sub' ) ) { continue; } foreach ( $nodes as $key => $node ) { // Check if node ID starts with `vaa-` and node parent starts with `vaa`. if ( 0 === strpos( $node->id , $slug . '-' ) && 0 === strpos( $node->parent , $slug ) ) { unset( $all_nodes['right'][ $location ][ $key ] ); } } } return $all_nodes; } /** * Remove submenu options for WAUC. * @since 1.7.4 * @see \WP_Admin_UI_Customize::admin_bar_menu_widget() * @param array $no_submenu * @return array */ public function filter_wauc_admin_bar_menu_widget_no_submenu( $no_submenu ) { $no_submenu[] = VAA_View_Admin_As_Admin_Bar::$root; return $no_submenu; } /** * Main Instance. * * Ensures only one instance of this class is loaded or can be loaded. * * @since 1.6 * @access public * @static * @param \VAA_View_Admin_As $caller The referrer class. * @return \VAA_View_Admin_As_Compat $this */ public static function get_instance( $caller = null ) { if ( is_null( self::$_instance ) ) { self::$_instance = new self( $caller ); } return self::$_instance; } } // End class VAA_View_Admin_As_Compat.