Add gravity flow demo

This commit is contained in:
Almira Krdzic
2018-06-28 10:02:07 +02:00
parent 1b5076bf2f
commit 12a5066018
1106 changed files with 317603 additions and 4720 deletions

View File

@@ -0,0 +1,917 @@
<?php
/**
* View Admin As - Class API
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* API class that holds general functions.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.6
* @version 1.8
*/
final class VAA_API
{
/**
* Check if a user has full access to this plugin.
*
* @since 1.8
* @access public
* @static
* @api
*
* @param \WP_User|int $user The user to check.
* @return bool
*/
public static function user_has_full_access( $user ) {
if ( ! $user instanceof WP_User ) {
$user = get_user_by( 'ID', $user );
if ( ! $user ) {
return false;
}
}
if ( is_multisite() ) {
return is_super_admin( $user->ID );
}
/**
* For single installations is_super_admin() isn't enough since it only checks for `delete_users`.
* @since 1.7.6
* @link https://wordpress.org/support/topic/required-capabilities-2/
*/
$caps = array(
'edit_users',
'delete_plugins',
);
/**
* Filter the capabilities required to gain full access to this plugin.
* Note: Single site only!
* Note: is_super_admin() is always checked!
*
* @since 1.8
* @param array $caps The default capabilities.
* @param \WP_User $user The user that is being validated.
* @return array
*/
$caps = apply_filters( 'view_admin_as_full_access_capabilities', $caps, $user );
foreach ( $caps as $cap ) {
if ( ! $user->has_cap( $cap ) ) {
return false;
}
}
return is_super_admin( $user->ID );
}
/**
* Check if the user is a super admin.
* This check is more strict for single installations since it checks VAA_API::user_has_full_access.
* It will validate the original user while in a view and no parameter is passed.
*
* @see \VAA_API::user_has_full_access()
* @see \VAA_View_Admin_As_Store::cur_user_has_full_access()
*
* @since 1.6.3
* @since 1.8 Check full access.
* @access public
* @static
* @api
*
* @param int|\WP_User $user (optional) Default: current user.
* @return bool
*/
public static function is_super_admin( $user = null ) {
if ( null === $user || view_admin_as()->store()->is_curUser( $user ) ) {
return view_admin_as()->store()->cur_user_has_full_access();
}
return self::user_has_full_access( $user );
}
/**
* Check if the user is a superior admin.
* It will validate the original user while in a view and no parameter is passed.
*
* @since 1.5.3
* @since 1.6 Moved to this class from main class
* @since 1.6.3 Improve is_super_admin() check
* @since 1.8 Enhance code to reflect VAA_API::is_super_admin() changes.
* @access public
* @static
* @api
*
* @param int|\WP_User $user_id (optional) Default: current user.
* @return bool
*/
public static function is_superior_admin( $user_id = null ) {
// If it's the current user or null, don't pass the user ID to make sure we check the original user status.
$is_super_admin = self::is_super_admin(
( null !== $user_id && view_admin_as()->store()->is_curUser( $user_id ) ) ? null : $user_id
);
// Full access is required.
if ( ! $is_super_admin ) {
return false;
}
if ( null === $user_id ) {
$user_id = view_admin_as()->store()->get_originalUserData( 'ID' );
} elseif ( $user_id instanceof WP_User ) {
$user_id = $user_id->ID;
}
// Is it one of the manually configured superior admins?
return (bool) ( in_array( (int) $user_id, self::get_superior_admins(), true ) );
}
/**
* Get the superior admin ID's (filter since 1.5.2)
*
* @since 1.5.3
* @since 1.6 Moved to this class from main class
* @access public
* @static
* @api
*
* @return array
*/
public static function get_superior_admins() {
static $superior_admins;
if ( ! is_null( $superior_admins ) ) return $superior_admins;
/**
* Grant admins the capability to view other admins. There is no UI for this!
*
* @since 1.5.2
* @param array
* @return int[] Requires a returned array of user ID's
*/
$superior_admins = array_unique( array_map( 'absint', array_filter(
(array) apply_filters( 'view_admin_as_superior_admins', array() ),
'is_numeric' // Only allow numeric values (user id's)
) ) );
return $superior_admins;
}
/**
* Check if the provided data is the same as the current view.
*
* @see \VAA_View_Admin_As_Controller::is_current_view()
*
* @since 1.7.1
* @access public
* @static
* @api
*
* @param mixed $data
* @param bool $type Only compare a single view type instead of all view data?
* If set, the data value should be the single view type data.
* If data is `null` then it will return true if that view type is active.
* If data is `false` then it will return true if this is the only active view type.
* @return bool
*/
public static function is_current_view( $data, $type = null ) {
$controller = view_admin_as()->controller();
if ( $controller ) {
return $controller->is_current_view( $data, $type );
}
return false;
}
/**
* Similar function to current_user_can().
*
* @see \VAA_View_Admin_As_View::current_view_can()
*
* @since 1.7.2
* @access public
* @static
* @api
*
* @param string $cap The capability.
* @param array $caps (optional) Capabilities to compare to.
* Defaults to the selected caps for the current view.
* @return bool
*/
public static function current_view_can( $cap, $caps = array() ) {
$view = view_admin_as()->view();
if ( $view ) {
return $view->current_view_can( $cap, $caps );
}
return false;
}
/**
* Is the current user modified?
*
* @see \VAA_View_Admin_As_View::current_view_can()
*
* @since 1.7.2
* @access public
* @static
* @api
*
* @return bool
*/
public static function is_user_modified() {
$view = view_admin_as()->view();
if ( $view ) {
return $view->is_user_modified();
}
return false;
}
/**
* Is any toolbar showing?
* Do not use this before the `init` hook.
*
* @since 1.7
* @access public
* @static
* @api
*
* @return bool
*/
public static function is_toolbar_showing() {
if ( is_admin_bar_showing() || self::is_vaa_toolbar_showing() ) {
return true;
}
return false;
}
/**
* Is our custom toolbar showing?
* Do not use this before the `init` hook.
*
* @since 1.6
* @access public
* @static
* @api
*
* @return bool
*/
public static function is_vaa_toolbar_showing() {
if ( class_exists( 'VAA_View_Admin_As_Toolbar' ) ) {
return (bool) VAA_View_Admin_As_Toolbar::$showing;
}
return false;
}
/**
* Is the customizer admin container currently rendering?
*
* @since 1.7.6
* @access public
* @static
* @api
*
* @return bool
*/
public static function is_customizer_admin() {
if ( is_customize_preview() && is_admin() ) {
return true;
}
return false;
}
/**
* Check if a view type is enabled. Pass an array to check multiple view types.
*
* @since 1.8
* @access public
* @static
* @api
*
* @param string|array $type The view type key.
* @return bool
*/
public static function is_view_type_enabled( $type ) {
$type = view_admin_as()->get_view_types( $type );
if ( is_array( $type ) ) {
foreach ( $type as $view_type ) {
if ( ! $view_type instanceof VAA_View_Admin_As_Type || ! $view_type->is_enabled() ) {
return false;
}
}
return true;
}
if ( $type instanceof VAA_View_Admin_As_Type ) {
return $type->is_enabled();
}
return false;
}
/**
* Generate a VAA action link.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param array $data View type data.
* @param string $nonce The nonce.
* @param string $url (optional) A URL. Of not passed it will generate a link from the current URL.
* @return string
*/
public static function get_vaa_action_link( $data, $nonce, $url = null ) {
$params = array(
'action' => 'view_admin_as',
'view_admin_as' => $data, // wp_json_encode( array( $type, $data ) ),
'_vaa_nonce' => (string) $nonce,
);
// @todo fix WP referrer/nonce checks and allow switching on any page without ajax.
// @see https://codex.wordpress.org/Function_Reference/check_admin_referer
if ( empty( $url ) ) {
if ( is_admin() ) {
$url = is_network_admin() ? network_admin_url() : admin_url();
} else {
// Since 1.7.5 Frontend url.
$url = get_site_url();
}
}
$url = add_query_arg( $params, ( $url ) ? $url : false );
return esc_url( $url, array( 'http', 'https' ) );
}
/**
* Appends the "reset-view" parameter to the current URL.
*
* @since 1.6
* @access public
* @static
* @api
*
* @param string $url (optional) Use a defined url create the reset link.
* @param bool $all (optional) Reset all views link?
* @return string
*/
public static function get_reset_link( $url = null, $all = false ) {
$params = 'reset-view';
if ( $all ) {
$params = 'reset-all-views';
}
$url = add_query_arg( $params, '', ( $url ) ? $url : false );
return esc_url( $url, array( 'http', 'https' ) );
}
/**
* Removes the "reset-view" or "reset-all-views" parameter to the current URL.
*
* @since 1.6
* @access public
* @static
* @api
*
* @param string $url (optional) Use a defined url to remove the reset link.
* @return string
*/
public static function remove_reset_link( $url = '' ) {
$url = remove_query_arg( array( 'reset-view', 'reset-all-views' ), ( $url ) ? $url : false );
return esc_url( $url, array( 'http', 'https' ) );
}
/**
* Get full array or array key(s).
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7.5 Option to pass an array of keys. Will always return an array (even if not found) + third require_all option.
* @access public
* @static
* @api
*
* @param array $array The requested array.
* @param string|array $key (optional) Return only a key of the requested array.
* @param bool $require_all (optional) In case of an array of keys, return `null` if not all keys are present?
* @return mixed
*/
public static function get_array_data( $array, $key = null, $require_all = false ) {
if ( null !== $key ) {
if ( ! is_array( $array ) ) {
return null;
}
// @since 1.7.5 Search for multiple keys.
if ( is_array( $key ) ) {
$return = array();
foreach ( $key as $k ) {
if ( isset( $array[ $k ] ) ) {
$return[ $k ] = $array[ $k ];
}
}
if ( $require_all && array_diff_key( array_flip( $key ), $return ) ) {
return null;
}
return $return;
}
if ( isset( $array[ $key ] ) ) {
return $array[ $key ];
}
return null; // return null if key is not found
}
return $array;
}
/**
* Set full array or array key.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @access public
* @static
* @api
*
* @param array $array Original array.
* @param mixed $var The new value.
* @param string $key (optional) The array key for the value.
* @param bool $append (optional) If the key doesn't exist in the original array, append it.
* @return mixed
*/
public static function set_array_data( $array, $var, $key = null, $append = false ) {
if ( null !== $key ) {
if ( true === $append && ! is_array( $array ) ) {
$array = array();
}
if ( is_array( $array ) && ( true === $append || isset( $array[ $key ] ) ) ) {
$array[ $key ] = $var;
return $array;
}
// Notify user if in debug mode
_doing_it_wrong(
__METHOD__,
'View Admin As: Key <code>' . (string) $key . '</code> does not exist',
null
);
// return no changes if key is not found or appending is not allowed.
return $array;
}
return $var;
}
/**
* Check if two arrays are the same.
* Does NOT support recursive arrays!
*
* @since 1.7
* @access public
* @static
* @api
*
* @param array $array1 Array one.
* @param array $array2 Array two.
* @param bool $recursive (optional) Compare recursively.
* @param bool $strict (optional) Strict comparison? Only available when comparing recursive.
* @return bool
*/
public static function array_equal( $array1, $array2, $recursive = true, $strict = false ) {
if ( ! is_array( $array1 ) || ! is_array( $array2 ) ) {
return false;
}
if ( $recursive ) {
return (
self::array_diff_assoc_recursive( $array1, $array2, $strict ) === self::array_diff_assoc_recursive( $array2, $array1, $strict )
);
}
// Check for recursive arrays.
$arr1 = array_filter( $array1, 'is_scalar' );
$arr2 = array_filter( $array2, 'is_scalar' );
if ( $array1 !== $arr1 || $array2 !== $arr2 ) {
return false;
}
return (
count( $arr1 ) === count( $arr2 ) &&
array_diff_assoc( $arr1, $arr2 ) === array_diff_assoc( $arr2, $arr1 )
);
}
/**
* Recursive version of `array_diff_assoc()`.
*
* @since 1.7.3
* @access public
* @static
* @api
*
* @param array $array1 Array one.
* @param array $array2 Array two.
* @param bool $strict Strict comparison?
* @return array
*/
public static function array_diff_assoc_recursive( $array1, $array2, $strict = false ) {
$return = array();
foreach ( $array1 as $key => $value ) {
if ( array_key_exists( $key, $array2 ) ) {
if ( is_array( $value ) ) {
if ( is_array( $array2[ $key ] ) ) {
$diff = self::array_diff_assoc_recursive( $value, $array2[ $key ], $strict );
if ( $diff ) {
$return[ $key ] = $diff;
}
} else {
$return[ $key ] = $value;
}
} else {
if ( $strict ) {
if ( $value !== $array2[ $key ] ) {
$return[ $key ] = $value;
}
} else {
if ( (string) $value !== (string) $array2[ $key ] ) {
$return[ $key ] = $value;
}
}
}
} else {
$return[ $key ] = $value;
}
}
return $return;
}
/**
* Check if an array has a key and optional compare or validate the value.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param array $array
* @param string $key
* @param array $args {
* Optional array of match arguments.
* @type mixed $compare A value to compare against (NOTE: strict comparison!).
* @type string|array $validation A variable function check, example: 'is_int' or 'MyClass::check'.
* }
* @return bool
*/
public static function array_has( $array, $key, $args = array() ) {
$isset = ( isset( $array[ $key ] ) );
if ( empty( $args ) || ! $isset ) {
return $isset;
}
$value = $array[ $key ];
if ( isset( $args['compare'] ) ) {
return ( $args['compare'] === $value );
}
if ( ! empty( $args['validation'] ) ) {
$validation = $args['validation'];
// Don't accept unavailable validation methods.
if ( ! is_callable( $validation ) ) {
return false;
}
if ( is_array( $validation ) ) {
return (bool) call_user_func( $validation, $value );
}
return (bool) $validation( $value );
}
return false;
}
/**
* Does a string starts with a given string?
*
* @since 1.4
* @since 1.7 Moved from VAA_View_Admin_As_Role_Defaults.
* @access public
* @static
* @api
*
* @param string $haystack The string to search in.
* @param string $needle The string to search for.
* @return bool
*/
public static function starts_with( $haystack, $needle ) {
// Search backwards starting from haystack length characters from the end.
return '' === $needle || 0 === strpos( $haystack, $needle );
}
/**
* Does a string ends with a given string?
*
* @since 1.4
* @since 1.7 Moved from VAA_View_Admin_As_Role_Defaults.
* @access public
* @static
* @api
*
* @param string $haystack The string to search in.
* @param string $needle The string to search for.
* @return bool
*/
public static function ends_with( $haystack, $needle ) {
// Search forward starting from end minus needle length characters.
return '' === $needle || ( strlen( $haystack ) - strlen( $needle ) === strrpos( $haystack, $needle ) );
}
/**
* Compare with the current WordPress version.
* Returns true when it's the provided version or newer.
*
* @since 1.6.4
* @since 1.7.2 Only check full version numbers by default.
* @access public
* @static
* @api
*
* @global string $wp_version WordPress version.
* @param int|string $version The WP version to check.
* @param bool $only_full_versions Only validate full versions without dev notes (RC1, dev, etc).
* @return bool
*/
public static function validate_wp_version( $version, $only_full_versions = true ) {
global $wp_version;
$version = strtolower( $version );
$compare = strtolower( $wp_version );
if ( $only_full_versions ) {
// Only leave the version numbers.
$version = explode( '-', $version );
$version = $version[0];
$compare = explode( '-', $compare );
$compare = $compare[0];
}
return (bool) version_compare( $version, $compare, '<=' );
}
/**
* Enhancement for is_callable(), also check for class_exists() or method_exists() when an array is passed.
* Prevents incorrect `true` when a class has a __call() method.
* Can also handle error notices.
*
* @since 1.7.4
* @access public
* @static
* @api
*
* @param callable|array $callable The callable data.
* @param bool|string $do_notice Add an error notice when it isn't?
* Pass `debug` to only show notice when WP_DEBUG is enabled.
* @param bool $syntax_only See is_callable() docs.
* @return bool
*/
public static function exists_callable( $callable, $do_notice = false, $syntax_only = false ) {
$pass = is_callable( $callable, $syntax_only );
if ( $pass && is_array( $callable ) ) {
if ( 1 === count( $callable ) ) {
$pass = class_exists( $callable[0] );
} else {
$pass = method_exists( $callable[0], $callable[1] );
}
}
if ( ! $pass && $do_notice ) {
if ( 'debug' === $do_notice ) {
$do_notice = ( defined( 'WP_DEBUG' ) && WP_DEBUG );
}
if ( ! is_string( $do_notice ) ) {
$callable = self::callable_to_string( $callable );
$do_notice = sprintf(
// Translators: %s stands for the requested class, method or function.
__( '%s does not exist or is not callable.', VIEW_ADMIN_AS_DOMAIN ),
'<code>' . $callable . '</code>'
);
}
view_admin_as()->add_error_notice( $callable, array(
'message' => $do_notice,
) );
}
return (boolean) $pass;
}
/**
* Convert callable variable to string for display.
*
* @since 1.7.4
* @access public
* @static
* @api
*
* @param callable|array $callable
* @return string
*/
public static function callable_to_string( $callable ) {
if ( is_string( $callable ) ) {
return $callable;
}
if ( is_object( $callable ) ) {
$callable = array( $callable, '' );
}
if ( is_array( $callable ) ) {
if ( is_object( $callable[0] ) ) {
$callable[0] = get_class( $callable[0] );
$callable = implode( '->', $callable );
} else {
$callable = implode( '::', $callable );
}
}
return (string) $callable;
}
/**
* AJAX request validator. Verifies caller and nonce.
* Returns the requested data.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param string $nonce The nonce to validate
* @param string $key The key to fetch.
* @param string $type The type of request.
* @return mixed
*/
public static function get_ajax_request( $nonce, $key = null, $type = 'post' ) {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return self::get_request( $nonce, $key, $type );
}
return null;
}
/**
* Normal request validator. Verifies caller and nonce.
* Returns the requested data.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param string $nonce The nonce to validate
* @param string $key The key to fetch.
* @param string $type The type of request.
* @return mixed
*/
public static function get_normal_request( $nonce, $key = null, $type = 'post' ) {
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
return self::get_request( $nonce, $key, $type );
}
return null;
}
/**
* Request validator. Verifies caller and nonce.
* Returns the requested data.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param string $nonce The nonce to validate
* @param string $key The key to fetch.
* @param string $type The type of request.
* @return mixed
*/
public static function get_request( $nonce, $key = null, $type = 'post' ) {
// @codingStandardsIgnoreLine >> Ignore $_GET and $_POST issues.
$data = ( 'get' === strtolower( (string) $type ) ) ? $_GET : $_POST;
if ( isset( $data[ $key ] ) && isset( $data['_vaa_nonce'] ) && wp_verify_nonce( $data['_vaa_nonce'], $nonce ) ) {
$request = self::get_array_data( $data, $key );
$request = self::maybe_json_decode( $request, true, true );
return $request;
}
return null;
}
/**
* AJAX request check.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param string $key The key to fetch.
* @param string $type The type of request.
* @return bool
*/
public static function is_ajax_request( $key = null, $type = 'post' ) {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return self::is_request( $key, $type );
}
return false;
}
/**
* Normal request check.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param string $key The key to fetch.
* @param string $type The type of request.
* @return bool
*/
public static function is_normal_request( $key = null, $type = 'post' ) {
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
return self::is_request( $key, $type );
}
return false;
}
/**
* Check if there is a request made.
*
* @since 1.7
* @access public
* @static
* @api
*
* @param string $key The key to check.
* @param string $type The type of request.
* @return bool
*/
public static function is_request( $key = null, $type = 'post' ) {
// @codingStandardsIgnoreLine >> Ignore $_GET and $_POST issues.
$data = ( 'get' === strtolower( (string) $type ) ) ? $_GET : $_POST;
if ( isset( $data[ $key ] ) ) {
return true;
}
return false;
}
/**
* Check if the value contains JSON.
* It the value is an array it will be parsed recursively.
*
* @link https://stackoverflow.com/questions/6041741/fastest-way-to-check-if-a-string-is-json-in-php
*
* @since 1.7.5
* @access public
* @static
* @api
*
* @param mixed $value The value to be checked for JSON data.
* @param bool $assoc See json_decode().
* @param bool $decode Decode with html_entity_decode() and stripcslashes()?
* @return mixed
*/
public static function maybe_json_decode( $value, $assoc = true, $decode = false ) {
if ( ! is_string( $value ) ) {
if ( is_array( $value ) ) {
foreach ( $value as $key => $val ) {
$value[ $key ] = self::maybe_json_decode( $val, $assoc, $decode );
}
}
return $value;
}
if ( 0 !== strpos( $value, '[' ) && 0 !== strpos( $value, '{' ) ) {
return $value;
}
if ( $decode ) {
$value = stripcslashes( html_entity_decode( $value ) );
}
$var = json_decode( $value, $assoc );
if ( null !== $var ) {
return $var;
}
return $value;
}
/**
* Enhanced is_admin() function with AJAX support.
*
* @see is_admin()
*
* @since 1.7.4
* @access public
* @static
* @api
*
* @return bool
*/
public static function is_admin() {
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
return is_admin();
}
// It's an ajax call, is_admin() would always return `true`. Compare the referrer url with the admin url.
return ( false !== strpos( (string) wp_get_referer(), admin_url() ) );
}
} // End class VAA_API.

View File

@@ -0,0 +1,224 @@
<?php
/**
* View Admin As - Class Base
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Base class that gets the VAA data from the main class.
* Use this class as an extender for other classes.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.5
* @since 1.7.3 Renamed from VAA_View_Admin_As_Class_Base
* @version 1.8
*/
abstract class VAA_View_Admin_As_Base
{
/**
* View Admin As object.
*
* @since 1.5
* @var \VAA_View_Admin_As
*/
protected $vaa = null;
/**
* View Admin As store object.
*
* @since 1.6
* @var \VAA_View_Admin_As_Store
*/
protected $store = null;
/**
* Custom capabilities.
*
* @since 1.6
* @var string[]
*/
protected $capabilities = array();
/**
* Construct function.
* Protected to make sure it isn't declared elsewhere.
*
* @since 1.5.3
* @since 1.6 $vaa param.
* @access protected
* @param \VAA_View_Admin_As $vaa (optional) Pass VAA object.
*/
protected function __construct( $vaa = null ) {
// Load resources.
$this->load_vaa( $vaa );
}
/**
* Init function to store data from the main class and enable functionality based on the current view.
*
* @since 1.5
* @since 1.6 $vaa param.
* @access public
* @final
* @param \VAA_View_Admin_As $vaa (optional) Pass VAA object.
* @return void
*/
final public function load_vaa( $vaa = null ) {
$this->vaa = $vaa;
if ( ! is_object( $vaa ) || 'VAA_View_Admin_As' !== get_class( $vaa ) ) {
$this->vaa = view_admin_as();
}
if ( $this->vaa && 'VAA_View_Admin_As_Store' !== get_class( $this ) ) {
$this->store = $this->vaa->store();
}
}
/**
* Is the main functionality enabled?
*
* @since 1.5
* @access public
* @final
* @return bool
*/
final public function is_vaa_enabled() {
return (bool) $this->vaa->is_enabled();
}
/**
* Check if the AJAX call is ok.
* Must always be used before AJAX data is processed.
*
* @since 1.7
* @access public
* @return bool
*/
public function is_valid_ajax() {
if ( defined( 'VAA_DOING_AJAX' ) && VAA_DOING_AJAX && $this->is_vaa_enabled() ) {
return true;
}
return false;
}
/**
* Extender function for WP current_user_can().
* Also checks if VAA is enabled.
*
* @since 1.7
* @access public
* @param string $capability (optional) The capability to check when the user isn't a super admin.
* @return bool
*/
public function current_user_can( $capability = null ) {
if ( $capability ) {
return ( $this->is_vaa_enabled() && ( VAA_API::is_super_admin() || current_user_can( $capability ) ) );
}
return ( $this->is_vaa_enabled() && VAA_API::is_super_admin() );
}
/**
* Add capabilities.
* Used for the _vaa_add_capabilities hook.
*
* @since 1.6
* @access public
* @param array $caps The capabilities.
* @return string[]
*/
public function add_capabilities( $caps ) {
foreach ( (array) $this->capabilities as $cap ) {
$caps[ $cap ] = $cap;
}
return $caps;
}
/**
* Add a new action to this plugin hooks registry.
*
* @since 1.8
* @see \VAA_View_Admin_As_Hooks::add_action()
* @inheritdoc
*/
public function add_action( $hook, $callback, $priority = 10, $accepted_args = 1 ) {
view_admin_as()->hooks()->add_action( $hook, $callback, $priority, $accepted_args );
}
/**
* Add a new filter to this plugin hooks registry.
*
* @since 1.8
* @see \VAA_View_Admin_As_Hooks::add_filter()
* @inheritdoc
*/
public function add_filter( $hook, $callback, $priority = 10, $accepted_args = 1 ) {
view_admin_as()->hooks()->add_filter( $hook, $callback, $priority, $accepted_args );
}
/**
* Magic method to output a string if trying to use the object as a string.
*
* @since 1.5.1
* @access public
* @return string
*/
public function __toString() {
return get_class( $this );
}
/**
* Magic method to keep the object from being cloned.
*
* @since 1.5.1
* @access public
* @return void
*/
public function __clone() {
_doing_it_wrong(
__FUNCTION__,
esc_html( get_class( $this ) . ': ' . __( 'This class does not want to be cloned', VIEW_ADMIN_AS_DOMAIN ) ),
null
);
}
/**
* Magic method to keep the object from being unserialized.
*
* @since 1.5.1
* @access public
* @return void
*/
public function __wakeup() {
_doing_it_wrong(
__FUNCTION__,
esc_html( get_class( $this ) . ': ' . __( 'This class does not want to wake up', VIEW_ADMIN_AS_DOMAIN ) ),
null
);
}
/**
* Magic method to prevent a fatal error when calling a method that does not exist.
*
* @since 1.5.1
* @access public
* @param string $method The method name.
* @param array $args The method arguments.
* @return null
*/
public function __call( $method = '', $args = array() ) {
_doing_it_wrong(
esc_html( get_class( $this ) . "::{$method}" ),
esc_html__( 'Method does not exist.', VIEW_ADMIN_AS_DOMAIN ),
null
);
unset( $method, $args );
return null;
}
} // End class VAA_View_Admin_As_Class_Base.

View File

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

View File

@@ -0,0 +1,640 @@
<?php
/**
* View Admin As - Class Controller
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* View controller class. Handles all view data.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.7
* @version 1.8
* @uses \VAA_View_Admin_As_Base Extends class
*/
final class VAA_View_Admin_As_Controller extends VAA_View_Admin_As_Base
{
/**
* The single instance of the class.
*
* @since 1.6
* @static
* @var \VAA_View_Admin_As_Controller
*/
private static $_instance = null;
/**
* Expiration time for view data.
*
* @since 1.3.4 (as $metaExpiration).
* @since 1.6.2 Moved from main class.
* @var int
*/
private $viewExpiration = 86400; // one day: ( 24 * 60 * 60 ).
/**
* VAA_View_Admin_As_Controller constructor.
*
* @since 1.6
* @since 1.6.1 $vaa param.
* @access protected
* @param \VAA_View_Admin_As $vaa The main VAA object.
*/
protected function __construct( $vaa ) {
self::$_instance = $this;
parent::__construct( $vaa );
// When a user logs in or out, reset the view to default.
$this->add_action( 'wp_login', array( $this, 'cleanup_views' ), 10, 2 );
$this->add_action( 'wp_login', array( $this, 'reset_view' ), 10, 2 );
$this->add_action( 'wp_logout', array( $this, 'reset_view' ) );
// Not needed, the delete_user actions already remove all metadata, keep code for possible future use.
//$this->add_action( 'remove_user_from_blog', array( $this->store, 'delete_user_meta' ) );
//$this->add_action( 'wpmu_delete_user', array( $this->store, 'delete_user_meta' ) );
//$this->add_action( 'wp_delete_user', array( $this->store, 'delete_user_meta' ) );
/**
* Change expiration time for view meta.
*
* @example You can set it to 1 to always clear everything after login.
* @example 0 will be overwritten!
*
* @param int $viewExpiration 86400 (1 day in seconds).
* @return int
*/
$this->viewExpiration = absint( apply_filters( 'view_admin_as_view_expiration', $this->viewExpiration ) );
}
/**
* Initializes after VAA is enabled.
*
* @since 1.6
* @access public
* @return void
*/
public function init() {
/**
* Reset view to default if something goes wrong.
*
* @since 0.1
* @since 1.2 Only check for key
* @example http://www.your.domain/wp-admin/?reset-view
*/
if ( VAA_API::is_request( 'reset-view', 'get' ) ) {
$this->reset_view();
}
/**
* Clear all user views.
*
* @since 1.3.4
* @example http://www.your.domain/wp-admin/?reset-all-views
*/
if ( VAA_API::is_request( 'reset-all-views', 'get' ) ) {
$this->reset_all_views();
}
// Reset hook.
$this->add_filter( 'view_admin_as_handle_ajax_reset', array( $this, 'reset_view' ) );
// Validation & update hooks for visitor view.
$this->add_filter( 'view_admin_as_validate_view_data_visitor', '__return_true' );
$this->add_filter( 'view_admin_as_update_view_visitor', array( $this, 'filter_update_view' ), 10, 3 );
// Get the current view.
$this->store->set_view( $this->get_view() );
// Short circuit needed for visitor view (BEFORE the current user is set).
if ( VAA_API::is_ajax_request( 'view_admin_as' ) ) {
$this->ajax_view_admin_as();
} else {
// Admin selector ajax return (fallback).
$this->add_action( 'wp_ajax_view_admin_as', array( $this, 'ajax_view_admin_as' ) );
//$this->add_action( 'wp_ajax_nopriv_view_admin_as', array( $this, 'ajax_view_admin_as' ) );
}
}
/**
* AJAX listener.
* Gets the AJAX input. If it is valid: pass it to the handler.
*
* @since 0.1
* @since 1.3 Added caps handler.
* @since 1.4 Added module handler.
* @since 1.5 Validate a nonce.
* Added global and user setting handler.
* @since 1.6 Moved to this class from main class.
* @since 1.6.2 Added visitor view handler + JSON view data.
* @access public
* @return void
*/
public function ajax_view_admin_as() {
$data = VAA_API::get_ajax_request( $this->store->get_nonce(), 'view_admin_as' );
if ( ! $data ) {
wp_send_json_error( __( 'Cheatin uh?', VIEW_ADMIN_AS_DOMAIN ) );
die();
}
define( 'VAA_DOING_AJAX', true );
$data = $this->validate_data_keys( $data );
$success = false;
if ( ! empty( $data ) ) {
$success = $this->ajax_handler( $data );
}
if ( true === $success ) {
wp_send_json_success( $success ); // ahw yeah.
die();
} elseif ( $success ) {
wp_send_json( $success );
die();
}
wp_send_json_error( array(
'type' => 'error',
'text' => esc_html__( 'Something went wrong, please try again.', VIEW_ADMIN_AS_DOMAIN ),
) );
die();
}
/**
* AJAX handler.
* Applies the data input.
*
* @since 1.7
* @param array $data Post data.
* @return array|bool
*/
private function ajax_handler( $data ) {
$success = false;
$view_types = array();
// Stop selecting the same view!
if ( $this->is_current_view( $data ) ) {
wp_send_json_error( array(
'type' => 'message',
'text' => esc_html__( 'This view is already selected!', VIEW_ADMIN_AS_DOMAIN ),
) );
}
/**
* Ajax return filters.
*
* @see `view_admin_as_update_view_{$key}`
* @see `view_admin_as_handle_ajax_{$key}`
*
* @since 1.7
* @param null $null Null.
* @param mixed $value View data value.
* @param string $key View data key.
* @return bool|array {
* In case of array. Uses wp_json_return() structure.
* @type bool $success Send JSON success or error?
* @type array $data {
* Optional extra data to send with the JSON return.
* In case of a view the page normally refreshes.
* @type string $redirect (URL) Redirect the user? (Only works on success).
* @type string $display Options: notice A notice type in the admin bar
* popup A popup/overlay with content
* @type string $type Options: success Ureka! (green) - Default when $success is true
* error Send an error (red) - Default when $success is false
* message Just a message (blue)
* warning Send a warning (orange)
* @type string $text The text to show
* @type array $list Show multiple messages (Popup only)
* @type string $textarea Textarea content (Popup only)
* }
* }
*/
foreach ( $data as $key => $value ) {
if ( $this->is_view_type( $key ) ) {
$view_types[] = $key;
$success = apply_filters( 'view_admin_as_update_view_' . $key, null, $value, $key );
} else {
$success = apply_filters( 'view_admin_as_handle_ajax_' . $key, null, $value, $key );
}
if ( true !== $success ) {
break;
}
}
if ( empty( $view_types ) ) {
return $success;
}
// Update the view on success.
if ( true === $success || ( isset( $success['success'] ) && true === $success['success'] ) ) {
// Remove view type keys that are not in the new view anymore.
$view = $this->store->get_view();
$view = array_intersect_key( $view, array_flip( $view_types ) );
$this->store->set_view( $view );
$this->update_view();
}
return $success;
}
/**
* Update regular view types.
*
* @since 1.7
* @param null $null Null.
* @param mixed $data The view data.
* @param string $type The view type.
* @return bool|array
*/
public function filter_update_view( $null, $data, $type ) {
$success = $null;
if ( ! empty( $data ) && ! empty( $type ) ) {
$this->store->set_view( $data, $type, true );
$success = true;
}
if ( $success && 'visitor' === $type && VAA_API::is_admin() ) {
$success = array(
'success' => true,
'data' => array(
'redirect' => esc_url( home_url() ),
),
);
}
return $success;
}
/**
* Check if the provided data is the same as the current view.
*
* @since 1.7
* @since 1.7.2 Data options: `null` for active view & `false` for only/single view.
* @param mixed $data The view data to compare with.
* @param bool $type Only compare a single view type instead of all view data?
* If set, the data value should be the single view type data or `null`.
* If data is `null` then it will return true if that view type is active.
* If data is `false` then it will return true if this is the only active view type.
* @return bool
*/
public function is_current_view( $data, $type = null ) {
if ( ! empty( $type ) ) {
$current = $this->store->get_view( $type );
if ( ! $current ) {
return false;
}
if ( is_array( $data ) ) {
return VAA_API::array_equal( $data, $current );
}
if ( null === $data ) {
return true;
}
if ( false === $data ) {
return ( 1 === count( $this->store->get_view() ) );
}
return ( (string) $data === (string) $current );
}
return VAA_API::array_equal( $data, $this->store->get_view() );
}
/**
* Is it a view type?
*
* @since 1.7
* @param string $type View type name to check
* @return bool
*/
public function is_view_type( $type ) {
return ( in_array( $type, $this->get_view_types(), true ) );
}
/**
* Get the available view type keys.
*
* @since 1.7
* @access public
* @return string[]
*/
public function get_view_types() {
static $view_types;
if ( ! is_null( $view_types ) ) return $view_types;
$view_types = array_keys( (array) view_admin_as()->get_view_types() );
$view_types[] = 'visitor';
/**
* Add basic view types for automated use in JS and through VAA.
*
* - Menu items require the class vaa-{TYPE}-item (through the add_node() meta key).
* - Menu items require the href attribute (the node needs to be an <a> element).
* @see \VAA_View_Admin_As_Form::do_view_title()
*
* @deprecated 1.8
*
* @since 1.6.2
* @param array $array Empty array.
* @return array An array of strings (view types).
*/
$dep_view_types = apply_filters( 'view_admin_as_view_types', array() );
if ( $dep_view_types ) {
/** @see https://developer.wordpress.org/reference/functions/apply_filters_deprecated/ */
if ( function_exists( '_deprecated_hook' ) ) {
_deprecated_hook( 'view_admin_as_view_types', 1.8, 'view_admin_as()->register_view_type()' );
}
$view_types = array_unique( array_merge(
array_filter( $dep_view_types, 'is_string' ),
$view_types
) );
}
return $view_types;
}
/**
* Get current view for the current session.
*
* @since 1.3.4
* @since 1.5 Single mode.
* @since 1.6 Moved to this class from main class.
* @since 1.7 Private method. Use store.
* @access private
* @return array
*/
private function get_view() {
$view_mode = $this->store->get_userSettings( 'view_mode' );
// Static actions.
$request = VAA_API::get_normal_request( $this->store->get_nonce(), 'view_admin_as', 'get' );
if ( $request && 'browse' === $view_mode ) {
$this->store->set_view( $this->validate_view_data( $request ) );
$this->update_view();
// Trigger page refresh.
// @todo fix WP referrer/nonce checks and allow switching on any page without ajax. See VAA_API.
if ( is_network_admin() ) {
wp_redirect( network_admin_url() );
} else {
wp_redirect( admin_url() );
}
}
// Single mode.
$request = VAA_API::get_normal_request( $this->store->get_nonce(), 'view_admin_as' );
if ( $request && 'single' === $view_mode ) {
return $this->validate_view_data( $request );
}
// Browse mode.
if ( 'browse' === $view_mode ) {
$meta = $this->store->get_userMeta( 'views' );
if ( isset( $meta[ $this->store->get_curUserSession() ]['view'] ) ) {
return $this->validate_view_data( $meta[ $this->store->get_curUserSession() ]['view'] );
}
}
return array();
}
/**
* Update view for the current session.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @access public
*
* @return bool
*/
private function update_view() {
$data = $this->validate_view_data( $this->store->get_view() );
if ( $data ) {
$meta = $this->store->get_userMeta( 'views' );
// Make sure it is an array (no array means no valid data so we can safely clear it).
if ( ! is_array( $meta ) ) {
$meta = array();
}
// Add the new view metadata and expiration date.
$meta[ $this->store->get_curUserSession() ] = array(
'view' => $data,
'expire' => ( time() + (int) $this->viewExpiration ),
);
// Update metadata (returns: true on success, false on failure).
return $this->store->update_userMeta( $meta, 'views', true );
}
return false;
}
/**
* Reset view to default.
* This function is also attached to the wp_login and wp_logout hook.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @access public
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/wp_login
*
* @param string $user_login (not used) String provided by the wp_login hook.
* @param \WP_User $user User object provided by the wp_login hook.
* @return bool
*/
public function reset_view( $user_login = null, $user = null ) {
// function is not triggered by the wp_login action hook.
if ( null === $user ) {
$user = $this->store->get_curUser();
}
if ( ! empty( $user->ID ) ) {
// Do not use the store as it currently doesn't support a different user ID.
$meta = get_user_meta( $user->ID, $this->store->get_userMetaKey(), true );
// Check if this user session has metadata.
if ( isset( $meta['views'][ $this->store->get_curUserSession() ] ) ) {
// Remove metadata from this session.
unset( $meta['views'][ $this->store->get_curUserSession() ] );
// Update current metadata if it is the current user.
if ( $this->store->get_curUser() && (int) $this->store->get_curUser()->ID === (int) $user->ID ) {
$this->store->set_userMeta( $meta );
}
// Update db metadata (returns: true on success, false on failure).
return update_user_meta( $user->ID, $this->store->get_userMetaKey(), $meta );
}
}
// No meta found, no reset needed.
return true;
}
/**
* Delete all expired View Admin As metadata for this user.
* This function is also attached to the wp_login hook.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @access public
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/wp_login
*
* @param string $user_login (not used) String provided by the wp_login hook.
* @param \WP_User $user User object provided by the wp_login hook.
* @return bool
*/
public function cleanup_views( $user_login = null, $user = null ) {
// function is not triggered by the wp_login action hook.
if ( null === $user ) {
$user = $this->store->get_curUser();
}
if ( ! empty( $user->ID ) ) {
// Do not use the store as it currently doesn't support a different user ID.
$meta = get_user_meta( $user->ID, $this->store->get_userMetaKey(), true );
// If meta exists, loop it.
if ( isset( $meta['views'] ) ) {
foreach ( (array) $meta['views'] as $key => $value ) {
// Check expiration date: if it doesn't exist or is in the past, remove it.
if ( ! isset( $meta['views'][ $key ]['expire'] ) || time() > (int) $meta['views'][ $key ]['expire'] ) {
unset( $meta['views'][ $key ] );
}
}
// Update current metadata if it is the current user.
if ( $this->store->get_curUser() && (int) $this->store->get_curUser()->ID === (int) $user->ID ) {
$this->store->set_userMeta( $meta );
}
// Update db metadata (returns: true on success, false on failure).
return update_user_meta( $user->ID, $this->store->get_userMetaKey(), $meta );
}
}
// No meta found, no cleanup needed.
return true;
}
/**
* Reset all View Admin As metadata for this user.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @access public
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/wp_login
*
* @param string $user_login (not used) String provided by the wp_login hook.
* @param \WP_User $user User object provided by the wp_login hook.
* @return bool
*/
public function reset_all_views( $user_login = null, $user = null ) {
// function is not triggered by the wp_login action hook.
if ( null === $user ) {
$user = $this->store->get_curUser();
}
if ( ! empty( $user->ID ) ) {
$meta = get_user_meta( $user->ID, $this->store->get_userMetaKey(), true );
// If meta exists, reset it.
if ( isset( $meta['views'] ) ) {
$meta['views'] = array();
// Update current metadata if it is the current user.
if ( $this->store->get_curUser() && (int) $this->store->get_curUser()->ID === (int) $user->ID ) {
$this->store->set_userMeta( $meta );
}
// Update db metadata (returns: true on success, false on failure).
return update_user_meta( $user->ID, $this->store->get_userMetaKey(), $meta );
}
}
// No meta found, no reset needed.
return true;
}
/**
* Remove all unsupported keys.
*
* @since 1.7
* @param array $data Input data.
* @return array
*/
public function validate_data_keys( $data ) {
if ( ! is_array( $data ) || empty( $data ) ) {
return array();
}
$allowed_keys = array_unique( array_merge(
// View types.
$this->get_view_types(),
// Module keys.
array_keys( $this->vaa->get_modules() ),
// VAA core keys.
array( 'setting', 'user_setting', 'reset' )
) );
$data = array_intersect_key( $data, array_flip( $allowed_keys ) );
return $data;
}
/**
* Validate data before changing the view.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7 Changed name to `validate_view_data` from `validate_view_as_data`
* @access public
*
* @param array $data Unvalidated data.
* @return array $data Validated data.
*/
public function validate_view_data( $data ) {
if ( ! is_array( $data ) || empty( $data ) ) {
return array();
}
// Only leave keys that are view types.
$data = array_intersect_key( $data, array_flip( $this->get_view_types() ) );
// We only want allowed keys and data, otherwise it's not added through this plugin.
foreach ( $data as $key => $value ) {
/**
* Validate the data.
* Hook is required!
*
* @since 1.6.2
* @since 1.7 Added third $key parameter
* @param null $null Ensures a validation filter is required.
* @param mixed $value Unvalidated view data.
* @param string $key The data key.
* @return mixed validated view data.
*/
$data[ $key ] = apply_filters( 'view_admin_as_validate_view_data_' . $key, null, $value, $key );
if ( null === $data[ $key ] ) {
unset( $data[ $key ] );
}
}
return $data;
}
/**
* Main Instance.
*
* Ensures only one instance of this class is loaded or can be loaded.
*
* @since 1.6
* @access public
* @static
* @param \VAA_View_Admin_As $caller The referrer class.
* @return \VAA_View_Admin_As_Controller $this
*/
public static function get_instance( $caller = null ) {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self( $caller );
}
return self::$_instance;
}
} // End class VAA_View_Admin_As_Controller.

View File

@@ -0,0 +1,746 @@
<?php
/**
* View Admin As - Form
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Form elements for View Admin As.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.7.2
* @since 1.8 Moved to the includes folder.
* @version 1.8
*/
class VAA_View_Admin_As_Form
{
/**
* Generate a view type title and it's view related data.
* The data is used in javascript to switch a view.
*
* @since 1.7
* @since 1.7.2 Moved to this class from admin bar class.
* @access public
* @static
*
* @param string $title The title content.
* @param string|\VAA_View_Admin_As_Type $type The view type.
* @param string $value The view value.
* @param array $attr (optional) Array of other attributes.
* @param string $elem (optional) HTML element type.
* @return string
*/
public static function do_view_title( $title, $type, $value, $attr = array(), $elem = 'span' ) {
$attr = (array) $attr;
$class = ( ! empty( $attr['class'] ) ) ? ' ' . $attr['class'] : '';
$attr['class'] = 'vaa-view-data' . $class;
if ( $type instanceof VAA_View_Admin_As_Type ) {
$attr['vaa-view-type'] = $type->get_type();
$attr['vaa-view-type-label'] = $type->get_label_singular();
} else {
$attr['vaa-view-type'] = $type;
}
$attr['vaa-view-value'] = $value;
$attr = self::parse_to_html_attr( $attr );
return '<' . $elem . ' ' . $attr . '>' . $title . '</' . $elem . '>';
}
/**
* Get multiple form elements in one call.
* Note: Method calls are limited to one parameter!
*
* @since 1.8
* @access public
* @static
*
* @param array $args An array of key => value (form method first parameter).
* @return string
*/
public static function do_multiple( $args ) {
$return = array();
foreach ( $args as $key => $value ) {
$method = $key;
if ( is_callable( array( 'VAA_View_Admin_As_Form', $key ) ) ) {
$return[] = self::$method( $value );
} elseif ( is_callable( array( 'VAA_View_Admin_As_Form', 'do_' . $key ) ) ) {
$method = 'do_' . $key;
$return[] = self::$method( $value );
}
}
return implode( '', $return );
}
/**
* Generate button HTML for node.
*
* @since 1.6.1
* @since 1.6.2 Added $element option.
* @since 1.7.2 Moved to this class from admin bar class.
* @access public
* @static
*
* @param array $args {
* (required) An array of field arguments.
* @type string $name (required)
* @type string $id (optional) Will be generated from $name if empty.
* @type string $label (optional)
* @type string $class (optional)
* @type string $element (optional)
* @type array $attr (optional)
* @type array $auto_js (optional) See VAA_View_Admin_As_Form::enable_auto_js().
* }
* @return string
*/
public static function do_button( $args ) {
$id = esc_attr( ( ! empty( $args['id'] ) ) ? $args['id'] : $args['name'] );
$name = str_replace( '-', '_', esc_attr( $args['name'] ) );
$elem = ( ! empty( $args['element'] ) ) ? $args['element'] : 'button';
$label = ( ! empty( $args['label'] ) ) ? $args['label'] : '';
$class = ( ! empty( $args['class'] ) ) ? ' ' . $args['class'] : '';
$args['attr']['id'] = $id;
$args['attr']['name'] = $name;
$args['attr']['class'] = 'button' . $class;
if ( isset( $args['value'] ) ) {
if ( is_bool( $args['value'] ) ) {
$args['value'] = (int) $args['value'];
}
$args['attr']['value'] = (string) $args['value'];
};
$attr = $args['attr'];
if ( ! empty( $args['auto_js'] ) && empty( $args['auto_js']['event'] ) ) {
$args['auto_js']['event'] = 'click';
}
$attr = self::enable_auto_js( $attr, $args );
$attr = self::parse_to_html_attr( $attr );
return '<' . $elem . ' ' . $attr . '>' . $label . '</' . $elem . '>';
}
/**
* Generate text input HTML for node.
*
* @since 1.6.1
* @since 1.6.3 Automatic show/hide description option.
* @since 1.7.2 Moved to this class from admin bar class.
* @access public
* @static
*
* @param array $args {
* (required) An array of field arguments.
* @type string $name (required)
* @type string $id (optional) Will be generated from $name if empty.
* @type string $placeholder (optional)
* @type string $default (optional)
* @type string $value (optional)
* @type string $label (optional)
* @type string $description (optional)
* @type string $help (optional)
* @type string $class (optional)
* @type array $type (optional) Optional input type attribute.
* @type array $attr (optional)
* @type array $auto_js (optional) See VAA_View_Admin_As_Form::enable_auto_js().
* @type bool $auto_showhide (optional) Pass `true` or int for auto show/hide description. Integer stands for the delay (default: 200).
* }
* @return string
*/
public static function do_input( $args ) {
$html = '';
$id = esc_attr( ( ! empty( $args['id'] ) ) ? $args['id'] : $args['name'] );
$name = str_replace( '-', '_', esc_attr( $args['name'] ) );
$default = ( ! empty( $args['default'] ) ) ? $args['default'] : '';
$placeholder = ( ! empty( $args['placeholder'] ) ) ? $args['placeholder'] : '';
$class = ( ! empty( $args['class'] ) ) ? $args['class'] : '';
$args['attr']['type'] = ( ! empty( $args['type'] ) ) ? $args['type'] : 'text';
$args['attr']['id'] = $id;
$args['attr']['name'] = $name;
$args['attr']['placeholder'] = $placeholder;
$args['attr']['value'] = ( ! empty( $args['value'] ) ) ? $args['value'] : $default;
$args['attr']['class'] = $class;
$attr = $args['attr'];
$attr = self::enable_auto_js( $attr, $args );
$attr = self::parse_to_html_attr( $attr );
$label_attr = array();
$desc_attr = array();
self::enable_auto_showhide( $id . '-desc', $label_attr, $desc_attr, $args );
$html .= self::do_help( $args, array(), array(), $label_attr );
$html .= self::do_label( $args, $id, $label_attr );
$html .= '<input ' . $attr . '/>';
$html .= self::do_description( $args, $desc_attr );
return $html;
}
/**
* Generate checkbox HTML for node.
*
* @since 1.6.1
* @since 1.6.3 Automatic show/hide description option + removable option.
* @since 1.7.2 Moved to this class from admin bar class.
* @access public
* @static
*
* @param array $args {
* (required) An array of field arguments.
* @type string $name (required)
* @type string $id (optional) Will be generated from $name if empty.
* @type string $compare (optional)
* @type string $value (optional)
* @type string $checkbox_value (optional) Default: 1.
* @type string $label (optional)
* @type string $description (optional)
* @type string $help (optional)
* @type string $class (optional)
* @type array $attr (optional)
* @type array $auto_js (optional) See VAA_View_Admin_As_Form::enable_auto_js().
* @type bool $auto_showhide (optional) Pass `true` or int for auto show/hide description. Integer stands for the delay (default: 200).
* @type bool $removable (optional)
* }
* @return string
*/
public static function do_checkbox( $args ) {
$html = '';
$id = esc_attr( ( ! empty( $args['id'] ) ) ? $args['id'] : $args['name'] );
$name = str_replace( '-', '_', esc_attr( $args['name'] ) );
if ( empty( $args['value'] ) ) {
$args['value'] = null;
}
if ( empty( $args['compare'] ) ) {
$args['compare'] = 1;
}
$checked = checked( $args['value'], $args['compare'], false );
$class = ( ! empty( $args['class'] ) ) ? ' ' . $args['class'] : '';
$args['attr']['type'] = 'checkbox';
$args['attr']['id'] = $id;
$args['attr']['name'] = $name;
$args['attr']['value'] = ( ! empty( $args['checkbox_value'] ) ) ? $args['checkbox_value'] : '1';
$args['attr']['class'] = 'checkbox' . $class;
$attr = $args['attr'];
$attr = self::enable_auto_js( $attr, $args );
$attr = self::parse_to_html_attr( $attr );
$label_attr = array();
$desc_attr = array();
self::enable_auto_showhide( $id . '-desc', $label_attr, $desc_attr, $args );
$html .= self::do_help( $args, array(), array(), $label_attr );
$html .= '<input ' . $attr . ' ' . $checked . '/>';
$html .= self::do_label( $args, $id, $label_attr );
if ( ! empty( $args['removable'] ) ) {
$html .= self::do_icon( 'dashicons-dismiss remove', array( 'title' => __( 'Remove', VIEW_ADMIN_AS_DOMAIN ) ) );
}
$html .= self::do_description( $args, $desc_attr );
return $html;
}
/**
* Generate radio HTML for node.
*
* @since 1.6.1
* @since 1.6.3 Automatic show/hide description option.
* @since 1.7.2 Moved to this class from admin bar class.
* @access public
* @static
*
* @param array $args {
* (required) An array of arrays with field arguments.
* @type string $name (required)
* @type string $id (optional) Will be generated from $name if empty.
* @type string $value (optional)
* @type string $description (optional)
* @type array $auto_js (optional) See VAA_View_Admin_As_Form::enable_auto_js().
* @type bool $auto_showhide (optional) Pass `true` or int for auto show/hide description. Integer stands for the delay (default: 200).
* @type array $values {
* Array of radio options data.
* @type array {
* @type string $compare (required)
* @type string $label (optional)
* @type string $description (optional)
* @type string $help (optional)
* @type string $class (optional)
* @type array $attr (optional)
* @type bool $auto_showhide (optional) Overwrite $data.
* }
* }
* }
* @return string
*/
public static function do_radio( $args ) {
$html = '';
if ( ! empty( $args['values'] ) ) {
foreach ( $args['values'] as $val ) {
$id = esc_attr( ( ( ! empty( $args['id'] ) ) ? $args['id'] : $args['name'] ) . '-' . $val['compare'] );
$name = str_replace( '-', '_', esc_attr( $args['name'] ) );
if ( empty( $args['value'] ) ) {
$args['value'] = null;
}
$checked = checked( $args['value'], $val['compare'], false );
$class = ( ! empty( $val['class'] ) ) ? ' ' . $val['class'] : '';
$class .= ' ' . esc_attr( $args['name'] );
$val['attr']['type'] = 'radio';
$val['attr']['id'] = $id;
$val['attr']['name'] = $name;
$val['attr']['value'] = $val['compare'];
$val['attr']['class'] = 'radio' . $class;
$attr = $val['attr'];
$attr = self::enable_auto_js( $attr, $args );
$attr = self::parse_to_html_attr( $attr );
$label_attr = array();
$desc_attr = array();
// Custom validation required.
if ( ( ! empty( $val['auto_showhide'] ) ) ||
( ! isset( $val['auto_showhide'] ) && ! empty( $args['auto_showhide'] ) )
) {
self::enable_auto_showhide( $id . '-desc', $label_attr, $desc_attr );
}
$html .= '<div class="vaa-radio-wrapper">';
$html .= self::do_help( $val, array(), array(), $label_attr );
$html .= '<input ' . $attr . ' ' . $checked . '/>';
$html .= self::do_label( $val, $id, $label_attr );
$html .= '<br>';
$html .= self::do_description( $val, $desc_attr );
$html .= '</div>';
} // End foreach().
$html .= self::do_description( $args );
} // End if().
return $html;
}
/**
* Generate selectbox HTML for node.
*
* @since 1.6.1
* @since 1.6.3 Automatic show/hide description option.
* @since 1.7.2 Moved to this class from admin bar class.
* @access public
* @static
*
* @param array $args {
* (required) An array of arrays with field arguments.
* @type string $name (required)
* @type string $id (optional) Will be generated from $name if empty.
* @type string $value (optional)
* @type string $label (optional)
* @type string $description (optional)
* @type string $help (optional)
* @type string $class (optional)
* @type array $attr (optional)
* @type array $auto_js (optional) See VAA_View_Admin_As_Form::enable_auto_js().
* @type bool $auto_showhide (optional) Pass `true` or int for auto show/hide description. Integer stands for the delay (default: 200).
* @type array $values {
* Arrays of selectbox value data.
* @type array {
* @type string $compare (required)
* @type string $value (optional) Alias for compare.
* @type string $label (optional)
* @type string $class (optional)
* @type array $attr (optional)
* }
* }
* }
* @return string
*/
public static function do_select( $args ) {
$html = '';
if ( ! empty( $args['values'] ) ) {
$id = esc_attr( ( ! empty( $args['id'] ) ) ? $args['id'] : $args['name'] );
$name = str_replace( '-', '_', esc_attr( $args['name'] ) );
$label_attr = array();
$desc_attr = array();
self::enable_auto_showhide( $id . '-desc', $label_attr, $desc_attr, $args );
$html .= self::do_help( $args, array(), array(), $label_attr );
$html .= self::do_label( $args, $id, $label_attr );
if ( empty( $args['value'] ) ) {
$args['value'] = null;
}
$class = ( ! empty( $args['class'] ) ) ? ' ' . $args['class'] : '';
$args['attr']['id'] = $id;
$args['attr']['name'] = $name;
$args['attr']['class'] = 'selectbox' . $class;
$attr = $args['attr'];
$attr = self::enable_auto_js( $attr, $args );
$attr = self::parse_to_html_attr( $attr );
$html .= '<select ' . $attr . '>';
foreach ( $args['values'] as $val ) {
if ( empty( $val['compare'] ) ) {
$val['compare'] = ( ! empty( $val['value'] ) ) ? $val['value'] : false;
}
$label = ( ! empty( $val['label'] ) ) ? $val['label'] : $val['compare'];
$selected = selected( $args['value'], $val['compare'], false );
$val['attr']['value'] = $val['compare'];
$attr = self::parse_to_html_attr( $val['attr'] );
$html .= '<option ' . $attr . ' ' . $selected . '>' . $label . '</option>';
}
$html .= '</select>';
$html .= self::do_description( $args, $desc_attr );
} // End if().
return $html;
}
/**
* Returns icon html for WP admin bar.
*
* @since 1.6.1
* @since 1.6.3 Added second $attr parameter.
* @since 1.7.2 Moved to this class from admin bar class.
* @since 1.7.3 Added third $content parameter.
* @since 1.7.6 Support SVG and file icons + Base64 encoded strings (just like WP admin menu's).
* @static
*
* @param string $icon The icon class, file or base64 encoded string.
* @param array $attr (optional) Extra attributes.
* @param string $content (optional) Icon content.
* @return string
*/
public static function do_icon( $icon, $attr = array(), $content = '' ) {
$class = 'ab-icon';
if ( false === strpos( $icon, '/' ) &&
0 !== strpos( $icon, 'data:' ) &&
0 !== strpos( $icon, 'http' )
) {
// It's an icon class.
$class .= ' dashicons ' . $icon;
} else {
// It's a Base64 encoded string or file URL.
$class .= ' vaa-icon-image';
$attr = self::merge_attr( $attr, array(
'style' => array( 'background-image: url("' . $icon . '") !important' ),
) );
}
if ( ! empty( $attr['class'] ) ) {
$class .= ' ' . (string) $attr['class'];
}
$attr['class'] = $class;
$attr['aria-hidden'] = 'true';
$attr = self::parse_to_html_attr( $attr );
return '<span ' . $attr . '>' . $content . '</span>';
}
/**
* Returns label html for WP admin bar.
*
* @since 1.6.1
* @since 1.6.3 Added third $attr parameter.
* @since 1.7.2 Moved to this class from admin bar class.
* @static
*
* @param string|array $label The label. Also accepts an array with a `label` key.
* @param string $for (optional) Add `for` attribute.
* @param array $attr (optional) Extra attributes.
* @return string
*/
public static function do_label( $label, $for = '', $attr = array() ) {
if ( is_array( $label ) ) {
if ( empty( $label['label'] ) ) {
return '';
}
$label = $label['label'];
}
$attr['for'] = $for;
$attr = self::parse_to_html_attr( $attr );
return '<label ' . $attr . '>' . $label . '</label>';
}
/**
* Returns description html for WP admin bar.
*
* @since 1.6.1
* @since 1.6.3 Added second $attr parameter.
* @since 1.7.2 Moved to this class from admin bar class.
* @since 1.7.5 Third parameter: element type.
* @static
*
* @param string|array $text The description text. Also accepts an array with a `description` key.
* @param array $attr (optional) Extra attributes.
* @param string $elem (optional) HTML element type. Default: paragraph.
* @return string
*/
public static function do_description( $text, $attr = array(), $elem = 'p' ) {
if ( is_array( $text ) ) {
if ( empty( $text['description'] ) ) {
return '';
}
$text = $text['description'];
} elseif ( ! is_string( $text ) ) {
return '';
}
$attr['class'] = 'ab-item description' . ( ( ! empty( $attr['class'] ) ) ? ' ' . $attr['class'] : '');
$attr = self::parse_to_html_attr( $attr );
return '<' . $elem . ' ' . $attr . '>' . $text . '</' . $elem . '>';
}
/**
* Returns help tooltip html for WP admin bar.
* It will also change auto show/hide trigger to the help icon if the help text is a boolean true instead of a string.
* @todo document this properly.
*
* @since 1.7.3
* @static
*
* @param string|array $text The help text. Also accepts an array with a `help` key.
* @param array $help_attr (optional) Extra help icon attributes.
* @param array $tooltip_attr (optional) Extra tooltip attributes.
* @param array $showhide_attr (optional) Overwrite existing show/hide attributes.
* @return string
*/
public static function do_help( $text, $help_attr = array(), $tooltip_attr = array(), &$showhide_attr = array() ) {
if ( is_array( $text ) ) {
if ( empty( $text['help'] ) ) {
return '';
}
$text = $text['help'];
} elseif ( ! $text ) {
return '';
}
// Reset auto show/hide settings is $test is true. Disables show/hide on the label and sets it on the help icon.
$help_attr = self::merge_attr( $help_attr, array(
'class' => 'vaa-help',
) );
if ( true === $text ) {
// Do nothing is auto show/hide isn't enabled.
if ( ! isset( $showhide_attr['vaa-showhide'] ) ) {
return '';
}
$help_attr['class'] .= ' ab-vaa-showhide';
$help_attr['vaa-showhide'] = $showhide_attr['vaa-showhide'];
unset( $showhide_attr['vaa-showhide'] );
}
if ( is_string( $text ) ) {
// ab-sub-wrapper for background, ab-item for text color.
$tooltip_attr = self::merge_attr( array(
'class' => 'ab-item ab-sub-wrapper vaa-tooltip',
), $tooltip_attr );
$tooltip_attr = self::parse_to_html_attr( $tooltip_attr );
$text = '<span ' . $tooltip_attr . '>' . $text . '</span>';
} else {
$text = '';
}
return self::do_icon( 'dashicons-editor-help', $help_attr, $text );
}
/**
* Auto-generate a JSON attribute for automatic JS handling.
*
* @internal Please do not use this yet since it's in development and subject to changes.
*
* @since 1.7.2
* @static
*
* @param array $attr The attributes array to append to.
* @param array $args {
* The form element args. Below parameters should be in the `auto_js` key.
*
* @type string $setting (required) The setting key.
* @type string $confirm (optional) Let JS generate a confirm box before running ajax?
* @type string $refresh (optional) Refresh after ajax return?
* @type string $key (optional, if values exists). The option key.
* @type array $values {
* The array of options. Alias: `value`.
* All options need to be key => value pairs. See type documentation.
* Recursive arrays supported (values in values).
* If a key parameter exists this array will be added as the values of that key.
*
* @type bool $required (optional) Whether this option is required or not (default: true).
* @type string $element (optional) The HTML element to use as selector (overwrites current element).
* @type string $attr (optional) Get an attribute value instead of using .val()?
* @type bool $json (optional) Parse value as JSON? (Default parser only).
* @type string $parser (optional) The value processor.
* `default` or empty : Normal handling.
* (single checkbox or input/textarea value)
* `multiple` or `multi` : Get multiple values.
* (default: name => value | checkbox: value => checked)
* `selected` : Get selected values only.
* (default: non empty values | checkbox: values of checked elements)
* }
* }
* @return array
*/
public static function enable_auto_js( $attr, $args ) {
if ( ! empty( $args['auto_js'] ) ) {
// Auto-generate values array based upon key and value keys.
if ( ! empty( $args['auto_js']['key'] ) ) {
if ( empty( $args['auto_js']['values'] ) ) {
// Single value data.
$value = null;
if ( ! empty( $args['auto_js']['value'] ) ) {
$value = $args['auto_js']['value'];
}
} else {
// Set the values as the values of the supplied key.
$value = array( 'values' => $args['auto_js']['values'] );
}
$values = array( $args['auto_js']['key'] => $value );
$args['auto_js']['values'] = $values;
}
unset( $args['auto_js']['key'] );
unset( $args['auto_js']['value'] );
$attr['vaa-auto-js'] = wp_json_encode( $args['auto_js'] );
}
return $attr;
}
/**
* Update auto show/hide trigger and target attributes to enable auto show/hide functionality.
*
* @since 1.7
* @since 1.7.2 Moved to this class from admin bar class.
* @since 1.7.3 Renamed from `enable_auto_showhide_desc` + allow multiple values for trigger.
* @static
*
* @param string $target The target element.
* @param array $trigger_attr Trigger element attributes.
* @param array $target_attr (optional) Target element attributes.
* @param array $args {
* (optional)Pass the full arguments array for auto_showhide key validation.
*
* @type bool|int|array $auto_showhide {
* Pass `true` for default handling of the first function parameter target.
* Pass an integer to just set the delay for the first function parameter target.
* Pass an array for full target data (multiple allowed), see parameters below. This will overwrite the first function parameter.
*
* @type array {
* @type string $target The selector string for jQuery.
* @type int $delay (optional) Set the delay in milliseconds.
* }
* }
* }
* @return void
*/
public static function enable_auto_showhide( $target, &$trigger_attr = array(), &$target_attr = array(), $args = array() ) {
if ( ! empty( $args ) && empty( $args['auto_showhide'] ) ) {
return;
}
$trigger_target = '.' . $target;
if ( ! empty( $args['auto_showhide'] ) && ! is_bool( $args['auto_showhide'] ) ) {
// Just the delay, keep the target value.
if ( is_numeric( $args['auto_showhide'] ) ) {
$trigger_target = wp_json_encode( array(
'target' => $trigger_target,
'delay' => $args['auto_showhide'],
) );
}
// Full data. Multiple targets allowed,
elseif ( is_array( $args['auto_showhide'] ) ) {
$trigger_target = wp_json_encode( $args['auto_showhide'] );
}
}
$trigger_attr = self::merge_attr( $trigger_attr, array(
'class' => 'ab-vaa-showhide',
'vaa-showhide' => $trigger_target,
) );
// @todo Find a way to auto create multiple targets.
if ( ! empty( $target ) ) {
$target_attr = self::merge_attr( $target_attr, array(
'class' => $target,
) );
}
}
/**
* Merge two arrays of attributes into one, combining values.
* It currently doesn't convert variable types.
*
* @since 1.7.3
* @static
*
* @param array $attr The current attributes.
* @param array $new The new attributes. Attribute names as key.
* @return string[]
*/
public static function merge_attr( $attr, $new ) {
foreach ( $new as $key => $value ) {
if ( empty( $attr[ $key ] ) ) {
$attr[ $key ] = $value;
continue;
}
if ( is_array( $attr[ $key ] ) ) {
$attr[ $key ] = array_merge( $attr[ $key ], (array) $value );
continue;
}
if ( is_array( $value ) ) {
$value = implode( ' ', $value );
}
$attr[ $key ] .= ( ! empty( $value ) ) ? ' ' . $value : '';
}
return $attr;
}
/**
* Converts an array of attributes to a HTML string format starting with a space.
*
* @since 1.6.1
* @since 1.7 Renamed from `parse_attr_to_html`
* @since 1.7.2 Support array values. (Example: CSS classes). Moved to this class from admin bar class.
* @static
*
* @param array $array Array to parse. (attribute => value pairs)
* @return string
*/
public static function parse_to_html_attr( $array ) {
$str = '';
if ( is_array( $array ) && ! empty( $array ) ) {
foreach ( $array as $attr => $value ) {
if ( is_array( $value ) ) {
$value = implode( ' ', $value );
}
$array[ $attr ] = esc_attr( $attr ) . '="' . esc_attr( $value ) . '"';
}
$str = implode( ' ', $array );
}
return $str;
}
} // End class VAA_View_Admin_As_Form.

View File

@@ -0,0 +1,455 @@
<?php
/**
* View Admin As - Class Hooks
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Hooks class that holds all registered actions and filters.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @link https://github.com/JoryHogeveen/view-admin-as/wiki/Actions-&-Filters
* @since 1.8
* @version 1.8
*/
class VAA_View_Admin_As_Hooks
{
/**
* The array of actions registered with WordPress.
*
* @since 1.8
* @access protected
* @var array $actions The actions registered with WordPress.
*/
protected $_actions = array();
/**
* The array of filters registered with WordPress.
*
* @since 1.8
* @access protected
* @var array $filters The filters registered with WordPress.
*/
protected $_filters = array();
/**
* Convert callable into an identifier.
*
* @since 1.8
* @access protected
* @see _wp_filter_build_unique_id()
* @param string $hook The name of the WordPress hook (that is, actions or filters).
* @param callable $callback The callable.
* @param int $priority The priority at which the function would be fired. Default: 10.
* @return string
*/
protected function _get_identifier( $hook, $callback, $priority ) {
if ( function_exists( '_wp_filter_build_unique_id' ) ) {
return _wp_filter_build_unique_id( $hook, $callback, $priority );
}
// Fallback since `_wp_filter_build_unique_id()` is a private WP function.
return VAA_API::callable_to_string( $callback );
}
/**
* Add a new action to the collection to be registered with WordPress.
*
* @since 1.8
* @see add_action()
* @param string $hook The name of the WordPress action.
* @param callable $callback The callable.
* @param int $priority (optional) The priority at which the function should be fired. Default: 10.
* @param int $accepted_args (optional) The number of arguments that should be passed to the $callback. Default: 1.
*/
public function add_action( $hook, $callback, $priority = 10, $accepted_args = 1 ) {
add_action( $hook, $callback, $priority, $accepted_args );
$this->_actions = $this->_add( $this->_actions, $hook, $callback, $priority, $accepted_args );
}
/**
* Add a new filter to the collection to be registered with WordPress.
*
* @since 1.8
* @see add_filter()
* @param string $hook The name of the WordPress filter.
* @param callable $callback The callable.
* @param int $priority (optional) The priority at which the function should be fired. Default: 10.
* @param int $accepted_args (optional) The number of arguments that should be passed to the $callback. Default: 1.
*/
public function add_filter( $hook, $callback, $priority = 10, $accepted_args = 1 ) {
add_filter( $hook, $callback, $priority, $accepted_args );
$this->_filters = $this->_add( $this->_filters, $hook, $callback, $priority, $accepted_args );
}
/**
* A utility function that is used to register the hooks into a single collection.
*
* @since 1.8
* @access protected
* @param array[] $hooks The collection of hooks (that is, actions or filters).
* @param string $hook The name of the WordPress filter that is being registered.
* @param callable $callback The callable.
* @param int $priority The priority at which the function should be fired.
* @param int $accepted_args The number of arguments that should be passed to the $callback.
* @return array The collection of actions and filters registered with WordPress.
*/
protected function _add( $hooks, $hook, $callback, $priority, $accepted_args ) {
if ( ! isset( $hooks[ $hook ] ) ) {
$hooks[ $hook ] = array();
}
if ( ! isset( $hooks[ $hook ][ $priority ] ) ) {
$hooks[ $hook ][ $priority ] = array();
}
$hooks[ $hook ][ $priority ][ $this->_get_identifier( $hook, $callback, $priority ) ] = array(
'hook' => $hook,
'callback' => $callback,
'priority' => $priority,
'accepted_args' => $accepted_args,
);
ksort( $hooks[ $hook ] );
return $hooks;
}
/**
* Remove an action from the collection registered with WordPress.
*
* @since 1.8
* @see remove_action()
* @param string $hook The name of the WordPress action.
* @param callable $callback The callable.
* @param int $priority (optional) The priority at which the function would be fired. Default: 10.
* Pass `null` to let this class try to find the priority.
*/
public function remove_action( $hook, $callback, $priority = 10 ) {
$priority = $this->_validate_priority( $this->_actions, $hook, $callback, $priority );
remove_action( $hook, $callback, $priority );
$this->_actions = $this->_remove( $this->_actions, $hook, $callback, $priority );
}
/**
* Remove a filter from the collection registered with WordPress.
*
* @since 1.8
* @see remove_filter()
* @param string $hook The name of the WordPress filter.
* @param callable $callback The callable.
* @param int $priority (optional) The priority at which the function would be fired. Default: 10.
* Pass `null` to let this class try to find the priority.
*/
public function remove_filter( $hook, $callback, $priority = 10 ) {
$priority = $this->_validate_priority( $this->_filters, $hook, $callback, $priority );
remove_filter( $hook, $callback, $priority );
$this->_filters = $this->_remove( $this->_filters, $hook, $callback, $priority );
}
/**
* A utility function that is used to remove registered hooks from a single collection.
*
* @since 1.8
* @access protected
* @param array[] $hooks The collection of hooks (that is, actions or filters).
* @param string $hook The name of the WordPress filter.
* @param callable $callback The callable.
* @param int $priority The priority at which the function should be fired.
* @return array The collection of actions and filters registered with WordPress.
*/
protected function _remove( $hooks, $hook, $callback, $priority ) {
unset( $hooks[ $hook ][ $priority ][ $this->_get_identifier( $hook, $callback, $priority ) ] );
if ( empty( $hooks[ $hook ][ $priority ] ) ) {
unset( $hooks[ $hook ][ $priority ] );
}
return $hooks;
}
/**
* Remove all hooks from the collection registered with WordPress.
*
* @since 1.8
* @param string $hook The name of the WordPress action.
* @param int|bool $priority (optional) The priority at which the function would be fired. Default: false (all).
*/
public function remove_all_hooks( $hook, $priority = false ) {
$this->remove_all_actions( $hook, $priority );
$this->remove_all_filters( $hook, $priority );
}
/**
* Remove all actions from the collection registered with WordPress.
*
* @since 1.8
* @see remove_all_actions()
* @param string $hook The name of the WordPress action.
* @param int|bool $priority (optional) The priority at which the function would be fired. Default: false (all).
*/
public function remove_all_actions( $hook, $priority = false ) {
remove_all_actions( $hook, $priority );
$this->_actions = $this->_remove_all( $this->_actions, $hook, $priority );
}
/**
* Remove all filters from the collection registered with WordPress.
*
* @since 1.8
* @see remove_all_filters()
* @param string $hook The name of the WordPress filter.
* @param int|bool $priority (optional) The priority at which the function would be fired. Default: false (all).
*/
public function remove_all_filters( $hook, $priority = false ) {
remove_all_filters( $hook, $priority );
$this->_filters = $this->_remove_all( $this->_filters, $hook, $priority );
}
/**
* A utility function that is used to remove all registered hooks from a single collection.
*
* @since 1.8
* @access protected
* @param array[] $hooks The collection of hooks (that is, actions or filters).
* @param string $hook The name of the WordPress filter.
* @param int|bool $priority The priority at which the function should be fired.
* @return array The collection of actions and filters registered with WordPress.
*/
protected function _remove_all( $hooks, $hook, $priority ) {
if ( false !== $priority ) {
unset( $hooks[ $hook ][ $priority ] );
return $hooks;
}
unset( $hooks[ $hook ] );
return $hooks;
}
/**
* Remove all plugin hooks from the collection registered with WordPress.
*
* @since 1.8
* @param string $hook (optional) The name of the WordPress action.
* @param int|bool $priority (optional) The priority at which the function would be fired. Default: false (all).
* @param string $class (optional) Only remove filters from a specific class.
*/
public function remove_own_hooks( $hook = null, $priority = false, $class = '' ) {
$this->remove_own_actions( $hook, $priority, $class );
$this->remove_own_filters( $hook, $priority, $class );
}
/**
* Remove all plugin actions from the collection registered with WordPress.
*
* @since 1.8
* @param string $hook (optional) The name of the WordPress action.
* @param int|bool $priority (optional) The priority at which the function would be fired. Default: false (all).
* @param string $class (optional) Only remove filters from a specific class.
*/
public function remove_own_actions( $hook = null, $priority = false, $class = '' ) {
$this->_actions = $this->_remove_own( $this->_actions, $hook, $priority, 'remove_action', $class );
}
/**
* Remove all plugin filters from the collection registered with WordPress.
*
* @since 1.8
* @param string $hook (optional) The name of the WordPress filter.
* @param int|bool $priority (optional) The priority at which the function would be fired. Default: false (all).
* @param string $class (optional) Only remove filters from a specific class.
*/
public function remove_own_filters( $hook = null, $priority = false, $class = '' ) {
$this->_filters = $this->_remove_own( $this->_filters, $hook, $priority, 'remove_filter', $class );
}
/**
* A utility function that is used to remove all registered plugin hooks from a single collection.
*
* Disable some PHPMD checks for this method.
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @todo Refactor to enable above checks?
*
* @since 1.8
* @access protected
* @param array[] $hooks The collection of hooks (that is, actions or filters).
* @param string $hook The name of the WordPress filter.
* @param int|bool $priority The priority at which the function should be fired.
* @param callable $function The function to use for removal.
* @param string $class Only remove filters from a specific class.
* @return array The collection of actions and filters registered with WordPress.
*/
protected function _remove_own( $hooks, $hook, $priority, $function, $class ) {
// Remove specific priority from hook.
if ( false !== $priority ) {
if ( isset( $hooks[ $hook ][ $priority ] ) ) {
foreach ( (array) $hooks[ $hook ][ $priority ] as $id => $args ) {
if ( $class ) {
$class_compare = ( isset( $args['callback'][0] ) ) ? $args['callback'][0] : '';
if ( is_object( $class_compare ) ) {
$class_compare = get_class( $class_compare );
}
if ( $class !== $class_compare ) {
continue;
}
}
// Remove it from WordPress.
$this->$function( $hook, $args['callback'], $priority );
unset( $hooks[ $hook ][ $priority ][ $id ] );
}
if ( empty( $hooks[ $hook ][ $priority ] ) ) {
unset( $hooks[ $hook ][ $priority ] );
}
}
return $hooks;
}
// Remove specific hook.
if ( null !== $hook ) {
if ( isset( $hooks[ $hook ] ) ) {
foreach ( (array) $hooks[ $hook ] as $priority => $foo ) {
$hooks = $this->_remove_own( $hooks, $hook, $priority, $function, $class );
}
if ( empty( $hooks[ $hook ] ) ) {
unset( $hooks[ $hook ] );
}
}
return $hooks;
}
// Remove everything.
foreach ( (array) $hooks as $hook => $foo ) {
$hooks = $this->_remove_own( $hooks, $hook, false, $function, $class );
}
return $hooks;
}
/**
* Validates the priority value.
* If it's passed as `null` it will attempt to find it.
*
* @since 1.8
* @param array[] $hooks The collection of hooks (that is, actions or filters).
* @param string $hook The name of the WordPress filter.
* @param callable $callback The callable.
* @param int $priority The priority at which the function should be fired.
* @return int Default: 10.
*/
protected function _validate_priority( $hooks, $hook, $callback, $priority ) {
if ( ! is_numeric( $priority ) ) {
$priority = $this->_find_priority( $hooks, $hook, $callback );
if ( ! $priority ) {
return 10;
}
}
return (int) $priority;
}
/**
* Finds the priority of a hook if unknown.
*
* @since 1.8
* @param array[] $hooks The collection of hooks (that is, actions or filters).
* @param string $hook The name of the WordPress filter.
* @param callable $callback The callable.
* @return int
*/
protected function _find_priority( $hooks, $hook, $callback ) {
if ( ! isset( $hooks[ $hook ] ) ) {
return null;
}
foreach ( (array) $hooks[ $hook ] as $priority => $registered ) {
foreach ( $registered as $args ) {
if ( $callback === $args['callback'] ) {
return $priority;
}
}
}
return null;
}
/**
* Return all registered hooks data.
* Can be used for debugging.
*
* @since 1.8
* @param string|array $keys The hook array keys to look for. Each key stands for a level deeper in the array.
* Order: hook type >> hook name >> priority >> function id >> hook args.
* In case of a string it will stand for the hook type.
* @param bool $objects Return the full object of a callback? Default: false, can cause PHP memory issues.
* @return array[]|mixed
*/
public function _get_hooks( $keys = null, $objects = false ) {
$data = array(
'actions' => $this->_actions,
'filters' => $this->_filters,
);
if ( ! $objects ) {
// Don't return full objects.
$data = $this->_convert_callback( $data );
}
if ( $keys ) {
$keys = (array) $keys;
foreach ( $keys as $key ) {
$data = VAA_API::get_array_data( $data, $key );
}
}
return $data;
}
/**
* Return all registered actions.
* Can be used for debugging.
*
* @since 1.8
* @param string|array $keys The hook array keys to look for. Each key stands for a level deeper in the array.
* Order: hook name >> priority >> function id >> hook args.
* In case of a string it will stand for the hook name.
* @param bool $objects Return the full object of a callback? Default: false, can cause PHP memory issues.
* @return array[]|mixed
*/
public function _get_actions( $keys = null, $objects = false ) {
$keys = (array) $keys;
array_unshift( $keys, 'actions' );
return $this->_get_hooks( $keys, $objects );
}
/**
* Return all registered filters.
* Can be used for debugging.
*
* @since 1.8
* @param string|array $keys The hook array keys to look for. Each key stands for a level deeper in the array.
* Order: hook name >> priority >> function id >> hook args.
* In case of a string it will stand for the hook name.
* @param bool $objects Return the full object of a callback? Default: false, can cause PHP memory issues.
* @return array[]|mixed
*/
public function _get_filters( $keys = null, $objects = false ) {
$keys = (array) $keys;
array_unshift( $keys, 'filters' );
return $this->_get_hooks( $keys, $objects );
}
/**
* Convert object types into object class names instead of full object data.
* @since 1.8
* @param array $hooks The collection of hooks (that is, actions or filters).
* @return array
*/
protected function _convert_callback( $hooks ) {
foreach ( (array) $hooks as $key => $val ) {
if ( is_object( $val ) ) {
$hooks[ $key ] = get_class( $val );
continue;
}
if ( is_array( $val ) ) {
$hooks[ $key ] = $this->_convert_callback( $val );
}
}
return $hooks;
}
} // End class VAA_View_Admin_As_Hooks.

View File

@@ -0,0 +1,230 @@
<?php
/**
* View Admin As - Class Module
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Base class for modules that use option data etc.
* Use this class as an extender for VAA modules other than view types.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.5 (This was one class with VAA_View_Admin_As_Class_Base)
* @version 1.8
* @uses \VAA_View_Admin_As_Base Extends class
*/
abstract class VAA_View_Admin_As_Module extends VAA_View_Admin_As_Base
{
/**
* Option key.
*
* @since 1.5
* @var string
*/
protected $optionKey = '';
/**
* Option data.
*
* @since 1.5
* @var mixed
*/
protected $optionData = false;
/**
* Enable functionalities?
*
* @since 1.5
* @var bool
*/
protected $enable = false;
/**
* Script localization data.
*
* @since 1.6
* @var array
*/
protected $scriptLocalization = array();
/**
* Is enabled?
*
* @since 1.5
* @access public
* @return bool
*/
public function is_enabled() {
return (bool) $this->enable;
}
/**
* Set plugin enabled true/false.
*
* @since 1.5.1
* @since 1.6.2 Make database update optional.
* @since 1.8 Make this method public.
* @access public
* @param bool $bool Enable or disable?
* @param bool $update_db Do database update? (default true).
* @return bool
*/
public function set_enable( $bool = false, $update_db = true ) {
$success = true;
if ( $update_db && $this->get_optionKey() ) {
$success = $this->update_optionData( (bool) $bool, 'enable', true );
}
if ( $success ) {
$this->enable = (bool) $bool;
}
return $success;
}
/**
* Helper function for ajax return data.
* Merges second param with data defaults.
*
* @since 1.7
* @access public
* @param bool $success Success return.
* @param array $data Array of detailed info.
* @param string $type Notice type.
* @return array
*/
public function ajax_data_return( $success, $data, $type = null ) {
if ( ! is_string( $type ) ) {
$type = ( $success ) ? 'success' : 'error';
}
$data = wp_parse_args( $data, array(
'display' => 'notice',
'type' => $type,
) );
return array(
'success' => (bool) $success,
'data' => $data,
);
}
/**
* Helper function for ajax notice return data.
* Merges second param with data defaults.
*
* @since 1.7
* @access public
* @param bool $success Success return.
* @param array $data Array of detailed info.
* @param string $type Notice type.
* @return array
*/
public function ajax_data_notice( $success, $data, $type = null ) {
$data['display'] = 'notice';
return $this->ajax_data_return( $success, $data, $type );
}
/**
* Helper function for ajax popup return data.
* Merges second param with data defaults.
*
* @since 1.7
* @access public
* @param bool $success Success return.
* @param array $data Array of detailed info.
* @param string $type Popup type.
* @return array
*/
public function ajax_data_popup( $success, $data, $type = null ) {
$data['display'] = 'popup';
return $this->ajax_data_return( $success, $data, $type );
}
/**
* Simple data validation.
* Meant to be overwritten by subclass.
*
* @since 1.7
* @access public
* @param null $null Null.
* @param mixed $data The view data.
* @return mixed
*/
public function validate_view_data( $null, $data = null ) {
if ( $data ) {
return $data;
}
return $null;
}
/**
* Get the class localisation strings
* @param string $key (optional) Data key.
* @return mixed
*/
public function get_scriptLocalization( $key = null ) {
return VAA_API::get_array_data( $this->scriptLocalization, $key );
}
/**
* Get the option key as used in the options table.
* @return string
*/
public function get_optionKey() {
return (string) $this->optionKey;
}
/**
* Get the class option data.
* @param string $key (optional) Data key.
* @return mixed
*/
public function get_optionData( $key = null ) {
return VAA_API::get_array_data( $this->optionData, $key );
}
/**
* Set the class localisation strings
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
*/
protected function set_scriptLocalization( $val, $key = null, $append = false ) {
$this->scriptLocalization = (array) VAA_API::set_array_data( $this->scriptLocalization, $val, $key, $append );
}
/**
* Set the option key as used in the options table.
* @param string $val Option key.
*/
protected function set_optionKey( $val ) {
$this->optionKey = (string) $val;
}
/**
* Set the class option data.
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
*/
protected function set_optionData( $val, $key = null, $append = false ) {
$this->optionData = VAA_API::set_array_data( $this->optionData, $val, $key, $append );
}
/**
* Update the class option data.
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
* @return bool
*/
protected function update_optionData( $val, $key = null, $append = false ) {
$this->set_optionData( $val, $key, $append );
return update_option( $this->get_optionKey(), $this->optionData );
}
} // End class VAA_View_Admin_As_Module.

View File

@@ -0,0 +1,926 @@
<?php
/**
* View Admin As - Class Settings
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Settings class that stores the VAA settings for use.
*
* @see VAA_View_Admin_As_Store
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.7
* @version 1.8
* @uses \VAA_View_Admin_As_Base Extends class
*/
class VAA_View_Admin_As_Settings extends VAA_View_Admin_As_Base
{
/**
* The key to use for filters.
* Passed to __construct() as first parameter.
*
* @since 1.8
* @var string
*/
private $_filter_postfix = '';
/**
* Is this option for a network installation?
* Can only be set with set_for_network().
*
* @since 1.7.5
* @see \VAA_View_Admin_As_Settings::store_optionData()
* @var bool
*/
protected $for_network = false;
/**
* The user ID for whom this metadata is for.
* Can only be set with store_userMeta().
*
* @since 1.7.5
* @see \VAA_View_Admin_As_Settings::store_userMeta()
* @var int
*/
protected $for_user = null;
/**
* Database option key.
* Always starts with `vaa_`.
* Keys are parsed with underscores as spacing.
*
* @since 1.4
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @var string
*/
protected $optionKey = null;
/**
* Database option data.
*
* @since 1.4
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @var array
*/
protected $optionData = array();
/**
* User meta key for settings ans views.
* Always starts with `vaa-`.
* Keys are parsed with dashes as spacing.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @var string
*/
protected $userMetaKey = null;
/**
* User meta value for settings ans views.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @var array
*/
protected $userMeta = array();
/**
* User meta from all users.
*
* @since 1.8
* @var array
*/
protected $allUserMeta = array();
/**
* Array of default settings.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @var array
*/
protected $defaultSettings = array();
/**
* Array of allowed settings.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @var array
*/
protected $allowedSettings = array();
/**
* Array of default settings.
*
* @since 1.5
* @since 1.5.2 Added force_group_users.
* @since 1.6 Moved to this class from main class.
* @since 1.6.1 Added freeze_locale.
* @since 1.7 Moved to this class from store class.
* @var array
*/
protected $defaultUserSettings = array();
/**
* Array of allowed settings.
* Setting name (key) => array( values ).
*
* @since 1.5
* @since 1.5.2 Added force_group_users.
* @since 1.6 Moved to this class from main class.
* @since 1.6.1 Added freeze_locale.
* @since 1.7 Moved to this class from store class.
* @var array
*/
protected $allowedUserSettings = array();
/**
* Sets the default data.
*
* @since 1.7
* @access protected
* @param string $id Identifier for this settings instance.
* @param array $args {
* (optional) Setting arguments.
* @type array $default The default settings (option)
* @type array $allowed The allowed settings (option). Use arrays to define all possible values for a setting.
* @type array $default_user The default user settings (meta)
* @type array $allowed_user The allowed user settings (meta). Use arrays to define all possible values for a setting.
* }
*/
protected function __construct( $id, $args = array() ) {
parent::__construct();
if ( empty( $id ) || ! is_string( $id ) ) {
return null;
}
$args = wp_parse_args( $args, array(
'default' => array(),
'allowed' => array(),
'default_user' => array(),
'allowed_user' => array(),
) );
$default = $args['default'];
$allowed = $args['allowed'];
$default_user = $args['default_user'];
$allowed_user = $args['allowed_user'];
if ( 'VAA_View_Admin_As_Store' === get_class( $this ) ) {
$this->set_optionKey( 'vaa_view_admin_as' );
$this->set_optionData( array(
'db_version' => null,
'settings' => null,
) );
$this->set_userMetaKey( 'vaa-view-admin-as' );
$this->set_userMeta( array(
'settings' => null,
'views' => null,
) );
$default = array(
'view_types' => array(),
);
$allowed = array(
'view_types' => array(), // No restriction to values.
);
$default_user = array(
'admin_menu_location' => 'top-secondary',
'disable_super_admin' => true,
'force_group_users' => false,
'freeze_locale' => false,
'hide_customizer' => false,
'hide_front' => false,
'view_mode' => 'browse',
);
$allowed_user = array(
'admin_menu_location' => array( 'top-secondary', 'my-account' ),
'disable_super_admin' => array( true, false ),
'force_group_users' => array( true, false ),
'freeze_locale' => array( true, false ),
'hide_customizer' => array( true, false ),
'hide_front' => array( true, false ),
'view_mode' => array( 'browse', 'single' ),
);
// @todo Remove?
$this->add_filter( 'view_admin_as_validate_view_data_setting', array( $this, 'filter_validate_settings' ), 10, 3 );
$this->add_filter( 'view_admin_as_validate_view_data_user_setting', array( $this, 'filter_validate_settings' ), 10, 3 );
$this->add_filter( 'view_admin_as_handle_ajax_setting', array( $this, 'filter_update_settings' ), 10, 3 );
$this->add_filter( 'view_admin_as_handle_ajax_user_setting', array( $this, 'filter_update_settings' ), 10, 3 );
// Make identifier empty for the filters.
$id = '';
} else {
if ( 'view-admin-as' === sanitize_title_with_dashes( $id ) ) {
_doing_it_wrong(
__METHOD__,
sprintf(
// Translators: %1$s stands for an option key and %2$s stands for a class name.
__( 'The setting key %1$s is reserved for class %2$s', VIEW_ADMIN_AS_DOMAIN ),
$id, 'VAA_View_Admin_As_Store'
),
''
);
return;
}
$this->set_optionKey( 'vaa_' . $id );
$this->set_userMetaKey( 'vaa-' . $id );
// Append underscore to the identifier for the filters.
$id = '_' . $id;
} // End if().
$this->_filter_postfix = $id;
/**
* Set the default global settings.
*
* @since 1.7
* @param array
* @return array
*/
$this->set_defaultSettings( apply_filters( 'view_admin_as_default_global_settings' . $id, $default ) );
/**
* Set the allowed global settings.
*
* @since 1.7
* @param array {
* Settings array (key = setting name).
* @type array Array of allowed values.
* }
* @return array
*/
$this->set_allowedSettings( apply_filters( 'view_admin_as_allowed_global_settings' . $id, $allowed ) );
/**
* Set the default settings for users.
*
* @since 1.7
* @param array
* @return array
*/
$this->set_defaultUserSettings( apply_filters( 'view_admin_as_default_user_settings' . $id, $default_user ) );
/**
* Set the allowed settings for users.
*
* @since 1.7
* @param array {
* Settings array (key = setting name).
* @type array Array of allowed values.
* }
* @return array
*/
$this->set_allowedUserSettings( apply_filters( 'view_admin_as_allowed_user_settings' . $id, $allowed_user ) );
}
/**
* Validate hook for settings.
*
* @since 1.7
* @param null $null Default return (invalid).
* @param mixed $data The view data.
* @param string $key The data key.
* @return mixed
*/
public function filter_validate_settings( $null, $data, $key ) {
if ( ! empty( $data ) && ! empty( $key ) ) {
if ( 'setting' === $key ) {
return $this->validate_settings( $data, 'global', false );
}
if ( 'user_setting' === $key ) {
return $this->validate_settings( $data, 'user', false );
}
}
return $null;
}
/**
* Validate hook for settings.
*
* @since 1.7
* @since 1.7.3 Renamed from filter_store_settings().
* @param null $null Default return (invalid).
* @param mixed $data The view data.
* @param string $key The data key.
* @return mixed
*/
public function filter_update_settings( $null, $data, $key ) {
if ( ! empty( $data ) && ! empty( $key ) ) {
if ( 'setting' === $key ) {
return $this->update_settings( $data, 'global' );
}
if ( 'user_setting' === $key ) {
return $this->update_settings( $data, 'user' );
}
}
return $null;
}
/**
* Validate setting data based on allowed settings.
* Will also merge with the default settings unless third $merge parameter is false.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class. Added third $merge parameter.
* @access public
*
* @param array $settings The new settings.
* @param string $type The type of settings (global / user).
* @param bool $merge Merge with defaults? (will return all settings).
* @return array|bool $settings / false
*/
public function validate_settings( $settings, $type, $merge = true ) {
if ( 'global' === $type ) {
$defaults = $this->get_defaultSettings();
$allowed = $this->get_allowedSettings();
} elseif ( 'user' === $type ) {
$defaults = $this->get_defaultUserSettings();
$allowed = $this->get_allowedUserSettings();
} else {
return false;
}
if ( $merge ) {
return $this->parse_settings( $settings, $defaults, $allowed );
}
foreach ( $settings as $setting => $value ) {
// Only pass the settings if the key and value matched the data in the allowed settings.
if ( ! array_key_exists( $setting, $allowed ) ) {
unset( $settings[ $setting ] );
}
// If setting key is allowed value is empty we don't need to validate.
if ( ! empty( $allowed[ $setting ] ) && ! in_array( $value, $allowed[ $setting ], true ) ) {
unset( $settings[ $setting ] );
}
}
return $settings;
}
/**
* Store settings based on allowed settings.
* Also merges with the default settings.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.7 Moved to this class from store class.
* @since 1.7.3 Renamed from store_settings().
* @access public
*
* @param array $settings The new settings.
* @param string $type The type of settings (global / user).
* @return bool
*/
public function update_settings( $settings, $type ) {
if ( 'global' === $type ) {
$current = $this->get_settings();
$defaults = $this->get_defaultSettings();
$allowed = $this->get_allowedSettings();
} elseif ( 'user' === $type ) {
$current = $this->get_userSettings();
$defaults = $this->get_defaultUserSettings();
$allowed = $this->get_allowedUserSettings();
} else {
return false;
}
if ( ! is_array( $current ) ) {
$current = $defaults;
}
$settings = apply_filters(
'view_admin_as_update_' . $type . '_settings' . $this->_filter_postfix,
$settings, $current, $defaults, $allowed
);
$settings = $this->validate_settings( $settings, $type, false );
foreach ( $settings as $setting => $value ) {
$current[ $setting ] = $value;
// Some settings need a reset.
if ( in_array( $setting, array( 'view_mode' ), true ) ) {
view_admin_as()->controller()->reset_view();
}
}
$new = $this->parse_settings( $current, $defaults, $allowed );
if ( 'global' === $type ) {
return $this->update_optionData( $new, 'settings', true );
} elseif ( 'user' === $type ) {
return $this->update_userMeta( $new, 'settings', true );
}
return false;
}
/**
* Parse the settings.
* Checks if the setting exists, removes it otherwise.
* Checks if the setting is allowed, otherwise sets it to the default value.
*
* @since 1.7
* @param array $settings The new settings.
* @param array $defaults The default settings.
* @param array $allowed The allowed settings.
* @return array
*/
public function parse_settings( $settings, $defaults, $allowed ) {
$settings = wp_parse_args( $settings, $defaults );
foreach ( $settings as $setting => $value ) {
if ( ! array_key_exists( $setting, $allowed ) ) {
// We don't have such a setting.
unset( $settings[ $setting ] );
} elseif ( ! empty( $allowed[ $setting ] ) && ! in_array( $value, $allowed[ $setting ], true ) ) {
// Set it to default if the allowed values are set and the value isn't allowed.
$settings[ $setting ] = $defaults[ $setting ];
}
}
return $settings;
}
/**
* Get the meta key results for all users.
*
* @since 1.8
* @global \wpdb $wpdb
* @return array {
* User ID's as array keys.
* @type array $meta_values The meta values. Column ID's as array keys.
* }
*/
public function get_all_user_meta() {
if ( ! empty( $this->allUserMeta ) ) {
return $this->allUserMeta;
}
global $wpdb;
$key = $this->get_userMetaKey();
// @todo Use WP_Meta_Query ?
$sql = 'SELECT * FROM ' . $wpdb->usermeta . ' WHERE meta_key = %s';
// @codingStandardsIgnoreLine >> $wpdb->prepare(), check returning false error.
$results = (array) $wpdb->get_results( $wpdb->prepare( $sql, $key ) );
$metas = array();
foreach ( $results as $key => $meta ) {
if ( ! isset( $metas[ $meta->user_id ] ) ) {
$metas[ $meta->user_id ] = array();
}
if ( ! empty( $meta->meta_value ) ) {
$metas[ $meta->user_id ][ $meta->umeta_id ] = maybe_unserialize( $meta->meta_value );
}
}
$this->allUserMeta = $metas;
return $metas;
}
/**
* Set the meta values for other users.
* Should be used together with get_all_user_meta() to get column id's.
*
* @since 1.8
* @see \VAA_View_Admin_As_Settings::get_all_user_meta()
* @param mixed $value
* @param int $user_id
* @param int $column_id
* @return bool
*/
public function update_other_user_meta( $value, $user_id, $column_id = null ) {
if ( ! $this->allUserMeta ) {
$this->get_all_user_meta();
}
// Validate settings.
$value = wp_parse_args( $value, array(
'settings' => array(),
) );
$value['settings'] = $this->validate_settings( $value['settings'], 'user', true );
if ( ! isset( $this->allUserMeta[ $user_id ] ) ) {
$column_id = 0;
$this->allUserMeta[ $user_id ] = array( $column_id => $value );
}
if ( ! is_int( $column_id ) ) {
reset( $this->allUserMeta[ $user_id ] );
$column_id = key( $this->allUserMeta[ $user_id ] );
}
$this->allUserMeta[ $user_id ][ $column_id ] = $value;
// @todo handle multiple columns.
return update_user_meta( $user_id, $this->get_userMetaKey(), $value );
}
/**
* Delete or reset all View Admin As metadata for this user.
*
* @since 1.5
* @since 1.6 Moved to this class from main class.
* @since 1.6.2 Option to remove the VAA metadata for all users.
* @since 1.7 Moved to this class from store class.
* @access public
*
* @param int|string $user_id ID of the user being deleted/removed (pass `all` for all users).
* @param \WP_User $user User object provided by the wp_login hook.
* @param bool $reset_only Only reset (not delete) the user meta.
* @return bool
*/
public function delete_user_meta( $user_id = null, $user = null, $reset_only = true ) {
/**
* Set the first parameter to `all` to remove the meta value for all users.
* @since 1.6.2
*/
if ( 'all' === $user_id ) {
return $this->delete_all_user_meta( $reset_only );
}
$id = false;
if ( is_numeric( $user_id ) ) {
// Delete hooks.
$id = (int) $user_id;
} elseif ( isset( $user->ID ) ) {
// Login/Logout hooks.
$id = (int) $user->ID;
}
if ( $id ) {
$success = true;
if ( $reset_only ) {
// Reset db metadata (returns: true on success, false on failure).
if ( get_user_meta( $id, $this->get_userMetaKey() ) ) {
$success = update_user_meta( $id, $this->get_userMetaKey(), false );
}
} else {
// Remove db metadata (returns: true on success, false on failure).
$success = delete_user_meta( $id, $this->get_userMetaKey() );
}
// Update current metadata if it is the current user.
if ( $success && (int) get_current_user_id() === $id ) {
$this->set_userMeta( false );
}
return $success;
}
// No user or metadata found, no deletion needed.
return true;
}
/**
* Delete or reset all View Admin As metadata for all users.
*
* @since 1.7
* @access public
*
* @see https://developer.wordpress.org/reference/classes/wpdb/update/
* @see https://developer.wordpress.org/reference/classes/wpdb/delete/
*
* @global \wpdb $wpdb
* @param bool $reset_only Only reset (not delete) the user meta.
* @return bool
*/
public function delete_all_user_meta( $reset_only = true ) {
global $wpdb;
if ( $reset_only ) {
// Reset.
return (bool) $wpdb->update(
$wpdb->usermeta, // table.
array( 'meta_value' => '' ), // data.
array( 'meta_key' => $this->get_userMetaKey() ) // where.
);
} else {
// Delete.
return (bool) $wpdb->delete(
$wpdb->usermeta, // table.
array( 'meta_key' => $this->get_userMetaKey() ) // where.
);
}
}
/**
* Get the option key as used in the options table.
* @return string
*/
public function get_optionKey() {
return (string) $this->optionKey;
}
/**
* Get the user meta key as used in the usermeta table.
* @return string
*/
public function get_userMetaKey() {
return (string) $this->userMetaKey;
}
/**
* Get the option data as used in the options table.
* @param string $key Key in the option array.
* @return mixed
*/
public function get_optionData( $key = null ) {
return VAA_API::get_array_data( $this->optionData, $key );
}
/**
* Get the user metadata as used in the usermeta table.
* @param string $key Key in the meta array.
* @return mixed
*/
public function get_userMeta( $key = null ) {
return VAA_API::get_array_data( $this->userMeta, $key );
}
/**
* Get the default settings.
* @param string $key Setting key.
* @return mixed
*/
public function get_defaultSettings( $key = null ) {
return VAA_API::get_array_data( $this->defaultSettings, $key );
}
/**
* Get the default user settings.
* @param string $key Setting key.
* @return mixed
*/
public function get_defaultUserSettings( $key = null ) {
return VAA_API::get_array_data( $this->defaultUserSettings, $key );
}
/**
* Get the allowed settings.
* @param string $key Setting key.
* @return array
*/
public function get_allowedSettings( $key = null ) {
return (array) VAA_API::get_array_data( $this->allowedSettings, $key );
}
/**
* Get the allowed user settings.
* @param string $key Setting key.
* @return array
*/
public function get_allowedUserSettings( $key = null ) {
return (array) VAA_API::get_array_data( $this->allowedUserSettings, $key );
}
/**
* Get the settings.
* @param string $key Setting key.
* @return mixed
*/
public function get_settings( $key = null ) {
return VAA_API::get_array_data(
$this->validate_settings(
$this->get_optionData( 'settings' ),
'global'
),
$key
);
}
/**
* Get the user settings.
* @param string $key Setting key.
* @return mixed
*/
public function get_userSettings( $key = null ) {
return VAA_API::get_array_data(
$this->validate_settings(
$this->get_userMeta( 'settings' ),
'user'
),
$key
);
}
/**
* Set the option key as used in the options table.
* @param string $val Option key.
* @return void
*/
protected function set_optionKey( $val ) {
$this->optionKey = (string) str_replace( array( ' ', '-' ), '_', sanitize_title_with_dashes( $val ) );
}
/**
* Set the option key as used in the options table.
* @param string $val Option key.
* @return void
*/
protected function set_userMetaKey( $val ) {
$this->userMetaKey = (string) sanitize_title_with_dashes( $val );
}
/**
* Set the default settings.
* @param array $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
protected function set_defaultSettings( $val, $key = null, $append = false ) {
$this->defaultSettings = VAA_API::set_array_data( $this->defaultSettings, $val, $key, $append );
}
/**
* Set the default user settings.
* @param array $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
protected function set_defaultUserSettings( $val, $key = null, $append = false ) {
$this->defaultUserSettings = VAA_API::set_array_data( $this->defaultUserSettings, $val, $key, $append );
}
/**
* Set the allowed settings.
* @param mixed $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
protected function set_allowedSettings( $val, $key = null, $append = false ) {
$this->allowedSettings = VAA_API::set_array_data( $this->allowedSettings, $val, $key, $append );
}
/**
* Set the allowed user settings.
* @param mixed $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
protected function set_allowedUserSettings( $val, $key = null, $append = false ) {
$this->allowedUserSettings = VAA_API::set_array_data( $this->allowedUserSettings, $val, $key, $append );
}
/**
* Set the settings.
* @param mixed $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_settings( $val, $key = null, $append = false ) {
$this->set_optionData(
$this->validate_settings(
VAA_API::set_array_data( $this->get_settings(), $val, $key, $append ),
'global'
),
'settings',
true
);
}
/**
* Set the user settings.
* @param mixed $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_userSettings( $val, $key = null, $append = false ) {
$this->set_userMeta(
$this->validate_settings(
VAA_API::set_array_data( $this->get_userSettings(), $val, $key, $append ),
'user'
),
'settings',
true
);
}
/**
* Set the plugin option data.
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_optionData( $val, $key = null, $append = false ) {
$this->optionData = VAA_API::set_array_data( $this->optionData, $val, $key, $append );
}
/**
* Set the user metadata.
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_userMeta( $val, $key = null, $append = false ) {
$this->userMeta = VAA_API::set_array_data( $this->userMeta, $val, $key, $append );
}
/**
* Store the option data.
* @param bool $network Is network option?
* @since 1.7.x
*/
protected function store_optionData( $network = false ) {
$this->set_for_network( $network );
if ( $this->is_for_network() ) {
$this->set_optionData( get_site_option( $this->get_optionKey() ) );
} else {
$this->set_optionData( get_option( $this->get_optionKey() ) );
}
}
/**
* Store the user meta.
* @since 1.7.x
* @param int $user_id The user ID this metadata is for.
* @param bool $single NOT SUPPORTED YET!
*/
protected function store_userMeta( $user_id, $single = true ) {
if ( ! is_int( $user_id ) ) {
return;
}
$this->for_user = $user_id;
$this->set_userMeta( get_user_meta( $this->for_user, $this->get_userMetaKey(), true ) );
}
/**
* Update the plugin option data.
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
* @return bool
*/
public function update_optionData( $val, $key = null, $append = false ) {
$this->set_optionData( $val, $key, $append );
if ( $this->is_for_network() ) {
return update_site_option( $this->get_optionKey(), $this->get_optionData() );
}
return update_option( $this->get_optionKey(), $this->get_optionData() );
}
/**
* Update the user metadata.
* @param mixed $val Data.
* @param string $key (optional) Data key.
* @param bool $append (optional) Append if it doesn't exist?
* @return bool
*/
public function update_userMeta( $val, $key = null, $append = false ) {
$this->set_userMeta( $val, $key, $append );
return update_user_meta( $this->for_user, $this->get_userMetaKey(), $this->get_userMeta() );
}
/**
* Set whether this instance if for a network option.
* @since 1.7.x
* @param bool $bool
*/
protected function set_for_network( $bool ) {
$this->for_network = (bool) $bool;
}
/**
* Set whether this instance if for a network option.
* @since 1.7.x
* @return bool
*/
public function is_for_network() {
return (bool) $this->for_network;
}
} // End class VAA_View_Admin_As_Settings.

View File

@@ -0,0 +1,557 @@
<?php
/**
* View Admin As - Class Store
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Store class that stores the VAA data for use.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.6
* @version 1.8
* @uses \VAA_View_Admin_As_Settings Extends class
*/
final class VAA_View_Admin_As_Store extends VAA_View_Admin_As_Settings
{
/**
* The single instance of the class.
*
* @since 1.6
* @static
* @var \VAA_View_Admin_As_Store
*/
private static $_instance = null;
/**
* The nonce.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @var string
*/
private $nonce = '';
/**
* The parsed nonce.
*
* @since 1.6.2
* @var string
*/
private $nonce_parsed = '';
/**
* View type data.
* You can add custom view data with VAA_View_Admin_As_Store::set_data().
*
* @see \VAA_View_Admin_As_Store::set_data()
* @since 1.7
* @var array {
* Default view data.
* @type bool[] $caps Since 1.3 Array of available capabilities.
* @type \WP_Role[] $roles Since 0.1 Array of available roles (WP_Role objects).
* @type string[] $rolenames Since 1.6.4 Array of role names (used for role translations).
* @type \WP_User[] $users Since 0.1 Array of available users (WP_User objects).
* @type string[] $languages Since 1.8 Array of available locale/languages.
* }
*/
private $data = array(
'caps' => array(),
'roles' => array(),
'rolenames' => array(),
'users' => array(),
'languages' => array(),
);
/**
* Current (initial) user object.
*
* @since 0.1
* @since 1.6 Moved to this class from main class.
* @var \WP_User
*/
private $curUser;
/**
* Current (initial) user session.
*
* @since 1.3.4
* @since 1.6 Moved to this class from main class.
* @var string
*/
private $curUserSession = '';
/**
* Current (initial) user data.
* Will contain all properties of the original current user object.
*
* @since 1.6.3
* @since 1.7.3 Not static anymore.
* @var array
*/
private $curUserData = array();
/**
* Does the current (initial) user has full access to all features of this plugin?
*
* @since 1.6.3
* @since 1.7.3 Not static anymore.
* @since 1.7.6 Renamed from $isCurUserSuperAdmin
* @var bool
*/
private $curUserHasFullAccess = false;
/**
* Selected view data as stored in the user meta.
* Format: array( VIEW_TYPE => VIEW_DATA ).
*
* @since 0.1
* @since 1.6 Moved to this class from main class.
* @var array
*/
private $view = array();
/**
* The selected user object (if a view is selected).
* Can be the same as $curUser depending on the selected view.
*
* @since 0.1
* @since 1.6 Moved to this class from main class.
* @var \WP_User
*/
private $selectedUser;
/**
* The selected capabilities (if a view is selected).
*
* @since 1.6.2
* @var bool[]
*/
private $selectedCaps = array();
/**
* Populate the instance.
* @since 1.6
*/
protected function __construct() {
parent::__construct( 'view-admin-as' );
self::$_instance = $this;
$this->init( true );
}
/**
* Store the current user and other user related data.
*
* @since 1.6.3 Moved to this class.
* @access public
* @param bool $redo (optional) Force re-init?
*/
public function init( $redo = false ) {
static $done = false;
if ( $done && ! $redo ) return;
$this->set_nonce( 'view-admin-as' );
// Get the current user.
$this->set_curUser( wp_get_current_user() );
// Get the current user session (WP 4.0+).
$this->set_curUserSession( (string) wp_get_session_token() );
$this->curUserHasFullAccess = VAA_API::user_has_full_access( $this->get_curUser() );
$this->curUserData = get_object_vars( $this->get_curUser() );
// Get database settings.
$this->store_optionData( VAA_View_Admin_As::is_network_active() );
// Get database settings of the current user.
$this->store_userMeta( get_current_user_id() );
$done = true;
}
/**
* Does the current (original) user has full access to this plugin?
* @since 1.8
* @return bool
*/
public function cur_user_has_full_access() {
return (bool) $this->curUserHasFullAccess;
}
/**
* Compare user to the current (original) user.
*
* @since 1.8
* @param \WP_User|int $user The user to compare.
* @return bool
*/
public function is_curUser( $user ) {
if ( $user instanceof WP_User ) {
$user = $user->ID;
}
if ( ! is_numeric( $user ) ) {
return false;
}
return (bool) ( (int) $this->get_curUser()->ID === (int) $user );
}
/**
* Helper function for is_super_admin().
* Will validate the original user if it is the current user or no user ID is passed.
* This can prevent invalid checks after a view is applied.
*
* @see \VAA_API::is_super_admin()
* @deprecated
* @todo Remove in 1.9
*
* @since 1.6.3
* @since 1.7.3 Not static anymore.
* @access public
* @param int $user_id (optional).
* @return bool
*/
public function is_super_admin( $user_id = null ) {
_deprecated_function( __FUNCTION__, '1.8', 'VAA_API::is_super_admin()' );
if ( null === $user_id || (int) $this->curUser->ID === (int) $user_id ) {
return $this->curUserHasFullAccess;
}
return VAA_API::user_has_full_access( $user_id );
}
/**
* Get data from the current user, similar to the WP_User object.
* Unlike the current user object this data isn't modified after in a view.
* This has all public WP_User properties stored as an array.
*
* @since 1.6.3
* @since 1.7.3 Not static anymore.
* @access public
* @param string $key (optional).
* @return mixed
*/
public function get_originalUserData( $key = null ) {
return VAA_API::get_array_data( $this->curUserData, $key );
}
/**
* Get current user.
* @return \WP_User $curUser Current user object.
*/
public function get_curUser() {
return $this->curUser;
}
/**
* Get current user session.
* @return string
*/
public function get_curUserSession() {
return (string) $this->curUserSession;
}
/**
* Get view data (meta).
* @since 1.7
* @param string $key Key for array.
* @return mixed
*/
public function get_view( $key = null ) {
return VAA_API::get_array_data( $this->view, $key );
}
/**
* Get view type data
*
* @since 1.7
* @param string $type Type key.
* @param string $key (optional) Type data key.
* @return mixed
*/
public function get_data( $type, $key = null ) {
if ( isset( $this->data[ $type ] ) ) {
return VAA_API::get_array_data( $this->data[ $type ], $key );
}
return null;
}
/**
* Get available capabilities.
* @param string $key Cap name.
* @return bool[]|bool Array of capabilities or a single capability value.
*/
public function get_caps( $key = null ) {
return $this->get_data( 'caps', $key );
}
/**
* Get available roles.
* @param string $key Role slug/key.
* @return \WP_Role[]|\WP_Role Array of role objects or a single role object.
*/
public function get_roles( $key = null ) {
return $this->get_data( 'roles', $key );
}
/**
* Get the role names. Translated by default.
* If key is provided but not found it will return the key (untranslated).
* @since 1.6.4
* @param string $key Role slug.
* @param bool $translate Translate the role name?
* @return string[]|string
*/
public function get_rolenames( $key = null, $translate = true ) {
$val = $this->get_data( 'rolenames', $key );
if ( ! $val ) {
/**
* Try to fetch role name from WP core. No security risk here.
* Check for the wp_roles() function in WP 4.3+.
* @since 1.8
*/
if ( function_exists( 'wp_roles' ) ) {
$wp_roles = wp_roles();
} else {
global $wp_roles;
}
if ( isset( $wp_roles->role_names[ $key ] ) ) {
$this->set_rolenames( $wp_roles->role_names[ $key ], $key, true );
return $this->get_rolenames( $key, $translate );
}
return ( $key ) ? $key : $val;
}
if ( $translate ) {
if ( is_array( $val ) ) {
$val = array_map( 'translate_user_role', $val );
} else {
$val = translate_user_role( $val );
}
}
return $val;
}
/**
* Get available users.
* @param string $key User key.
* @return \WP_User[]|\WP_User Array of user objects or a single user object.
*/
public function get_users( $key = null ) {
return $this->get_data( 'users', $key );
}
/**
* Get available languages.
* @param string $key Locale key.
* @return string[]|string Array of language names or a single language name.
*/
public function get_languages( $key = null ) {
return $this->get_data( 'languages', $key );
}
/**
* Get the selected user object of a view.
* @return \WP_User
*/
public function get_selectedUser() {
return $this->selectedUser;
}
/**
* Get selected capabilities of a view.
* @param string $key Cap name.
* @return bool[]|bool Array of capabilities or a single capability value.
*/
public function get_selectedCaps( $key = null ) {
return VAA_API::get_array_data( $this->selectedCaps, $key );
}
/**
* Get the nonce.
* @param string $parsed Return parsed nonce?
* @return string
*/
public function get_nonce( $parsed = null ) {
return ( $parsed ) ? $this->nonce_parsed : $this->nonce;
}
/**
* Get plugin version.
* @todo Move to API.
* @return string
*/
public function get_version() {
return strtolower( (string) VIEW_ADMIN_AS_VERSION );
}
/**
* Get plugin database version.
* @todo Move to API.
* @return string
*/
public function get_dbVersion() {
return strtolower( (string) VIEW_ADMIN_AS_DB_VERSION );
}
/**
* Set the current user object.
* @param \WP_User $val User object.
* @return void
*/
public function set_curUser( WP_User $val ) {
$this->curUser = $val;
}
/**
* Set the current user session.
* @param string $val User session ID.
* @return void
*/
public function set_curUserSession( $val ) {
$this->curUserSession = (string) $val;
}
/**
* Set the view data.
* @param mixed $val Value.
* @param string $key (optional) View key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_view( $val, $key = null, $append = false ) {
$this->view = (array) VAA_API::set_array_data( $this->view, $val, $key, $append );
}
/**
* Set view type data.
*
* @since 1.7
* @param string $type
* @param mixed $val
* @param string $key
* @param bool $append
* @return void
*/
public function set_data( $type, $val, $key = null, $append = false ) {
if ( VAA_API::exists_callable( array( $this, 'set_' . $type ) ) ) {
$method = 'set_' . $type;
$this->$method( $val, $key, $append );
return;
}
$current = ( isset( $this->data[ $type ] ) ) ? $this->data[ $type ] : array();
$this->data[ $type ] = (array) VAA_API::set_array_data( $current, $val, $key, $append );
}
/**
* Set the available capabilities.
* @param mixed $val Value.
* @param string $key (optional) Cap key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_caps( $val, $key = null, $append = false ) {
$this->data['caps'] = (array) VAA_API::set_array_data( $this->data['caps'], $val, $key, $append );
}
/**
* Set the available roles.
* @param mixed $val Value.
* @param string $key (optional) Role name.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_roles( $val, $key = null, $append = false ) {
$this->data['roles'] = (array) VAA_API::set_array_data( $this->data['roles'], $val, $key, $append );
}
/**
* Set the role name translations.
* @since 1.6.4
* @param mixed $val Value.
* @param string $key (optional) Role name.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_rolenames( $val, $key = null, $append = false ) {
$this->data['rolenames'] = (array) VAA_API::set_array_data( $this->data['rolenames'], $val, $key, $append );
}
/**
* Set the available users.
* @param mixed $val Value.
* @param string $key (optional) User key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_users( $val, $key = null, $append = false ) {
$this->data['users'] = (array) VAA_API::set_array_data( $this->data['users'], $val, $key, $append );
}
/**
* Set the languages.
* @since 1.8
* @param mixed $val Value.
* @param string $key (optional) Role name.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
public function set_languages( $val, $key = null, $append = false ) {
$this->data['languages'] = (array) VAA_API::set_array_data( $this->data['languages'], $val, $key, $append );
}
/**
* Set the selected user object for the current view.
* @param \WP_User $val User object.
* @return void
*/
public function set_selectedUser( $val ) {
$this->selectedUser = $val;
}
/**
* Set the selected capabilities for the current view.
* @param array $val Selected capabilities.
* @return void
*/
public function set_selectedCaps( $val ) {
$this->selectedCaps = array_filter( (array) $val );
}
/**
* Set the nonce.
* Also sets a parsed version of the nonce with wp_create_nonce().
* @param string $val Nonce.
* @return void
*/
public function set_nonce( $val ) {
$this->nonce = (string) $val;
$this->nonce_parsed = wp_create_nonce( (string) $val );
}
/**
* Main Instance.
*
* Ensures only one instance of this class is loaded or can be loaded.
*
* @since 1.6
* @access public
* @static
* @param \VAA_View_Admin_As $caller The referrer class.
* @return \VAA_View_Admin_As_Store $this
*/
public static function get_instance( $caller = null ) {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self( $caller );
}
return self::$_instance;
}
} // End class VAA_View_Admin_As_Store.

View File

@@ -0,0 +1,475 @@
<?php
/**
* View Admin As - View Type
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* View Type class base.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.8
* @version 1.8
* @uses \VAA_View_Admin_As_Base Extends class
*/
abstract class VAA_View_Admin_As_Type extends VAA_View_Admin_As_Base
{
/**
* View type settings.
*
* @since 1.8
* @var array
*/
private $settings = array(
'enabled' => true,
);
/**
* The view type.
*
* @since 1.8
* @var string
*/
protected $type = '';
/**
* The view type label.
*
* @since 1.8
* @var string
*/
protected $label = '';
/**
* The view type singular label.
*
* @since 1.8
* @var string
*/
protected $label_singular = '';
/**
* The view type description.
*
* @since 1.8
* @var string
*/
protected $description = '';
/**
* The icon for this view type.
*
* @since 1.8
* @var string
*/
protected $icon = '';
/**
* Selected view.
*
* @since 1.8
* @var mixed
*/
protected $selected = null;
/**
* Does the original user has access?
*
* @since 1.8
* @var bool
*/
protected $user_has_access = false;
/**
* The hook priorities for this type.
*
* @since 1.8
* @var int[]
*/
protected $priorities = array(
'toolbar' => 10,
'view_title' => 10,
'validate_view_data' => 10,
'update_view' => 10,
'do_view' => 10,
);
/**
* The capability required for this view type.
*
* @since 1.8
* @var string
*/
protected $cap = 'view_admin_as';
/**
* Populate the instance.
*
* @since 1.8
* @access protected
* @param \VAA_View_Admin_As $vaa The main VAA object.
*/
protected function __construct( $vaa ) {
static $done;
if ( ! $done ) {
$this->add_filter( 'view_admin_as_update_global_settings', array( 'VAA_View_Admin_As_Type', 'filter_update_view_types' ), 1, 3 );
$done = true;
}
parent::__construct( $vaa );
$this->vaa->register_view_type( array(
'id' => $this->type,
'instance' => $this,
) );
$this->user_has_access = $this->current_user_can( $this->cap );
if ( ! $this->has_access() ) {
return;
}
$view_types = $this->store->get_settings( 'view_types' );
if ( isset( $view_types[ $this->type ] ) ) {
$this->settings = $view_types[ $this->type ];
}
if ( $this->is_enabled() ) {
$this->add_action( 'vaa_view_admin_as_pre_init', array( $this, 'init' ) );
}
}
/**
* Does the original user has access to this view type?
*
* @since 1.8
* @access public
* @return bool
*/
public function has_access() {
return (bool) ( $this->is_vaa_enabled() && $this->user_has_access );
}
/**
* Is enabled?
*
* @since 1.8
* @access public
* @return bool
*/
public function is_enabled() {
return ( ! empty( $this->settings['enabled'] ) );
}
/**
* Set plugin enabled true/false.
*
* @since 1.8
* @access public
* @param bool $bool Enable or disable?
* @param bool $update_db Do database update? (default true).
* @return bool
*/
public function set_enable( $bool = false, $update_db = true ) {
$success = true;
if ( $update_db ) {
$success = $this->update_settings( (bool) $bool, 'enable', true );
}
if ( $success ) {
$this->settings['enabled'] = (bool) $bool;
}
return $success;
}
/**
* Setup module and hooks.
*
* @since 1.8
* @access protected
* @return bool Successful init?
*/
public function init() {
$this->store_data();
if ( $this->has_access() && $this->get_data() ) {
$this->init_hooks();
return true;
}
return false;
}
/**
* Setup hooks.
*
* @since 1.8
* @access protected
*/
protected function init_hooks() {
$this->add_action( 'vaa_admin_bar_menu', array( $this, 'admin_bar_menu' ), $this->get_priority( 'toolbar' ), 2 );
$this->add_filter( 'view_admin_as_validate_view_data_' . $this->type, array( $this, 'validate_view_data' ), $this->get_priority( 'validate_view_data' ), 3 );
$this->add_filter( 'view_admin_as_update_view_' . $this->type, array( $this, 'update_view' ), $this->get_priority( 'update_view' ), 3 );
$this->add_action( 'vaa_view_admin_as_do_view', array( $this, 'do_view' ), $this->get_priority( 'do_view' ) );
}
/**
* Apply this view type if active.
*
* @since 1.8
* @access public
* @return bool Is this view type active?
*/
public function do_view() {
$this->selected = $this->store->get_view( $this->type );
if ( $this->selected ) {
$this->add_filter( 'vaa_admin_bar_view_titles', array( $this, 'view_title' ), $this->get_priority( 'view_title' ) );
return true;
}
return false;
}
/**
* Helper method for the view object.
* Adds the actions and filters to modify the current user object.
* Can only be run once.
*
* @since 1.8
* @access public
* @return void
*/
public function init_user_modifications() {
$this->vaa->view()->init_user_modifications();
}
/**
* View update handler (Ajax probably), called from main handler.
*
* @since 1.8 Renamed from `ajax_handler`
* @access public
* @param null $null Null.
* @param array $data The ajax data for this module.
* @param string $type The view type.
* @return bool
*/
public function update_view( $null, $data, $type = null ) {
if ( $type !== $this->type ) {
return $null;
}
if ( $this->get_data( $data ) ) {
$this->store->set_view( $data, $this->type, true );
return true;
}
return false;
}
/**
* Validate data for this view type
*
* @since 1.8
* @access public
* @param null $null Default return (invalid)
* @param mixed $data The view data
* @return mixed
*/
abstract public function validate_view_data( $null, $data = null );
/**
* Change the VAA admin bar menu title.
*
* @since 1.8
* @access public
* @param array $titles The current title(s).
* @return array
*/
abstract public function view_title( $titles = array() );
/**
* Add the admin bar items.
*
* @since 1.8
* @access public
* @param \WP_Admin_Bar $admin_bar The toolbar object.
* @param string $root The root item.
*/
abstract public function admin_bar_menu( $admin_bar, $root );
/**
* Store the available languages.
*
* @since 1.8
* @access private
*/
abstract public function store_data();
/**
* Set the view type data.
*
* @since 1.8
* @access public
* @param mixed $val
* @param string $key (optional) The data key.
* @param bool $append (optional) Append if it doesn't exist?
*/
public function set_data( $val, $key = null, $append = true ) {
$this->store->set_data( $this->type, $val, $key, $append );
}
/**
* Get the view type data.
*
* @since 1.8
* @access public
* @param string $key (optional) The data key.
* @return mixed
*/
public function get_data( $key = null ) {
return $this->store->get_data( $this->type, $key );
}
/**
* Get the view type id.
*
* @since 1.8
* @access public
* @return string
*/
public function get_type() {
return $this->type;
}
/**
* Get the view type label.
*
* @since 1.8
* @access public
* @return string
*/
public function get_label() {
return $this->label;
}
/**
* Get the view type singular label.
*
* @since 1.8
* @access public
* @return string
*/
public function get_label_singular() {
return $this->label_singular;
}
/**
* Get the view type description.
*
* @since 1.8
* @access public
* @return string
*/
public function get_description() {
return $this->description;
}
/**
* Get an action priority.
* Default: toolbar priority.
*
* @since 1.8
* @param string $key
* @return int
*/
public function get_priority( $key = 'toolbar' ) {
return (int) ( isset( $this->priorities[ $key ] ) ) ? $this->priorities[ $key ] : 10;
}
/**
* Get the view type settings.
*
* @since 1.8
* @param string $key Key in the setting array.
* @return mixed
*/
final public function get_settings( $key = null ) {
return VAA_API::get_array_data( $this->settings, $key );
}
/**
* Set the view type settings.
*
* @since 1.8
* @param mixed $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return void
*/
final public function set_settings( $val, $key = null, $append = false ) {
$this->settings = VAA_API::set_array_data( $this->settings, $val, $key, $append );
$view_types = (array) $this->store->get_settings( 'view_types' );
$view_types[ $this->type ] = $this->get_settings();
$settings = array(
'view_types' => $view_types,
);
$this->store->set_settings( $settings );
}
/**
* Update the view type settings in the database.
* Also sets the settings within this instance and VAA store.
*
* @since 1.8
* @param mixed $val Settings.
* @param string $key (optional) Setting key.
* @param bool $append (optional) Append if it doesn't exist?
* @return bool
*/
final public function update_settings( $val, $key = null, $append = false ) {
$this->set_settings( $val, $key, $append ); // Also updates store.
return $this->store->update_optionData( $this->store->get_optionData() );
}
/**
* Update the active view types.
*
* @since 1.8
* @static
* @param array $data
* @return mixed
*/
final public static function filter_update_view_types( $data ) {
if ( empty( $data['view_types'] ) ) {
return $data;
}
foreach ( $data['view_types'] as $type => $settings ) {
$type = view_admin_as()->get_view_types( $type );
if ( ! $type instanceof VAA_View_Admin_As_Type ) {
unset( $data['view_types'][ $type ] );
continue;
}
$type->set_settings( $settings );
}
$data['view_types'] = view_admin_as()->store()->get_settings( 'view_types' );
return $data;
}
} // End class VAA_View_Admin_As_Type.

View File

@@ -0,0 +1,167 @@
<?php
/**
* View Admin As - Class Update
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Update class used for version control and updates.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.6
* @version 1.7.4
* @uses \VAA_View_Admin_As_Base Extends class
*/
final class VAA_View_Admin_As_Update extends VAA_View_Admin_As_Base
{
/**
* The single instance of the class.
*
* @since 1.6
* @static
* @var \VAA_View_Admin_As_Update
*/
private static $_instance = null;
/**
* Is this a new installation?
*
* @since 1.7
* @static
* @var bool
*/
public static $fresh_install = false;
/**
* Populate the instance.
*
* @since 1.6
* @since 1.6.1 $vaa param.
* @access protected
* @param \VAA_View_Admin_As $vaa The main VAA object.
*/
protected function __construct( $vaa ) {
self::$_instance = $this;
parent::__construct( $vaa );
}
/**
* Check the correct DB version in the DB.
*
* @since 1.4
* @since 1.6 Moved to this class from main class.
* @access public
* @return void
*/
public function maybe_db_update() {
$db_version = strtolower( $this->store->get_optionData( 'db_version' ) );
if ( ! $db_version ) {
self::$fresh_install = true;
}
if ( self::$fresh_install || version_compare( $db_version, $this->store->get_dbVersion(), '<' ) ) {
$this->db_update();
}
}
/**
* Update settings.
*
* @since 1.4
* @since 1.6 Moved to this class from main class.
* @access private
* @return void
*/
private function db_update() {
$defaults = array(
'db_version' => $this->store->get_dbVersion(),
);
$current_db_version = strtolower( $this->store->get_optionData( 'db_version' ) );
// No need to run update script if it's a clean installation.
if ( $current_db_version ) {
// Clear the user views for update to 1.5+.
if ( version_compare( $current_db_version, '1.5', '<' ) ) {
/**
* Reset user meta for all users.
* @since 1.6.2 Use `all` param from delete_user_meta().
*/
$this->store->delete_user_meta( 'all', false, true ); // true for reset_only.
// Reset currently loaded data.
$this->store->set_userMeta( false );
}
if ( version_compare( $current_db_version, '1.7.2', '<' ) ) {
$this->update_1_7_2();
}
}
// Update version, append if needed.
$this->store->set_optionData( $this->store->get_dbVersion(), 'db_version', true );
// Update option data.
$this->store->update_optionData( wp_parse_args( $this->store->get_optionData(), $defaults ) );
// Main update finished, hook used to update modules.
do_action( 'vaa_view_admin_as_db_update' );
}
/**
* Update to version 1.7.2.
* Changes yes/no options to boolean types.
*
* @since 1.7.2
* @access private
* @return void
*/
private function update_1_7_2() {
$meta = $this->store->get_all_user_meta();
foreach ( $meta as $user_id => $values ) {
foreach ( $values as $column_id => $value ) {
if ( ! empty( $value['settings'] ) && is_array( $value['settings'] ) ) {
foreach ( $value['settings'] as $key => $val ) {
if ( is_bool( $val ) ) {
// Update already done.
continue;
}
if ( in_array( $key, array( 'force_group_users', 'freeze_locale', 'hide_front' ), true ) ) {
$value['settings'][ $key ] = ( 'yes' === $val );
}
}
$this->store->update_other_user_meta( $value, $user_id, $column_id );
}
}
}
// Re-init VAA store.
$this->store->init( true );
}
/**
* Main Instance.
*
* Ensures only one instance of this class is loaded or can be loaded.
*
* @since 1.6
* @access public
* @static
* @param \VAA_View_Admin_As $caller The referrer class.
* @return \VAA_View_Admin_As_Update $this
*/
public static function get_instance( $caller = null ) {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self( $caller );
}
return self::$_instance;
}
} // End class VAA_View_Admin_As_Update.

View File

@@ -0,0 +1,926 @@
<?php
/**
* View Admin As - Class Init (Main class)
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* Plugin initializer class.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 0.1
* @version 1.8
*/
final class VAA_View_Admin_As
{
/**
* The single instance of the class.
*
* @since 1.4.1
* @static
* @var \VAA_View_Admin_As
*/
private static $_instance = null;
/**
* Enable functionalities for this user?
*
* @since 0.1
* @var bool
*/
private $enable = false;
/**
* Var that holds all the notices.
*
* @since 1.5.1
* @var array[] {
* @type string $message The notice message.
* @type string $type (optional) The WP notice type class(es).
* }
*/
private $notices = array();
/**
* VAA Hooks.
*
* @since 1.8
* @var \VAA_View_Admin_As_Hooks
*/
private $hooks = null;
/**
* VAA Store.
*
* @since 1.6
* @var \VAA_View_Admin_As_Store
*/
private $store = null;
/**
* VAA Controller.
*
* @since 1.6
* @var \VAA_View_Admin_As_Controller
*/
private $controller = null;
/**
* VAA View handler.
*
* @since 1.6
* @var \VAA_View_Admin_As_View
*/
private $view = null;
/**
* VAA UI classes that are loaded.
*
* @since 1.5
* @see \VAA_View_Admin_As::load_ui()
* @var object[]
*/
private $ui = array();
/**
* Other VAA modules that are loaded.
*
* @since 1.4
* @see \VAA_View_Admin_As::load_modules()
* @see \VAA_View_Admin_As::register_module()
* @var \VAA_View_Admin_As_Module[]
*/
private $modules = array();
/**
* View types.
*
* @since 1.8
* @see \VAA_View_Admin_As::load_modules()
* @see \VAA_View_Admin_As::register_view_type()
* @var \VAA_View_Admin_As_Type[]
*/
private $view_types = array();
/**
* Class registry
*
* @since 1.8
* @var array
*/
private $classes = array(
'VAA_API' => 'includes/class-api.php',
'VAA_View_Admin_As_Base' => 'includes/class-base.php',
'VAA_View_Admin_As_Hooks' => 'includes/class-hooks.php',
'VAA_View_Admin_As_Settings' => 'includes/class-settings.php',
'VAA_View_Admin_As_Store' => 'includes/class-store.php',
'VAA_View_Admin_As_Controller' => 'includes/class-controller.php',
'VAA_View_Admin_As_View' => 'includes/class-view.php',
'VAA_View_Admin_As_Update' => 'includes/class-update.php',
'VAA_View_Admin_As_Compat' => 'includes/class-compat.php',
'VAA_View_Admin_As_Type' => 'includes/class-type.php',
'VAA_View_Admin_As_Module' => 'includes/class-module.php',
'VAA_View_Admin_As_Form' => 'includes/class-form.php',
);
/**
* Init function to register plugin hook.
* Private to make sure it isn't declared elsewhere.
*
* @since 0.1
* @since 1.3.3 Changes init hook to plugins_loaded for theme compatibility.
* @since 1.4.1 Creates instance.
* @since 1.5 Make private.
* @since 1.5.1 Added notice on class name conflict + validate versions.
* @since 1.8 spl_autoload_register().
* @access private
*/
private function __construct() {
self::$_instance = $this;
spl_autoload_register( array( $this, '_autoload' ) );
add_action( 'init', array( $this, 'load_textdomain' ) );
if ( is_admin() ) {
add_action( 'admin_notices', array( $this, 'do_admin_notices' ) );
}
// Returns false on conflict.
if ( ! $this->validate_versions() ) {
return;
}
// Lets start!
add_action( 'plugins_loaded', array( $this, 'init' ), -99999 );
}
/**
* Class autoloader if needed.
*
* @since 1.8
* @access private
* @internal
* @param string $class The class name.
*/
public function _autoload( $class ) {
if ( 0 !== strpos( $class, 'VAA_' ) ) {
return;
}
if ( isset( $this->classes[ $class ] ) ) {
$this->include_file( VIEW_ADMIN_AS_DIR . $this->classes[ $class ], $class );
}
}
/**
* Instantiate function that checks if the plugin is already loaded.
*
* @since 1.6
* @access public
* @param bool $redo (optional) Force re-init?
*/
public function init( $redo = false ) {
static $done = false;
if ( $done && ! $redo ) return;
// We can't do this check before `plugins_loaded` hook.
if ( ! is_user_logged_in() ) {
return;
}
if ( ! $done && ! $this->load() ) {
return;
}
$this->run();
$done = true;
}
/**
* Verify that our classes don't exist yet.
* Returns false on conflict.
*
* @since 1.6
* @access private
* @return bool Load successfully completed?
*/
private function load() {
foreach ( $this->classes as $class => $file ) {
if ( ! $this->include_file( VIEW_ADMIN_AS_DIR . $file, $class ) ) {
return false;
}
}
return true;
}
/**
* Run the plugin!
* Check current user, load necessary data and register all used hooks.
*
* @since 0.1
* @access private
* @return void
*/
private function run() {
$this->hooks = new VAA_View_Admin_As_Hooks();
$this->store = VAA_View_Admin_As_Store::get_instance( $this );
$this->controller = VAA_View_Admin_As_Controller::get_instance( $this );
$this->view = VAA_View_Admin_As_View::get_instance( $this );
$this->set_enabled();
$this->load_modules();
// Check if a database update is needed.
VAA_View_Admin_As_Update::get_instance( $this )->maybe_db_update();
if ( $this->is_enabled() ) {
if ( VAA_View_Admin_As_Update::$fresh_install ) {
$this->welcome_notice();
}
// Fix some compatibility issues, more to come!
VAA_View_Admin_As_Compat::get_instance( $this )->init();
/**
* Plugin enabled + update and compat scripts done.
*
* @since 1.8
* @param \VAA_View_Admin_As $this The main View Admin As object instance.
*/
do_action( 'vaa_view_admin_as_pre_init', $this );
$this->controller->init();
$this->view->init();
$this->load_ui();
/**
* Init is finished. Hook is used for other classes related to View Admin As.
*
* @since 1.5
* @param \VAA_View_Admin_As $this The main View Admin As object instance.
*/
do_action( 'vaa_view_admin_as_init', $this );
}
}
/**
* Try to enable plugin functionality.
*
* @since 1.7.2
* @access public
* @return bool
*/
public function set_enabled() {
$this->enable = $this->validate_user();
return $this->enable;
}
/**
* Is enabled?
*
* @since 1.5
* @access public
* @return bool
*/
public function is_enabled() {
return (bool) $this->enable;
}
/**
* Validate if the current user has access to the functionalities.
*
* @since 0.1 Check if the current user had administrator rights (is_super_admin).
* Disable plugin functions for network admin pages.
* @since 1.4 Make sure we have a session for the current user.
* @since 1.5.1 If a user has the correct capability (view_admin_as + edit_users) this plugin is also enabled, use with care.
* Note that in network installations the non-admin user also needs the manage_network_users
* capability (of not the edit_users will return false).
* @since 1.5.3 Enable on network pages for superior admins.
* @since 1.6.3 Created this function.
* @access public
*
* @return bool
*/
public function validate_user() {
$valid = false;
if ( ( VAA_API::is_super_admin()
|| ( current_user_can( 'view_admin_as' ) && current_user_can( 'edit_users' ) ) )
&& ( ! is_network_admin() || VAA_API::is_superior_admin( $this->store->get_curUser()->ID ) )
&& $this->store->get_curUserSession()
) {
$valid = true;
}
return $valid;
}
/**
* Include a file. Optionally checks if the class already exists.
*
* @since 1.7.1
* @access public
*
* @param string $file The file name.
* @param string $class (optional) The class name.
* @return bool
*/
public function include_file( $file, $class = '' ) {
static $loaded = array();
if ( in_array( $file, $loaded, true ) ) {
return true;
}
if ( ! file_exists( $file ) ) {
return false;
}
// Load file.
if ( empty( $class ) || ! class_exists( $class, false ) ) {
include_once $file;
} else {
$this->add_error_notice( $class . '::' . __METHOD__, array(
'type' => 'notice-error',
'message' => __( 'Plugin not fully loaded because of a conflict with an other plugin or theme', VIEW_ADMIN_AS_DOMAIN )
// Translators: %s stands for the class name.
. ' <code>(' . sprintf( __( 'Class %s already exists', VIEW_ADMIN_AS_DOMAIN ), $class ) . ')</code>',
) );
return false;
}
$loaded[] = $file;
return true;
}
/**
* Helper function to include files. Checks class existence and throws an error if needed.
* Also adds the class to a supplied group if available.
*
* @since 1.7
* @access public
* @param array[]|string[] $includes {
* An array of files to include.
* @type string $file The file to include. Directory starts from the plugin folder.
* @type string $class The class name.
* }
* @param array $group A reference array.
* @return array $group
*/
public function load_files( $includes, &$group = null ) {
$group = (array) $group;
foreach ( $includes as $key => $inc ) {
if ( is_string( $inc ) ) {
$inc = array(
'file' => $inc,
);
if ( is_string( $key ) ) {
$inc['class'] = $key;
}
}
if ( empty( $inc['file'] ) ) {
continue;
}
$class = ( ! empty( $inc['class'] ) ) ? $inc['class'] : '';
$this->include_file( VIEW_ADMIN_AS_DIR . $inc['file'], $class );
// If it's a class file, add the class instance to the group.
if ( ! empty( $class ) && VAA_API::exists_callable( array( $class, 'get_instance' ) ) ) {
$group[ $key ] = call_user_func( array( $class, 'get_instance' ), $this );
}
}
return $group;
}
/**
* Load the user interface.
*
* @since 1.5
* @since 1.5.1 Added notice on class name conflict.
* @since 1.6 Added our toolbar class.
* @access private
* @return void
*/
private function load_ui() {
$includes = array(
'ui' => array(
'file' => 'ui/class-ui.php',
'class' => 'VAA_View_Admin_As_UI',
),
'admin_bar' => array(
'file' => 'ui/class-admin-bar.php',
'class' => 'VAA_View_Admin_As_Admin_Bar',
),
);
// Compat for < 4.2 since it breaks due to WP calling require() instead of require_once().
if ( VAA_API::validate_wp_version( '4.2' ) ) {
$includes['toolbar'] = array(
'file' => 'ui/class-toolbar.php',
'class' => 'VAA_View_Admin_As_Toolbar',
);
}
// Include UI files and add them to the `ui` property.
$this->load_files( $includes, $this->ui );
}
/**
* Load the modules.
*
* @since 1.5
* @access private
* @return void
*/
private function load_modules() {
$includes = array(
'role_switcher' => array(
'file' => 'modules/class-roles.php',
'class' => 'VAA_View_Admin_As_Roles',
),
'user_switcher' => array(
'file' => 'modules/class-users.php',
'class' => 'VAA_View_Admin_As_Users',
),
'capability_switcher' => array(
'file' => 'modules/class-caps.php',
'class' => 'VAA_View_Admin_As_Caps',
),
'language_switcher' => array(
'file' => 'modules/class-languages.php',
'class' => 'VAA_View_Admin_As_Languages',
),
'role_defaults' => array(
'file' => 'modules/class-role-defaults.php',
'class' => 'VAA_View_Admin_As_Role_Defaults',
),
'role_manager' => array(
'file' => 'modules/class-role-manager.php',
'class' => 'VAA_View_Admin_As_Role_Manager',
),
);
if ( VAA_API::exists_callable( array( 'RUA_App', 'instance' ) ) ) {
$includes['rua_level'] = array(
'file' => 'modules/class-restrict-user-access.php',
'class' => 'VAA_View_Admin_As_RUA',
);
}
if ( VAA_API::exists_callable( array( 'Groups_Group', 'get_groups' ) ) ) {
$includes['groups'] = array(
'file' => 'modules/class-groups.php',
'class' => 'VAA_View_Admin_As_Groups',
);
}
// Run include code but do not register modules yet (leave that to the modules).
$this->load_files( $includes );
/**
* Modules loaded. Hook is used for other modules related to View Admin As.
*
* @since 1.6.2
* @param \VAA_View_Admin_As $this The main View Admin As object instance.
*/
do_action( 'vaa_view_admin_as_modules_loaded', $this );
}
/**
* Load plugin textdomain.
*
* @since 1.2
* @since 1.6 Hooked into init hook, check for is_enabled() required.
* @access public
* @return void
*/
public function load_textdomain() {
if ( ! $this->is_enabled() && empty( $this->notices ) ) {
return;
}
load_plugin_textdomain( VIEW_ADMIN_AS_DOMAIN );
/**
* Frontend translation of roles is not working by default (Darn you WordPress!).
* Needs to be in init action to work.
* @see https://core.trac.wordpress.org/ticket/37539
*/
$wp_mo = WP_LANG_DIR . '/admin-' . get_locale() . '.mo';
if ( ! is_admin() && file_exists( $wp_mo ) ) {
load_textdomain( 'default', $wp_mo );
}
}
/**
* Get the hooks class.
*
* @since 1.8
* @access public
* @return \VAA_View_Admin_As_Hooks
*/
public function hooks() {
return $this->hooks;
}
/**
* Get the store class.
*
* @since 1.6
* @access public
* @return \VAA_View_Admin_As_Store
*/
public function store() {
return $this->store;
}
/**
* Get the controller class.
*
* @since 1.7
* @access public
* @return \VAA_View_Admin_As_Controller
*/
public function controller() {
return $this->controller;
}
/**
* Get the view class.
*
* @since 1.6
* @access public
* @return \VAA_View_Admin_As_View
*/
public function view() {
return $this->view;
}
/**
* Get UI classes.
* If a key is provided it will only return that UI class.
*
* @since 1.6.1
* @access public
* @see \VAA_View_Admin_As::load_ui()
* @param string $key (optional) UI class name.
* @return \VAA_View_Admin_As_Module|\VAA_View_Admin_As_Module[]
*/
public function get_ui( $key = null ) {
return VAA_API::get_array_data( $this->ui, $key );
}
/**
* Get view types.
* If a key is provided it will only return that view type.
*
* @since 1.8
* @access public
* @param string $key (optional) The type key.
* @param bool $check_access (optional) Check if the user has access? Default: true.
* @return \VAA_View_Admin_As_Type|\VAA_View_Admin_As_Type[]
*/
public function get_view_types( $key = null, $check_access = true ) {
$view_types = $this->view_types;
if ( $check_access ) {
foreach ( $view_types as $type => $instance ) {
if ( ! $instance->has_access() ) {
unset( $view_types[ $type ] );
}
}
}
$view_types = VAA_API::get_array_data( $view_types, $key );
return $view_types;
}
/**
* Register view types.
*
* @since 1.8
* @param array $data {
* Required. An array of module info.
* @type string $id The view type name, choose wisely since this is used for validation.
* @type VAA_View_Admin_As_Type $instance The view type class reference/instance.
* }
* @return bool Successfully registered?
*/
public function register_view_type( $data ) {
if ( ! empty( $data['id'] ) && is_string( $data['id'] ) &&
! empty( $data['instance'] ) && $data['instance'] instanceof VAA_View_Admin_As_Type
) {
$this->view_types[ $data['id'] ] = $data['instance'];
return true;
}
return false;
}
/**
* Get current modules.
* If a key is provided it will only return that module.
*
* @since 1.5
* @access public
* @see VAA_View_Admin_As::load_modules()
* @param string $key (optional) The module key.
* @return object|object[]
*/
public function get_modules( $key = null ) {
return VAA_API::get_array_data( $this->modules, $key );
}
/**
* Register extra modules.
*
* @since 1.6.1
* @param array $data {
* Required. An array of module info.
* @type string $id The module name, choose wisely since this is used for validation.
* @type VAA_View_Admin_As_Module $instance The module class reference/instance.
* }
* @return bool Successfully registered?
*/
public function register_module( $data ) {
if ( ! empty( $data['id'] ) && is_string( $data['id'] ) &&
! empty( $data['instance'] ) && $data['instance'] instanceof VAA_View_Admin_As_Module
) {
$this->modules[ $data['id'] ] = $data['instance'];
return true;
}
return false;
}
/**
* Add a welcome notice for new users.
*
* @since 1.7
* @access public
*/
public function welcome_notice() {
$this->add_notice( 'vaa-welcome', array(
'type' => 'notice-success',
'message' => sprintf(
// Translators: %s stands for `Dashboard` (link element).
__( 'For the best experience you can start from the %s since not all views are allowed to access all admin pages.', VIEW_ADMIN_AS_DOMAIN ),
'<a class="button button-primary" href="' . admin_url() . '">' . __( 'Dashboard' ) . '</a>'
),
'prepend' => __( 'Thank you for installing View Admin As!', VIEW_ADMIN_AS_DOMAIN ),
) );
}
/**
* Add error notices to generate.
* Automatically generated a bug report link at the end of the notice.
*
* @since 1.7.2
* @access public
*
* @param string $id
* @param array $notice {
* Required array.
* @type string $message The notice message.
* @type string $type (optional) The WP notice type class(es).
* @type string $prepend (optional) Prepend the message (bold). Default: View Admin As.
* Pass `false` or `null` to remove.
* }
* @return void
*/
public function add_error_notice( $id, $notice ) {
if ( empty( $notice['message'] ) ) {
return;
}
$notice['type'] = ( ! empty( $notice['type'] ) ) ? $notice['type'] : 'notice-error';
// @todo Add debug_backtrace to body?
$report = array(
'title' => __( 'Error', VIEW_ADMIN_AS_DOMAIN ) . ': ' . $id,
'body' => $notice['message'],
);
$report_link = add_query_arg( $report, 'https://github.com/JoryHogeveen/view-admin-as/issues/new' );
$notice['message'] = $notice['message']
. ' <a href="' . $report_link . '" target="_blank">'
. __( 'Click here to report this error!', VIEW_ADMIN_AS_DOMAIN )
. '</a>';
$this->add_notice( $id, $notice );
}
/**
* Add notices to generate.
*
* @since 1.5.1
* @access public
*
* @param string $id
* @param array $notice {
* Required array.
* @type string $message The notice message.
* @type string $type (optional) The WP notice type class(es).
* @type string $prepend (optional) Prepend the message (bold). Default: View Admin As.
* Pass `false` or `null` to remove.
* }
* @return void
*/
public function add_notice( $id, $notice ) {
if ( ! empty( $notice['message'] ) ) {
$notice = array_merge( array(
'type' => '',
'prepend' => __( 'View Admin As', VIEW_ADMIN_AS_DOMAIN ),
), $notice );
if ( $notice['prepend'] ) {
$notice['message'] = '<strong>' . $notice['prepend'] . ':</strong> ' . $notice['message'];
}
$this->notices[ $id ] = array(
'type' => $notice['type'],
'message' => $notice['message'],
);
}
}
/**
* Echo admin notices.
*
* @since 1.5.1
* @access public
* @see 'admin_notices'
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/admin_notices
* @return void
*/
public function do_admin_notices() {
foreach ( $this->notices as $notice ) {
if ( isset( $notice['type'] ) && ! empty( $notice['message'] ) ) {
echo '<div class="' . $notice['type'] . ' notice is-dismissible"><p>' . $notice['message'] . '</p></div>';
}
}
}
/**
* Validate plugin activate.
* Checks for valid resources.
*
* @since 1.5.1
* @since 1.6 Returns conflict status.
* @access private
* @global string $wp_version WordPress version.
* @return bool
*/
private function validate_versions() {
global $wp_version;
// Start positive!
$valid = true;
// Validate WP.
$min_wp_version = '4.1';
if ( version_compare( $wp_version, $min_wp_version, '<' ) ) {
$this->add_notice( 'wp-version', array(
'type' => 'notice-error',
'message' => sprintf(
// Translators: %1$s stands for "WordPress", %2$s stands for the version.
__( 'Plugin deactivated, %1$s version %2$s or higher is required', VIEW_ADMIN_AS_DOMAIN ),
'WordPress',
$min_wp_version
),
) );
$valid = false;
}
if ( ! $valid ) {
// Too bad..
require_once ABSPATH . 'wp-admin/includes/plugin.php';
deactivate_plugins( VIEW_ADMIN_AS_BASENAME );
}
return $valid;
}
/**
* Sets update class to run a DB update.
* @since 1.8
*/
public static function run_db_update() {
// Make sure the main class is initialized.
view_admin_as();
// Set the update class to a fresh installation which will trigger the update.
VAA_View_Admin_As_Update::$fresh_install = true;
}
/**
* Is this plugin network enabled.
*
* @since 1.7.5
* @return bool
*/
public static function is_network_active() {
static $check;
if ( is_bool( $check ) ) {
return $check;
}
require_once ABSPATH . 'wp-admin/includes/plugin.php';
$check = (bool) is_plugin_active_for_network( VIEW_ADMIN_AS_BASENAME );
return $check;
}
/**
* Main View Admin As instance.
* Ensures only one instance of View Admin As is loaded or can be loaded.
*
* @since 1.4.1
* @access public
* @static
* @see view_admin_as()
* @return \VAA_View_Admin_As $this The main View Admin As object instance.
*/
public static function get_instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Magic method to output a string if trying to use the object as a string.
*
* @since 1.5
* @access public
* @return string
*/
public function __toString() {
return get_class( $this );
}
/**
* Magic method to keep the object from being cloned.
*
* @since 1.5
* @access public
* @return void
*/
public function __clone() {
_doing_it_wrong(
__FUNCTION__,
esc_html( get_class( $this ) . ': ' . __( 'This class does not want to be cloned', VIEW_ADMIN_AS_DOMAIN ) ),
null
);
}
/**
* Magic method to keep the object from being unserialized.
*
* @since 1.5
* @access public
* @return void
*/
public function __wakeup() {
_doing_it_wrong(
__FUNCTION__,
esc_html( get_class( $this ) . ': ' . __( 'This class does not want to wake up', VIEW_ADMIN_AS_DOMAIN ) ),
null
);
}
/**
* Magic method to prevent a fatal error when calling a method that doesn't exist.
*
* @since 1.5
* @access public
* @param string $method The method name.
* @param array $args The method arguments.
* @return null
*/
public function __call( $method = '', $args = array() ) {
_doing_it_wrong(
esc_html( get_class( $this ) . "::{$method}" ),
esc_html__( 'Method does not exist.', VIEW_ADMIN_AS_DOMAIN ),
null
);
unset( $method, $args );
return null;
}
} // End class VAA_View_Admin_As.

View File

@@ -0,0 +1,535 @@
<?php
/**
* View Admin As - Class View
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
*/
if ( ! defined( 'VIEW_ADMIN_AS_DIR' ) ) {
die();
}
/**
* View handler class.
*
* @author Jory Hogeveen <info@keraweb.nl>
* @package View_Admin_As
* @since 1.6
* @since 1.7 Class got split up: data handling/updating is now in VAA_View_Admin_As_Controller.
* @version 1.8
* @uses \VAA_View_Admin_As_Base Extends class
*/
final class VAA_View_Admin_As_View extends VAA_View_Admin_As_Base
{
/**
* The single instance of the class.
*
* @since 1.6
* @static
* @var \VAA_View_Admin_As_View
*/
private static $_instance = null;
/**
* Is the current user modified?
*
* @since 1.7.2
* @var bool
*/
private $is_user_modified = false;
/**
* VAA_View_Admin_As_View constructor.
*
* @since 1.6
* @since 1.6.1 $vaa param.
* @access protected
* @param \VAA_View_Admin_As $vaa The main VAA object.
*/
protected function __construct( $vaa ) {
self::$_instance = $this;
parent::__construct( $vaa );
}
/**
* Initializes after VAA is enabled.
*
* @since 1.6
* @access public
* @return void
*/
public function init() {
if ( $this->store->get_view() ) {
$this->do_view();
}
}
/**
* Apply view data.
*
* @since 1.6.3 Put logic in it's own function.
* @access private
* @return void
*/
private function do_view() {
// @since 1.6.4 Set the current user as the selected user by default.
$this->store->set_selectedUser( $this->store->get_curUser() );
$this->store->set_selectedCaps( $this->store->get_curUser()->allcaps );
/**
* VISITOR.
* Current user object views (switches current user).
*
* @since 1.6.2 Visitor view.
*/
if ( $this->store->get_view( 'visitor' ) ) {
/**
* Change current user object so changes can be made on various screen settings.
* wp_set_current_user() returns the new user object.
*
* If it is a visitor view it will convert the false return from 'user' to 0.
*/
$this->store->set_selectedUser( wp_set_current_user( 0 ) );
// @since 1.6.2 Set the caps for this view (user view).
if ( isset( $this->store->get_selectedUser()->allcaps ) ) {
$this->store->set_selectedCaps( $this->store->get_selectedUser()->allcaps );
}
}
/**
* View data is set, apply the view.
* This hook can be used by other modules to enable a view.
*
* Temporary modifications to the current user are set on priority 99.
* This functionality has a separate action: `vaa_view_admin_as_modify_current_user`.
*
* @since 1.6.3
* @param array
*/
do_action( 'vaa_view_admin_as_do_view', $this->store->get_view() );
/**
* Force own locale on view.
*
* @since 1.6.1
* @since 1.7.5 Add filter `view_admin_as_freeze_locale`.
*
* @param bool $freeze_locale The user setting.
* @return bool
*/
$freeze_locale = apply_filters( 'view_admin_as_freeze_locale', $this->store->get_userSettings( 'freeze_locale' ) );
if ( $freeze_locale && (int) $this->store->get_curUser()->ID !== (int) $this->store->get_selectedUser()->ID ) {
$this->add_action( 'after_setup_theme', array( $this, 'freeze_locale' ), 0 );
}
}
/**
* Adds the actions and filters to modify the current user object.
* Can only be run once.
*
* @since 1.6.3
* @access public
* @return void
*/
public function init_user_modifications() {
static $done;
if ( $done ) return;
$this->is_user_modified = true;
$this->add_action( 'vaa_view_admin_as_do_view', array( $this, 'modify_user' ), 99 );
/**
* Make sure the $current_user view data isn't overwritten again by switch_blog functions.
* @see This filter is documented in wp-includes/ms-blogs.php
* @since 1.6.3
*/
$this->add_action( 'switch_blog', array( $this, 'modify_user' ) );
/**
* Prevent some meta updates for the current user while in modification to the current user are active.
* @since 1.6.3
*/
$this->add_filter( 'update_user_metadata' , array( $this, 'filter_prevent_update_user_metadata' ), 999999999, 3 );
/**
* Get capabilities and user level from current user view object instead of database.
* @since 1.6.4
*/
$this->add_filter( 'get_user_metadata' , array( $this, 'filter_overrule_get_user_metadata' ), 999999999, 3 );
// `user_has_cap` priority.
$priority = -999999999;
if ( $this->store->get_view( 'caps' ) ) {
// Overwrite everything when the capability view is active.
remove_all_filters( 'user_has_cap' );
$priority = 999999999;
}
/**
* The priority value of the VAA `user_has_cap` filter.
* Runs as first by default.
*
* @since 1.7.2
* @param int $priority
* @return int
*/
$priority = (int) apply_filters( 'view_admin_as_user_has_cap_priority', $priority );
/**
* Change the capabilities.
*
* @since 1.7.1
* @since 1.7.2 Changed priority to set is at the beginning instead of as last
* to allow other plugins to filter based on the modified user.
*/
$this->add_filter( 'user_has_cap', array( $this, 'filter_user_has_cap' ), $priority, 4 );
/**
* Map the capabilities (map_meta_cap is used for compatibility with network admins).
* Filter as last to check other plugin changes as well.
*
* @since 0.1
*/
$this->add_filter( 'map_meta_cap', array( $this, 'filter_map_meta_cap' ), 999999999, 4 );
/**
* Disable super admin status for the current user.
* @since 1.7.3
* @since 1.8 Check for multisite.
*/
if ( is_multisite() &&
! is_network_admin() &&
is_super_admin( $this->store->get_selectedUser()->ID ) &&
$this->store->get_userSettings( 'disable_super_admin' )
) {
$this->disable_super_admin();
}
$done = true;
}
/**
* Update the current user's WP_User instance with the current view capabilities.
*
* @since 1.6.3
* @access public
* @return void
*/
public function modify_user() {
// Can be the current or selected WP_User object (depending on the user view).
$user = $this->store->get_selectedUser();
/**
* Allow other modules to hook after the initial changes to the current user.
*
* @since 1.6.3
* @since 1.6.4 Changed name (was: `vaa_view_admin_as_modify_current_user`).
* @param \WP_User $user The modified user object.
*/
do_action( 'vaa_view_admin_as_modify_user', $user );
}
/**
* Prevent some updates to the current user like roles and capabilities.
* to prevent problems when making changes within a view.
*
* IMPORTANT! This filter should ONLY be used when a view is selected!
*
* @since 1.6.3
* @access public
* @see init_current_user_modifications()
*
* @see 'update_user_metadata' filter
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/update_(meta_type)_metadata
* @link http://hookr.io/filters/update_user_metadata/
*
* @global \wpdb $wpdb
* @param null $null Whether to allow updating metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @return mixed
*/
public function filter_prevent_update_user_metadata( $null, $object_id, $meta_key ) {
global $wpdb;
$user = $this->store->get_selectedUser();
// Check if the object being updated is the current user.
if ( (int) $user->ID === (int) $object_id ) {
// Capabilities meta key check.
if ( empty( $user->cap_key ) ) {
$user->cap_key = $wpdb->get_blog_prefix() . 'capabilities';
}
// Do not update the current user capabilities or user level while in a view.
if ( in_array( $meta_key, array(
$user->cap_key,
$wpdb->get_blog_prefix() . 'capabilities',
$wpdb->get_blog_prefix() . 'user_level',
), true ) ) {
return false;
}
}
return $null;
}
/**
* Return view roles when getting the current user data to prevent reloading current user data within a view.
*
* IMPORTANT! This filter should ONLY be used when a view is selected!
*
* @since 1.6.4
* @access public
* @see init_current_user_modifications()
*
* @see 'get_user_metadata' filter
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/get_(meta_type)_metadata
*
* @global \wpdb $wpdb
* @param null $null The value update_metadata() should return.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @return mixed
*/
public function filter_overrule_get_user_metadata( $null, $object_id, $meta_key ) {
global $wpdb;
$user = $this->store->get_selectedUser();
// Check if the object being updated is the current user.
if ( (int) $user->ID === (int) $object_id ) {
// Return the current user capabilities or user level while in a view.
// Always return an array to fix $single usage.
// Current user cap key should be equal to the meta_key for capabilities.
if ( ! empty( $user->cap_key ) && $meta_key === $user->cap_key ) {
return array( $user->caps );
}
// Fallback if cap_key doesn't exists.
if ( $meta_key === $wpdb->get_blog_prefix() . 'capabilities' ) {
return array( $user->caps );
}
if ( $meta_key === $wpdb->get_blog_prefix() . 'user_level' ) {
if ( ! isset( $user->user_level ) ) {
// Make sure the key exists. Result will be filtered in `filter_prevent_update_user_metadata()`.
$user->update_user_level_from_caps();
}
return array( $user->user_level );
}
}
return $null;
}
/**
* Change capabilities when the user has selected a view.
* If the capability isn't in the chosen view, then make the value for this capability empty and add "do_not_allow".
*
* @since 0.1
* @since 1.5 Changed function name to map_meta_cap (was change_caps).
* @since 1.6 Moved to this class from main class.
* @since 1.6.2 Use logic from current_view_can().
* @since 1.6.3 Prefix function name with `filter_`.
* @since 1.7.2 Use the `user_has_cap` filter for compatibility enhancements.
* @access public
*
* @param array $caps The actual (mapped) cap names, if the caps are not mapped this returns the requested cap.
* @param string $cap The capability that was requested.
* @param int $user_id The ID of the user.
* @param array $args Adds the context to the cap. Typically the object ID (not used).
* @return array $caps
*/
public function filter_map_meta_cap( $caps, $cap, $user_id, $args = array() ) {
if ( (int) $this->store->get_selectedUser()->ID !== (int) $user_id ) {
return $caps;
}
$filter_caps = (array) $this->store->get_selectedCaps();
if ( ! $this->store->get_view( 'caps' ) ) {
/**
* Apply user_has_cap filters to make sure we are compatible with modifications from other plugins.
*
* Issues found:
* - Restrict User Access - Overwrites our filtered capabilities. (fixed since RUA 0.15.x).
* - Groups - Overwrites our filtered capabilities. (fixed in Groups module).
*
* @since 1.7.2
* @see \WP_User::has_cap()
*/
$filter_caps = apply_filters(
'user_has_cap',
$filter_caps,
$caps,
// Replicate arguments for `user_has_cap`.
array_merge( array( $cap, $user_id ), (array) $args ),
$this->store->get_selectedUser()
);
}
foreach ( (array) $caps as $actual_cap ) {
if ( ! $this->current_view_can( $actual_cap, $filter_caps ) ) {
// Regular users. Assuming this capability never exists..
$caps['vaa_do_not_allow'] = 'vaa_do_not_allow';
// Network admins.
$caps['do_not_allow'] = 'do_not_allow';
}
}
return $caps;
}
/**
* Overwrite the user's capabilities.
*
* @since 1.6.3
* @access public
*
* @param array $allcaps All the capabilities of the user.
* @param array $caps Actual capabilities for meta capability.
* @param array $args [0] Requested capability.
* [1] User ID.
* [2] Associated object ID.
* @param \WP_User $user (WP 3.7+) The user object.
* @return array
*/
public function filter_user_has_cap( $allcaps, $caps, $args, $user = null ) {
$user_id = ( $user ) ? $user->ID : $args[1];
if ( is_numeric( $user_id ) && (int) $user_id === (int) $this->store->get_selectedUser()->ID ) {
return (array) $this->store->get_selectedCaps();
}
return $allcaps;
}
/**
* Remove the current user from the list of super admins.
* This sets/changes the global $super_admins variable which overwrites the site option.
*
* @since 1.7.3
* @access public
* @see grant_super_admin() >> wp-includes/capabilities.php
* @see revoke_super_admin() >> wp-includes/capabilities.php
* @see get_super_admins() >> wp-includes/capabilities.php
* @see is_super_admin() >> wp-includes/capabilities.php
* @link https://developer.wordpress.org/reference/functions/is_super_admin/
*
* @global array $super_admins
* @param \WP_User|int|string $user (optional) A user to remove. Both a user object or a user field is accepted.
* @param string $field (optional) A user field key to get the user data by.
*/
public function disable_super_admin( $user = null, $field = 'id' ) {
global $super_admins;
if ( ! isset( $super_admins ) ) {
$super_admins = get_super_admins();
}
$user = ( null !== $user ) ? $user : $this->store->get_selectedUser();
if ( ! $user instanceof WP_User ) {
$user = get_user_by( $field, $user );
}
// Remove current user from the super admins array.
// Effectively disables functions grant_super_admin() and revoke_super_admin().
if ( ! empty( $user->user_login ) && is_array( $super_admins ) ) {
$key = array_search( $user->user_login, $super_admins, true );
if ( false !== $key ) {
unset( $super_admins[ $key ] );
$GLOBALS['super_admins'] = $super_admins;
}
}
}
/**
* Similar function to current_user_can().
*
* @since 1.6.2
* @since 1.8 Check for non-scalar types being passed as first parameter.
* @access public
*
* @param string $cap The capability.
* @param array $caps (optional) Capabilities to compare to.
* Defaults to the selected caps for the current view.
* @return bool
*/
public function current_view_can( $cap, $caps = array() ) {
if ( empty( $caps ) ) {
$caps = $this->store->get_selectedCaps();
}
if ( ! is_scalar( $cap ) ) {
$cap = (array) $cap;
foreach ( $cap as $capability ) {
if ( ! $this->current_view_can( $capability, $caps ) ) {
return false;
}
}
return true;
}
$cap = (string) $cap;
if ( is_array( $caps ) &&
! empty( $caps[ $cap ] ) &&
'do_not_allow' !== $cap &&
'do_not_allow' !== $caps[ $cap ]
) {
return true;
}
return false;
}
/**
* Is the current user modified?
*
* @since 1.7.2
* @access public
* @return bool
*/
public function is_user_modified() {
return (bool) $this->is_user_modified;
}
/**
* Set the locale for the current view.
*
* @since 1.6.1
* @access public
* @return bool Will return false when used with older WP versions.
*/
public function freeze_locale() {
if ( function_exists( 'get_user_locale' ) && function_exists( 'switch_to_locale' ) ) {
$locale = get_user_locale( $this->store->get_curUser()->ID );
if ( get_locale() !== $locale ) {
switch_to_locale( $locale );
}
return true;
}
return false;
}
/**
* Main Instance.
*
* Ensures only one instance of this class is loaded or can be loaded.
*
* @since 1.6
* @access public
* @static
* @param \VAA_View_Admin_As $caller The referrer class.
* @return \VAA_View_Admin_As_View $this
*/
public static function get_instance( $caller = null ) {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self( $caller );
}
return self::$_instance;
}
} // End class VAA_View_Admin_As_View.

View File

@@ -0,0 +1,2 @@
<?php
//Nothing to see here