├── assets ├── css │ ├── view-admin-as.css │ └── view-admin-as.min.css ├── img │ ├── loader-dark.gif │ └── loader.gif └── js │ ├── view-admin-as.js │ └── view-admin-as.min.js ├── includes ├── class-api.php ├── class-base.php ├── class-compat.php ├── class-controller.php ├── class-form.php ├── class-hooks.php ├── class-module.php ├── class-settings.php ├── class-store.php ├── class-type.php ├── class-update.php ├── class-util.php ├── class-vaa.php ├── class-view.php └── index.php ├── index.php ├── license.txt ├── modules ├── class-caps.php ├── class-groups.php ├── class-languages.php ├── class-restrict-user-access.php ├── class-role-defaults.php ├── class-role-manager.php ├── class-roles.php ├── class-users.php └── index.php ├── readme.txt ├── ui ├── class-admin-bar.php ├── class-toolbar.php ├── class-ui.php ├── index.php └── templates │ ├── adminbar-caps-actions.php │ ├── adminbar-caps-items.php │ ├── adminbar-language-items.php │ ├── adminbar-role-items.php │ ├── adminbar-settings-user.php │ ├── adminbar-user-actions.php │ ├── adminbar-user-items.php │ └── index.php ├── uninstall.php └── view-admin-as.php /assets/img/loader-dark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoryHogeveen/view-admin-as/b2c6e5c85fa5ea21519486cbf6eeaa07963a0993/assets/img/loader-dark.gif -------------------------------------------------------------------------------- /assets/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoryHogeveen/view-admin-as/b2c6e5c85fa5ea21519486cbf6eeaa07963a0993/assets/img/loader.gif -------------------------------------------------------------------------------- /includes/class-api.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * API class that is also extends utility functions. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.6.0 19 | * @version 1.8.7 20 | * @uses \VAA_Util Extends class 21 | */ 22 | final class VAA_API extends VAA_Util 23 | { 24 | /** 25 | * Check if a user has full access to this plugin. 26 | * 27 | * @since 1.8.0 28 | * @access public 29 | * @static 30 | * @api 31 | * 32 | * @param \WP_User|int $user The user to check. 33 | * @return bool 34 | */ 35 | public static function user_has_full_access( $user ) { 36 | if ( ! $user instanceof WP_User ) { 37 | $user = get_user_by( 'ID', $user ); 38 | if ( ! $user ) { 39 | return false; 40 | } 41 | } 42 | 43 | if ( is_multisite() ) { 44 | return is_super_admin( $user->ID ); 45 | } 46 | 47 | /** 48 | * For single installations is_super_admin() isn't enough since it only checks for `delete_users`. 49 | * @since 1.7.6 50 | * @link https://wordpress.org/support/topic/required-capabilities-2/ 51 | */ 52 | $caps = array( 53 | 'edit_users', 54 | 'delete_plugins', 55 | ); 56 | 57 | /** 58 | * Filter the capabilities required to gain full access to this plugin. 59 | * Note: Single site only! 60 | * Note: is_super_admin() is always checked! 61 | * 62 | * @since 1.8.0 63 | * @param array $caps The default capabilities. 64 | * @param \WP_User $user The user that is being validated. 65 | * @return array 66 | */ 67 | $caps = apply_filters( 'view_admin_as_full_access_capabilities', $caps, $user ); 68 | 69 | foreach ( $caps as $cap ) { 70 | if ( ! $user->has_cap( $cap ) ) { 71 | return false; 72 | } 73 | } 74 | 75 | return is_super_admin( $user->ID ); 76 | } 77 | 78 | /** 79 | * Check if the user is a super admin. 80 | * This check is more strict for single installations since it checks VAA_API::user_has_full_access. 81 | * It will validate the original user while in a view and no parameter is passed. 82 | * 83 | * @see \VAA_API::user_has_full_access() 84 | * @see \VAA_View_Admin_As_Store::cur_user_has_full_access() 85 | * 86 | * @since 1.6.3 87 | * @since 1.8.0 Check full access. 88 | * @access public 89 | * @static 90 | * @api 91 | * 92 | * @param int|\WP_User $user (optional) Default: current user. 93 | * @return bool 94 | */ 95 | public static function is_super_admin( $user = null ) { 96 | if ( null === $user || view_admin_as()->store()->is_curUser( $user ) ) { 97 | return view_admin_as()->store()->cur_user_has_full_access(); 98 | } 99 | 100 | return self::user_has_full_access( $user ); 101 | } 102 | 103 | /** 104 | * Check if the user is a superior admin. 105 | * It will validate the original user while in a view and no parameter is passed. 106 | * 107 | * @since 1.5.3 108 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 109 | * @since 1.6.3 Improve is_super_admin() check 110 | * @since 1.8.0 Enhance code to reflect VAA_API::is_super_admin() changes. 111 | * @access public 112 | * @static 113 | * @api 114 | * 115 | * @param int|\WP_User $user_id (optional) Default: current user. 116 | * @return bool 117 | */ 118 | public static function is_superior_admin( $user_id = null ) { 119 | 120 | // If it's the current user or null, don't pass the user ID to make sure we check the original user status. 121 | $is_super_admin = self::is_super_admin( 122 | ( null !== $user_id && view_admin_as()->store()->is_curUser( $user_id ) ) ? null : $user_id 123 | ); 124 | 125 | // Full access is required. 126 | if ( ! $is_super_admin ) { 127 | return false; 128 | } 129 | 130 | if ( null === $user_id ) { 131 | $user_id = view_admin_as()->store()->get_originalUserData( 'ID' ); 132 | } elseif ( $user_id instanceof WP_User ) { 133 | $user_id = $user_id->ID; 134 | } 135 | 136 | // Is it one of the manually configured superior admins? 137 | return (bool) ( in_array( (int) $user_id, self::get_superior_admins(), true ) ); 138 | } 139 | 140 | /** 141 | * Get the superior admin ID's (filter since 1.5.2). 142 | * 143 | * @since 1.5.3 144 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 145 | * @access public 146 | * @static 147 | * @api 148 | * 149 | * @return int[] 150 | */ 151 | public static function get_superior_admins() { 152 | static $superior_admins; 153 | if ( ! is_null( $superior_admins ) ) return $superior_admins; 154 | 155 | /** 156 | * Grant admins the capability to view other admins. There is no UI for this! 157 | * 158 | * @since 1.5.2 159 | * @param array 160 | * @return int[] Requires a returned array of user ID's 161 | */ 162 | $superior_admins = (array) apply_filters( 'view_admin_as_superior_admins', array() ); 163 | 164 | // Only allow unique numeric values (user id's). 165 | $superior_admins = array_unique( array_map( 'absint', array_filter( $superior_admins, 'is_numeric' ) ) ); 166 | 167 | return $superior_admins; 168 | } 169 | 170 | /** 171 | * Get the current active view. Returns `null` if no view (type) is active. 172 | * 173 | * @see \VAA_View_Admin_As_Store::get_view() 174 | * 175 | * @since 1.8.3 176 | * @access public 177 | * @static 178 | * @api 179 | * 180 | * @param string $type (optional) A view type. Will return `null` if this view type is not active. 181 | * @return mixed 182 | */ 183 | public static function get_current_view( $type = null ) { 184 | $store = view_admin_as()->store(); 185 | if ( $store ) { 186 | return $store->get_view( $type ); 187 | } 188 | return null; 189 | } 190 | 191 | /** 192 | * Get the human readable name(s) of a view. 193 | * 194 | * @since 1.8.7 195 | * @access public 196 | * @static 197 | * @api 198 | * 199 | * @param array $view (optional) View data. Will use the current view if omitted. 200 | * @param string|array $type (optional) A view type. Will return `null` if this view type is not active. 201 | * @return array 202 | */ 203 | public static function get_view_titles( $view = array(), $type = null ) { 204 | if ( ! $view ) { 205 | $view = self::get_current_view(); 206 | } 207 | $view = self::get_array_data( $view, $type ); 208 | 209 | if ( ! $view ) { 210 | return array(); 211 | } 212 | 213 | $titles = array(); 214 | 215 | /** 216 | * Filter what to show when a view is applied. 217 | * 218 | * @hooked 219 | * 5: user 220 | * 8: role 221 | * 10: group (Groups) 222 | * 10: rua_level (Restrict User Access) 223 | * 80: caps 224 | * 90: locale (Languages) 225 | * 999: role defaults (appends an icon) 226 | * 227 | * @since 1.8.7 228 | * 229 | * @param array $titles The current title(s). 230 | * @param array $view The view data. 231 | * 232 | * @return array 233 | */ 234 | $titles = apply_filters( 'vaa_view_admin_as_view_titles', $titles, $view ); 235 | 236 | return $titles; 237 | } 238 | 239 | /** 240 | * Is the current user in an active view. 241 | * 242 | * @since 1.8.4 243 | * @access public 244 | * @static 245 | * @api 246 | * 247 | * @param string $type (optional) Check for a single view type. 248 | * @return bool 249 | */ 250 | public static function is_view_active( $type = null ) { 251 | return (bool) self::get_current_view( $type ); 252 | } 253 | 254 | /** 255 | * Check if the provided data is the same as the current view. 256 | * 257 | * @see \VAA_View_Admin_As_Controller::is_current_view() 258 | * 259 | * @since 1.7.1 260 | * @access public 261 | * @static 262 | * @api 263 | * 264 | * @param mixed $data 265 | * @param bool $type Only compare a single view type instead of all view data? 266 | * If set, the data value should be the single view type data. 267 | * If data is `null` then it will return true if that view type is active. 268 | * If data is `false` then it will return true if this is the only active view type. 269 | * @return bool 270 | */ 271 | public static function is_current_view( $data, $type = null ) { 272 | $controller = view_admin_as()->controller(); 273 | if ( $controller ) { 274 | return $controller->is_current_view( $data, $type ); 275 | } 276 | return false; 277 | } 278 | 279 | /** 280 | * Is the current user modified? 281 | * Returns true if the currently active user's capabilities or roles are changed by the selected view. 282 | * 283 | * @see \VAA_View_Admin_As_View::current_view_can() 284 | * 285 | * @since 1.7.2 286 | * @access public 287 | * @static 288 | * @api 289 | * 290 | * @return bool 291 | */ 292 | public static function is_user_modified() { 293 | $view = view_admin_as()->view(); 294 | if ( $view ) { 295 | return $view->is_user_modified(); 296 | } 297 | return false; 298 | } 299 | 300 | /** 301 | * Similar function to current_user_can() but applies to the currently active view. 302 | * 303 | * @see \VAA_View_Admin_As_View::current_view_can() 304 | * 305 | * @since 1.7.2 306 | * @access public 307 | * @static 308 | * @api 309 | * 310 | * @param string $cap The capability. 311 | * @param array $caps (optional) Capabilities to compare to. 312 | * Defaults to the selected caps for the current view. 313 | * @return bool 314 | */ 315 | public static function current_view_can( $cap, $caps = array() ) { 316 | $view = view_admin_as()->view(); 317 | if ( $view ) { 318 | return $view->current_view_can( $cap, $caps ); 319 | } 320 | return false; 321 | } 322 | 323 | /** 324 | * Set the current view. 325 | * 326 | * @see \VAA_View_Admin_As_Controller::update() 327 | * @see \VAA_View_Admin_As_Controller::update_view() 328 | * 329 | * @since 1.8.3 330 | * @access public 331 | * @static 332 | * @api 333 | * 334 | * @param array $view The view. 335 | * @return bool 336 | */ 337 | public static function update_view( $view ) { 338 | $controller = view_admin_as()->controller(); 339 | if ( $controller ) { 340 | $view = array_intersect_key( $view, array_flip( $controller->get_view_types() ) ); 341 | $success = $controller->update( $view ); 342 | return ( true === $success ); 343 | } 344 | return false; 345 | } 346 | 347 | /** 348 | * Check if a view type is enabled. Pass an array to check multiple view types. 349 | * 350 | * @since 1.8.0 351 | * @access public 352 | * @static 353 | * @api 354 | * 355 | * @param string|array $type The view type key. 356 | * @return bool 357 | */ 358 | public static function is_view_type_enabled( $type ) { 359 | $type = view_admin_as()->get_view_types( $type ); 360 | if ( is_array( $type ) ) { 361 | foreach ( $type as $view_type ) { 362 | if ( ! $view_type instanceof VAA_View_Admin_As_Type || ! $view_type->is_enabled() ) { 363 | return false; 364 | } 365 | } 366 | return true; 367 | } 368 | if ( $type instanceof VAA_View_Admin_As_Type ) { 369 | return $type->is_enabled(); 370 | } 371 | return false; 372 | } 373 | 374 | /** 375 | * Generate a VAA action link. 376 | * 377 | * @since 1.7.0 378 | * @since 1.8.2 Switched $nonce and $url parameters order. 379 | * @access public 380 | * @static 381 | * @api 382 | * 383 | * @param array $data View type data. 384 | * @param string $url (optional) A URL. Of not passed it will generate a link from the current URL. 385 | * @param string $nonce (optional) Use a different nonce. Pass `false` to omit nonce. 386 | * @return string 387 | */ 388 | public static function get_vaa_action_link( $data, $url = null, $nonce = null ) { 389 | 390 | $params = array( 391 | 'action' => 'view_admin_as', 392 | 'view_admin_as' => $data, // wp_json_encode( array( $type, $data ) ), 393 | ); 394 | 395 | if ( null === $nonce ) { 396 | $nonce = view_admin_as()->store()->get_nonce( true ); 397 | } 398 | if ( $nonce ) { 399 | $params['_vaa_nonce'] = (string) $nonce; 400 | } 401 | 402 | // @todo fix WP referrer/nonce checks and allow switching on any page without ajax. 403 | // @see https://codex.wordpress.org/Function_Reference/check_admin_referer 404 | if ( null === $url ) { 405 | if ( is_admin() ) { 406 | $url = is_network_admin() ? network_admin_url() : admin_url(); 407 | } else { 408 | // Since 1.7.5 Frontend url. 409 | $url = get_site_url(); 410 | } 411 | } 412 | 413 | $url = add_query_arg( $params, ( $url ) ? $url : false ); 414 | 415 | return esc_url( $url, array( 'http', 'https' ) ); 416 | } 417 | 418 | /** 419 | * Appends the "reset-view" parameter to the current URL. 420 | * 421 | * @since 1.6.0 422 | * @access public 423 | * @static 424 | * @api 425 | * 426 | * @param string $url (optional) Supply the URL to create the reset link. 427 | * @param bool $all (optional) Reset all views link? 428 | * @return string 429 | */ 430 | public static function get_reset_link( $url = '', $all = false ) { 431 | $params = 'reset-view'; 432 | if ( $all ) { 433 | $params = 'reset-all-views'; 434 | } 435 | $url = add_query_arg( $params, '', ( $url ) ? $url : false ); 436 | return esc_url( $url, array( 'http', 'https' ) ); 437 | } 438 | 439 | /** 440 | * Removes the "reset-view" or "reset-all-views" parameter to the current URL. 441 | * 442 | * @since 1.6.0 443 | * @access public 444 | * @static 445 | * @api 446 | * 447 | * @param string $url (optional) Supply the URL to remove the reset link. 448 | * @return string 449 | */ 450 | public static function remove_reset_link( $url = '' ) { 451 | $url = remove_query_arg( array( 'reset-view', 'reset-all-views' ), ( $url ) ? $url : false ); 452 | return esc_url( $url, array( 'http', 'https' ) ); 453 | } 454 | 455 | /** 456 | * Is any toolbar showing? 457 | * Do not use this before the `init` hook. 458 | * 459 | * @since 1.7.0 460 | * @access public 461 | * @static 462 | * @api 463 | * 464 | * @return bool 465 | */ 466 | public static function is_toolbar_showing() { 467 | return (bool) ( is_admin_bar_showing() || self::is_vaa_toolbar_showing() ); 468 | } 469 | 470 | /** 471 | * Is our custom toolbar showing? 472 | * Do not use this before the `init` hook. 473 | * 474 | * @since 1.6.0 475 | * @access public 476 | * @static 477 | * @api 478 | * 479 | * @return bool 480 | */ 481 | public static function is_vaa_toolbar_showing() { 482 | 483 | if ( class_exists( 'VAA_View_Admin_As_Toolbar' ) ) { 484 | return (bool) VAA_View_Admin_As_Toolbar::$showing; 485 | } 486 | return false; 487 | } 488 | 489 | /** 490 | * Enhanced is_admin() function with AJAX support. 491 | * 492 | * @see is_admin() 493 | * 494 | * @since 1.7.4 495 | * @access public 496 | * @static 497 | * @api 498 | * 499 | * @return bool 500 | */ 501 | public static function is_admin() { 502 | if ( ! VAA_Util::doing_ajax() ) { 503 | return is_admin(); 504 | } 505 | // It's an ajax call, is_admin() would always return `true`. Compare the referrer url with the admin url. 506 | return ( false !== strpos( (string) wp_get_referer(), admin_url() ) ); 507 | } 508 | 509 | /** 510 | * Is the customizer admin container currently rendering? 511 | * 512 | * @since 1.7.6 513 | * @access public 514 | * @static 515 | * @api 516 | * 517 | * @return bool 518 | */ 519 | public static function is_customizer_admin() { 520 | return (bool) ( is_customize_preview() && is_admin() ); 521 | } 522 | 523 | 524 | /** 525 | * Is this a block editor page? 526 | * 527 | * @since 1.8.7 528 | * @access public 529 | * @static 530 | * @api 531 | * 532 | * @return bool 533 | */ 534 | public static function is_block_editor() { 535 | if ( ! function_exists( 'get_current_screen' ) ) { 536 | return false; 537 | } 538 | $screen = get_current_screen(); 539 | if ( method_exists( $screen, 'is_block_editor' ) ) { 540 | return $screen->is_block_editor(); 541 | } 542 | return false; 543 | } 544 | 545 | /** 546 | * Backwards compat method for apply_shortcodes() since WP 5.4. 547 | * @todo deprecate when 5.4 is the minimum version of WP. 548 | * 549 | * @since 1.8.6 550 | * @param string $content 551 | * @param bool $ignore_html 552 | * 553 | * @return string 554 | */ 555 | public static function apply_shortcodes( $content, $ignore_html = false ) { 556 | if ( function_exists( 'apply_shortcodes' ) ) { 557 | return apply_shortcodes( $content, $ignore_html ); 558 | } 559 | return do_shortcode( $content, $ignore_html ); 560 | } 561 | 562 | /** 563 | * Compare with the current WordPress version. 564 | * Returns true when it's the provided version or newer. 565 | * 566 | * @since 1.6.4 567 | * @since 1.7.2 Only check full version numbers by default. 568 | * @access public 569 | * @static 570 | * @api 571 | * 572 | * @global string $wp_version WordPress version. 573 | * @param int|string $version The WP version to check. 574 | * @param bool $only_full_versions Only validate full versions without dev notes (RC1, dev, etc). 575 | * @return bool 576 | */ 577 | public static function validate_wp_version( $version, $only_full_versions = true ) { 578 | global $wp_version; 579 | $version = strtolower( $version ); 580 | $compare = strtolower( $wp_version ); 581 | if ( $only_full_versions ) { 582 | // Only leave the version numbers. 583 | $version = explode( '-', $version ); 584 | $version = $version[0]; 585 | $compare = explode( '-', $compare ); 586 | $compare = $compare[0]; 587 | } 588 | return (bool) version_compare( $version, $compare, '<=' ); 589 | } 590 | 591 | } // End class VAA_API. 592 | -------------------------------------------------------------------------------- /includes/class-base.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * Base class that gets the VAA data from the main class. 15 | * Use this class as an extender for other classes. 16 | * 17 | * @author Jory Hogeveen 18 | * @package View_Admin_As 19 | * @since 1.5.0 20 | * @since 1.7.3 Renamed from `VAA_View_Admin_As_Class_Base`. 21 | * @version 1.8.7 22 | */ 23 | abstract class VAA_View_Admin_As_Base 24 | { 25 | /** 26 | * View Admin As object. 27 | * 28 | * @since 1.5.0 29 | * @var \VAA_View_Admin_As 30 | */ 31 | protected $vaa = null; 32 | 33 | /** 34 | * View Admin As store object. 35 | * 36 | * @since 1.6.0 37 | * @var \VAA_View_Admin_As_Store 38 | */ 39 | protected $store = null; 40 | 41 | /** 42 | * Custom capabilities. 43 | * 44 | * @since 1.6.0 45 | * @var string[] 46 | */ 47 | protected $capabilities = array(); 48 | 49 | /** 50 | * Construct function. 51 | * Protected to make sure it isn't declared elsewhere. 52 | * 53 | * @since 1.5.3 54 | * @since 1.6.0 `$vaa` param. 55 | * @access protected 56 | * @param \VAA_View_Admin_As $vaa (optional) Pass VAA object. 57 | */ 58 | protected function __construct( $vaa = null ) { 59 | // Load resources. 60 | $this->load_vaa( $vaa ); 61 | } 62 | 63 | /** 64 | * Init function to store data from the main class and enable functionality based on the current view. 65 | * 66 | * @since 1.5.0 67 | * @since 1.6.0 `$vaa` param. 68 | * @access public 69 | * @final 70 | * @param \VAA_View_Admin_As $vaa (optional) Pass VAA object. 71 | * @return void 72 | */ 73 | final public function load_vaa( $vaa = null ) { 74 | $this->vaa = $vaa; 75 | if ( ! is_object( $vaa ) || 'VAA_View_Admin_As' !== get_class( $vaa ) ) { 76 | $this->vaa = view_admin_as(); 77 | } 78 | if ( $this->vaa && 'VAA_View_Admin_As_Store' !== get_class( $this ) ) { 79 | $this->store = $this->vaa->store(); 80 | } 81 | } 82 | 83 | /** 84 | * Is the main functionality enabled? 85 | * 86 | * @since 1.5.0 87 | * @access public 88 | * @final 89 | * @return bool 90 | */ 91 | final public function is_vaa_enabled() { 92 | return (bool) $this->vaa->is_enabled(); 93 | } 94 | 95 | /** 96 | * Check if the AJAX call is ok. 97 | * Must always be used before AJAX data is processed. 98 | * 99 | * @since 1.7.0 100 | * @access public 101 | * @return bool 102 | */ 103 | public function is_valid_ajax() { 104 | if ( defined( 'VAA_DOING_AJAX' ) && VAA_DOING_AJAX && $this->is_vaa_enabled() ) { 105 | return true; 106 | } 107 | return false; 108 | } 109 | 110 | /** 111 | * Extender function for WP current_user_can(). 112 | * Also checks if VAA is enabled. 113 | * 114 | * @since 1.7.0 115 | * @access public 116 | * @param string $capability (optional) The capability to check when the user isn't a super admin. 117 | * @return bool 118 | */ 119 | public function current_user_can( $capability = null ) { 120 | if ( $capability ) { 121 | return ( $this->is_vaa_enabled() && ( VAA_API::is_super_admin() || current_user_can( $capability ) ) ); 122 | } 123 | return ( $this->is_vaa_enabled() && VAA_API::is_super_admin() ); 124 | } 125 | 126 | /** 127 | * Add capabilities. 128 | * Used for the _vaa_add_capabilities hook. 129 | * 130 | * @since 1.6.0 131 | * @access public 132 | * @param array $caps The capabilities. 133 | * @return string[] 134 | */ 135 | public function add_capabilities( $caps ) { 136 | foreach ( (array) $this->capabilities as $cap ) { 137 | $caps[ $cap ] = $cap; 138 | } 139 | return $caps; 140 | } 141 | 142 | /** 143 | * Add a new action to this plugin hooks registry. 144 | * 145 | * @since 1.8.0 146 | * @see \VAA_View_Admin_As_Hooks::add_action() 147 | * @inheritdoc 148 | */ 149 | public function add_action( $hook, $callback, $priority = 10, $accepted_args = 1 ) { 150 | view_admin_as()->hooks()->add_action( $hook, $callback, $priority, $accepted_args ); 151 | } 152 | 153 | /** 154 | * Add a new filter to this plugin hooks registry. 155 | * 156 | * @since 1.8.0 157 | * @see \VAA_View_Admin_As_Hooks::add_filter() 158 | * @inheritdoc 159 | */ 160 | public function add_filter( $hook, $callback, $priority = 10, $accepted_args = 1 ) { 161 | view_admin_as()->hooks()->add_filter( $hook, $callback, $priority, $accepted_args ); 162 | } 163 | 164 | /** 165 | * Run action using this plugin hooks registry. 166 | * 167 | * @since 1.8.7 168 | * @see \VAA_View_Admin_As_Hooks::do_action() 169 | * @inheritdoc 170 | */ 171 | public function do_action( $tag ) { 172 | return call_user_func_array( array( view_admin_as()->hooks(), 'do_action' ), func_get_args() ); 173 | } 174 | 175 | /** 176 | * Magic method to output a string if trying to use the object as a string. 177 | * 178 | * @since 1.5.1 179 | * @access public 180 | * @return string 181 | */ 182 | public function __toString() { 183 | return get_class( $this ); 184 | } 185 | 186 | /** 187 | * Magic method to keep the object from being cloned. 188 | * 189 | * @since 1.5.1 190 | * @access public 191 | * @return void 192 | */ 193 | public function __clone() { 194 | _doing_it_wrong( 195 | __FUNCTION__, 196 | esc_html( get_class( $this ) . ': ' . __( 'This class does not want to be cloned', VIEW_ADMIN_AS_DOMAIN ) ), 197 | null 198 | ); 199 | } 200 | 201 | /** 202 | * Magic method to keep the object from being unserialized. 203 | * 204 | * @since 1.5.1 205 | * @access public 206 | * @return void 207 | */ 208 | public function __wakeup() { 209 | _doing_it_wrong( 210 | __FUNCTION__, 211 | esc_html( get_class( $this ) . ': ' . __( 'This class does not want to wake up', VIEW_ADMIN_AS_DOMAIN ) ), 212 | null 213 | ); 214 | } 215 | 216 | /** 217 | * Magic method to prevent a fatal error when calling a method that does not exist. 218 | * 219 | * @since 1.5.1 220 | * @access public 221 | * @param string $method The method name. 222 | * @param array $args The method arguments. 223 | * @return null 224 | */ 225 | public function __call( $method = '', $args = array() ) { 226 | _doing_it_wrong( 227 | esc_html( get_class( $this ) . "::{$method}" ), 228 | esc_html__( 'Method does not exist.', VIEW_ADMIN_AS_DOMAIN ), 229 | null 230 | ); 231 | unset( $method, $args ); 232 | return null; 233 | } 234 | 235 | } // End class VAA_View_Admin_As_Class_Base. 236 | -------------------------------------------------------------------------------- /includes/class-module.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * Base class for modules that use option data etc. 15 | * Use this class as an extender for VAA modules other than view types. 16 | * 17 | * @author Jory Hogeveen 18 | * @package View_Admin_As 19 | * @since 1.5.0 (This was one class with VAA_View_Admin_As_Class_Base) 20 | * @version 1.8.4 21 | * @uses \VAA_View_Admin_As_Base Extends class 22 | */ 23 | abstract class VAA_View_Admin_As_Module extends VAA_View_Admin_As_Base 24 | { 25 | /** 26 | * Option key. 27 | * 28 | * @since 1.5.0 29 | * @var string 30 | */ 31 | protected $optionKey = ''; 32 | 33 | /** 34 | * Option data. 35 | * 36 | * @since 1.5.0 37 | * @var mixed 38 | */ 39 | protected $optionData = false; 40 | 41 | /** 42 | * Enable functionalities? 43 | * 44 | * @since 1.5.0 45 | * @var bool 46 | */ 47 | protected $enable = false; 48 | 49 | /** 50 | * Script localization data. 51 | * 52 | * @since 1.6.0 53 | * @var array 54 | */ 55 | protected $scriptLocalization = array(); 56 | 57 | /** 58 | * Is enabled? 59 | * 60 | * @since 1.5.0 61 | * @access public 62 | * @return bool 63 | */ 64 | public function is_enabled() { 65 | return (bool) $this->enable; 66 | } 67 | 68 | /** 69 | * Set plugin enabled true/false. 70 | * 71 | * @since 1.5.1 72 | * @since 1.6.2 Make database update optional. 73 | * @since 1.8.0 Make this method public. 74 | * @access public 75 | * @param bool $bool Enable or disable? 76 | * @param bool $update_db Do database update? (default true). 77 | * @return bool 78 | */ 79 | public function set_enable( $bool = false, $update_db = true ) { 80 | $success = true; 81 | if ( $update_db && $this->get_optionKey() ) { 82 | $success = $this->update_optionData( (bool) $bool, 'enable', true ); 83 | } 84 | if ( $success ) { 85 | $this->enable = (bool) $bool; 86 | } 87 | return $success; 88 | } 89 | 90 | /** 91 | * Helper function for ajax return data. 92 | * Merges second param with data defaults. 93 | * 94 | * @since 1.7.0 95 | * @access public 96 | * @param bool $success Success return. 97 | * @param array $data Array of detailed info. 98 | * @param string $type Notice type. 99 | * @return array 100 | */ 101 | public function ajax_data_return( $success, $data, $type = null ) { 102 | if ( ! is_string( $type ) ) { 103 | $type = ( $success ) ? 'success' : 'error'; 104 | } 105 | $defaults = array( 106 | 'display' => 'notice', 107 | 'type' => $type, 108 | ); 109 | return array( 110 | 'success' => (bool) $success, 111 | 'data' => array_merge( $defaults, $data ), 112 | ); 113 | } 114 | 115 | /** 116 | * Helper function for ajax notice return data. 117 | * Merges second param with data defaults. 118 | * 119 | * @since 1.7.0 120 | * @access public 121 | * @param bool $success Success return. 122 | * @param array $data Array of detailed info. 123 | * @param string $type Notice type. 124 | * @return array 125 | */ 126 | public function ajax_data_notice( $success, $data, $type = null ) { 127 | $data['display'] = 'notice'; 128 | return $this->ajax_data_return( $success, $data, $type ); 129 | } 130 | 131 | /** 132 | * Helper function for ajax popup return data. 133 | * Merges second param with data defaults. 134 | * 135 | * @since 1.7.0 136 | * @access public 137 | * @param bool $success Success return. 138 | * @param array $data Array of detailed info. 139 | * @param string $type Popup type. 140 | * @return array 141 | */ 142 | public function ajax_data_popup( $success, $data, $type = null ) { 143 | $data['display'] = 'popup'; 144 | return $this->ajax_data_return( $success, $data, $type ); 145 | } 146 | 147 | /** 148 | * Simple data validation. 149 | * Meant to be overwritten by subclass. 150 | * 151 | * @since 1.7.0 152 | * @access public 153 | * @param null $null Null. 154 | * @param mixed $data The view data. 155 | * @return mixed 156 | */ 157 | public function validate_view_data( $null, $data = null ) { 158 | if ( $data ) { 159 | return $data; 160 | } 161 | return $null; 162 | } 163 | 164 | /** 165 | * Get the class localisation strings 166 | * @param string $key (optional) Data key. 167 | * @return mixed 168 | */ 169 | public function get_scriptLocalization( $key = null ) { 170 | return VAA_API::get_array_data( $this->scriptLocalization, $key ); 171 | } 172 | 173 | /** 174 | * Get the option key as used in the options table. 175 | * @return string 176 | */ 177 | public function get_optionKey() { 178 | return (string) $this->optionKey; 179 | } 180 | 181 | /** 182 | * Get the class option data. 183 | * @param string $key (optional) Data key. 184 | * @return mixed 185 | */ 186 | public function get_optionData( $key = null ) { 187 | return VAA_API::get_array_data( $this->optionData, $key ); 188 | } 189 | 190 | /** 191 | * Set the class localisation strings 192 | * @param mixed $val Data. 193 | * @param string $key (optional) Data key. 194 | * @param bool $append (optional) Append if it doesn't exist? 195 | */ 196 | protected function set_scriptLocalization( $val, $key = null, $append = false ) { 197 | $this->scriptLocalization = (array) VAA_API::set_array_data( $this->scriptLocalization, $val, $key, $append ); 198 | } 199 | 200 | /** 201 | * Set the option key as used in the options table. 202 | * @param string $val Option key. 203 | */ 204 | protected function set_optionKey( $val ) { 205 | $this->optionKey = (string) $val; 206 | } 207 | 208 | /** 209 | * Set the class option data. 210 | * @param mixed $val Data. 211 | * @param string $key (optional) Data key. 212 | * @param bool $append (optional) Append if it doesn't exist? 213 | */ 214 | protected function set_optionData( $val, $key = null, $append = false ) { 215 | $this->optionData = VAA_API::set_array_data( $this->optionData, $val, $key, $append ); 216 | } 217 | 218 | /** 219 | * Update the class option data. 220 | * @param mixed $val Data. 221 | * @param string $key (optional) Data key. 222 | * @param bool $append (optional) Append if it doesn't exist? 223 | * @return bool 224 | */ 225 | protected function update_optionData( $val, $key = null, $append = false ) { 226 | $this->set_optionData( $val, $key, $append ); 227 | return update_option( $this->get_optionKey(), $this->optionData ); 228 | } 229 | 230 | } // End class VAA_View_Admin_As_Module. 231 | -------------------------------------------------------------------------------- /includes/class-store.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * Store class that stores the VAA data for use. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.6.0 19 | * @version 1.8.0 20 | * @uses \VAA_View_Admin_As_Settings Extends class 21 | */ 22 | final class VAA_View_Admin_As_Store extends VAA_View_Admin_As_Settings 23 | { 24 | /** 25 | * The single instance of the class. 26 | * 27 | * @since 1.6.0 28 | * @static 29 | * @var \VAA_View_Admin_As_Store 30 | */ 31 | private static $_instance = null; 32 | 33 | /** 34 | * The nonce. 35 | * 36 | * @since 1.3.4 37 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 38 | * @var string 39 | */ 40 | private $nonce = ''; 41 | 42 | /** 43 | * The parsed nonce. 44 | * 45 | * @since 1.6.2 46 | * @var string 47 | */ 48 | private $nonce_parsed = ''; 49 | 50 | /** 51 | * View type data. 52 | * You can add custom view data with VAA_View_Admin_As_Store::set_data(). 53 | * 54 | * @see \VAA_View_Admin_As_Store::set_data() 55 | * @since 1.7.0 56 | * @var array { 57 | * Default view data. 58 | * @type bool[] $caps Since 1.3.0 Array of available capabilities. 59 | * @type \WP_Role[] $roles Since 0.1.0 Array of available roles (WP_Role objects). 60 | * @type string[] $rolenames Since 1.6.4 Array of role names (used for role translations). 61 | * @type \WP_User[] $users Since 0.1.0 Array of available users (WP_User objects). 62 | * @type string[] $languages Since 1.8.0 Array of available locale/languages. 63 | * } 64 | */ 65 | private $data = array( 66 | 'caps' => array(), 67 | 'roles' => array(), 68 | 'rolenames' => array(), 69 | 'users' => array(), 70 | 'languages' => array(), 71 | ); 72 | 73 | /** 74 | * Current (initial) user object. 75 | * 76 | * @since 0.1.0 77 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 78 | * @var \WP_User 79 | */ 80 | private $curUser; 81 | 82 | /** 83 | * Current (initial) user session. 84 | * 85 | * @since 1.3.4 86 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 87 | * @var string 88 | */ 89 | private $curUserSession = ''; 90 | 91 | /** 92 | * Current (initial) user data. 93 | * Will contain all properties of the original current user object. 94 | * 95 | * @since 1.6.3 96 | * @since 1.7.3 Not static anymore. 97 | * @var array 98 | */ 99 | private $curUserData = array(); 100 | 101 | /** 102 | * Does the current (initial) user has full access to all features of this plugin? 103 | * 104 | * @since 1.6.3 105 | * @since 1.7.3 Not static anymore. 106 | * @since 1.7.6 Renamed from `$isCurUserSuperAdmin`. 107 | * @var bool 108 | */ 109 | private $curUserHasFullAccess = false; 110 | 111 | /** 112 | * Selected view data as stored in the user meta. 113 | * Format: array( VIEW_TYPE => VIEW_DATA ). 114 | * 115 | * @since 0.1.0 116 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 117 | * @var array 118 | */ 119 | private $view = array(); 120 | 121 | /** 122 | * The selected user object (if a view is selected). 123 | * Can be the same as $curUser depending on the selected view. 124 | * 125 | * @since 0.1.0 126 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 127 | * @var \WP_User 128 | */ 129 | private $selectedUser; 130 | 131 | /** 132 | * The selected capabilities (if a view is selected). 133 | * 134 | * @since 1.6.2 135 | * @var bool[] 136 | */ 137 | private $selectedCaps = array(); 138 | 139 | /** 140 | * Populate the instance. 141 | * @since 1.6.0 142 | */ 143 | protected function __construct() { 144 | parent::__construct( 'view-admin-as' ); 145 | self::$_instance = $this; 146 | 147 | $this->init( true ); 148 | } 149 | 150 | /** 151 | * Store the current user and other user related data. 152 | * 153 | * @since 1.6.3 Moved to this class. 154 | * @access public 155 | * @param bool $redo (optional) Force re-init? 156 | */ 157 | public function init( $redo = false ) { 158 | static $done = false; 159 | if ( $done && ! $redo ) return; 160 | 161 | $this->set_nonce( 'view-admin-as' ); 162 | 163 | // Get the current user. 164 | $this->set_curUser( wp_get_current_user() ); 165 | 166 | // Get the current user session (WP 4.0+). 167 | $this->set_curUserSession( (string) wp_get_session_token() ); 168 | 169 | $this->curUserHasFullAccess = VAA_API::user_has_full_access( $this->get_curUser() ); 170 | $this->curUserData = get_object_vars( $this->get_curUser() ); 171 | 172 | // Get database settings. 173 | $this->store_optionData( VAA_View_Admin_As::is_network_active() ); 174 | // Get database settings of the current user. 175 | $this->store_userMeta( get_current_user_id() ); 176 | 177 | $done = true; 178 | } 179 | 180 | /** 181 | * Does the current (original) user has full access to this plugin? 182 | * @since 1.8.0 183 | * @return bool 184 | */ 185 | public function cur_user_has_full_access() { 186 | return (bool) $this->curUserHasFullAccess; 187 | } 188 | 189 | /** 190 | * Compare user to the current (original) user. 191 | * 192 | * @since 1.8.0 193 | * @param \WP_User|int $user The user to compare. 194 | * @return bool 195 | */ 196 | public function is_curUser( $user ) { 197 | if ( $user instanceof WP_User ) { 198 | $user = $user->ID; 199 | } 200 | if ( ! is_numeric( $user ) ) { 201 | return false; 202 | } 203 | return (bool) ( (int) $this->get_curUser()->ID === (int) $user ); 204 | } 205 | 206 | /** 207 | * Helper function for is_super_admin(). 208 | * Will validate the original user if it is the current user or no user ID is passed. 209 | * This can prevent invalid checks after a view is applied. 210 | * 211 | * @see \VAA_API::is_super_admin() 212 | * @deprecated 1.8.0 213 | * @todo Remove in 1.9 214 | * 215 | * @since 1.6.3 216 | * @since 1.7.3 Not static anymore. 217 | * @access public 218 | * @param int $user_id (optional). 219 | * @return bool 220 | */ 221 | public function is_super_admin( $user_id = null ) { 222 | _deprecated_function( __FUNCTION__, '1.8', 'VAA_API::is_super_admin()' ); 223 | if ( null === $user_id || (int) $this->curUser->ID === (int) $user_id ) { 224 | return $this->curUserHasFullAccess; 225 | } 226 | return VAA_API::user_has_full_access( $user_id ); 227 | } 228 | 229 | /** 230 | * Get data from the current user, similar to the WP_User object. 231 | * Unlike the current user object this data isn't modified after in a view. 232 | * This has all public WP_User properties stored as an array. 233 | * 234 | * @since 1.6.3 235 | * @since 1.7.3 Not static anymore. 236 | * @access public 237 | * @param string $key (optional). 238 | * @return mixed 239 | */ 240 | public function get_originalUserData( $key = null ) { 241 | return VAA_API::get_array_data( $this->curUserData, $key ); 242 | } 243 | 244 | /** 245 | * Get current user. 246 | * @return \WP_User $curUser Current user object. 247 | */ 248 | public function get_curUser() { 249 | return $this->curUser; 250 | } 251 | 252 | /** 253 | * Get current user session. 254 | * @return string 255 | */ 256 | public function get_curUserSession() { 257 | return (string) $this->curUserSession; 258 | } 259 | 260 | /** 261 | * Get view data. 262 | * @since 1.7.0 263 | * @param string $key Key for array. 264 | * @return mixed 265 | */ 266 | public function get_view( $key = null ) { 267 | return VAA_API::get_array_data( $this->view, $key ); 268 | } 269 | 270 | /** 271 | * Get view type data 272 | * @since 1.7.0 273 | * @param string $type Type key. 274 | * @param string $key (optional) Type data key. 275 | * @return mixed 276 | */ 277 | public function get_data( $type, $key = null ) { 278 | if ( isset( $this->data[ $type ] ) ) { 279 | return VAA_API::get_array_data( $this->data[ $type ], $key ); 280 | } 281 | return null; 282 | } 283 | 284 | /** 285 | * Get available capabilities. 286 | * @param string $key Cap name. 287 | * @return bool[]|bool Array of capabilities or a single capability value. 288 | */ 289 | public function get_caps( $key = null ) { 290 | return $this->get_data( 'caps', $key ); 291 | } 292 | 293 | /** 294 | * Get available roles. 295 | * @param string $key Role slug/key. 296 | * @return \WP_Role[]|\WP_Role Array of role objects or a single role object. 297 | */ 298 | public function get_roles( $key = null ) { 299 | return $this->get_data( 'roles', $key ); 300 | } 301 | 302 | /** 303 | * Get the role names. Translated by default. 304 | * If key is provided but not found it will return the key (untranslated). 305 | * @since 1.6.4 306 | * @param string $key Role slug. 307 | * @param bool $translate Translate the role name? 308 | * @return string[]|string 309 | */ 310 | public function get_rolenames( $key = null, $translate = true ) { 311 | $val = $this->get_data( 'rolenames', $key ); 312 | if ( ! $val ) { 313 | 314 | /** 315 | * Try to fetch role name from WP core. No security risk here. 316 | * Check for the wp_roles() function in WP 4.3+. 317 | * @since 1.8.0 318 | */ 319 | if ( function_exists( 'wp_roles' ) ) { 320 | $wp_roles = wp_roles(); 321 | } else { 322 | global $wp_roles; 323 | } 324 | if ( isset( $wp_roles->role_names[ $key ] ) ) { 325 | $this->set_rolenames( $wp_roles->role_names[ $key ], $key, true ); 326 | return $this->get_rolenames( $key, $translate ); 327 | } 328 | 329 | return ( $key ) ? $key : $val; 330 | } 331 | if ( $translate ) { 332 | if ( is_array( $val ) ) { 333 | $val = array_map( 'translate_user_role', $val ); 334 | } else { 335 | $val = translate_user_role( $val ); 336 | } 337 | } 338 | return $val; 339 | } 340 | 341 | /** 342 | * Get available users. 343 | * @param string $key User key. 344 | * @return \WP_User[]|\WP_User Array of user objects or a single user object. 345 | */ 346 | public function get_users( $key = null ) { 347 | return $this->get_data( 'users', $key ); 348 | } 349 | 350 | /** 351 | * Get available languages. 352 | * @since 1.8.0 353 | * @param string $key Locale key. 354 | * @return string[]|string Array of language names or a single language name. 355 | */ 356 | public function get_languages( $key = null ) { 357 | return $this->get_data( 'languages', $key ); 358 | } 359 | 360 | /** 361 | * Get the selected user object of a view. 362 | * @return \WP_User 363 | */ 364 | public function get_selectedUser() { 365 | return $this->selectedUser; 366 | } 367 | 368 | /** 369 | * Get selected capabilities of a view. 370 | * @param string $key Cap name. 371 | * @return bool[]|bool Array of capabilities or a single capability value. 372 | */ 373 | public function get_selectedCaps( $key = null ) { 374 | return VAA_API::get_array_data( $this->selectedCaps, $key ); 375 | } 376 | 377 | /** 378 | * Get the nonce. 379 | * @param string $parsed Return parsed nonce? 380 | * @return string 381 | */ 382 | public function get_nonce( $parsed = null ) { 383 | return ( $parsed ) ? $this->nonce_parsed : $this->nonce; 384 | } 385 | 386 | /** 387 | * Get plugin version. 388 | * @todo Move to API. 389 | * @return string 390 | */ 391 | public function get_version() { 392 | return strtolower( (string) VIEW_ADMIN_AS_VERSION ); 393 | } 394 | 395 | /** 396 | * Get plugin database version. 397 | * @todo Move to API. 398 | * @return string 399 | */ 400 | public function get_dbVersion() { 401 | return strtolower( (string) VIEW_ADMIN_AS_DB_VERSION ); 402 | } 403 | 404 | /** 405 | * Set the current user object. 406 | * @param \WP_User $val User object. 407 | * @return void 408 | */ 409 | public function set_curUser( WP_User $val ) { 410 | $this->curUser = $val; 411 | } 412 | 413 | /** 414 | * Set the current user session. 415 | * @param string $val User session ID. 416 | * @return void 417 | */ 418 | public function set_curUserSession( $val ) { 419 | $this->curUserSession = (string) $val; 420 | } 421 | 422 | /** 423 | * Set the view data. 424 | * @param mixed $val Value. 425 | * @param string $key (optional) View key. 426 | * @param bool $append (optional) Append if it doesn't exist? 427 | * @return void 428 | */ 429 | public function set_view( $val, $key = null, $append = false ) { 430 | $this->view = (array) VAA_API::set_array_data( $this->view, $val, $key, $append ); 431 | } 432 | 433 | /** 434 | * Set view type data. 435 | * 436 | * @since 1.7.0 437 | * @param string $type 438 | * @param mixed $val 439 | * @param string $key 440 | * @param bool $append 441 | * @return void 442 | */ 443 | public function set_data( $type, $val, $key = null, $append = false ) { 444 | if ( VAA_API::exists_callable( array( $this, 'set_' . $type ) ) ) { 445 | $method = 'set_' . $type; 446 | $this->$method( $val, $key, $append ); 447 | return; 448 | } 449 | $current = ( isset( $this->data[ $type ] ) ) ? $this->data[ $type ] : array(); 450 | $this->data[ $type ] = (array) VAA_API::set_array_data( $current, $val, $key, $append ); 451 | } 452 | 453 | /** 454 | * Set the available capabilities. 455 | * @param mixed $val Value. 456 | * @param string $key (optional) Cap key. 457 | * @param bool $append (optional) Append if it doesn't exist? 458 | * @return void 459 | */ 460 | public function set_caps( $val, $key = null, $append = false ) { 461 | $this->data['caps'] = (array) VAA_API::set_array_data( $this->data['caps'], $val, $key, $append ); 462 | } 463 | 464 | /** 465 | * Set the available roles. 466 | * @param mixed $val Value. 467 | * @param string $key (optional) Role name. 468 | * @param bool $append (optional) Append if it doesn't exist? 469 | * @return void 470 | */ 471 | public function set_roles( $val, $key = null, $append = false ) { 472 | $this->data['roles'] = (array) VAA_API::set_array_data( $this->data['roles'], $val, $key, $append ); 473 | } 474 | 475 | /** 476 | * Set the role name translations. 477 | * @since 1.6.4 478 | * @param mixed $val Value. 479 | * @param string $key (optional) Role name. 480 | * @param bool $append (optional) Append if it doesn't exist? 481 | * @return void 482 | */ 483 | public function set_rolenames( $val, $key = null, $append = false ) { 484 | $this->data['rolenames'] = (array) VAA_API::set_array_data( $this->data['rolenames'], $val, $key, $append ); 485 | } 486 | 487 | /** 488 | * Set the available users. 489 | * @param mixed $val Value. 490 | * @param string $key (optional) User key. 491 | * @param bool $append (optional) Append if it doesn't exist? 492 | * @return void 493 | */ 494 | public function set_users( $val, $key = null, $append = false ) { 495 | $this->data['users'] = (array) VAA_API::set_array_data( $this->data['users'], $val, $key, $append ); 496 | } 497 | 498 | /** 499 | * Set the languages. 500 | * @since 1.8.0 501 | * @param mixed $val Value. 502 | * @param string $key (optional) Role name. 503 | * @param bool $append (optional) Append if it doesn't exist? 504 | * @return void 505 | */ 506 | public function set_languages( $val, $key = null, $append = false ) { 507 | $this->data['languages'] = (array) VAA_API::set_array_data( $this->data['languages'], $val, $key, $append ); 508 | } 509 | 510 | /** 511 | * Set the selected user object for the current view. 512 | * @param \WP_User $val User object. 513 | * @return void 514 | */ 515 | public function set_selectedUser( $val ) { 516 | $this->selectedUser = $val; 517 | } 518 | 519 | /** 520 | * Set the selected capabilities for the current view. 521 | * @param array $val Selected capabilities. 522 | * @return void 523 | */ 524 | public function set_selectedCaps( $val ) { 525 | $this->selectedCaps = array_filter( (array) $val ); 526 | } 527 | 528 | /** 529 | * Set the nonce. 530 | * Also sets a parsed version of the nonce with wp_create_nonce(). 531 | * @param string $val Nonce. 532 | * @return void 533 | */ 534 | public function set_nonce( $val ) { 535 | $this->nonce = (string) $val; 536 | $this->nonce_parsed = wp_create_nonce( (string) $val ); 537 | } 538 | 539 | /** 540 | * Main Instance. 541 | * 542 | * Ensures only one instance of this class is loaded or can be loaded. 543 | * 544 | * @since 1.6.0 545 | * @access public 546 | * @static 547 | * @param \VAA_View_Admin_As $caller The referrer class. 548 | * @return \VAA_View_Admin_As_Store $this 549 | */ 550 | public static function get_instance( $caller = null ) { 551 | if ( is_null( self::$_instance ) ) { 552 | self::$_instance = new self( $caller ); 553 | } 554 | return self::$_instance; 555 | } 556 | 557 | } // End class VAA_View_Admin_As_Store. 558 | -------------------------------------------------------------------------------- /includes/class-type.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * View Type class base. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.8.0 19 | * @version 1.8.7 20 | * @uses \VAA_View_Admin_As_Base Extends class 21 | */ 22 | abstract class VAA_View_Admin_As_Type extends VAA_View_Admin_As_Base 23 | { 24 | /** 25 | * View type settings. 26 | * 27 | * @since 1.8.0 28 | * @var array 29 | */ 30 | private $settings = array( 31 | 'enabled' => true, 32 | ); 33 | 34 | /** 35 | * The view type. 36 | * 37 | * @since 1.8.0 38 | * @var string 39 | */ 40 | protected $type = ''; 41 | 42 | /** 43 | * The view type label. 44 | * 45 | * @since 1.8.0 46 | * @var string 47 | */ 48 | protected $label = ''; 49 | 50 | /** 51 | * The view type singular label. 52 | * 53 | * @since 1.8.0 54 | * @var string 55 | */ 56 | protected $label_singular = ''; 57 | 58 | /** 59 | * The view type description. 60 | * 61 | * @since 1.8.0 62 | * @var string 63 | */ 64 | protected $description = ''; 65 | 66 | /** 67 | * The icon for this view type. 68 | * 69 | * @since 1.8.0 70 | * @var string 71 | */ 72 | protected $icon = ''; 73 | 74 | /** 75 | * Selected view. 76 | * 77 | * @since 1.8.0 78 | * @var mixed 79 | */ 80 | protected $selected = null; 81 | 82 | /** 83 | * Does the original user has access? 84 | * 85 | * @since 1.8.0 86 | * @var bool 87 | */ 88 | protected $user_has_access = false; 89 | 90 | /** 91 | * The hook priorities for this type. 92 | * 93 | * @since 1.8.0 94 | * @var int[] 95 | */ 96 | protected $priorities = array( 97 | 'toolbar' => 10, 98 | 'view_title' => 10, 99 | 'validate_view_data' => 10, 100 | 'update_view' => 10, 101 | 'do_view' => 10, 102 | ); 103 | 104 | /** 105 | * The capability required for this view type. 106 | * 107 | * @since 1.8.0 108 | * @var string 109 | */ 110 | protected $cap = 'view_admin_as'; 111 | 112 | /** 113 | * Populate the instance. 114 | * 115 | * @since 1.8.0 116 | * @access protected 117 | * @param \VAA_View_Admin_As $vaa The main VAA object. 118 | */ 119 | protected function __construct( $vaa ) { 120 | static $done; 121 | if ( ! $done ) { 122 | $this->add_filter( 'view_admin_as_update_global_settings', array( 'VAA_View_Admin_As_Type', 'filter_update_view_types' ), 1, 3 ); 123 | $done = true; 124 | } 125 | 126 | parent::__construct( $vaa ); 127 | 128 | $this->vaa->register_view_type( array( 129 | 'id' => $this->type, 130 | 'instance' => $this, 131 | ) ); 132 | 133 | $this->user_has_access = $this->current_user_can( $this->cap ); 134 | 135 | if ( ! $this->has_access() ) { 136 | return; 137 | } 138 | 139 | $view_types = $this->store->get_settings( 'view_types' ); 140 | if ( isset( $view_types[ $this->type ] ) ) { 141 | $this->settings = $view_types[ $this->type ]; 142 | } 143 | 144 | if ( $this->is_enabled() ) { 145 | $this->add_action( 'vaa_view_admin_as_pre_init', array( $this, 'setup' ) ); 146 | 147 | if ( did_action( 'init' ) ) { 148 | $this->init(); 149 | } else { 150 | $this->add_action( 'init', array( $this, 'init' ) ); 151 | } 152 | } 153 | } 154 | 155 | /** 156 | * Does the original user has access to this view type? 157 | * 158 | * @since 1.8.0 159 | * @access public 160 | * @return bool 161 | */ 162 | public function has_access() { 163 | return (bool) ( $this->is_vaa_enabled() && $this->user_has_access ); 164 | } 165 | 166 | /** 167 | * Is enabled? 168 | * 169 | * @since 1.8.0 170 | * @access public 171 | * @return bool 172 | */ 173 | public function is_enabled() { 174 | return ( ! empty( $this->settings['enabled'] ) ); 175 | } 176 | 177 | /** 178 | * Set plugin enabled true/false. 179 | * 180 | * @since 1.8.0 181 | * @access public 182 | * @param bool $bool Enable or disable? 183 | * @param bool $update_db Do database update? (default true). 184 | * @return bool 185 | */ 186 | public function set_enable( $bool = false, $update_db = true ) { 187 | $success = true; 188 | if ( $update_db ) { 189 | $success = $this->update_settings( (bool) $bool, 'enable', true ); 190 | } 191 | if ( $success ) { 192 | $this->settings['enabled'] = (bool) $bool; 193 | } 194 | return $success; 195 | } 196 | 197 | /** 198 | * Setup module and hooks. 199 | * 200 | * @since 1.8.0 Renamed from init() 201 | * @since 1.8.10 202 | * @access protected 203 | * @return bool Successful setup? 204 | */ 205 | public function setup() { 206 | 207 | $this->store_data(); 208 | 209 | if ( $this->has_access() && $this->get_data() ) { 210 | $this->init_hooks(); 211 | return true; 212 | } 213 | 214 | return false; 215 | } 216 | 217 | /** 218 | * Init module and hooks. 219 | * 220 | * @since 1.8.10 221 | * @access protected 222 | * @return bool Successful init? 223 | */ 224 | public function init() { 225 | return true; 226 | } 227 | 228 | /** 229 | * Setup hooks. 230 | * 231 | * @since 1.8.0 232 | * @access protected 233 | */ 234 | protected function init_hooks() { 235 | 236 | $this->add_action( 'vaa_admin_bar_menu', array( $this, 'admin_bar_menu' ), $this->get_priority( 'toolbar' ), 2 ); 237 | 238 | $this->add_filter( 'view_admin_as_validate_view_data_' . $this->type, array( $this, 'validate_view_data' ), $this->get_priority( 'validate_view_data' ), 3 ); 239 | $this->add_filter( 'view_admin_as_update_view_' . $this->type, array( $this, 'update_view' ), $this->get_priority( 'update_view' ), 3 ); 240 | 241 | $this->add_action( 'vaa_view_admin_as_do_view', array( $this, 'do_view' ), $this->get_priority( 'do_view' ) ); 242 | 243 | $this->add_filter( 'vaa_view_admin_as_view_titles', array( $this, 'view_title' ), $this->get_priority( 'view_title' ), 2 ); 244 | } 245 | 246 | /** 247 | * Apply this view type if active. 248 | * 249 | * @since 1.8.0 250 | * @access public 251 | * @return bool Is this view type active? 252 | */ 253 | public function do_view() { 254 | 255 | $this->selected = $this->store->get_view( $this->type ); 256 | 257 | if ( $this->selected ) { 258 | return true; 259 | } 260 | return false; 261 | } 262 | 263 | /** 264 | * Helper method for the view object. 265 | * Adds the actions and filters to modify the current user object. 266 | * Can only be run once. 267 | * 268 | * @since 1.8.0 269 | * @access public 270 | * @return void 271 | */ 272 | public function init_user_modifications() { 273 | $this->vaa->view()->init_user_modifications(); 274 | } 275 | 276 | /** 277 | * View update handler (Ajax probably), called from main handler. 278 | * 279 | * @since 1.8.0 Renamed from `ajax_handler()`. 280 | * @access public 281 | * @param null $null Null. 282 | * @param array $data The ajax data for this module. 283 | * @param string $type The view type. 284 | * @return bool 285 | */ 286 | public function update_view( $null, $data, $type = null ) { 287 | 288 | if ( $type !== $this->type ) { 289 | return $null; 290 | } 291 | 292 | if ( $this->get_data( $data ) ) { 293 | $this->store->set_view( $data, $this->type, true ); 294 | return true; 295 | } 296 | return false; 297 | } 298 | 299 | /** 300 | * Validate data for this view type 301 | * 302 | * @since 1.8.0 303 | * @access public 304 | * @param null $null Default return (invalid) 305 | * @param mixed $data The view data 306 | * @return mixed 307 | */ 308 | abstract public function validate_view_data( $null, $data = null ); 309 | 310 | /** 311 | * Add the admin bar items. 312 | * 313 | * @since 1.8.0 314 | * @access public 315 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 316 | * @param string $root The root item. 317 | */ 318 | abstract public function admin_bar_menu( $admin_bar, $root ); 319 | 320 | /** 321 | * Store the available languages. 322 | * 323 | * @since 1.8.0 324 | * @access private 325 | */ 326 | abstract public function store_data(); 327 | 328 | /** 329 | * Update the view titles if this view is selected. 330 | * 331 | * @since 1.8.0 332 | * @since 1.8.7 Added second required `$view` param and convert to default method. 333 | * @access public 334 | * @param array $titles The current title(s). 335 | * @param array $view The view data. 336 | * @return array 337 | */ 338 | public function view_title( $titles, $view ) { 339 | if ( isset( $view[ $this->type ] ) ) { 340 | $title = $this->get_view_title( $view[ $this->type ] ); 341 | if ( $title ) { 342 | $titles[ $this->label_singular ] = $title; 343 | } 344 | } 345 | return $titles; 346 | } 347 | 348 | /** 349 | * Set the view type data. 350 | * 351 | * @since 1.8.0 352 | * @access public 353 | * @param mixed $val 354 | * @param string $key (optional) The data key. 355 | * @param bool $append (optional) Append if it doesn't exist? 356 | */ 357 | public function set_data( $val, $key = null, $append = true ) { 358 | $this->store->set_data( $this->type, $val, $key, $append ); 359 | } 360 | 361 | /** 362 | * Get the view type data. 363 | * 364 | * @since 1.8.0 365 | * @access public 366 | * @param string $key (optional) The data key. 367 | * @return mixed 368 | */ 369 | public function get_data( $key = null ) { 370 | return $this->store->get_data( $this->type, $key ); 371 | } 372 | 373 | /** 374 | * Get the view type id. 375 | * 376 | * @since 1.8.0 377 | * @access public 378 | * @return string 379 | */ 380 | public function get_type() { 381 | return $this->type; 382 | } 383 | 384 | /** 385 | * Get the view type label. 386 | * 387 | * @since 1.8.0 388 | * @access public 389 | * @return string 390 | */ 391 | public function get_label() { 392 | return $this->label; 393 | } 394 | 395 | /** 396 | * Get the view type singular label. 397 | * 398 | * @since 1.8.0 399 | * @access public 400 | * @return string 401 | */ 402 | public function get_label_singular() { 403 | return $this->label_singular; 404 | } 405 | 406 | /** 407 | * Get the view type description. 408 | * 409 | * @since 1.8.0 410 | * @access public 411 | * @return string 412 | */ 413 | public function get_description() { 414 | return $this->description; 415 | } 416 | 417 | /** 418 | * Get the view title. 419 | * 420 | * @since 1.8.7 421 | * @param string $key The data key. 422 | * @return string 423 | */ 424 | public function get_view_title( $key ) { 425 | $title = $this->get_data( $key ); 426 | 427 | /** 428 | * Change the display title for view type nodes. 429 | * 430 | * @since 1.8.0 431 | * @param string $title View title. 432 | * @param string $key View data key. 433 | * @return string 434 | */ 435 | $title = apply_filters( 'vaa_admin_bar_view_title_' . $this->type, $title, $key ); 436 | 437 | return $title; 438 | } 439 | 440 | /** 441 | * Get an action priority. 442 | * Default: toolbar priority. 443 | * 444 | * @since 1.8.0 445 | * @param string $key 446 | * @return int 447 | */ 448 | public function get_priority( $key = 'toolbar' ) { 449 | return (int) ( isset( $this->priorities[ $key ] ) ) ? $this->priorities[ $key ] : 10; 450 | } 451 | 452 | /** 453 | * Get the view type settings. 454 | * 455 | * @since 1.8.0 456 | * @param string $key Key in the setting array. 457 | * @return mixed 458 | */ 459 | final public function get_settings( $key = null ) { 460 | return VAA_API::get_array_data( $this->settings, $key ); 461 | } 462 | 463 | /** 464 | * Set the view type settings. 465 | * 466 | * @since 1.8.0 467 | * @param mixed $val Settings. 468 | * @param string $key (optional) Setting key. 469 | * @param bool $append (optional) Append if it doesn't exist? 470 | * @return void 471 | */ 472 | final public function set_settings( $val, $key = null, $append = false ) { 473 | $this->settings = VAA_API::set_array_data( $this->settings, $val, $key, $append ); 474 | 475 | $view_types = (array) $this->store->get_settings( 'view_types' ); 476 | 477 | $view_types[ $this->type ] = $this->get_settings(); 478 | 479 | $settings = array( 480 | 'view_types' => $view_types, 481 | ); 482 | $this->store->set_settings( $settings ); 483 | } 484 | 485 | 486 | /** 487 | * Update the view type settings in the database. 488 | * Also sets the settings within this instance and VAA store. 489 | * 490 | * @since 1.8.0 491 | * @param mixed $val Settings. 492 | * @param string $key (optional) Setting key. 493 | * @param bool $append (optional) Append if it doesn't exist? 494 | * @return bool 495 | */ 496 | final public function update_settings( $val, $key = null, $append = false ) { 497 | $this->set_settings( $val, $key, $append ); // Also updates store. 498 | return $this->store->update_optionData( $this->store->get_optionData() ); 499 | } 500 | 501 | /** 502 | * Update the active view types. 503 | * 504 | * @since 1.8.0 505 | * @static 506 | * @param array $data 507 | * @return mixed 508 | */ 509 | final public static function filter_update_view_types( $data ) { 510 | if ( empty( $data['view_types'] ) ) { 511 | return $data; 512 | } 513 | 514 | foreach ( $data['view_types'] as $type => $settings ) { 515 | $type = view_admin_as()->get_view_types( $type ); 516 | if ( ! $type instanceof VAA_View_Admin_As_Type ) { 517 | unset( $data['view_types'][ $type ] ); 518 | continue; 519 | } 520 | $type->set_settings( $settings ); 521 | } 522 | 523 | $data['view_types'] = view_admin_as()->store()->get_settings( 'view_types' ); 524 | 525 | return $data; 526 | } 527 | 528 | } // End class VAA_View_Admin_As_Type. 529 | -------------------------------------------------------------------------------- /includes/class-update.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * Update class used for version control and updates. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.6.0 19 | * @version 1.7.4 20 | * @uses \VAA_View_Admin_As_Base Extends class 21 | */ 22 | final class VAA_View_Admin_As_Update extends VAA_View_Admin_As_Base 23 | { 24 | /** 25 | * The single instance of the class. 26 | * 27 | * @since 1.6.0 28 | * @static 29 | * @var \VAA_View_Admin_As_Update 30 | */ 31 | private static $_instance = null; 32 | 33 | /** 34 | * Is this a new installation? 35 | * 36 | * @since 1.7.0 37 | * @static 38 | * @var bool 39 | */ 40 | public static $fresh_install = false; 41 | 42 | /** 43 | * Populate the instance. 44 | * 45 | * @since 1.6.0 46 | * @since 1.6.1 `$vaa` param. 47 | * @access protected 48 | * @param \VAA_View_Admin_As $vaa The main VAA object. 49 | */ 50 | protected function __construct( $vaa ) { 51 | self::$_instance = $this; 52 | parent::__construct( $vaa ); 53 | } 54 | 55 | /** 56 | * Check the correct DB version in the DB. 57 | * 58 | * @since 1.4.0 59 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 60 | * @access public 61 | * @return void 62 | */ 63 | public function maybe_db_update() { 64 | $db_version = strtolower( (string) $this->store->get_optionData( 'db_version' ) ); 65 | if ( ! $db_version ) { 66 | self::$fresh_install = true; 67 | } 68 | if ( self::$fresh_install || version_compare( $db_version, $this->store->get_dbVersion(), '<' ) ) { 69 | $this->db_update(); 70 | } 71 | } 72 | 73 | /** 74 | * Update settings. 75 | * 76 | * @since 1.4.0 77 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 78 | * @access private 79 | * @return void 80 | */ 81 | private function db_update() { 82 | $defaults = array( 83 | 'db_version' => $this->store->get_dbVersion(), 84 | ); 85 | 86 | $current_db_version = strtolower( (string) $this->store->get_optionData( 'db_version' ) ); 87 | 88 | // No need to run update script if it's a clean installation. 89 | if ( $current_db_version ) { 90 | 91 | // Clear the user views for update to 1.5+. 92 | if ( version_compare( $current_db_version, '1.5', '<' ) ) { 93 | /** 94 | * Reset user meta for all users. 95 | * @since 1.6.2 Use `all` param from delete_user_meta(). 96 | */ 97 | $this->store->delete_user_meta( 'all', false, true ); // true for reset_only. 98 | // Reset currently loaded data. 99 | $this->store->set_userMeta( false ); 100 | } 101 | 102 | if ( version_compare( $current_db_version, '1.7.2', '<' ) ) { 103 | $this->update_1_7_2(); 104 | } 105 | } 106 | 107 | // Update version, append if needed. 108 | $this->store->set_optionData( $this->store->get_dbVersion(), 'db_version', true ); 109 | // Update option data. 110 | $this->store->update_optionData( wp_parse_args( $this->store->get_optionData(), $defaults ) ); 111 | 112 | // Main update finished, hook used to update modules. 113 | $this->do_action( 'vaa_view_admin_as_db_update' ); 114 | } 115 | 116 | /** 117 | * Update to version 1.7.2. 118 | * Changes yes/no options to boolean types. 119 | * 120 | * @since 1.7.2 121 | * @access private 122 | * @return void 123 | */ 124 | private function update_1_7_2() { 125 | 126 | $meta = $this->store->get_all_user_meta(); 127 | 128 | foreach ( $meta as $user_id => $values ) { 129 | foreach ( $values as $column_id => $value ) { 130 | if ( ! empty( $value['settings'] ) && is_array( $value['settings'] ) ) { 131 | foreach ( $value['settings'] as $key => $val ) { 132 | if ( is_bool( $val ) ) { 133 | // Update already done. 134 | continue; 135 | } 136 | if ( in_array( $key, array( 'force_group_users', 'freeze_locale', 'hide_front' ), true ) ) { 137 | $value['settings'][ $key ] = ( 'yes' === $val ); 138 | } 139 | } 140 | $this->store->update_other_user_meta( $value, $user_id, $column_id ); 141 | } 142 | } 143 | } 144 | 145 | // Re-init VAA store. 146 | $this->store->init( true ); 147 | } 148 | 149 | /** 150 | * Main Instance. 151 | * 152 | * Ensures only one instance of this class is loaded or can be loaded. 153 | * 154 | * @since 1.6.0 155 | * @access public 156 | * @static 157 | * @param \VAA_View_Admin_As $caller The referrer class. 158 | * @return \VAA_View_Admin_As_Update $this 159 | */ 160 | public static function get_instance( $caller = null ) { 161 | if ( is_null( self::$_instance ) ) { 162 | self::$_instance = new self( $caller ); 163 | } 164 | return self::$_instance; 165 | } 166 | 167 | } // End class VAA_View_Admin_As_Update. 168 | -------------------------------------------------------------------------------- /includes/class-util.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * Utility class that holds general functions. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.8.5 19 | * @version 1.8.7 20 | */ 21 | abstract class VAA_Util 22 | { 23 | /** 24 | * Get full array or array key(s). 25 | * 26 | * @since 1.5.0 27 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 28 | * @since 1.7.5 Option to pass an array of keys. Will always return an array (even if not found) + third require_all option. 29 | * @access public 30 | * @static 31 | * @api 32 | * 33 | * @param array $array The requested array. 34 | * @param string|array $key (optional) Return only a key of the requested array. 35 | * @param bool $require_all (optional) In case of an array of keys, return `null` if not all keys are present? 36 | * @return mixed 37 | */ 38 | public static function get_array_data( $array, $key = null, $require_all = false ) { 39 | $return = $array; 40 | if ( null !== $key ) { 41 | $return = null; 42 | if ( ! is_array( $array ) ) { 43 | return $return; // Key's not available in non-arrays. 44 | } 45 | // @since 1.7.5 Search for multiple keys. 46 | if ( is_array( $key ) ) { 47 | $return = array(); 48 | foreach ( $key as $k ) { 49 | if ( isset( $array[ $k ] ) ) { 50 | $return[ $k ] = $array[ $k ]; 51 | } 52 | } 53 | if ( $require_all && array_diff_key( array_flip( $key ), $return ) ) { 54 | $return = null; // Not all keys found. 55 | } 56 | } elseif ( isset( $array[ $key ] ) ) { 57 | $return = $array[ $key ]; // Key found. 58 | } 59 | } 60 | return $return; 61 | } 62 | 63 | /** 64 | * Set full array or array key. 65 | * 66 | * @since 1.5.0 67 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 68 | * @access public 69 | * @static 70 | * @api 71 | * 72 | * @param array $array Original array. 73 | * @param mixed $var The new value. 74 | * @param string $key (optional) The array key for the value. 75 | * @param bool $append (optional) If the key doesn't exist in the original array, append it. 76 | * @return mixed 77 | */ 78 | public static function set_array_data( $array, $var, $key = null, $append = false ) { 79 | if ( null !== $key ) { 80 | if ( true === $append && ! is_array( $array ) ) { 81 | $array = array(); 82 | } 83 | if ( is_array( $array ) && ( true === $append || isset( $array[ $key ] ) ) ) { 84 | $array[ $key ] = $var; 85 | return $array; 86 | } 87 | 88 | // Notify user if in debug mode 89 | _doing_it_wrong( 90 | __METHOD__, 91 | 'View Admin As: Key ' . esc_html( (string) $key ) . ' does not exist', 92 | null 93 | ); 94 | 95 | // return no changes if key is not found or appending is not allowed. 96 | return $array; 97 | } 98 | return $var; 99 | } 100 | 101 | /** 102 | * Check if two arrays are the same. 103 | * Does NOT support recursive arrays! 104 | * 105 | * @since 1.7.0 106 | * @access public 107 | * @static 108 | * @api 109 | * 110 | * @param array $array1 Array one. 111 | * @param array $array2 Array two. 112 | * @param bool $recursive (optional) Compare recursively. 113 | * @param bool $strict (optional) Strict comparison? Only available when comparing recursive. 114 | * @return bool 115 | */ 116 | public static function array_equal( $array1, $array2, $recursive = true, $strict = false ) { 117 | if ( ! is_array( $array1 ) || ! is_array( $array2 ) ) { 118 | return false; 119 | } 120 | if ( $recursive ) { 121 | return ( 122 | self::array_diff_assoc_recursive( $array1, $array2, $strict ) === self::array_diff_assoc_recursive( $array2, $array1, $strict ) 123 | ); 124 | } 125 | // Check for recursive arrays. 126 | $arr1 = array_filter( $array1, 'is_scalar' ); 127 | $arr2 = array_filter( $array2, 'is_scalar' ); 128 | if ( $array1 !== $arr1 || $array2 !== $arr2 ) { 129 | return false; 130 | } 131 | return ( 132 | count( $arr1 ) === count( $arr2 ) && 133 | array_diff_assoc( $arr1, $arr2 ) === array_diff_assoc( $arr2, $arr1 ) 134 | ); 135 | } 136 | 137 | /** 138 | * Recursive version of `array_diff_assoc()`. 139 | * 140 | * @since 1.7.3 141 | * @access public 142 | * @static 143 | * @api 144 | * 145 | * @param array $array1 Array one. 146 | * @param array $array2 Array two. 147 | * @param bool $strict Strict comparison? 148 | * @return array 149 | */ 150 | public static function array_diff_assoc_recursive( $array1, $array2, $strict = false ) { 151 | $return = array(); 152 | 153 | foreach ( $array1 as $key => $value ) { 154 | if ( array_key_exists( $key, $array2 ) ) { 155 | if ( is_array( $value ) ) { 156 | if ( is_array( $array2[ $key ] ) ) { 157 | $diff = self::array_diff_assoc_recursive( $value, $array2[ $key ], $strict ); 158 | if ( $diff ) { 159 | $return[ $key ] = $diff; 160 | } 161 | } else { 162 | $return[ $key ] = $value; 163 | } 164 | } else { 165 | if ( $strict ) { 166 | if ( $value !== $array2[ $key ] ) { 167 | $return[ $key ] = $value; 168 | } 169 | } else { 170 | if ( (string) $value !== (string) $array2[ $key ] ) { 171 | $return[ $key ] = $value; 172 | } 173 | } 174 | } 175 | } else { 176 | $return[ $key ] = $value; 177 | } 178 | } 179 | 180 | return $return; 181 | } 182 | 183 | /** 184 | * Check if an array has a key and optional compare or validate the value. 185 | * 186 | * @since 1.7.0 187 | * @access public 188 | * @static 189 | * @api 190 | * 191 | * @param array $array 192 | * @param string $key 193 | * @param array $args { 194 | * Optional array of match arguments. 195 | * @type mixed $compare A value to compare against (NOTE: strict comparison!). 196 | * @type callable $validation A variable function check, example: 'is_int' or 'MyClass::check'. 197 | * } 198 | * @return bool 199 | */ 200 | public static function array_has( $array, $key, $args = array() ) { 201 | $isset = ( isset( $array[ $key ] ) ); 202 | if ( empty( $args ) || ! $isset ) { 203 | return $isset; 204 | } 205 | $value = $array[ $key ]; 206 | if ( isset( $args['compare'] ) ) { 207 | return ( $args['compare'] === $value ); 208 | } 209 | if ( ! empty( $args['validation'] ) ) { 210 | // Don't accept unavailable validation methods. 211 | if ( is_callable( $args['validation'] ) ) { 212 | return (bool) call_user_func( $args['validation'], $value ); 213 | } 214 | } 215 | return false; 216 | } 217 | 218 | /** 219 | * Does a string starts with a given string? 220 | * 221 | * @since 1.4.0 222 | * @since 1.7.0 Moved from `VAA_View_Admin_As_Role_Defaults`. 223 | * @access public 224 | * @static 225 | * @api 226 | * 227 | * @param string $haystack The string to search in. 228 | * @param string $needle The string to search for. 229 | * @return bool 230 | */ 231 | public static function starts_with( $haystack, $needle ) { 232 | // Search backwards starting from haystack length characters from the end. 233 | return '' === $needle || 0 === strpos( $haystack, $needle ); 234 | } 235 | 236 | /** 237 | * Does a string ends with a given string? 238 | * 239 | * @since 1.4.0 240 | * @since 1.7.0 Moved from `VAA_View_Admin_As_Role_Defaults`. 241 | * @access public 242 | * @static 243 | * @api 244 | * 245 | * @param string $haystack The string to search in. 246 | * @param string $needle The string to search for. 247 | * @return bool 248 | */ 249 | public static function ends_with( $haystack, $needle ) { 250 | // Search forward starting from end minus needle length characters. 251 | return '' === $needle || ( strlen( $haystack ) - strlen( $needle ) === strrpos( $haystack, $needle ) ); 252 | } 253 | 254 | /** 255 | * Enhancement for is_callable(), also check for class_exists() or method_exists() when an array is passed. 256 | * Prevents incorrect `true` when a class has a __call() method. 257 | * Can also handle error notices. 258 | * 259 | * @since 1.7.4 260 | * @access public 261 | * @static 262 | * @api 263 | * 264 | * @param callable|array $callable The callable data. 265 | * @param bool|string $do_notice Add an error notice when it isn't? 266 | * Pass `debug` to only show notice when WP_DEBUG is enabled. 267 | * @param bool $syntax_only See is_callable() docs. 268 | * @return bool 269 | */ 270 | public static function exists_callable( $callable, $do_notice = false, $syntax_only = false ) { 271 | $pass = is_callable( $callable, $syntax_only ); 272 | if ( $pass && is_array( $callable ) ) { 273 | if ( 1 === count( $callable ) ) { 274 | $pass = class_exists( $callable[0] ); 275 | } else { 276 | $pass = method_exists( $callable[0], $callable[1] ); 277 | } 278 | } 279 | if ( ! $pass && $do_notice ) { 280 | if ( 'debug' === $do_notice ) { 281 | $do_notice = ( defined( 'WP_DEBUG' ) && WP_DEBUG ); 282 | } 283 | if ( ! is_string( $do_notice ) ) { 284 | $callable = self::callable_to_string( $callable ); 285 | $do_notice = sprintf( 286 | // Translators: %s stands for the requested class, method or function. 287 | __( '%s does not exist or is not callable.', VIEW_ADMIN_AS_DOMAIN ), 288 | '' . $callable . '' 289 | ); 290 | } 291 | view_admin_as()->add_error_notice( $callable, $do_notice ); 292 | } 293 | return (bool) $pass; 294 | } 295 | 296 | /** 297 | * Convert callable variable to string for display. 298 | * 299 | * @since 1.7.4 300 | * @access public 301 | * @static 302 | * @api 303 | * 304 | * @param callable|array $callable 305 | * @return string 306 | */ 307 | public static function callable_to_string( $callable ) { 308 | if ( is_string( $callable ) ) { 309 | return $callable; 310 | } 311 | if ( is_object( $callable ) ) { 312 | $callable = array( $callable, '' ); 313 | } 314 | if ( is_array( $callable ) ) { 315 | if ( is_object( $callable[0] ) ) { 316 | $callable[0] = get_class( $callable[0] ); 317 | $callable = implode( '->', $callable ); 318 | } else { 319 | $callable = implode( '::', $callable ); 320 | } 321 | } 322 | return (string) $callable; 323 | } 324 | 325 | /** 326 | * AJAX request validator. Verifies caller and nonce. 327 | * Returns the requested data. 328 | * 329 | * @since 1.7.0 330 | * @access public 331 | * @static 332 | * @api 333 | * 334 | * @param string $nonce The nonce to validate 335 | * @param string $key The key to fetch. 336 | * @param string $type The type of request. 337 | * @return mixed 338 | */ 339 | public static function get_ajax_request( $nonce, $key = null, $type = 'post' ) { 340 | if ( self::doing_ajax() ) { 341 | return self::get_request( $nonce, $key, $type ); 342 | } 343 | return null; 344 | } 345 | 346 | /** 347 | * Normal request validator. Verifies caller and nonce. 348 | * Returns the requested data. 349 | * 350 | * @since 1.7.0 351 | * @access public 352 | * @static 353 | * @api 354 | * 355 | * @param string $nonce The nonce to validate 356 | * @param string $key The key to fetch. 357 | * @param string $type The type of request. 358 | * @return mixed 359 | */ 360 | public static function get_normal_request( $nonce, $key = null, $type = 'post' ) { 361 | if ( ! self::doing_ajax() ) { 362 | return self::get_request( $nonce, $key, $type ); 363 | } 364 | return null; 365 | } 366 | 367 | /** 368 | * Request validator. Verifies caller and nonce. 369 | * Returns the requested data. 370 | * 371 | * @since 1.7.0 372 | * @access public 373 | * @static 374 | * @api 375 | * 376 | * @param string $nonce The nonce to validate 377 | * @param string $key The key to fetch. 378 | * @param string $type The type of request. 379 | * @return mixed 380 | */ 381 | public static function get_request( $nonce, $key = null, $type = 'post' ) { 382 | // @codingStandardsIgnoreLine >> Ignore $_GET and $_POST issues. 383 | $data = ( 'get' === strtolower( (string) $type ) ) ? $_GET : $_POST; 384 | if ( isset( $data[ $key ] ) && isset( $data['_vaa_nonce'] ) && wp_verify_nonce( $data['_vaa_nonce'], $nonce ) ) { 385 | $request = self::get_array_data( $data, $key ); 386 | $request = self::maybe_json_decode( $request, true, true ); 387 | return $request; 388 | } 389 | return null; 390 | } 391 | 392 | /** 393 | * JSON request check. 394 | * 395 | * @since 1.8.7 396 | * @access public 397 | * @static 398 | * @api 399 | * 400 | * @param string $key The key to fetch. 401 | * @param string $type The type of request. 402 | * @return bool 403 | */ 404 | public static function is_json_request( $key = null, $type = 'post' ) { 405 | if ( self::doing_json() ) { 406 | return self::is_request( $key, $type ); 407 | } 408 | return false; 409 | } 410 | 411 | /** 412 | * AJAX request check. 413 | * 414 | * @since 1.7.0 415 | * @access public 416 | * @static 417 | * @api 418 | * 419 | * @param string $key The key to fetch. 420 | * @param string $type The type of request. 421 | * @return bool 422 | */ 423 | public static function is_ajax_request( $key = null, $type = 'post' ) { 424 | if ( self::doing_ajax() ) { 425 | return self::is_request( $key, $type ); 426 | } 427 | return false; 428 | } 429 | 430 | /** 431 | * Normal request check. 432 | * 433 | * @since 1.7.0 434 | * @access public 435 | * @static 436 | * @api 437 | * 438 | * @param string $key The key to fetch. 439 | * @param string $type The type of request. 440 | * @return bool 441 | */ 442 | public static function is_normal_request( $key = null, $type = 'post' ) { 443 | if ( ! self::doing_ajax() ) { 444 | return self::is_request( $key, $type ); 445 | } 446 | return false; 447 | } 448 | 449 | /** 450 | * Check if there is a request made. 451 | * 452 | * @since 1.7.0 453 | * @since 1.8.8 Support for any request type. 454 | * @access public 455 | * @static 456 | * @api 457 | * 458 | * @param string $key The key to check. 459 | * @param string $type The type of request. 460 | * @return bool 461 | */ 462 | public static function is_request( $key = null, $type = 'post' ) { 463 | if ( ! $key && ! $type ) { 464 | // Any request. 465 | return true; 466 | } 467 | 468 | // @codingStandardsIgnoreLine >> Ignore $_GET and $_POST issues. 469 | $data = ( 'get' === strtolower( (string) $type ) ) ? $_GET : $_POST; 470 | if ( isset( $data[ $key ] ) ) { 471 | return true; 472 | } 473 | return false; 474 | } 475 | 476 | /** 477 | * Check if the current request is for JSON/REST. 478 | * Also check WP 5.0 function wp_is_json_request(). 479 | * 480 | * @see wp_is_json_request() 481 | * 482 | * @since 1.8.8 483 | * @access public 484 | * @static 485 | * @api 486 | * 487 | * @return bool 488 | */ 489 | public static function doing_json() { 490 | if ( function_exists( 'wp_is_json_request' ) ) { 491 | return wp_is_json_request(); 492 | } 493 | // Fallback to referer. 494 | return ( false !== strpos( (string) wp_get_referer(), '/wp-json/' ) ); 495 | } 496 | 497 | /** 498 | * Check if the current request is AJAX. 499 | * Also check WP 4.7 function wp_doing_ajax(). 500 | * 501 | * @see wp_doing_ajax() 502 | * 503 | * @since 1.8.5 504 | * @access public 505 | * @static 506 | * @api 507 | * 508 | * @return bool 509 | */ 510 | public static function doing_ajax() { 511 | // @todo VAA_DOING_AJAX handler 512 | if ( function_exists( 'wp_doing_ajax' ) ) { 513 | return wp_doing_ajax(); 514 | } 515 | return ! defined( 'DOING_AJAX' ) || ! DOING_AJAX; 516 | } 517 | 518 | /** 519 | * Check if the value contains JSON. 520 | * It the value is an array it will be parsed recursively. 521 | * 522 | * @link https://stackoverflow.com/questions/6041741/fastest-way-to-check-if-a-string-is-json-in-php 523 | * 524 | * @since 1.7.5 525 | * @access public 526 | * @static 527 | * @api 528 | * 529 | * @param mixed $value The value to be checked for JSON data. 530 | * @param bool $assoc See json_decode(). 531 | * @param bool $decode Decode with html_entity_decode() and stripcslashes()? 532 | * @return mixed 533 | */ 534 | public static function maybe_json_decode( $value, $assoc = true, $decode = false ) { 535 | if ( ! is_string( $value ) ) { 536 | if ( is_array( $value ) ) { 537 | foreach ( $value as $key => $val ) { 538 | $value[ $key ] = self::maybe_json_decode( $val, $assoc, $decode ); 539 | } 540 | } 541 | return $value; 542 | } 543 | if ( 0 !== strpos( $value, '[' ) && 0 !== strpos( $value, '{' ) ) { 544 | return $value; 545 | } 546 | if ( $decode ) { 547 | $value = stripcslashes( html_entity_decode( $value ) ); 548 | } 549 | $var = json_decode( $value, $assoc ); 550 | if ( null !== $var ) { 551 | return $var; 552 | } 553 | return $value; 554 | } 555 | 556 | /** 557 | * Check if debug is enabled. 558 | * 559 | * @since 1.8.7 560 | * @access public 561 | * @static 562 | * @api 563 | * 564 | * @return bool 565 | */ 566 | public static function debug() { 567 | return defined( 'WP_DEBUG' ) && WP_DEBUG; 568 | } 569 | 570 | } // End class VAA_Util. 571 | -------------------------------------------------------------------------------- /includes/class-view.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * View handler class. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.6.0 19 | * @since 1.7.0 Class got split up: data handling/updating is now in VAA_View_Admin_As_Controller. 20 | * @version 1.8.7 21 | * @uses \VAA_View_Admin_As_Base Extends class 22 | */ 23 | final class VAA_View_Admin_As_View extends VAA_View_Admin_As_Base 24 | { 25 | /** 26 | * The single instance of the class. 27 | * 28 | * @since 1.6.0 29 | * @static 30 | * @var \VAA_View_Admin_As_View 31 | */ 32 | private static $_instance = null; 33 | 34 | /** 35 | * Is the current user modified? 36 | * 37 | * @since 1.7.2 38 | * @var bool 39 | */ 40 | private $is_user_modified = false; 41 | 42 | /** 43 | * VAA_View_Admin_As_View constructor. 44 | * 45 | * @since 1.6.0 46 | * @since 1.6.1 `$vaa` param. 47 | * @access protected 48 | * @param \VAA_View_Admin_As $vaa The main VAA object. 49 | */ 50 | protected function __construct( $vaa ) { 51 | self::$_instance = $this; 52 | parent::__construct( $vaa ); 53 | } 54 | 55 | /** 56 | * Initializes after VAA is enabled. 57 | * 58 | * @since 1.6.0 59 | * @access public 60 | * @return void 61 | */ 62 | public function init() { 63 | if ( VAA_API::is_view_active() ) { 64 | $this->do_view(); 65 | } 66 | } 67 | 68 | /** 69 | * Apply view data. 70 | * 71 | * @since 1.6.3 Put logic in it's own function. 72 | * @access private 73 | * @return void 74 | */ 75 | private function do_view() { 76 | 77 | // @since 1.6.4 Set the current user as the selected user by default. 78 | $this->store->set_selectedUser( $this->store->get_curUser() ); 79 | $this->store->set_selectedCaps( $this->store->get_curUser()->allcaps ); 80 | 81 | /** 82 | * VISITOR. 83 | * Current user object views (switches current user). 84 | * 85 | * @since 1.6.2 Visitor view. 86 | */ 87 | if ( $this->store->get_view( 'visitor' ) ) { 88 | 89 | /** 90 | * Change current user object so changes can be made on various screen settings. 91 | * wp_set_current_user() returns the new user object. 92 | * 93 | * If it is a visitor view it will convert the false return from 'user' to 0. 94 | */ 95 | $this->store->set_selectedUser( wp_set_current_user( 0 ) ); 96 | 97 | // @since 1.6.2 Set the caps for this view (user view). 98 | if ( isset( $this->store->get_selectedUser()->allcaps ) ) { 99 | $this->store->set_selectedCaps( $this->store->get_selectedUser()->allcaps ); 100 | } 101 | } 102 | 103 | /** 104 | * View data is set, apply the view. 105 | * This hook can be used by other modules to enable a view. 106 | * 107 | * Temporary modifications to the current user are set on priority 99. 108 | * This functionality has a separate action: `vaa_view_admin_as_modify_current_user`. 109 | * 110 | * @hooked 111 | * 2: user 112 | * 5: role 113 | * 8: caps 114 | * 10: locale (Languages) 115 | * 10: group (Groups) 116 | * 10: rua_level (Restrict User Access) 117 | * 118 | * @since 1.6.3 119 | * @param array 120 | */ 121 | $this->do_action( 'vaa_view_admin_as_do_view', $this->store->get_view() ); 122 | 123 | /** 124 | * Force own locale on view. 125 | * 126 | * @since 1.6.1 127 | * @since 1.7.5 Add filter `view_admin_as_freeze_locale`. 128 | * 129 | * @param bool $freeze_locale The user setting. 130 | * @return bool 131 | */ 132 | $freeze_locale = apply_filters( 'view_admin_as_freeze_locale', $this->store->get_userSettings( 'freeze_locale' ) ); 133 | if ( $freeze_locale && (int) $this->store->get_curUser()->ID !== (int) $this->store->get_selectedUser()->ID ) { 134 | $this->add_action( 'after_setup_theme', array( $this, 'freeze_locale' ), 0 ); 135 | } 136 | } 137 | 138 | /** 139 | * Adds the actions and filters to modify the current user object. 140 | * Can only be run once. 141 | * 142 | * @since 1.6.3 143 | * @access public 144 | * @return void 145 | */ 146 | public function init_user_modifications() { 147 | static $done; 148 | if ( $done ) return; 149 | 150 | $this->is_user_modified = true; 151 | 152 | $this->add_action( 'vaa_view_admin_as_do_view', array( $this, 'modify_user' ), 99 ); 153 | 154 | /** 155 | * Make sure the $current_user view data isn't overwritten again by switch_blog functions. 156 | * @see This filter is documented in wp-includes/ms-blogs.php 157 | * @since 1.6.3 158 | */ 159 | $this->add_action( 'switch_blog', array( $this, 'modify_user' ) ); 160 | 161 | /** 162 | * Prevent some meta updates for the current user while in modification to the current user are active. 163 | * @since 1.6.3 164 | */ 165 | $this->add_filter( 'update_user_metadata', array( $this, 'filter_prevent_update_user_metadata' ), 999999999, 3 ); 166 | 167 | /** 168 | * Get capabilities and user level from current user view object instead of database. 169 | * @since 1.6.4 170 | */ 171 | $this->add_filter( 'get_user_metadata', array( $this, 'filter_overrule_get_user_metadata' ), 999999999, 3 ); 172 | 173 | /** 174 | * The priority value of the VAA `user_has_cap` filter. 175 | * Runs as first by default. 176 | * 177 | * @since 1.7.2 178 | * @param int $priority Default: -999999999. 179 | * @return int 180 | */ 181 | $priority = (int) apply_filters( 'view_admin_as_user_has_cap_priority', -999999999 ); 182 | 183 | /** 184 | * Change the capabilities. 185 | * 186 | * @since 1.7.1 187 | * @since 1.7.2 Changed priority to set is at the beginning instead of as last 188 | * to allow other plugins to filter based on the modified user. 189 | */ 190 | $this->add_filter( 'user_has_cap', array( $this, 'filter_user_has_cap' ), $priority, 4 ); 191 | 192 | /** 193 | * Map the capabilities (map_meta_cap is used for compatibility with network admins). 194 | * Filter as last to check other plugin changes as well. 195 | * 196 | * @since 0.1.0 197 | */ 198 | $this->add_filter( 'map_meta_cap', array( $this, 'filter_map_meta_cap' ), 999999999, 4 ); 199 | 200 | /** 201 | * Disable super admin status for the current user. 202 | * @since 1.7.3 203 | * @since 1.8.0 Check for multisite. 204 | */ 205 | if ( 206 | is_multisite() 207 | && ! is_network_admin() 208 | && is_super_admin( $this->store->get_selectedUser()->ID ) 209 | && $this->store->get_userSettings( 'disable_super_admin' ) 210 | ) { 211 | $this->disable_super_admin(); 212 | } 213 | 214 | $done = true; 215 | } 216 | 217 | /** 218 | * Update the current user's WP_User instance with the current view capabilities. 219 | * 220 | * @since 1.6.3 221 | * @access public 222 | * @return void 223 | */ 224 | public function modify_user() { 225 | 226 | // Can be the current or selected WP_User object (depending on the user view). 227 | $user = $this->store->get_selectedUser(); 228 | 229 | /** 230 | * Allow other modules to hook after the initial changes to the current user. 231 | * 232 | * @since 1.6.3 233 | * @since 1.6.4 Renamed from `vaa_view_admin_as_modify_current_user`. 234 | * @param \WP_User $user The modified user object. 235 | */ 236 | $this->do_action( 'vaa_view_admin_as_modify_user', $user ); 237 | } 238 | 239 | /** 240 | * Prevent some updates to the current user like roles and capabilities. 241 | * to prevent problems when making changes within a view. 242 | * 243 | * IMPORTANT! This filter should ONLY be used when a view is selected! 244 | * 245 | * @since 1.6.3 246 | * @access public 247 | * @see init_user_modifications() 248 | * 249 | * @see 'update_user_metadata' filter 250 | * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/update_(meta_type)_metadata 251 | * @link http://hookr.io/filters/update_user_metadata/ 252 | * 253 | * @global \wpdb $wpdb 254 | * @param null $null Whether to allow updating metadata for the given type. 255 | * @param int $object_id Object ID. 256 | * @param string $meta_key Meta key. 257 | * @return mixed 258 | */ 259 | public function filter_prevent_update_user_metadata( $null, $object_id, $meta_key ) { 260 | global $wpdb; 261 | $user = $this->store->get_selectedUser(); 262 | 263 | // Check if the object being updated is the current user. 264 | if ( (int) $user->ID === (int) $object_id ) { 265 | 266 | // Capabilities meta key check. 267 | if ( empty( $user->cap_key ) ) { 268 | $user->cap_key = $wpdb->get_blog_prefix() . 'capabilities'; 269 | } 270 | 271 | // Do not update the current user capabilities or user level while in a view. 272 | if ( in_array( $meta_key, array( 273 | $user->cap_key, 274 | $wpdb->get_blog_prefix() . 'capabilities', 275 | $wpdb->get_blog_prefix() . 'user_level', 276 | ), true ) ) { 277 | return false; 278 | } 279 | } 280 | return $null; 281 | } 282 | 283 | /** 284 | * Return view roles when getting the current user data to prevent reloading current user data within a view. 285 | * 286 | * IMPORTANT! This filter should ONLY be used when a view is selected! 287 | * 288 | * @since 1.6.4 289 | * @access public 290 | * @see init_user_modifications() 291 | * 292 | * @see 'get_user_metadata' filter 293 | * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/get_(meta_type)_metadata 294 | * 295 | * @global \wpdb $wpdb 296 | * @param null $null The value update_metadata() should return. 297 | * @param int $object_id Object ID. 298 | * @param string $meta_key Meta key. 299 | * @return mixed 300 | */ 301 | public function filter_overrule_get_user_metadata( $null, $object_id, $meta_key ) { 302 | global $wpdb; 303 | $user = $this->store->get_selectedUser(); 304 | 305 | // Check if the object being updated is the current user. 306 | if ( (int) $user->ID === (int) $object_id ) { 307 | 308 | // Return the current user capabilities or user level while in a view. 309 | // Always return an array to fix $single usage. 310 | 311 | // Current user cap key should be equal to the meta_key for capabilities. 312 | if ( ! empty( $user->cap_key ) && $meta_key === $user->cap_key ) { 313 | return array( $user->caps ); 314 | } 315 | // Fallback if cap_key doesn't exists. 316 | if ( $meta_key === $wpdb->get_blog_prefix() . 'capabilities' ) { 317 | return array( $user->caps ); 318 | } 319 | if ( $meta_key === $wpdb->get_blog_prefix() . 'user_level' ) { 320 | if ( ! isset( $user->user_level ) ) { 321 | // Make sure the key exists. Result will be filtered in `filter_prevent_update_user_metadata()`. 322 | $user->update_user_level_from_caps(); 323 | } 324 | return array( $user->user_level ); 325 | } 326 | } 327 | return $null; 328 | } 329 | 330 | /** 331 | * Change capabilities when the user has selected a view. 332 | * If the capability isn't in the chosen view, then make the value for this capability empty and add "do_not_allow". 333 | * 334 | * @since 0.1.0 335 | * @since 1.5.0 Renamed from `change_caps()`. 336 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 337 | * @since 1.6.2 Use logic from `self::current_view_can()`. 338 | * @since 1.6.3 Prefix function name with `filter_`. 339 | * @since 1.7.2 Use the `user_has_cap` filter for compatibility enhancements. 340 | * @access public 341 | * 342 | * @param array $caps The actual (mapped) cap names, if the caps are not mapped this returns the requested cap. 343 | * @param string $cap The capability that was requested. 344 | * @param int $user_id The ID of the user. 345 | * @param array $args Adds the context to the cap. Typically the object ID (not used). 346 | * @return array $caps 347 | */ 348 | public function filter_map_meta_cap( $caps, $cap, $user_id, $args = array() ) { 349 | 350 | if ( (int) $this->store->get_selectedUser()->ID !== (int) $user_id ) { 351 | return $caps; 352 | } 353 | 354 | $filter_caps = (array) $this->store->get_selectedCaps(); 355 | 356 | if ( ! $this->store->get_view( 'caps' ) ) { 357 | /** 358 | * Apply user_has_cap filters to make sure we are compatible with modifications from other plugins. 359 | * 360 | * Issues found: 361 | * - Restrict User Access - Overwrites our filtered capabilities. (fixed since RUA 0.15.x). 362 | * - Groups - Overwrites our filtered capabilities. (fixed in Groups module). 363 | * 364 | * @since 1.7.2 365 | * @see \WP_User::has_cap() 366 | */ 367 | $filter_caps = apply_filters( 368 | 'user_has_cap', 369 | $filter_caps, 370 | $caps, 371 | // Replicate arguments for `user_has_cap`. 372 | array_merge( array( $cap, $user_id ), (array) $args ), 373 | $this->store->get_selectedUser() 374 | ); 375 | } 376 | 377 | /** 378 | * Everyone is allowed to exist. 379 | * @since 1.8.3 380 | * @see \WP_User::has_cap() 381 | * @link https://wordpress.org/support/topic/compatibility-with-view-admin-as-2/ 382 | */ 383 | $filter_caps['exist'] = true; 384 | 385 | foreach ( (array) $caps as $actual_cap ) { 386 | if ( ! $this->current_view_can( $actual_cap, $filter_caps ) ) { 387 | // Regular users. Assuming this capability never exists.. 388 | $caps['vaa_do_not_allow'] = 'vaa_do_not_allow'; 389 | // Network admins. 390 | $caps['do_not_allow'] = 'do_not_allow'; 391 | } 392 | } 393 | 394 | return $caps; 395 | } 396 | 397 | /** 398 | * Overwrite the user's capabilities. 399 | * 400 | * @since 1.6.3 401 | * @access public 402 | * 403 | * @param array $allcaps All the capabilities of the user. 404 | * @param array $caps Actual capabilities for meta capability. 405 | * @param array $args [0] Requested capability. 406 | * [1] User ID. 407 | * [2] Associated object ID. 408 | * @param \WP_User $user (WP 3.7+) The user object. 409 | * @return array 410 | */ 411 | public function filter_user_has_cap( $allcaps, $caps, $args, $user = null ) { 412 | $user_id = ( $user ) ? $user->ID : $args[1]; 413 | if ( is_numeric( $user_id ) && (int) $user_id === (int) $this->store->get_selectedUser()->ID ) { 414 | return (array) $this->store->get_selectedCaps(); 415 | } 416 | return $allcaps; 417 | } 418 | 419 | /** 420 | * Remove the current user from the list of super admins. 421 | * This sets/changes the global $super_admins variable which overwrites the site option. 422 | * 423 | * @since 1.7.3 424 | * @access public 425 | * @see grant_super_admin() >> wp-includes/capabilities.php 426 | * @see revoke_super_admin() >> wp-includes/capabilities.php 427 | * @see get_super_admins() >> wp-includes/capabilities.php 428 | * @see is_super_admin() >> wp-includes/capabilities.php 429 | * @link https://developer.wordpress.org/reference/functions/is_super_admin/ 430 | * 431 | * @global array $super_admins 432 | * @param \WP_User|int|string $user (optional) A user to remove. Both a user object or a user field is accepted. 433 | * @param string $field (optional) A user field key to get the user data by. 434 | */ 435 | public function disable_super_admin( $user = null, $field = 'id' ) { 436 | global $super_admins; 437 | 438 | if ( ! isset( $super_admins ) ) { 439 | $super_admins = get_super_admins(); 440 | } 441 | 442 | $user = ( null !== $user ) ? $user : $this->store->get_selectedUser(); 443 | if ( ! $user instanceof WP_User ) { 444 | $user = get_user_by( $field, $user ); 445 | } 446 | 447 | // Remove current user from the super admins array. 448 | // Effectively disables functions grant_super_admin() and revoke_super_admin(). 449 | if ( ! empty( $user->user_login ) && is_array( $super_admins ) ) { 450 | $key = array_search( $user->user_login, $super_admins, true ); 451 | if ( false !== $key ) { 452 | unset( $super_admins[ $key ] ); 453 | $GLOBALS['super_admins'] = $super_admins; 454 | } 455 | } 456 | } 457 | 458 | /** 459 | * Similar function to current_user_can(). 460 | * 461 | * @since 1.6.2 462 | * @since 1.8.0 Check for non-scalar types being passed as first parameter. 463 | * @access public 464 | * 465 | * @param string $cap The capability. 466 | * @param array $caps (optional) Capabilities to compare to. 467 | * Defaults to the selected caps for the current view. 468 | * @return bool 469 | */ 470 | public function current_view_can( $cap, $caps = array() ) { 471 | 472 | if ( empty( $caps ) ) { 473 | $caps = $this->store->get_selectedCaps(); 474 | } 475 | 476 | if ( ! is_scalar( $cap ) ) { 477 | $cap = (array) $cap; 478 | foreach ( $cap as $capability ) { 479 | if ( ! $this->current_view_can( $capability, $caps ) ) { 480 | return false; 481 | } 482 | } 483 | return true; 484 | } 485 | 486 | $cap = (string) $cap; 487 | 488 | if ( 489 | is_array( $caps ) 490 | && ! empty( $caps[ $cap ] ) 491 | && 'do_not_allow' !== $cap 492 | && 'do_not_allow' !== $caps[ $cap ] 493 | ) { 494 | return true; 495 | } 496 | return false; 497 | } 498 | 499 | /** 500 | * Is the current user modified? 501 | * 502 | * @since 1.7.2 503 | * @access public 504 | * @return bool 505 | */ 506 | public function is_user_modified() { 507 | return (bool) $this->is_user_modified; 508 | } 509 | 510 | /** 511 | * Set the locale for the current view. 512 | * 513 | * @since 1.6.1 514 | * @access public 515 | * @return bool Will return false when used with older WP versions. 516 | */ 517 | public function freeze_locale() { 518 | if ( function_exists( 'get_user_locale' ) && function_exists( 'switch_to_locale' ) ) { 519 | $locale = get_user_locale( $this->store->get_curUser()->ID ); 520 | if ( get_locale() !== $locale ) { 521 | switch_to_locale( $locale ); 522 | } 523 | return true; 524 | } 525 | return false; 526 | } 527 | 528 | /** 529 | * Main Instance. 530 | * 531 | * Ensures only one instance of this class is loaded or can be loaded. 532 | * 533 | * @since 1.6.0 534 | * @access public 535 | * @static 536 | * @param \VAA_View_Admin_As $caller The referrer class. 537 | * @return \VAA_View_Admin_As_View $this 538 | */ 539 | public static function get_instance( $caller = null ) { 540 | if ( is_null( self::$_instance ) ) { 541 | self::$_instance = new self( $caller ); 542 | } 543 | return self::$_instance; 544 | } 545 | 546 | } // End class VAA_View_Admin_As_View. 547 | -------------------------------------------------------------------------------- /includes/index.php: -------------------------------------------------------------------------------- 1 | 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | -------------------------------------------------------------------------------- /modules/class-caps.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * User switcher view type. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.3.0 View type existed in core. 19 | * @since 1.8.0 Created this class. 20 | * @version 1.8.7 21 | * @uses \VAA_View_Admin_As_Type Extends class 22 | */ 23 | class VAA_View_Admin_As_Caps extends VAA_View_Admin_As_Type 24 | { 25 | /** 26 | * The single instance of the class. 27 | * 28 | * @since 1.8.0 29 | * @static 30 | * @var \VAA_View_Admin_As_Caps 31 | */ 32 | private static $_instance = null; 33 | 34 | /** 35 | * @since 1.8.0 36 | * @var string 37 | */ 38 | protected $type = 'caps'; 39 | 40 | /** 41 | * The icon for this view type. 42 | * 43 | * @since 1.8.0 44 | * @var string 45 | */ 46 | protected $icon = 'dashicons-forms'; 47 | 48 | /** 49 | * Populate the instance. 50 | * 51 | * @since 1.8.0 52 | * @access protected 53 | * @param \VAA_View_Admin_As $vaa The main VAA object. 54 | */ 55 | protected function __construct( $vaa ) { 56 | self::$_instance = $this; 57 | parent::__construct( $vaa ); 58 | 59 | if ( ! $this->has_access() ) { 60 | return; 61 | } 62 | 63 | $this->priorities = array( 64 | 'toolbar' => 10, 65 | 'view_title' => 80, 66 | 'validate_view_data' => 10, 67 | 'update_view' => 10, 68 | 'do_view' => 8, 69 | ); 70 | } 71 | 72 | /** 73 | * @inheritDoc 74 | */ 75 | public function init() { 76 | $this->label = __( 'Capabilities', VIEW_ADMIN_AS_DOMAIN ); 77 | $this->label_singular = __( 'Capability', VIEW_ADMIN_AS_DOMAIN ); 78 | return parent::init(); 79 | } 80 | 81 | /** 82 | * Apply the user view. 83 | * 84 | * @since 1.8.0 85 | * @access public 86 | */ 87 | public function do_view() { 88 | 89 | if ( parent::do_view() ) { 90 | 91 | $this->add_filter( 'view_admin_as_user_has_cap_priority', array( $this, 'filter_user_has_cap_priority' ) ); 92 | $this->add_action( 'vaa_view_admin_as_modify_user', array( $this, 'modify_user' ), 2, 2 ); 93 | $this->init_user_modifications(); 94 | } 95 | } 96 | 97 | /** 98 | * Make sure to run `user_has_cap` view filter as last if this view is active. 99 | * 100 | * @since 1.8.3 101 | * @return int 102 | */ 103 | public function filter_user_has_cap_priority() { 104 | return 999999999; 105 | } 106 | 107 | /** 108 | * Modify the current user object. 109 | * 110 | * @since 1.3.0 111 | * @param \WP_User $user The modified user object. 112 | */ 113 | public function modify_user( $user ) { 114 | 115 | $view_data = $this->store->get_view( $this->type ); 116 | 117 | if ( is_array( $view_data ) ) { 118 | // @since 1.6.3 Set the current user's caps (roles) to the current view. 119 | $user->allcaps = array_merge( 120 | (array) array_filter( $view_data ), 121 | (array) $user->caps // Contains the current user roles. 122 | ); 123 | // Set the selected capabilities. 124 | $this->store->set_selectedCaps( $user->allcaps ); 125 | } 126 | } 127 | 128 | /** 129 | * Update the view titles if this view is selected. 130 | * 131 | * @since 1.8.0 132 | * @since 1.8.7 Added second required `$view` param. 133 | * @access public 134 | * @param array $titles The current title(s). 135 | * @param array $view Current view data. 136 | * @return array 137 | */ 138 | public function view_title( $titles, $view ) { 139 | if ( isset( $view[ $this->type ] ) ) { 140 | $title = $this->get_view_title( $view[ $this->type ] ); 141 | if ( $title ) { 142 | $titles[ /* No need for view type key. */ ] = $title; 143 | } 144 | } 145 | return $titles; 146 | } 147 | 148 | /** 149 | * Get the view title. 150 | * 151 | * @since 1.8.7 152 | * @param string $key The data key. 153 | * @return string 154 | */ 155 | public function get_view_title( $key ) { 156 | $title = $this->label; 157 | 158 | /** 159 | * Change the display title for view type nodes. 160 | * 161 | * @since 1.8.0 162 | * @param string $title View title. 163 | * @param string $key View data key. 164 | * @return string 165 | */ 166 | $title = apply_filters( 'vaa_admin_bar_view_title_' . $this->type, $title, $key ); 167 | 168 | return $title; 169 | } 170 | 171 | /** 172 | * Validate data for this view type 173 | * 174 | * @since 1.7.0 175 | * @since 1.8.0 Moved from `VAA_View_Admin_As_Controller`. 176 | * @access public 177 | * @param null $null Default return (invalid) 178 | * @param mixed $data The view data 179 | * @return mixed 180 | */ 181 | public function validate_view_data( $null, $data = null ) { 182 | // Caps data must be an array 183 | if ( is_array( $data ) ) { 184 | 185 | // The data is an array, most likely from the database. 186 | $data = array_map( 'absint', $data ); 187 | // Sort the new caps the same way we sort the existing caps. 188 | ksort( $data ); 189 | 190 | // Only allow assigned capabilities if it isn't a super admin. 191 | if ( ! VAA_API::is_super_admin() ) { 192 | $data = array_intersect_key( $data, $this->store->get_caps() ); 193 | } 194 | 195 | // @since 1.7.4 Forbidden capabilities. 196 | unset( $data['do_not_allow'] ); 197 | unset( $data['vaa_do_not_allow'] ); 198 | 199 | return $data; 200 | } 201 | return $null; 202 | } 203 | 204 | /** 205 | * View update handler (Ajax probably), called from main handler. 206 | * 207 | * @since 1.8.0 Renamed from `ajax_handler()`. 208 | * @access public 209 | * @param null $null Null. 210 | * @param array $data The ajax data for this module. 211 | * @param string $type The view type. 212 | * @return bool 213 | */ 214 | public function update_view( $null, $data, $type = null ) { 215 | $success = $null; 216 | if ( ! is_array( $data ) || $this->type !== $type ) { 217 | return $success; 218 | } 219 | 220 | // Check if the selected caps are equal to the default caps. 221 | if ( VAA_API::array_equal( $this->store->get_curUser()->allcaps, $data ) ) { 222 | // The selected caps are equal to the current user default caps so we can reset the view. 223 | $this->vaa->controller()->reset_view(); 224 | if ( $this->selected ) { 225 | // The user was in a custom caps view. 226 | $success = true; // and continue. 227 | } else { 228 | // The user was in his default view, notify the user. 229 | $success = array( 230 | 'success' => false, 231 | 'data' => array( 232 | 'type' => 'message', 233 | 'text' => esc_html__( 'These are your default capabilities!', VIEW_ADMIN_AS_DOMAIN ), 234 | ), 235 | ); 236 | } 237 | } else { 238 | // Store the selected caps. 239 | $new_caps = array_map( 'absint', $data ); 240 | 241 | // Check if the new caps selection is different. 242 | if ( VAA_API::array_equal( $this->selected, $new_caps ) ) { 243 | $success = array( 244 | 'success' => false, 245 | 'data' => array( 246 | 'type' => 'message', 247 | 'text' => esc_html__( 'This view is already selected!', VIEW_ADMIN_AS_DOMAIN ), 248 | ), 249 | ); 250 | } else { 251 | $this->store->set_view( $data, $type, true ); 252 | $success = true; 253 | } 254 | } 255 | return $success; 256 | } 257 | 258 | /** 259 | * Add the admin bar items. 260 | * 261 | * @since 1.5.0 262 | * @since 1.8.0 Moved from `VAA_View_Admin_As_Admin_Bar`. 263 | * @access public 264 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 265 | * @param string $root The root item. 266 | */ 267 | public function admin_bar_menu( $admin_bar, $root ) { 268 | static $done; 269 | if ( $done ) return; 270 | 271 | /** 272 | * Make sure we have the latest added capabilities. 273 | * It can be that a plugin/theme adds a capability after the initial call to store_caps (hook: 'plugins_loaded'). 274 | * 275 | * @see \VAA_View_Admin_As::run() 276 | * @since 1.4.1 277 | */ 278 | $this->store_data(); 279 | 280 | if ( ! $this->get_data() ) { 281 | return; 282 | } 283 | 284 | /** 285 | * Whether the capability manager should be loaded as a submenu from the title element or as a separate node below the title. 286 | * Default: true. 287 | * Useful if you have a plugin that adds another sub-node below the capability title. 288 | * 289 | * @since 1.7.5 290 | * @return bool 291 | */ 292 | $title_submenu = (bool) apply_filters( 'vaa_admin_bar_caps_do_title_submenu', true ); 293 | 294 | $main_root = $root; 295 | $root = $main_root . '-caps'; 296 | 297 | $admin_bar->add_group( array( 298 | 'id' => $root, 299 | 'parent' => $main_root, 300 | 'meta' => array( 301 | 'class' => 'ab-sub-secondary', 302 | ), 303 | ) ); 304 | 305 | $title_class = ''; 306 | if ( $title_submenu ) { 307 | $title_class .= ( $this->selected ) ? ' current' : ''; 308 | } else { 309 | $title_class .= ' ab-vaa-toggle active'; 310 | } 311 | 312 | $admin_bar->add_node( array( 313 | 'id' => $root . '-title', 314 | 'parent' => $root, 315 | 'title' => VAA_View_Admin_As_Form::do_icon( $this->icon ) . $this->label, 316 | 'href' => false, 317 | 'meta' => array( 318 | 'class' => 'vaa-has-icon ab-vaa-title' . $title_class, 319 | 'tabindex' => '0', 320 | ), 321 | ) ); 322 | 323 | /** 324 | * Add items at the beginning of the caps group. 325 | * 326 | * @since 1.5.0 327 | * @see 'admin_bar_menu' action 328 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 329 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 330 | * @param string $root The current root item. 331 | * @param string $main_root The main root item. 332 | */ 333 | $this->do_action( 'vaa_admin_bar_caps_before', $admin_bar, $root, $main_root ); 334 | 335 | if ( $title_submenu ) { 336 | $admin_bar->add_group( array( 337 | 'id' => $root . '-manager', 338 | 'parent' => $root . '-title', 339 | ) ); 340 | } else { 341 | $admin_bar->add_node( array( 342 | 'id' => $root . '-manager', 343 | 'parent' => $root, 344 | 'title' => __( 'Manager', VIEW_ADMIN_AS_DOMAIN ), 345 | 'href' => false, 346 | 'meta' => array( 347 | 'class' => ( $this->selected ) ? 'current' : '', 348 | 'tabindex' => '0', 349 | ), 350 | ) ); 351 | } 352 | 353 | // Capabilities submenu. 354 | $admin_bar->add_node( array( 355 | 'id' => $root . '-applycaps', 356 | 'parent' => $root . '-manager', 357 | 'title' => VAA_View_Admin_As_Form::do_button( array( 358 | 'name' => 'apply-caps-view', 359 | 'label' => __( 'Apply view', VIEW_ADMIN_AS_DOMAIN ), 360 | 'class' => 'button-primary', 361 | ) ) 362 | . VAA_View_Admin_As_Form::do_button( array( 363 | 'name' => 'close-caps-popup', 364 | 'label' => VAA_View_Admin_As_Form::do_icon( 'dashicons-editor-contract' ), 365 | 'class' => 'button-secondary vaa-icon vaa-hide-responsive', 366 | 'element' => 'a', 367 | ) ) 368 | . VAA_View_Admin_As_Form::do_button( array( 369 | 'name' => 'open-caps-popup', 370 | 'label' => VAA_View_Admin_As_Form::do_icon( 'dashicons-editor-expand' ), 371 | 'class' => 'button-secondary vaa-icon vaa-hide-responsive', 372 | 'element' => 'a', 373 | ) ), 374 | 'href' => false, 375 | 'meta' => array( 376 | 'class' => 'vaa-button-container', 377 | ), 378 | ) ); 379 | 380 | /** 381 | * Add items at the before of the caps selection options. 382 | * 383 | * @since 1.7.0 384 | * @see 'admin_bar_menu' action 385 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 386 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 387 | * @param string $root The current root item. ($root.'-manager') 388 | * @param string $main_root The main root item. 389 | */ 390 | $this->do_action( 'vaa_admin_bar_caps_manager_before', $admin_bar, $root . '-manager', $main_root ); 391 | 392 | $admin_bar->add_group( array( 393 | 'id' => $root . '-select', 394 | 'parent' => $root . '-manager', 395 | ) ); 396 | 397 | // Used in templates 398 | $parent = $root . '-select'; 399 | 400 | /** 401 | * Add items at the before of the caps actions. 402 | * 403 | * @since 1.7.0 404 | * @see 'admin_bar_menu' action 405 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 406 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 407 | * @param string $parent The current root item. 408 | * @param string $main_root The main root item. 409 | */ 410 | $this->do_action( 'vaa_admin_bar_caps_actions_before', $admin_bar, $parent, $main_root ); 411 | 412 | // Add caps actions. 413 | include VIEW_ADMIN_AS_DIR . 'ui/templates/adminbar-caps-actions.php'; 414 | 415 | /** 416 | * Add items at the after of the caps actions. 417 | * 418 | * @since 1.7.0 419 | * @see 'admin_bar_menu' action 420 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 421 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 422 | * @param string $parent The current root item. 423 | * @param string $main_root The main root item. 424 | */ 425 | $this->do_action( 'vaa_admin_bar_caps_actions_after', $admin_bar, $parent, $main_root ); 426 | 427 | // Add the caps. 428 | include VIEW_ADMIN_AS_DIR . 'ui/templates/adminbar-caps-items.php'; 429 | 430 | /** 431 | * Add items at the end of the caps group. 432 | * 433 | * @since 1.5.0 434 | * @see 'admin_bar_menu' action 435 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 436 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 437 | * @param string $root The current root item. 438 | * @param string $main_root The main root item. 439 | */ 440 | $this->do_action( 'vaa_admin_bar_caps_after', $admin_bar, $root, $main_root ); 441 | 442 | $done = true; 443 | } 444 | 445 | /** 446 | * Store available capabilities. 447 | * 448 | * @since 1.4.1 449 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 450 | * @since 1.8.0 Moved from `VAA_View_Admin_As_Store`. 451 | * @access public 452 | * @return void 453 | */ 454 | public function store_data() { 455 | 456 | // Get current user capabilities. 457 | $caps = $this->store->get_originalUserData( 'allcaps' ); 458 | if ( empty( $caps ) ) { 459 | // Fallback. 460 | $caps = $this->store->get_curUser()->allcaps; 461 | } 462 | 463 | // Only allow to add capabilities for an admin (or super admin). 464 | if ( VAA_API::is_super_admin() ) { 465 | 466 | /** 467 | * Add compatibility for other cap managers. 468 | * 469 | * @since 1.5.0 470 | * @see \VAA_View_Admin_As_Compat->init() 471 | * @param array $caps An empty array, waiting to be filled with capabilities. 472 | * @return array 473 | */ 474 | $all_caps = apply_filters( 'view_admin_as_get_capabilities', array() ); 475 | 476 | $add_caps = array(); 477 | // Add new capabilities to the capability array as disabled. 478 | foreach ( $all_caps as $cap_key => $cap_val ) { 479 | if ( is_numeric( $cap_key ) ) { 480 | // Try to convert numeric (faulty) keys. 481 | $add_caps[ (string) $cap_val ] = 0; 482 | } else { 483 | $add_caps[ (string) $cap_key ] = 0; 484 | } 485 | } 486 | 487 | $caps = array_merge( $add_caps, $caps ); 488 | 489 | } // End if(). 490 | 491 | // Remove role names. 492 | $caps = array_diff_key( $caps, $this->store->get_roles() ); 493 | // And sort alphabetical. 494 | ksort( $caps ); 495 | 496 | $this->set_data( $caps ); 497 | } 498 | 499 | /** 500 | * Set the view type data. 501 | * 502 | * @since 1.8.0 503 | * @access public 504 | * @param mixed $val 505 | * @param string $key (optional) The data key. 506 | * @param bool $append (optional) Append if it doesn't exist? 507 | */ 508 | public function set_data( $val, $key = null, $append = true ) { 509 | $this->store->set_caps( $val, $key, $append ); 510 | } 511 | 512 | /** 513 | * Get the view type data. 514 | * 515 | * @since 1.8.0 516 | * @access public 517 | * @param string $key (optional) The data key. 518 | * @return mixed 519 | */ 520 | public function get_data( $key = null ) { 521 | return $this->store->get_caps( $key ); 522 | } 523 | 524 | /** 525 | * Main Instance. 526 | * 527 | * Ensures only one instance of this class is loaded or can be loaded. 528 | * 529 | * @since 1.8.0 530 | * @access public 531 | * @static 532 | * @param \VAA_View_Admin_As $caller The referrer class. 533 | * @return \VAA_View_Admin_As_Caps $this 534 | */ 535 | public static function get_instance( $caller = null ) { 536 | if ( is_null( self::$_instance ) ) { 537 | self::$_instance = new self( $caller ); 538 | } 539 | return self::$_instance; 540 | } 541 | 542 | } // End class VAA_View_Admin_As_Caps. 543 | -------------------------------------------------------------------------------- /modules/class-languages.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * Language switcher add-on. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.7.5 19 | * @version 1.8.7 20 | * @uses \VAA_View_Admin_As_Type Extends class 21 | */ 22 | class VAA_View_Admin_As_Languages extends VAA_View_Admin_As_Type 23 | { 24 | /** 25 | * The single instance of the class. 26 | * 27 | * @since 1.7.5 28 | * @static 29 | * @var \VAA_View_Admin_As_Languages 30 | */ 31 | private static $_instance = null; 32 | 33 | /** 34 | * Option key. 35 | * 36 | * @since 1.7.5 37 | * @var string 38 | */ 39 | protected $optionKey = 'languages'; 40 | 41 | /** 42 | * @since 1.7.5 43 | * @var string 44 | */ 45 | protected $type = 'locale'; 46 | 47 | /** 48 | * The icon for this view type. 49 | * 50 | * @since 1.8.0 51 | * @var string 52 | */ 53 | protected $icon = 'dashicons-translation'; 54 | 55 | /** 56 | * Populate the instance. 57 | * 58 | * @since 1.7.5 59 | * @access protected 60 | * @param \VAA_View_Admin_As $vaa The main VAA object. 61 | */ 62 | protected function __construct( $vaa ) { 63 | self::$_instance = $this; 64 | parent::__construct( $vaa ); 65 | 66 | if ( ! $this->has_access() ) { 67 | return; 68 | } 69 | 70 | $this->priorities = array( 71 | 'toolbar' => 9, 72 | 'view_title' => 90, 73 | 'validate_view_data' => 10, 74 | 'update_view' => 10, 75 | 'do_view' => 10, 76 | ); 77 | } 78 | 79 | /** 80 | * @inheritDoc 81 | */ 82 | public function init() { 83 | $this->label = __( 'Languages', VIEW_ADMIN_AS_DOMAIN ); 84 | $this->label_singular = __( 'Language', VIEW_ADMIN_AS_DOMAIN ); 85 | return parent::init(); 86 | } 87 | 88 | /** 89 | * Apply the language view. 90 | * 91 | * @since 1.7.5 92 | * @access public 93 | */ 94 | public function do_view() { 95 | 96 | if ( parent::do_view() ) { 97 | 98 | $this->add_filter( 'locale', array( $this, 'filter_locale' ) ); 99 | $this->add_action( 'after_setup_theme', array( $this, 'action_switch_to_locale' ), 0 ); 100 | 101 | // Overwrite user setting for freeze locale. 102 | $this->add_filter( 'view_admin_as_freeze_locale', '__return_false', 99 ); 103 | } 104 | } 105 | 106 | /** 107 | * Change the site language. 108 | * 109 | * @since 1.7.5 110 | * @access public 111 | * param string $locale 112 | * @return string 113 | */ 114 | public function filter_locale() { 115 | return $this->selected; 116 | } 117 | 118 | /** 119 | * Change the site language. 120 | * 121 | * @since 1.7.5 122 | * @access public 123 | */ 124 | public function action_switch_to_locale() { 125 | if ( function_exists( 'switch_to_locale' ) ) { 126 | switch_to_locale( $this->selected ); 127 | } 128 | } 129 | 130 | /** 131 | * Validate data for this view type 132 | * 133 | * @since 1.7.5 134 | * @param null $null Default return (invalid) 135 | * @param mixed $data The view data 136 | * @return mixed 137 | */ 138 | public function validate_view_data( $null, $data = null ) { 139 | if ( is_string( $data ) && $this->get_data( $data ) ) { 140 | return $data; 141 | } 142 | return $null; 143 | } 144 | 145 | /** 146 | * Update the view titles if this view is selected. 147 | * 148 | * @since 1.7.5 149 | * @since 1.8.0 Renamed from `vaa_admin_bar_view_titles()`. 150 | * @since 1.8.7 Added second required `$view` param. 151 | * @access public 152 | * @param array $titles The current title(s). 153 | * @param array $view View data. 154 | * @return array 155 | */ 156 | public function view_title( $titles, $view ) { 157 | if ( isset( $view[ $this->type ] ) ) { 158 | $title = $this->get_view_title( $view[ $this->type ] ); 159 | if ( $title ) { 160 | $titles[ /* No need for view type key. */ ] = $title; 161 | } 162 | } 163 | return $titles; 164 | } 165 | 166 | /** 167 | * Get the view title. 168 | * 169 | * @since 1.8.0 170 | * @param string $key The locale. 171 | * @return string 172 | */ 173 | public function get_view_title( $key ) { 174 | $title = $this->get_data( $key ); 175 | 176 | /** 177 | * Change the display title for language nodes. 178 | * 179 | * @since 1.8.0 180 | * @param string $title Language (native). 181 | * @param string $key The locale. 182 | * @return string 183 | */ 184 | $title = apply_filters( 'vaa_admin_bar_view_title_' . $this->type, $title, $key ); 185 | 186 | return $title; 187 | } 188 | 189 | /** 190 | * Add the admin bar items. 191 | * 192 | * @since 1.7.5 193 | * @access public 194 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 195 | * @param string $root The root item. 196 | */ 197 | public function admin_bar_menu( $admin_bar, $root ) { 198 | static $done; 199 | if ( $done ) return; 200 | 201 | $main_root = $root; 202 | $root = $main_root . '-locale'; 203 | 204 | $admin_bar->add_group( array( 205 | 'id' => $root, 206 | 'parent' => $main_root, 207 | 'meta' => array( 208 | 'class' => 'ab-sub-secondary', 209 | ), 210 | ) ); 211 | 212 | $admin_bar->add_node( array( 213 | 'id' => $root . '-title', 214 | 'parent' => $root, 215 | 'title' => VAA_View_Admin_As_Form::do_icon( $this->icon ) . $this->label, 216 | 'href' => false, 217 | 'meta' => array( 218 | 'class' => 'vaa-has-icon ab-vaa-title' . ( ( $this->store->get_view( $this->type ) ) ? ' current' : '' ), 219 | 'tabindex' => '0', 220 | ), 221 | ) ); 222 | 223 | $admin_bar->add_group( array( 224 | 'id' => $root . '-languages', 225 | 'parent' => $root . '-title', 226 | 'meta' => array( 227 | 'class' => 'vaa-auto-max-height', 228 | ), 229 | ) ); 230 | 231 | /** 232 | * Add items at the beginning of the rua group. 233 | * 234 | * @see 'admin_bar_menu' action 235 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 236 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 237 | * @param string $root The current root item. 238 | */ 239 | $this->do_action( 'vaa_admin_bar_languages_before', $admin_bar, $root ); 240 | 241 | // Add the levels. 242 | include VIEW_ADMIN_AS_DIR . 'ui/templates/adminbar-language-items.php'; 243 | 244 | /** 245 | * Add items at the end of the rua group. 246 | * 247 | * @see 'admin_bar_menu' action 248 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 249 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 250 | * @param string $root The current root item. 251 | */ 252 | $this->do_action( 'vaa_admin_bar_languages_after', $admin_bar, $root ); 253 | } 254 | 255 | /** 256 | * Store the available languages. 257 | * 258 | * @since 1.7.5 259 | * @since 1.8.0 Renamed from `store_languages()`. 260 | * @access public 261 | */ 262 | public function store_data() { 263 | 264 | $installed = get_available_languages(); 265 | 266 | if ( ! $installed || ( 1 === count( $installed ) && 'en_US' === reset( $installed ) ) ) { 267 | return; 268 | } 269 | 270 | $existing = (array) $this->store->get_optionData( $this->optionKey ); 271 | $languages = $existing; 272 | 273 | if ( array_diff_key( array_flip( $installed ), $existing ) ) { 274 | // New languages detected. Call the WP API to get language info. 275 | $languages = $this->get_wp_languages( $languages ); 276 | } 277 | 278 | $data_languages['en_US'] = 'English'; 279 | 280 | // Same order as WordPress. 281 | sort( $installed ); 282 | 283 | foreach ( $installed as $locale ) { 284 | if ( array_key_exists( $locale, $languages ) ) { 285 | $data_languages[ $locale ] = $languages[ $locale ]; 286 | } 287 | } 288 | 289 | if ( $languages !== $existing ) { 290 | $this->store->update_optionData( $data_languages, $this->optionKey, true ); 291 | } 292 | 293 | $this->set_data( $data_languages ); 294 | } 295 | 296 | /** 297 | * Call the WP API to get language info. 298 | * 299 | * @since 1.7.5 300 | * @param array $languages Existing languages. 301 | * @return array 302 | */ 303 | private function get_wp_languages( $languages ) { 304 | if ( ! file_exists( ABSPATH . 'wp-admin/includes/translation-install.php' ) ) { 305 | // @todo Notice on debug. 306 | return $languages; 307 | } 308 | require_once ABSPATH . 'wp-admin/includes/translation-install.php'; 309 | 310 | if ( ! function_exists( 'wp_get_available_translations' ) ) { 311 | return $languages; 312 | } 313 | $wp_languages = wp_get_available_translations(); 314 | 315 | if ( ! $wp_languages ) { 316 | return $languages; 317 | } 318 | 319 | foreach ( $wp_languages as $locale => $language_info ) { 320 | $name = $locale; 321 | if ( isset( $language_info['native_name'] ) ) { 322 | $name = $language_info['native_name']; 323 | } 324 | $languages[ $locale ] = $name; 325 | } 326 | 327 | return $languages; 328 | } 329 | 330 | /** 331 | * Set the view type data. 332 | * 333 | * @since 1.8.0 334 | * @access public 335 | * @param mixed $val 336 | * @param string $key (optional) The data key. 337 | * @param bool $append (optional) Append if it doesn't exist? 338 | */ 339 | public function set_data( $val, $key = null, $append = true ) { 340 | $this->store->set_languages( $val, $key, $append ); 341 | } 342 | 343 | /** 344 | * Get a language by locale. 345 | * 346 | * @since 1.7.5 347 | * @since 1.8.0 Renamed from `get_languages()`. 348 | * @access public 349 | * @param string $key (optional) The language locale. 350 | * @return mixed 351 | */ 352 | public function get_data( $key = '-1' ) { 353 | if ( ! is_string( $key ) ) { 354 | return false; 355 | } 356 | if ( '-1' === $key ) { 357 | $key = null; 358 | } 359 | return $this->store->get_languages( $key ); 360 | } 361 | 362 | /** 363 | * Main Instance. 364 | * 365 | * Ensures only one instance of this class is loaded or can be loaded. 366 | * 367 | * @since 1.7.5 368 | * @access public 369 | * @static 370 | * @param \VAA_View_Admin_As $caller The referrer class. 371 | * @return \VAA_View_Admin_As_Languages $this 372 | */ 373 | public static function get_instance( $caller = null ) { 374 | if ( is_null( self::$_instance ) ) { 375 | self::$_instance = new self( $caller ); 376 | } 377 | return self::$_instance; 378 | } 379 | 380 | } // End class VAA_View_Admin_As_Languages. 381 | -------------------------------------------------------------------------------- /modules/class-roles.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * User switcher view type. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 0.1.0 View type existed in core. 19 | * @since 1.8.0 Created this class. 20 | * @version 1.8.7 21 | * @uses \VAA_View_Admin_As_Type Extends class 22 | */ 23 | class VAA_View_Admin_As_Roles extends VAA_View_Admin_As_Type 24 | { 25 | /** 26 | * The single instance of the class. 27 | * 28 | * @since 1.8.0 29 | * @static 30 | * @var \VAA_View_Admin_As_Roles 31 | */ 32 | private static $_instance = null; 33 | 34 | /** 35 | * @since 1.8.0 36 | * @var string 37 | */ 38 | protected $type = 'role'; 39 | 40 | /** 41 | * The icon for this view type. 42 | * 43 | * @since 1.8.0 44 | * @var string 45 | */ 46 | protected $icon = 'dashicons-groups'; 47 | 48 | /** 49 | * Populate the instance. 50 | * 51 | * @since 1.8.0 52 | * @access protected 53 | * @param \VAA_View_Admin_As $vaa The main VAA object. 54 | */ 55 | protected function __construct( $vaa ) { 56 | self::$_instance = $this; 57 | 58 | if ( is_network_admin() ) { 59 | return; 60 | } 61 | 62 | parent::__construct( $vaa ); 63 | 64 | // Roles should always be stored because of dependencies. 65 | if ( ! $this->is_enabled() ) { 66 | $this->store_data(); 67 | } 68 | 69 | if ( ! $this->has_access() ) { 70 | return; 71 | } 72 | 73 | $this->priorities = array( 74 | 'toolbar' => 20, 75 | 'view_title' => 8, 76 | 'validate_view_data' => 10, 77 | 'update_view' => 10, 78 | 'do_view' => 5, 79 | ); 80 | } 81 | 82 | /** 83 | * @inheritDoc 84 | */ 85 | public function init() { 86 | $this->label = __( 'Roles', VIEW_ADMIN_AS_DOMAIN ); 87 | $this->label_singular = __( 'Role', VIEW_ADMIN_AS_DOMAIN ); 88 | return parent::init(); 89 | } 90 | 91 | /** 92 | * Apply the user view. 93 | * 94 | * @since 1.8.0 95 | * @access public 96 | */ 97 | public function do_view() { 98 | 99 | if ( parent::do_view() ) { 100 | 101 | $this->add_action( 'vaa_view_admin_as_modify_user', array( $this, 'modify_user' ), 2, 2 ); 102 | $this->init_user_modifications(); 103 | } 104 | } 105 | 106 | /** 107 | * Modify the current user object. 108 | * 109 | * @since 1.8.0 110 | * @param \WP_User $user The modified user object. 111 | */ 112 | public function modify_user( $user ) { 113 | 114 | if ( $this->get_data( $this->selected ) instanceof WP_Role ) { 115 | // @since 1.6.3 Set the current user's role to the current view. 116 | $user->caps = array( $this->selected => 1 ); 117 | // Sets the `allcaps` and `roles` properties correct. 118 | $user->get_role_caps(); 119 | // Set the selected capabilities. 120 | $this->store->set_selectedCaps( $user->allcaps ); 121 | } 122 | } 123 | 124 | /** 125 | * Get the view title. 126 | * 127 | * @since 1.8.0 128 | * @param string|\WP_Role $key 129 | * @return string 130 | */ 131 | public function get_view_title( $key ) { 132 | $title = ( is_scalar( $key ) ) ? $key : ''; 133 | $role = $key; 134 | if ( ! $role instanceof \WP_Role ) { 135 | $role = $this->store->get_roles( $role ); 136 | } 137 | if ( $role ) { 138 | $title = $this->store->get_rolenames( $role->name ); 139 | } 140 | 141 | /** 142 | * Change the display title for role nodes. 143 | * 144 | * @since 1.8.0 145 | * @param string $title Role name (translated). 146 | * @param \WP_Role $key The role name. 147 | * @return string 148 | */ 149 | $title = apply_filters( 'vaa_admin_bar_view_title_' . $this->type, $title, $key ); 150 | 151 | return $title; 152 | } 153 | 154 | /** 155 | * Validate data for this view type 156 | * 157 | * @since 1.7.0 158 | * @since 1.8.0 Moved from `VAA_View_Admin_As_Controller`. 159 | * @access public 160 | * @param null $null Default return (invalid) 161 | * @param mixed $data The view data 162 | * @return mixed 163 | */ 164 | public function validate_view_data( $null, $data = null ) { 165 | // User data must be a number and exists in the loaded array of user id's. 166 | if ( is_string( $data ) && array_key_exists( $data, $this->get_data() ) ) { 167 | return $data; 168 | } 169 | return $null; 170 | } 171 | 172 | /** 173 | * Add the admin bar items. 174 | * 175 | * @since 1.5.0 176 | * @since 1.8.0 Moved from `VAA_View_Admin_As_Admin_Bar`. 177 | * @access public 178 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 179 | * @param string $root The root item. 180 | */ 181 | public function admin_bar_menu( $admin_bar, $root ) { 182 | static $done; 183 | if ( $done ) return; 184 | 185 | /** 186 | * Make sure we have the latest added roles. 187 | * It can be that a plugin/theme adds a role after the initial call to store_roles (hook: 'plugins_loaded'). 188 | * 189 | * @see \VAA_View_Admin_As::run() 190 | * @since 1.6.3 191 | */ 192 | $this->store_data(); 193 | 194 | if ( ! $this->get_data() ) { 195 | return; 196 | } 197 | 198 | $main_root = $root; 199 | $root = $main_root . '-roles'; 200 | 201 | $admin_bar->add_group( array( 202 | 'id' => $root, 203 | 'parent' => $main_root, 204 | 'meta' => array( 205 | 'class' => 'ab-sub-secondary', 206 | ), 207 | ) ); 208 | $admin_bar->add_node( array( 209 | 'id' => $root . '-title', 210 | 'parent' => $root, 211 | 'title' => VAA_View_Admin_As_Form::do_icon( $this->icon ) . $this->label, 212 | 'href' => false, 213 | 'meta' => array( 214 | 'class' => 'vaa-has-icon ab-vaa-title ab-vaa-toggle active', 215 | 'tabindex' => '0', 216 | ), 217 | ) ); 218 | 219 | /** 220 | * Add items at the beginning of the roles group. 221 | * 222 | * @since 1.5.0 223 | * @see 'admin_bar_menu' action 224 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 225 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 226 | * @param string $root The current root item. 227 | * @param string $main_root The main root item. 228 | */ 229 | $this->do_action( 'vaa_admin_bar_roles_before', $admin_bar, $main_root ); 230 | 231 | // Add the roles. 232 | include VIEW_ADMIN_AS_DIR . 'ui/templates/adminbar-role-items.php'; 233 | 234 | /** 235 | * Add items at the end of the roles group. 236 | * 237 | * @since 1.5.0 238 | * @see 'admin_bar_menu' action 239 | * @link https://codex.wordpress.org/Class_Reference/WP_Admin_Bar 240 | * @param \WP_Admin_Bar $admin_bar The toolbar object. 241 | * @param string $root The current root item. 242 | * @param string $main_root The main root item. 243 | */ 244 | $this->do_action( 'vaa_admin_bar_roles_after', $admin_bar, $root, $main_root ); 245 | 246 | $done = true; 247 | } 248 | 249 | /** 250 | * Store available roles. 251 | * 252 | * @since 1.5.0 253 | * @since 1.5.2 Get role objects instead of arrays. 254 | * @since 1.6.0 Moved from `VAA_View_Admin_As`. 255 | * @since 1.8.0 Moved from `VAA_View_Admin_As_Store`. 256 | * @access public 257 | * @global \WP_Roles $wp_roles 258 | * @return void 259 | */ 260 | public function store_data() { 261 | 262 | // @since 1.6.3 Check for the wp_roles() function in WP 4.3+. 263 | if ( function_exists( 'wp_roles' ) ) { 264 | $wp_roles = wp_roles(); 265 | } else { 266 | global $wp_roles; 267 | } 268 | 269 | // Store available roles (role_objects for objects, roles for arrays). 270 | $roles = $wp_roles->role_objects; 271 | 272 | if ( ! VAA_API::is_super_admin() ) { 273 | 274 | // The current user is not a super admin (or regular admin in single installations). 275 | unset( $roles['administrator'] ); 276 | 277 | // @see https://codex.wordpress.org/Plugin_API/Filter_Reference/editable_roles. 278 | $editable_roles = apply_filters( 'editable_roles', $wp_roles->roles ); 279 | 280 | // Current user has the view_admin_as capability, otherwise this functions would'nt be called. 281 | foreach ( $roles as $role_key => $role ) { 282 | if ( ! array_key_exists( $role_key, $editable_roles ) ) { 283 | // Remove roles that this user isn't allowed to edit. 284 | unset( $roles[ $role_key ] ); 285 | } 286 | elseif ( $role instanceof WP_Role && $role->has_cap( 'view_admin_as' ) ) { 287 | // Remove roles that have the view_admin_as capability. 288 | unset( $roles[ $role_key ] ); 289 | } 290 | } 291 | } 292 | 293 | // @since 1.6.4 Set role names. 294 | $role_names = array(); 295 | foreach ( $roles as $role_key => $role ) { 296 | if ( isset( $wp_roles->role_names[ $role_key ] ) ) { 297 | $role_names[ $role_key ] = $wp_roles->role_names[ $role_key ]; 298 | } else { 299 | $role_names[ $role_key ] = $role->name; 300 | } 301 | } 302 | 303 | $this->store->set_rolenames( $role_names ); 304 | $this->set_data( $roles ); 305 | } 306 | 307 | /** 308 | * Set the view type data. 309 | * 310 | * @since 1.8.0 311 | * @access public 312 | * @param mixed $val 313 | * @param string $key (optional) The data key. 314 | * @param bool $append (optional) Append if it doesn't exist? 315 | */ 316 | public function set_data( $val, $key = null, $append = true ) { 317 | $this->store->set_roles( $val, $key, $append ); 318 | } 319 | 320 | /** 321 | * Get the view type data. 322 | * 323 | * @since 1.8.0 324 | * @access public 325 | * @param string $key (optional) The data key. 326 | * @return mixed 327 | */ 328 | public function get_data( $key = null ) { 329 | return $this->store->get_roles( $key ); 330 | } 331 | 332 | /** 333 | * Main Instance. 334 | * 335 | * Ensures only one instance of this class is loaded or can be loaded. 336 | * 337 | * @since 1.8.0 338 | * @access public 339 | * @static 340 | * @param \VAA_View_Admin_As $caller The referrer class. 341 | * @return \VAA_View_Admin_As_Roles $this 342 | */ 343 | public static function get_instance( $caller = null ) { 344 | if ( is_null( self::$_instance ) ) { 345 | self::$_instance = new self( $caller ); 346 | } 347 | return self::$_instance; 348 | } 349 | 350 | } // End class VAA_View_Admin_As_Roles. 351 | -------------------------------------------------------------------------------- /modules/index.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | if ( ! class_exists( 'WP_Admin_Bar' ) && file_exists( ABSPATH . WPINC . '/class-wp-admin-bar.php' ) ) { 14 | require_once ABSPATH . WPINC . '/class-wp-admin-bar.php'; 15 | } 16 | 17 | if ( class_exists( 'WP_Admin_Bar' ) ) { 18 | 19 | /** 20 | * Toolbar UI for View Admin As. 21 | * 22 | * @author Jory Hogeveen 23 | * @package View_Admin_As 24 | * @since 1.6.0 25 | * @version 1.8.7 26 | * @see wp-includes/class-wp-admin-bar.php 27 | * @uses \WP_Admin_Bar Extends class 28 | */ 29 | final class VAA_View_Admin_As_Toolbar extends WP_Admin_Bar 30 | { 31 | /** 32 | * The single instance of the class. 33 | * 34 | * @since 1.6.0 35 | * @static 36 | * @var \VAA_View_Admin_As_Toolbar 37 | */ 38 | private static $_instance = null; 39 | 40 | /** 41 | * Is this toolbar being rendered? 42 | * 43 | * @since 1.6.0 44 | * @static 45 | * @var bool 46 | */ 47 | public static $showing = false; 48 | 49 | /** 50 | * View Admin As store. 51 | * 52 | * @since 1.6.0 53 | * @var \VAA_View_Admin_As_Store 54 | */ 55 | private $vaa_store = null; 56 | 57 | /** 58 | * Construct function. 59 | * Protected to make sure it isn't declared elsewhere. 60 | * 61 | * @since 1.6.0 62 | * @since 1.6.1 `$vaa` param. 63 | * @access protected 64 | * @param \VAA_View_Admin_As $vaa The main VAA object. 65 | */ 66 | protected function __construct( $vaa ) { 67 | self::$_instance = $this; 68 | $this->vaa_store = view_admin_as()->store(); 69 | 70 | view_admin_as()->hooks()->add_action( 'vaa_view_admin_as_init', array( $this, 'vaa_init' ) ); 71 | } 72 | 73 | /** 74 | * Init function that initializes this plugin after the main VAA class is loaded. 75 | * 76 | * @since 1.6.0 77 | * @access public 78 | * @see 'vaa_view_admin_as_init' action 79 | * @return void 80 | */ 81 | public function vaa_init() { 82 | // @since 1.7.6 Changed hook from `init` to `wp_loaded` (later). 83 | view_admin_as()->hooks()->add_action( 'wp_loaded', array( $this, 'vaa_toolbar_init' ) ); 84 | } 85 | 86 | /** 87 | * Init function for the toolbar. 88 | * 89 | * @since 1.6.0 90 | * @since 1.6.2 Check for customizer preview. 91 | * @since 1.7.6 Add customizer support by only enabling it in the container, not the preview window. 92 | * @since 1.8.7 Add JSON, AJAX and REST support. 93 | * @access public 94 | * @return void 95 | */ 96 | public function vaa_toolbar_init() { 97 | if ( 98 | VAA_API::is_toolbar_showing() 99 | || VAA_API::doing_ajax() 100 | || VAA_API::doing_json() 101 | || ( ! is_admin() && is_customize_preview() ) 102 | ) { 103 | return; 104 | } 105 | 106 | if ( 107 | ( is_customize_preview() && ! $this->vaa_store->get_userSettings( 'hide_customizer' ) ) 108 | || ( ! is_admin() && ! $this->vaa_store->get_userSettings( 'hide_front' ) ) 109 | || $this->vaa_store->get_view() 110 | ) { 111 | 112 | self::$showing = true; 113 | 114 | view_admin_as()->hooks()->add_action( 'wp_footer', array( $this, 'vaa_toolbar_render' ), 100 ); 115 | view_admin_as()->hooks()->add_action( 'customize_controls_print_footer_scripts', array( $this, 'vaa_toolbar_render' ), 100 ); 116 | } 117 | } 118 | 119 | /** 120 | * Render our toolbar using the render function from WP_Admin_bar. 121 | * 122 | * @since 1.6.0 123 | * @access public 124 | * @return void 125 | */ 126 | public function vaa_toolbar_render() { 127 | 128 | $this->add_group( array( 129 | 'id' => 'top-secondary', 130 | 'meta' => array( 131 | 'class' => 'ab-top-secondary', 132 | ), 133 | ) ); 134 | 135 | // Load our admin bar nodes and force the location. 136 | view_admin_as()->hooks()->do_action( 'vaa_toolbar_menu', $this, 'top-secondary' ); 137 | 138 | /** 139 | * Add classes to the toolbar menu (front only). 140 | * @since 1.6.0 141 | * @param array $array Empty array. 142 | * @return array 143 | */ 144 | $toolbar_classes = apply_filters( 'view_admin_as_toolbar_classes', array() ); 145 | echo '
'; 146 | 147 | $this->render(); 148 | 149 | echo '
'; 150 | } 151 | 152 | /** 153 | * Main Instance. 154 | * 155 | * Ensures only one instance of this class is loaded or can be loaded. 156 | * 157 | * @since 1.6.0 158 | * @access public 159 | * @static 160 | * @param \VAA_View_Admin_As $caller The referrer class. 161 | * @return \VAA_View_Admin_As_Toolbar $this 162 | */ 163 | public static function get_instance( $caller = null ) { 164 | if ( is_null( self::$_instance ) ) { 165 | self::$_instance = new self( $caller ); 166 | } 167 | return self::$_instance; 168 | } 169 | 170 | } // End class VAA_View_Admin_As_Toolbar. 171 | 172 | } // End if(). 173 | -------------------------------------------------------------------------------- /ui/class-ui.php: -------------------------------------------------------------------------------- 1 | 6 | * @package View_Admin_As 7 | */ 8 | 9 | if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) { 10 | die(); 11 | } 12 | 13 | /** 14 | * UI hooks for View Admin As. 15 | * 16 | * @author Jory Hogeveen 17 | * @package View_Admin_As 18 | * @since 1.6.0 19 | * @since 1.7.0 Renamed from `VAA_View_Admin_As_Admin`. 20 | * @version 1.8.9 21 | * @uses \VAA_View_Admin_As_Base Extends class 22 | */ 23 | final class VAA_View_Admin_As_UI extends VAA_View_Admin_As_Base 24 | { 25 | /** 26 | * The single instance of the class. 27 | * 28 | * @since 1.6.0 29 | * @static 30 | * @var \VAA_View_Admin_As_UI 31 | */ 32 | private static $_instance = null; 33 | 34 | /** 35 | * Plugin links. 36 | * 37 | * @since 1.6.1 38 | * @var array[] 39 | */ 40 | private $links = array(); 41 | 42 | /** 43 | * Construct function. 44 | * 45 | * @since 1.6.0 46 | * @since 1.6.1 `$vaa` param. 47 | * @access protected 48 | * @param \VAA_View_Admin_As $vaa The main VAA object. 49 | */ 50 | protected function __construct( $vaa ) { 51 | self::$_instance = $this; 52 | parent::__construct( $vaa ); 53 | 54 | $this->add_action( 'wp_meta', array( $this, 'action_wp_meta' ) ); 55 | $this->add_action( 'plugin_row_meta', array( $this, 'action_plugin_row_meta' ), 10, 2 ); 56 | $this->add_filter( 'removable_query_args', array( $this, 'filter_removable_query_args' ) ); 57 | 58 | $this->add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 59 | $this->add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 60 | // @since 1.7.6.1 Add scripts to the customizer container hook. 61 | $this->add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 62 | 63 | $this->add_filter( 'wp_die_handler', array( $this, 'filter_wp_die_handler' ) ); 64 | 65 | /** 66 | * Compat with front and WP version lower than 4.2.0. 67 | * @since 1.6.4 68 | * @link https://developer.wordpress.org/reference/functions/wp_admin_canonical_url/ 69 | */ 70 | if ( ! is_admin() || ! VAA_API::validate_wp_version( '4.2' ) ) { 71 | $this->add_action( 'wp_head', array( $this, 'remove_query_args' ) ); 72 | } 73 | } 74 | 75 | /** 76 | * Adds a 'View Admin As: Reset view' link to the Meta sidebar widget if the admin bar is hidden. 77 | * 78 | * @since 1.6.1 79 | * @access public 80 | */ 81 | public function action_wp_meta() { 82 | if ( ! VAA_API::is_toolbar_showing() && VAA_API::is_view_active() ) { 83 | $link = __( 'View Admin As', VIEW_ADMIN_AS_DOMAIN ) . ': ' . __( 'Reset view', VIEW_ADMIN_AS_DOMAIN ); 84 | $url = VAA_API::get_reset_link(); 85 | echo '
  • ' . esc_html( $link ) . '
  • '; 86 | } 87 | } 88 | 89 | /** 90 | * Show row meta on the plugin screen. 91 | * 92 | * @since 1.6.1 93 | * @see \WP_Plugins_List_Table::single_row() 94 | * @param array[] $links The existing links. 95 | * @param string $file The plugin file. 96 | * @return array 97 | */ 98 | public function action_plugin_row_meta( $links, $file ) { 99 | if ( VIEW_ADMIN_AS_BASENAME === $file ) { 100 | $icon_attr = array( 101 | 'style' => array( 102 | 'font-size: inherit;', 103 | 'line-height: inherit;', 104 | 'display: inline;', 105 | 'vertical-align: text-top;', 106 | ), 107 | ); 108 | foreach ( $this->get_links() as $id => $link ) { 109 | $title = VAA_View_Admin_As_Form::do_icon( $link['icon'], $icon_attr ) . ' ' . esc_html( $link['title'] ); 110 | 111 | $links[ $id ] = '' . $title . ''; 112 | } 113 | } 114 | return $links; 115 | } 116 | 117 | /** 118 | * Plugin links. 119 | * 120 | * @since 1.6.1 121 | * @since 1.6.2 Added Slack channel link 122 | * @return array[] 123 | */ 124 | public function get_links() { 125 | if ( ! empty( $this->links ) ) { 126 | return $this->links; 127 | } 128 | 129 | $this->links = array( 130 | 'support' => array( 131 | 'title' => __( 'Support', VIEW_ADMIN_AS_DOMAIN ), 132 | 'description' => __( 'Need support?', VIEW_ADMIN_AS_DOMAIN ), 133 | 'icon' => 'dashicons-sos', 134 | 'url' => 'https://wordpress.org/support/plugin/view-admin-as/', 135 | ), 136 | 'slack' => array( 137 | 'title' => __( 'Slack', VIEW_ADMIN_AS_DOMAIN ), 138 | 'description' => __( 'Quick help via Slack', VIEW_ADMIN_AS_DOMAIN ), 139 | 'icon' => 'dashicons-format-chat', 140 | 'url' => 'https://keraweb.slack.com/messages/plugin-vaa/', 141 | ), 142 | 'review' => array( 143 | 'title' => __( 'Review', VIEW_ADMIN_AS_DOMAIN ), 144 | 'description' => __( 'Give 5 stars on WordPress.org!', VIEW_ADMIN_AS_DOMAIN ), 145 | 'icon' => 'dashicons-star-filled', 146 | 'url' => 'https://wordpress.org/support/plugin/view-admin-as/reviews/', 147 | ), 148 | 'translate' => array( 149 | 'title' => __( 'Translate', VIEW_ADMIN_AS_DOMAIN ), 150 | 'description' => __( 'Help translating this plugin!', VIEW_ADMIN_AS_DOMAIN ), 151 | 'icon' => 'dashicons-translation', 152 | 'url' => 'https://translate.wordpress.org/projects/wp-plugins/view-admin-as', 153 | ), 154 | 'issue' => array( 155 | 'title' => __( 'Report issue', VIEW_ADMIN_AS_DOMAIN ), 156 | 'description' => __( 'Have ideas or a bug report?', VIEW_ADMIN_AS_DOMAIN ), 157 | 'icon' => 'dashicons-lightbulb', 158 | 'url' => 'https://github.com/JoryHogeveen/view-admin-as/issues', 159 | ), 160 | 'docs' => array( 161 | 'title' => __( 'Documentation', VIEW_ADMIN_AS_DOMAIN ), 162 | 'description' => __( 'Documentation', VIEW_ADMIN_AS_DOMAIN ), 163 | 'icon' => 'dashicons-book-alt', 164 | 'url' => 'https://github.com/JoryHogeveen/view-admin-as/wiki', 165 | ), 166 | 'github' => array( 167 | 'title' => __( 'GitHub', VIEW_ADMIN_AS_DOMAIN ), 168 | 'description' => __( 'Follow development on GitHub', VIEW_ADMIN_AS_DOMAIN ), 169 | 'icon' => 'dashicons-editor-code', 170 | 'url' => 'https://github.com/JoryHogeveen/view-admin-as/tree/dev', 171 | ), 172 | 'donate' => array( 173 | 'title' => __( 'Donate', VIEW_ADMIN_AS_DOMAIN ), 174 | 'description' => __( 'Buy me a coffee!', VIEW_ADMIN_AS_DOMAIN ), 175 | 'icon' => 'dashicons-smiley', 176 | 'url' => 'https://www.keraweb.nl/donate.php?for=view-admin-as', 177 | ), 178 | 'plugins' => array( 179 | 'title' => __( 'Plugins', VIEW_ADMIN_AS_DOMAIN ), 180 | 'description' => __( 'Check out my other plugins', VIEW_ADMIN_AS_DOMAIN ), 181 | 'icon' => 'dashicons-admin-plugins', 182 | 'url' => 'https://profiles.wordpress.org/keraweb/#content-plugins', 183 | ), 184 | ); 185 | 186 | return $this->links; 187 | } 188 | 189 | /** 190 | * Filter the list of query arguments which get removed from admin area URLs in WordPress. 191 | * 192 | * @since 1.6.4 193 | * @access public 194 | * @link https://core.trac.wordpress.org/ticket/23367 195 | * 196 | * @param array $args List of removable query arguments. 197 | * @return array Updated list of removable query arguments. 198 | */ 199 | public function filter_removable_query_args( $args ) { 200 | $vaa_args = array( 201 | 'reset-view', 202 | 'reset-all-views', 203 | 'view_admin_as', 204 | '_vaa_nonce', 205 | ); 206 | 207 | return array_merge( $args, $vaa_args ); 208 | } 209 | 210 | /** 211 | * Remove query arguments from the url. 212 | * Same logic as WP uses since v4.2.0. 213 | * 214 | * @since 1.6.4 215 | * @see wp_admin_canonical_url() 216 | * @return void 217 | */ 218 | public function remove_query_args() { 219 | $removable_query_args = $this->filter_removable_query_args( array() ); 220 | 221 | // @since 1.8.9 Check if args actually exist. 222 | foreach ( $removable_query_args as $index => $arg ) { 223 | if ( ! isset( $_GET[ $arg ] ) ) { 224 | unset( $removable_query_args[ $index ] ); 225 | } 226 | } 227 | 228 | if ( empty( $removable_query_args ) ) { 229 | return; 230 | } 231 | 232 | $request_uri = $_SERVER['REQUEST_URI']; 233 | // @since 1.7.6 Some plugins overwrite `REQUEST_URI` and set it to `ORIG_REQUEST_URI`. 234 | if ( ! empty( $_SERVER['ORIG_REQUEST_URI'] ) ) { 235 | $request_uri = $_SERVER['ORIG_REQUEST_URI']; 236 | } 237 | 238 | // Ensure we're using an absolute URL. 239 | $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $request_uri ); 240 | $filtered_url = remove_query_arg( $removable_query_args, $current_url ); 241 | ?> 242 | 243 | 248 | store->get_version(); 269 | 270 | wp_enqueue_style( 271 | 'vaa_view_admin_as_style', 272 | VIEW_ADMIN_AS_URL . 'assets/css/view-admin-as' . $suffix . '.css', 273 | array( 'admin-bar' ), 274 | $version 275 | ); 276 | wp_enqueue_script( 277 | 'vaa_view_admin_as_script', 278 | VIEW_ADMIN_AS_URL . 'assets/js/view-admin-as' . $suffix . '.js', 279 | array( 'jquery', 'admin-bar' ), 280 | $version, 281 | true // load in footer. 282 | ); 283 | 284 | /** 285 | * Add data to the VAA script localization. 286 | * @since 1.7.0 287 | * @param array $array Empty array (Will be overwritten with VAA core data so use unique keys). 288 | * @return array 289 | */ 290 | $script_localization = array_merge( 291 | (array) apply_filters( 'view_admin_as_script_localization', array() ), 292 | array( 293 | // Data. 294 | 'ajaxurl' => admin_url( 'admin-ajax.php' ), 295 | 'siteurl' => get_site_url(), 296 | 'settings' => $this->store->get_settings(), 297 | 'settings_user' => $this->store->get_userSettings(), 298 | 'view' => $this->store->get_view(), 299 | 'view_types' => $this->vaa->controller()->get_view_types(), 300 | // Other. 301 | //'_loader_icon' => VIEW_ADMIN_AS_URL . 'assets/img/loader.gif', 302 | '_debug' => ( defined( 'WP_DEBUG' ) ) ? (bool) WP_DEBUG : false, 303 | '_vaa_nonce' => $this->store->get_nonce( true ), 304 | // i18n. 305 | '__no_users_found' => esc_html__( 'No users found.', VIEW_ADMIN_AS_DOMAIN ), 306 | '__key_already_exists' => esc_html__( 'Key already exists.', VIEW_ADMIN_AS_DOMAIN ), 307 | '__success' => esc_html__( 'Success', VIEW_ADMIN_AS_DOMAIN ), 308 | '__confirm' => esc_html__( 'Are you sure?', VIEW_ADMIN_AS_DOMAIN ), 309 | '__download' => esc_html__( 'Download', VIEW_ADMIN_AS_DOMAIN ), 310 | ) 311 | ); 312 | 313 | wp_localize_script( 'vaa_view_admin_as_script', 'VAA_View_Admin_As', $script_localization ); 314 | } 315 | 316 | /** 317 | * Add options to the access denied page when the user has selected a view and did something this view is not allowed. 318 | * 319 | * @since 1.3.0 320 | * @since 1.5.1 Check for SSL (Moved to `VAA_API`). 321 | * @since 1.6.0 More options and better description. 322 | * @since 1.7.0 Moved from `VAA_View_Admin_As`. 323 | * @since 1.8.0 Renamed from `die_handler()`. 324 | * @access public 325 | * @see wp_die() 326 | * 327 | * @param callable $callback WP die callback. 328 | * @return callable $callback WP die callback. 329 | */ 330 | public function filter_wp_die_handler( $callback ) { 331 | 332 | // Only do something if a view is selected. 333 | if ( ! VAA_API::is_view_active() ) { 334 | return $callback; 335 | } 336 | 337 | $options = array(); 338 | 339 | if ( is_network_admin() ) { 340 | $options[] = array( 341 | 'text' => __( 'Go to network dashboard', VIEW_ADMIN_AS_DOMAIN ), 342 | 'url' => network_admin_url(), 343 | ); 344 | } else { 345 | $options[] = array( 346 | 'text' => __( 'Go to dashboard', VIEW_ADMIN_AS_DOMAIN ), 347 | 'url' => admin_url(), 348 | ); 349 | $options[] = array( 350 | 'text' => __( 'Go to homepage', VIEW_ADMIN_AS_DOMAIN ), 351 | 'url' => get_bloginfo( 'url' ), 352 | ); 353 | } 354 | 355 | // Reset url. 356 | $options[] = array( 357 | 'text' => __( 'Reset the view', VIEW_ADMIN_AS_DOMAIN ), 358 | 'url' => VAA_API::get_reset_link(), 359 | ); 360 | 361 | /** 362 | * Add or remove options to the die/error handler pages. 363 | * 364 | * @since 1.6.2 365 | * @param array $options { 366 | * Required array of arrays. 367 | * @type array { 368 | * @type string $text The text to show. 369 | * @type string $url The link. 370 | * } 371 | * } 372 | * @return array[] 373 | */ 374 | $options = apply_filters( 'view_admin_as_error_page_options', $options ); 375 | ?> 376 |
    377 |

    :

    378 | 379 |
      380 | 381 |
    • 382 | 383 |
    384 |
    385 |
    386 | add_node( 29 | array( 30 | 'id' => $root . '-filtercaps', 31 | 'parent' => $parent, 32 | 'title' => VAA_View_Admin_As_Form::do_input( 33 | array( 34 | 'name' => $root . '-filtercaps', 35 | 'placeholder' => esc_attr__( 'Filter', VIEW_ADMIN_AS_DOMAIN ), 36 | ) 37 | ), 38 | 'href' => false, 39 | 'meta' => array( 40 | 'class' => 'ab-vaa-input ab-vaa-filter filter-caps vaa-column-one-half vaa-column-first', 41 | ), 42 | ) 43 | ); 44 | 45 | // Select filter 46 | $role_select_options = array( 47 | array( 48 | 'value' => 'default', 49 | 'label' => __( 'Default', VIEW_ADMIN_AS_DOMAIN ), 50 | ), 51 | ); 52 | // View filter 53 | if ( VAA_API::is_view_active() ) { 54 | $data_caps = wp_json_encode( $this->store->get_selectedCaps() ); 55 | $role_select_options[] = array( 56 | 'compare' => 'vaa', 57 | 'label' => '= ' . __( 'Current view', VIEW_ADMIN_AS_DOMAIN ), 58 | 'attr' => array( 59 | 'data-caps' => $data_caps, 60 | ), 61 | ); 62 | $role_select_options[] = array( 63 | 'compare' => 'reversed-vaa', 64 | 'label' => '≠ ' . __( 'Current view', VIEW_ADMIN_AS_DOMAIN ), 65 | 'attr' => array( 66 | 'data-caps' => $data_caps, 67 | 'data-reverse' => '1', 68 | ), 69 | ); 70 | } 71 | // Role filters 72 | foreach ( $this->store->get_roles() as $role_key => $role ) { 73 | $data_caps = wp_json_encode( $role->capabilities ); 74 | $role_select_options[] = array( 75 | 'compare' => esc_attr( $role_key ), 76 | 'label' => '= ' . $this->store->get_rolenames( $role_key ), 77 | 'attr' => array( 78 | 'data-caps' => $data_caps, 79 | ), 80 | ); 81 | $role_select_options[] = array( 82 | 'compare' => 'reversed-' . esc_attr( $role_key ), 83 | 'label' => '≠ ' . $this->store->get_rolenames( $role_key ), 84 | 'attr' => array( 85 | 'data-caps' => $data_caps, 86 | 'data-reverse' => '1', 87 | ), 88 | ); 89 | } 90 | $admin_bar->add_node( 91 | array( 92 | 'id' => $root . '-selectrolecaps', 93 | 'parent' => $parent, 94 | 'title' => VAA_View_Admin_As_Form::do_select( 95 | array( 96 | 'name' => $root . '-selectrolecaps', 97 | 'values' => $role_select_options, 98 | ) 99 | ), 100 | 'href' => false, 101 | 'meta' => array( 102 | 'class' => 'ab-vaa-select select-role-caps vaa-column-one-half vaa-column-last', 103 | 'html' => '', 104 | ), 105 | ) 106 | ); 107 | 108 | // Select/deselect 109 | $admin_bar->add_node( 110 | array( 111 | 'id' => $root . '-bulkselectcaps', 112 | 'parent' => $parent, 113 | 'title' => VAA_View_Admin_As_Form::do_button( 114 | array( 115 | 'name' => 'select-all-caps', 116 | 'label' => __( 'Select', VIEW_ADMIN_AS_DOMAIN ), 117 | 'classes' => 'button-secondary', 118 | ) 119 | ) . ' ' . VAA_View_Admin_As_Form::do_button( 120 | array( 121 | 'name' => 'deselect-all-caps', 122 | 'label' => __( 'Deselect', VIEW_ADMIN_AS_DOMAIN ), 123 | 'classes' => 'button-secondary', 124 | ) 125 | ), 126 | 'href' => false, 127 | 'meta' => array( 128 | 'class' => 'ab-vaa-input vaa-button-container vaa-clear-float', 129 | ), 130 | ) 131 | ); 132 | 133 | } else { 134 | _doing_it_wrong( __FILE__, esc_html__( 'No toolbar resources found.', VIEW_ADMIN_AS_DOMAIN ), '1.7' ); 135 | } // End if(). 136 | -------------------------------------------------------------------------------- /ui/templates/adminbar-caps-items.php: -------------------------------------------------------------------------------- 1 | store->get_caps() as $cap => $granted ) { 29 | $class = 'vaa-cap-item'; 30 | $checked = (bool) $granted; 31 | // check if we've selected a capability view and we've changed some capabilities. 32 | $selected_caps = $this->store->get_view( $this->type ); 33 | if ( isset( $selected_caps[ $cap ] ) ) { 34 | $checked = (bool) $selected_caps[ $cap ]; 35 | } 36 | // Check for this capability in any view set. 37 | if ( $this->vaa->view()->current_view_can( $cap ) ) { 38 | $class .= ' current'; 39 | } 40 | // The list of capabilities. 41 | $caps_items .= 42 | '
    ' 43 | . VAA_View_Admin_As_Form::do_checkbox( 44 | array( 45 | 'name' => 'vaa_cap_' . esc_attr( $cap ), 46 | 'value' => $checked, 47 | 'compare' => true, 48 | 'checkbox_value' => esc_attr( $cap ), 49 | 'label' => $cap, 50 | ) 51 | ) 52 | . '
    '; 53 | } 54 | $admin_bar->add_node( 55 | array( 56 | 'id' => $root . '-select-options', 57 | 'parent' => $parent, 58 | 'title' => $caps_items, 59 | 'href' => false, 60 | 'meta' => array( 61 | 'class' => 'ab-vaa-multipleselect vaa-auto-max-height', 62 | ), 63 | ) 64 | ); 65 | 66 | } else { 67 | _doing_it_wrong( __FILE__, esc_html__( 'No toolbar resources found.', VIEW_ADMIN_AS_DOMAIN ), '1.7' ); 68 | } // End if(). 69 | -------------------------------------------------------------------------------- /ui/templates/adminbar-language-items.php: -------------------------------------------------------------------------------- 1 | store->get_languages() as $locale => $language ) { 27 | $href = VAA_API::get_vaa_action_link( array( $this->type => $locale ) ); 28 | $class = 'vaa-' . $this->type . '-item'; 29 | $title = $this->get_view_title( $locale ); 30 | 31 | $view_title = ( $locale !== $title ) ? $language . '  ' . $locale . '' : $locale; 32 | 33 | $view_title = VAA_View_Admin_As_Form::do_view_title( $view_title, $this, $locale ); 34 | 35 | // Check if this role is the current view. 36 | if ( VAA_API::is_current_view( $locale, $this->type ) ) { 37 | $class .= ' current'; 38 | if ( 1 === count( $this->store->get_view() ) ) { 39 | $href = false; 40 | } 41 | } 42 | 43 | $admin_bar->add_node( 44 | array( 45 | 'id' => $root . '-' . $this->type . '-' . $locale, 46 | 'parent' => $parent, 47 | 'title' => $view_title, 48 | 'href' => $href, 49 | 'meta' => array( 50 | // Translators: %s stands for the translated role name. 51 | 'title' => sprintf( __( 'View as %s', VIEW_ADMIN_AS_DOMAIN ), $title ), 52 | 'class' => $class, 53 | ), 54 | ) 55 | ); 56 | 57 | } // End foreach(). 58 | 59 | } else { 60 | _doing_it_wrong( __FILE__, esc_html__( 'No toolbar resources found.', VIEW_ADMIN_AS_DOMAIN ), '1.7' ); 61 | } // End if(). 62 | -------------------------------------------------------------------------------- /ui/templates/adminbar-role-items.php: -------------------------------------------------------------------------------- 1 | store->get_roles() as $role_key => $role ) { 28 | $href = VAA_API::get_vaa_action_link( array( $this->type => $role_key ) ); 29 | $class = 'vaa-' . $this->type . '-item'; 30 | $title = $this->get_view_title( $role ); 31 | 32 | $view_title = VAA_View_Admin_As_Form::do_view_title( $title, $this, $role_key ); 33 | 34 | /** 35 | * Check if the users need to be grouped under their roles. 36 | * @var \VAA_View_Admin_As_Users $user_view_type 37 | */ 38 | $user_view_type = view_admin_as()->get_view_types( 'user' ); 39 | if ( $user_view_type instanceof VAA_View_Admin_As_Users && $user_view_type->group_user_roles() ) { 40 | // Used to align items properly when some roles don't have users. 41 | $class .= ' vaa-menupop'; 42 | // Check if the current view is a user with this role. 43 | if ( 44 | $this->store->get_view( 'user' ) 45 | && in_array( $role_key, $this->store->get_selectedUser()->roles, true ) 46 | ) { 47 | $class .= ' current-parent'; 48 | } 49 | // If there are users with this role, add a counter. 50 | $user_count = 0; 51 | foreach ( $this->store->get_users() as $user ) { 52 | if ( in_array( $role_key, $user->roles, true ) ) { 53 | $user_count ++; 54 | } 55 | } 56 | if ( 0 < $user_count ) { 57 | $view_title = $view_title . ' (' . $user_count . ')'; 58 | } 59 | } 60 | 61 | // Check if this role is the current view. 62 | if ( VAA_API::is_current_view( $role_key, $this->type ) ) { 63 | $class .= ' current'; 64 | if ( 1 === count( $this->store->get_view() ) ) { 65 | $href = false; 66 | } 67 | } 68 | 69 | $admin_bar->add_node( 70 | array( 71 | 'id' => $root . '-' . $this->type . '-' . $role_key, 72 | 'parent' => $parent, 73 | 'title' => $view_title, 74 | 'href' => $href, 75 | 'meta' => array( 76 | // Translators: %s stands for the translated role name. 77 | 'title' => sprintf( __( 'View as %s', VIEW_ADMIN_AS_DOMAIN ), $title ), 78 | 'class' => $class, 79 | ), 80 | ) 81 | ); 82 | 83 | } // End foreach(). 84 | 85 | } else { 86 | _doing_it_wrong( __FILE__, esc_html__( 'No toolbar resources found.', VIEW_ADMIN_AS_DOMAIN ), '1.7' ); 87 | } // End if(). 88 | -------------------------------------------------------------------------------- /ui/templates/adminbar-settings-user.php: -------------------------------------------------------------------------------- 1 | store ) 27 | && isset( $admin_bar ) && $admin_bar instanceof WP_Admin_Bar 28 | && isset( $root ) 29 | ) { 30 | 31 | /** 32 | * admin_menu_location setting. 33 | * 34 | * @since 1.5.0 35 | */ 36 | $admin_bar->add_node( 37 | array( 38 | 'id' => $root . '-admin-menu-location', 39 | 'parent' => $root, 40 | 'title' => VAA_View_Admin_As_Form::do_select( 41 | array( 42 | 'name' => $root . '-admin-menu-location', 43 | 'value' => $this->store->get_userSettings( 'admin_menu_location' ), 44 | 'label' => __( 'Location', VIEW_ADMIN_AS_DOMAIN ) . ':   ', 45 | 'description' => __( 'Change the location of this menu node', VIEW_ADMIN_AS_DOMAIN ), 46 | 'help' => true, 47 | 'values' => array( 48 | array( 49 | 'compare' => 'top-secondary', 50 | 'label' => __( 'Default', VIEW_ADMIN_AS_DOMAIN ), 51 | ), 52 | array( 53 | 'compare' => 'my-account', 54 | 'label' => __( 'My account', VIEW_ADMIN_AS_DOMAIN ), 55 | ), 56 | ), 57 | 'auto_showhide' => true, 58 | 'auto_js' => array( 59 | 'setting' => 'user_setting', 60 | 'key' => 'admin_menu_location', 61 | 'refresh' => true, 62 | ), 63 | ) 64 | ), 65 | 'href' => false, 66 | 'meta' => array( 67 | 'class' => 'auto-height ab-vaa-select', 68 | ), 69 | ) 70 | ); 71 | 72 | /** 73 | * view_mode setting. 74 | * 75 | * @since 1.5.0 76 | */ 77 | $admin_bar->add_node( 78 | array( 79 | 'id' => $root . '-view-mode', 80 | 'parent' => $root, 81 | 'title' => VAA_View_Admin_As_Form::do_radio( 82 | array( 83 | 'name' => $root . '-view-mode', 84 | 'value' => $this->store->get_userSettings( 'view_mode' ), 85 | 'values' => array( 86 | array( 87 | 'compare' => 'browse', 88 | 'label' => __( 'Browse mode', VIEW_ADMIN_AS_DOMAIN ), 89 | 'description' => __( 'Store view and use WordPress with this view', VIEW_ADMIN_AS_DOMAIN ), 90 | 'help' => true, 91 | ), 92 | array( 93 | 'compare' => 'single', 94 | 'label' => __( 'Single switch mode', VIEW_ADMIN_AS_DOMAIN ), 95 | 'description' => __( 'Choose view on every pageload. This setting doesn\'t store views', VIEW_ADMIN_AS_DOMAIN ), 96 | 'help' => true, 97 | ), 98 | ), 99 | 'auto_showhide' => true, 100 | 'auto_js' => array( 101 | 'setting' => 'user_setting', 102 | 'key' => 'view_mode', 103 | 'refresh' => false, 104 | ), 105 | ) 106 | ), 107 | 'href' => false, 108 | 'meta' => array( 109 | 'class' => 'auto-height', 110 | ), 111 | ) 112 | ); 113 | 114 | /** 115 | * Disable super admin checks while switched. 116 | * 117 | * @since 1.7.3 118 | * @since 1.8.0 Don't use VAA_API since users that are super admins but don't have full access could 119 | * still want to use this setting. 120 | * Also check if the installation is a network. 121 | */ 122 | if ( is_multisite() && is_super_admin( view_admin_as()->store()->get_curUser()->ID ) ) { 123 | $admin_bar->add_node( 124 | array( 125 | 'id' => $root . '-disable-super-admin', 126 | 'parent' => $root, 127 | 'title' => VAA_View_Admin_As_Form::do_checkbox( 128 | array( 129 | 'name' => $root . '-disable-super-admin', 130 | 'value' => $this->store->get_userSettings( 'disable_super_admin' ), 131 | 'compare' => true, 132 | 'label' => __( 'Disable super admin', VIEW_ADMIN_AS_DOMAIN ), 133 | 'description' => __( 'Disable super admin status while switched to another view', VIEW_ADMIN_AS_DOMAIN ), 134 | 'help' => true, 135 | 'auto_showhide' => true, 136 | 'auto_js' => array( 137 | 'setting' => 'user_setting', 138 | 'key' => 'disable_super_admin', 139 | 'refresh' => ( $this->store->get_view() ) ? true : false, 140 | ), 141 | ) 142 | ), 143 | 'href' => false, 144 | 'meta' => array( 145 | 'class' => 'auto-height', 146 | ), 147 | ) 148 | ); 149 | } 150 | 151 | /** 152 | * hide_front setting. 153 | * 154 | * @since 1.6.0 155 | */ 156 | $admin_bar->add_node( 157 | array( 158 | 'id' => $root . '-hide-front', 159 | 'parent' => $root, 160 | 'title' => VAA_View_Admin_As_Form::do_checkbox( 161 | array( 162 | 'name' => $root . '-hide-front', 163 | 'value' => $this->store->get_userSettings( 'hide_front' ), 164 | 'compare' => true, 165 | 'label' => __( 'Hide on frontend', VIEW_ADMIN_AS_DOMAIN ), 166 | 'description' => __( 'Hide on frontend when no view is selected and the admin bar is not shown', VIEW_ADMIN_AS_DOMAIN ), 167 | 'help' => true, 168 | 'auto_showhide' => true, 169 | 'auto_js' => array( 170 | 'setting' => 'user_setting', 171 | 'key' => 'hide_front', 172 | 'refresh' => false, 173 | ), 174 | ) 175 | ), 176 | 'href' => false, 177 | 'meta' => array( 178 | 'class' => 'auto-height', 179 | ), 180 | ) 181 | ); 182 | 183 | /** 184 | * hide_customizer setting. 185 | * 186 | * @since 1.7.6 187 | */ 188 | $admin_bar->add_node( 189 | array( 190 | 'id' => $root . '-hide-customizer', 191 | 'parent' => $root, 192 | 'title' => VAA_View_Admin_As_Form::do_checkbox( 193 | array( 194 | 'name' => $root . '-hide-customizer', 195 | 'value' => $this->store->get_userSettings( 'hide_customizer' ), 196 | 'compare' => true, 197 | 'label' => __( 'Hide on customizer', VIEW_ADMIN_AS_DOMAIN ), 198 | 'description' => __( 'Hide on customizer when no view is selected', VIEW_ADMIN_AS_DOMAIN ), 199 | 'help' => true, 200 | 'auto_showhide' => true, 201 | 'auto_js' => array( 202 | 'setting' => 'user_setting', 203 | 'key' => 'hide_customizer', 204 | 'refresh' => VAA_API::is_customizer_admin(), 205 | ), 206 | ) 207 | ), 208 | 'href' => false, 209 | 'meta' => array( 210 | 'class' => 'auto-height', 211 | ), 212 | ) 213 | ); 214 | 215 | /** 216 | * freeze_locale setting. 217 | * Force own locale on view, WP 4.7+ only. 218 | * 219 | * @see https://github.com/JoryHogeveen/view-admin-as/issues/21 220 | * @since 1.6.1 221 | */ 222 | if ( VAA_API::validate_wp_version( '4.7' ) ) { 223 | $admin_bar->add_node( 224 | array( 225 | 'id' => $root . '-freeze-locale', 226 | 'parent' => $root, 227 | 'title' => VAA_View_Admin_As_Form::do_checkbox( 228 | array( 229 | 'name' => $root . '-freeze-locale', 230 | 'value' => $this->store->get_userSettings( 'freeze_locale' ), 231 | 'compare' => true, 232 | 'label' => __( 'Freeze locale', VIEW_ADMIN_AS_DOMAIN ), 233 | 'description' => __( 'Force your own locale setting to the current view', VIEW_ADMIN_AS_DOMAIN ), 234 | 'help' => true, 235 | 'auto_showhide' => true, 236 | 'auto_js' => array( 237 | 'setting' => 'user_setting', 238 | 'key' => 'freeze_locale', 239 | 'refresh' => ( $this->store->get_view( 'user' ) ) ? true : false, 240 | ), 241 | ) 242 | ), 243 | 'href' => false, 244 | 'meta' => array( 245 | 'class' => 'auto-height', 246 | ), 247 | ) 248 | ); 249 | } 250 | 251 | } // End if(). 252 | -------------------------------------------------------------------------------- /ui/templates/adminbar-user-actions.php: -------------------------------------------------------------------------------- 1 | ajax_search() || $this->group_user_roles() ) { 32 | 33 | $title = ''; 34 | if ( $this->group_user_roles() ) { 35 | $title = VAA_View_Admin_As_Form::do_description( __( 'Users are grouped under their roles', VIEW_ADMIN_AS_DOMAIN ) ); 36 | } 37 | if ( $this->ajax_search() ) { 38 | $title .= VAA_View_Admin_As_Form::do_select( array( 39 | 'name' => $root . '-search-by', 40 | 'values' => $this->search_users_by_select_values(), 41 | 'class' => 'vaa-wide', 42 | ) ); 43 | } 44 | $title .= VAA_View_Admin_As_Form::do_input( array( 45 | 'name' => $root . '-search', 46 | 'placeholder' => __( 'Search', VIEW_ADMIN_AS_DOMAIN ), 47 | 'class' => 'vaa-wide', 48 | ) ); 49 | 50 | $admin_bar->add_node( array( 51 | 'id' => $root . '-search', 52 | 'parent' => $root, 53 | 'title' => $title, 54 | 'href' => false, 55 | 'meta' => array( 56 | 'class' => 'ab-vaa-search search-users' . ( ( $this->ajax_search() ) ? ' search-ajax' : '' ), 57 | 'html' => '
      ', 58 | ), 59 | ) ); 60 | } 61 | 62 | } else { 63 | _doing_it_wrong( __FILE__, esc_html__( 'No toolbar resources found.', VIEW_ADMIN_AS_DOMAIN ), '1.7' ); 64 | } // End if(). 65 | -------------------------------------------------------------------------------- /ui/templates/adminbar-user-items.php: -------------------------------------------------------------------------------- 1 | store->get_users() as $user ) { 32 | // Reset parent for each loop due to groupUserRoles. 33 | $item_parent = $parent; 34 | 35 | $href = VAA_API::get_vaa_action_link( array( $this->type => $user->ID ) ); 36 | $class = 'vaa-' . $this->type . '-item'; 37 | $title = $this->get_view_title( $user ); 38 | 39 | $view_title = VAA_View_Admin_As_Form::do_view_title( $title, $this, $user->ID ); 40 | 41 | /** 42 | * Add the user roles to the user title? 43 | * Only available if users are not grouped under their roles. 44 | * @see VAA_View_Admin_As_Users::get_view_title_roles() 45 | */ 46 | if ( ! $this->group_user_roles() ) { 47 | $view_title .= $this->get_view_title_roles( $user ); 48 | } 49 | 50 | // Check if this user is the current view. 51 | if ( VAA_API::is_current_view( $user->ID, $this->type ) ) { 52 | $class .= ' current'; 53 | if ( 1 === count( $this->store->get_view() ) ) { 54 | $href = false; 55 | } 56 | } 57 | 58 | $user_node = array( 59 | 'id' => $root . '-' . $this->type . '-' . $user->ID, 60 | 'parent' => $item_parent, 61 | 'title' => $view_title, 62 | 'href' => $href, 63 | 'meta' => array( 64 | // Translators: %s stands for the user view title (display name by default). 65 | 'title' => sprintf( __( 'View as %s', VIEW_ADMIN_AS_DOMAIN ), $title ), 66 | 'class' => $class, 67 | ), 68 | ); 69 | 70 | if ( $this->group_user_roles() ) { 71 | // Users grouped under roles. 72 | foreach ( $user->roles as $role ) { 73 | $user_role_node = $user_node; 74 | $item_parent = $main_root . '-roles-role-' . $role; 75 | $group = $item_parent . '-users'; 76 | if ( ! $admin_bar->get_node( $group ) ) { 77 | $admin_bar->add_group( array( 78 | 'id' => $group, 79 | 'parent' => $item_parent, 80 | 'meta' => array( 81 | 'class' => 'vaa-auto-max-height', 82 | ), 83 | ) ); 84 | } 85 | $user_role_node['id'] .= '-' . $role; 86 | $user_role_node['parent'] = $group; 87 | $admin_bar->add_node( $user_role_node ); 88 | } 89 | } else { 90 | $admin_bar->add_node( $user_node ); 91 | } 92 | 93 | } // End foreach(). 94 | 95 | } else { 96 | _doing_it_wrong( __FILE__, esc_html__( 'No toolbar resources found.', VIEW_ADMIN_AS_DOMAIN ), '1.7' ); 97 | } // End if(). 98 | -------------------------------------------------------------------------------- /ui/templates/index.php: -------------------------------------------------------------------------------- 1 | 8 | * @package view-admin-as 9 | * @since 1.3.4 10 | * @version 1.8.2 11 | */ 12 | 13 | //if uninstall not called from WordPress exit 14 | if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { 15 | die(); 16 | } 17 | 18 | vaa_uninstall(); 19 | 20 | if ( is_multisite() ) { 21 | global $wp_version; 22 | if ( version_compare( $wp_version, '4.5.999', '<' ) ) { 23 | // @codingStandardsIgnoreLine >> Backwards compat (Sadly does not work for large networks -> return false). 24 | $blogs = wp_get_sites(); 25 | } else { 26 | $blogs = get_sites(); 27 | } 28 | if ( $blogs ) { 29 | foreach ( $blogs as $blog ) { 30 | $blog = (array) $blog; 31 | vaa_uninstall( intval( $blog['blog_id'] ) ); 32 | } 33 | vaa_uninstall( 'site' ); 34 | } 35 | } 36 | 37 | function vaa_uninstall( $blog_id = false ) { 38 | 39 | // Delete all View Admin As options 40 | $option_keys = array( 'vaa_view_admin_as', 'vaa_role_defaults', 'vaa_role_manager' ); 41 | 42 | if ( $blog_id ) { 43 | 44 | if ( 'site' === $blog_id ) { 45 | foreach ( $option_keys as $option_key ) { 46 | delete_site_option( $option_key ); 47 | } 48 | } else { 49 | foreach ( $option_keys as $option_key ) { 50 | delete_blog_option( $blog_id, $option_key ); 51 | } 52 | } 53 | 54 | } else { 55 | 56 | foreach ( $option_keys as $option_key ) { 57 | delete_option( $option_key ); 58 | } 59 | 60 | // Delete all View Admin As user metadata 61 | $user_meta_keys = array( 62 | 'vaa-view-admin-as', 63 | // Older (not used anymore) keys 64 | 'view-admin-as', 65 | ); 66 | 67 | foreach ( $user_meta_keys as $user_meta_key ) { 68 | delete_metadata( 'user', null, $user_meta_key, '', true ); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /view-admin-as.php: -------------------------------------------------------------------------------- 1 | 4 | * @package View_Admin_As 5 | * @since 0.1.0 6 | * @version 1.8.10 7 | * @licence GPL-2.0+ 8 | * @link https://github.com/JoryHogeveen/view-admin-as 9 | * 10 | * @wordpress-plugin 11 | * Plugin Name: View Admin As 12 | * Plugin URI: https://wordpress.org/plugins/view-admin-as/ 13 | * Description: View the WordPress admin as a different role or visitor, switch between users, temporarily change your capabilities, set default screen settings for roles. 14 | * Version: 1.8.10 15 | * Author: Jory Hogeveen 16 | * Author URI: https://www.keraweb.nl 17 | * Text Domain: view-admin-as 18 | * Domain Path: /languages/ 19 | * License: GPL-2.0+ 20 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 21 | * GitHub Plugin URI: https://github.com/JoryHogeveen/view-admin-as 22 | * 23 | * @copyright 2015-2019 Jory Hogeveen 24 | * 25 | * This program is free software; you can redistribute it and/or modify 26 | * it under the terms of the GNU General Public License as published by 27 | * the Free Software Foundation; either version 2 of the License, or 28 | * ( at your option ) any later version. 29 | * 30 | * This program is distributed in the hope that it will be useful, 31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | * GNU General Public License for more details. 34 | * 35 | * You should have received a copy of the GNU General Public License 36 | * along with this program; if not, write to the Free Software 37 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 38 | * MA 02110-1301, USA. 39 | */ 40 | 41 | if ( ! defined( 'ABSPATH' ) ) { 42 | die(); 43 | } 44 | 45 | if ( ! class_exists( 'VAA_View_Admin_As' ) && ! function_exists( 'view_admin_as' ) ) { 46 | 47 | define( 'VIEW_ADMIN_AS_VERSION', '1.8.10' ); 48 | define( 'VIEW_ADMIN_AS_DB_VERSION', '1.8' ); 49 | define( 'VIEW_ADMIN_AS_DOMAIN', 'view-admin-as' ); 50 | define( 'VIEW_ADMIN_AS_FILE', __FILE__ ); 51 | define( 'VIEW_ADMIN_AS_BASENAME', plugin_basename( VIEW_ADMIN_AS_FILE ) ); 52 | 53 | /** 54 | * Added must-use (mu-plugins) compatibility. 55 | * 56 | * @since 1.7.3 57 | * Move this file into the root of your mu-plugins directory, not in the `view-admin-as` subdirectory. 58 | * This is a limitation of WordPress and probably won't change soon. 59 | * @example 60 | * Plugins dir: /wp-content/mu-plugins/view-admin-as/... 61 | * This file dir: /wp-content/mu-plugins/view-admin-as.php 62 | * 63 | * @since 1.7.4 Compatibility with mu-plugin loader scripts. 64 | * @example https://gist.github.com/JoryHogeveen/b91d144c9916df430c821fcd834a9667 65 | */ 66 | if ( 0 === strpos( VIEW_ADMIN_AS_FILE, WPMU_PLUGIN_DIR ) ) { 67 | define( 'VIEW_ADMIN_AS_MU', true ); 68 | if ( basename( VIEW_ADMIN_AS_FILE ) === VIEW_ADMIN_AS_BASENAME ) { 69 | // This file is in the mu root folder. 70 | define( 'VIEW_ADMIN_AS_DIR', plugin_dir_path( VIEW_ADMIN_AS_FILE ) . trailingslashit( 'view-admin-as' ) ); 71 | define( 'VIEW_ADMIN_AS_URL', plugin_dir_url( VIEW_ADMIN_AS_FILE ) . trailingslashit( 'view-admin-as' ) ); 72 | } else { 73 | // This file is in the VAA folder, probably loaded using a mu-plugin loader. 74 | define( 'VIEW_ADMIN_AS_DIR', plugin_dir_path( VIEW_ADMIN_AS_FILE ) ); 75 | define( 'VIEW_ADMIN_AS_URL', plugin_dir_url( VIEW_ADMIN_AS_FILE ) ); 76 | } 77 | } else { 78 | define( 'VIEW_ADMIN_AS_MU', false ); 79 | define( 'VIEW_ADMIN_AS_DIR', plugin_dir_path( VIEW_ADMIN_AS_FILE ) ); 80 | define( 'VIEW_ADMIN_AS_URL', plugin_dir_url( VIEW_ADMIN_AS_FILE ) ); 81 | } 82 | 83 | /** 84 | * PHP 5.5+ function. 85 | * @see boolval() 86 | * @todo Move to a separate file? 87 | */ 88 | if ( ! function_exists( 'boolval' ) ) { 89 | function boolval( $val ) { 90 | return (bool) $val; 91 | } 92 | } 93 | 94 | // Include main init class file. 95 | require_once VIEW_ADMIN_AS_DIR . 'includes/class-vaa.php'; 96 | 97 | /** 98 | * Main instance of View Admin As. 99 | * Returns the main instance of VAA_View_Admin_As to prevent the need to use globals. 100 | * 101 | * @since 1.4.1 102 | * @since 1.6.4 Changed to lowercase (style fix). 103 | * @return \VAA_View_Admin_As 104 | */ 105 | function view_admin_as() { 106 | return VAA_View_Admin_As::get_instance(); 107 | } 108 | 109 | // Instantiate View Admin As. 110 | view_admin_as(); 111 | 112 | // end if class_exists. 113 | } else { 114 | 115 | // @since 1.5.1 added notice on class name conflict. 116 | add_action( 'admin_notices', 'view_admin_as_conflict_admin_notice' ); 117 | function view_admin_as_conflict_admin_notice() { 118 | echo '

      ' . esc_html__( 'View Admin As', 'view-admin-as' ) . ': ' 119 | . esc_html__( 'Plugin not activated because of a conflict with an other plugin or theme', 'view-admin-as' ) 120 | // Translators: %s stands for the class name. 121 | . ' (' . sprintf( esc_html__( 'Class %s already exists', 'view-admin-as' ), 'VAA_View_Admin_As' ) . ')

      '; 122 | } 123 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; 124 | deactivate_plugins( plugin_basename( __FILE__ ) ); 125 | 126 | } // End if(). 127 | --------------------------------------------------------------------------------