diff --git a/includes/class-indieauth-authorize.php b/includes/class-authorize.php similarity index 77% rename from includes/class-indieauth-authorize.php rename to includes/class-authorize.php index bba4bb5..0f80a47 100644 --- a/includes/class-indieauth-authorize.php +++ b/includes/class-authorize.php @@ -5,6 +5,10 @@ * @package IndieAuth */ +namespace IndieAuth; + +use IndieAuth\Token\User as Token_User; + /** * IndieAuth Authorize class. * @@ -12,12 +16,12 @@ * * @since 1.0.0 */ -class IndieAuth_Authorize { +class Authorize { /** * Error object. * - * @var WP_Error|WP_OAuth_Response|null + * @var \WP_Error|OAuth_Response|null */ public $error = null; @@ -58,30 +62,30 @@ public function load() { // WordPress validates the auth cookie at priority 10 and this cannot be overridden by an earlier priority. // It validates the logged in cookie at 20 and can be overridden by something with a higher priority. - add_filter( 'determine_current_user', array( $this, 'determine_current_user' ), 15 ); - add_filter( 'rest_authentication_errors', array( $this, 'rest_authentication_errors' ) ); + \add_filter( 'determine_current_user', array( $this, 'determine_current_user' ), 15 ); + \add_filter( 'rest_authentication_errors', array( $this, 'rest_authentication_errors' ) ); - add_filter( 'indieauth_scopes', array( $this, 'get_indieauth_scopes' ), 9 ); - add_filter( 'indieauth_response', array( $this, 'get_indieauth_response' ), 9 ); - add_filter( 'wp_rest_server_class', array( $this, 'wp_rest_server_class' ) ); - add_filter( 'rest_request_after_callbacks', array( $this, 'return_oauth_error' ), 10, 3 ); + \add_filter( 'indieauth_scopes', array( $this, 'get_indieauth_scopes' ), 9 ); + \add_filter( 'indieauth_response', array( $this, 'get_indieauth_response' ), 9 ); + \add_filter( 'wp_rest_server_class', array( $this, 'wp_rest_server_class' ) ); + \add_filter( 'rest_request_after_callbacks', array( $this, 'return_oauth_error' ), 10, 3 ); } /** * Ensures responses to any IndieAuth endpoints are always OAuth Responses rather than WP_Error. * - * @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client. - * @param array $handler Route handler used for the request. - * @param WP_REST_Request $request Request used to generate the response. - * @return WP_REST_Response|WP_OAuth_Response|mixed Modified response. + * @param \WP_REST_Response|\WP_HTTP_Response|\WP_Error|mixed $response Result to send to the client. + * @param array $handler Route handler used for the request. + * @param \WP_REST_Request $request Request used to generate the response. + * @return \WP_REST_Response|OAuth_Response|mixed Modified response. */ public static function return_oauth_error( $response, $handler, $request ) { if ( 0 !== strpos( $request->get_route(), '/indieauth/1.0/' ) ) { return $response; } - if ( is_wp_error( $response ) ) { + if ( \is_wp_error( $response ) ) { return wp_error_to_oauth_response( $response ); } return $response; @@ -98,7 +102,7 @@ public static function return_oauth_error( $response, $handler, $request ) { */ public static function wp_rest_server_class( $class ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.classFound global $current_user; - if ( defined( 'REST_REQUEST' ) && REST_REQUEST && $current_user instanceof WP_User && 0 === $current_user->ID ) { + if ( defined( 'REST_REQUEST' ) && REST_REQUEST && $current_user instanceof \WP_User && 0 === $current_user->ID ) { /* * For our authentication to work, we need to remove the cached lack * of a current user, so the next time it checks, we can detect that @@ -137,16 +141,16 @@ public function get_indieauth_response( $response ) { * Attached to the rest_authentication_errors filter. Passes through existing * errors registered on the filter. * - * @param WP_Error|null|true $error Current error, null or true. - * @return WP_Error|null|true Error if one is set, unchanged otherwise. + * @param \WP_Error|null|true $error Current error, null or true. + * @return \WP_Error|null|true Error if one is set, unchanged otherwise. */ public function rest_authentication_errors( $error = null ) { - if ( is_user_logged_in() ) { + if ( \is_user_logged_in() ) { // Another OAuth2 plugin successfully authenticated. return $error; } - if ( is_wp_error( $this->error ) ) { + if ( \is_wp_error( $this->error ) ) { return $this->error; } @@ -193,9 +197,9 @@ public function determine_current_user( $user_id ) { } } - $this->error = new WP_OAuth_Response( + $this->error = new OAuth_Response( 'unauthorized', - __( 'User Not Found on this Site', 'indieauth' ), + \__( 'User Not Found on this Site', 'indieauth' ), 401, array( 'response' => $params, @@ -217,16 +221,16 @@ public function determine_current_user( $user_id ) { public function get_authorization_header() { $auth = null; if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) { - $auth = wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $auth = \wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized } elseif ( ! empty( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) { // When Apache speaks via FastCGI with PHP, then the authorization header is often available as REDIRECT_HTTP_AUTHORIZATION. - $auth = wp_unslash( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $auth = \wp_unslash( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized } else { $headers = getallheaders(); // Check for the authorization header case-insensitively. foreach ( $headers as $key => $value ) { if ( strtolower( $key ) === 'authorization' ) { - $auth = wp_unslash( $value ); + $auth = \wp_unslash( $value ); break; } } @@ -278,7 +282,7 @@ public function get_token_from_request() { if ( empty( $_POST['access_token'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing return null; } - $token = sanitize_text_field( wp_unslash( $_POST['access_token'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + $token = \sanitize_text_field( \wp_unslash( $_POST['access_token'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( is_string( $token ) ) { return $token; @@ -290,15 +294,15 @@ public function get_token_from_request() { * Verifies Access Token. * * @param string $token The token to verify. - * @return array|WP_OAuth_Response Return either the token information or an OAuth Error Object. + * @return array|OAuth_Response Return either the token information or an OAuth Error Object. */ public function verify_access_token( $token ) { $tokens = new Token_User( '_indieauth_token_' ); $return = $tokens->get( $token ); if ( empty( $return ) ) { - return new WP_OAuth_Response( + return new OAuth_Response( 'invalid_token', - __( 'Invalid access token', 'indieauth' ), + \__( 'Invalid access token', 'indieauth' ), 401 ); } @@ -306,7 +310,7 @@ public function verify_access_token( $token ) { return $return; } $return['last_accessed'] = time(); - $return['last_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; + $return['last_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? \sanitize_text_field( \wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; $tokens->update( $token, $return ); if ( array_key_exists( 'exp', $return ) ) { $return['expires_in'] = $return['exp'] - time(); @@ -318,15 +322,15 @@ public function verify_access_token( $token ) { * Verifies authorization code. * * @param string $code Authorization Code. - * @return array|WP_OAuth_Response Return either the code information or an OAuth Error object. + * @return array|OAuth_Response Return either the code information or an OAuth Error object. */ public static function verify_authorization_code( $code ) { $tokens = new Token_User( '_indieauth_code_' ); $return = $tokens->get( $code ); if ( empty( $return ) ) { - return new WP_OAuth_Response( + return new OAuth_Response( 'invalid_code', - __( 'Invalid authorization code', 'indieauth' ), + \__( 'Invalid authorization code', 'indieauth' ), 401 ); } diff --git a/includes/class-autoloader.php b/includes/class-autoloader.php new file mode 100644 index 0000000..e184801 --- /dev/null +++ b/includes/class-autoloader.php @@ -0,0 +1,106 @@ +prefix = $prefix; + $this->prefix_length = \strlen( $prefix ); + $this->path = \rtrim( $path . '/' ); + } + + /** + * Registers Autoloader's autoload function. + * + * @throws \Exception When autoload_function cannot be registered. + * + * @param string $prefix Namespace prefix all classes have in common. + * @param string $path Path to the files to be loaded. + */ + public static function register_path( $prefix, $path ) { + $loader = new self( $prefix, $path ); + \spl_autoload_register( array( $loader, 'load' ) ); + } + + /** + * Loads a class if its namespace starts with `$this->prefix`. + * + * @param string $class_name The class to be loaded. + */ + public function load( $class_name ) { + if ( \strpos( $class_name, $this->prefix . self::NS_SEPARATOR ) !== 0 ) { + return; + } + + // Strip prefix from the start (ala PSR-4). + $class_name = \substr( $class_name, $this->prefix_length + 1 ); + $class_name = \strtolower( $class_name ); + $dir = ''; + + $last_ns_pos = \strripos( $class_name, self::NS_SEPARATOR ); + if ( false !== $last_ns_pos ) { + $namespace = \substr( $class_name, 0, $last_ns_pos ); + $namespace = \str_replace( '_', '-', $namespace ); + $class_name = \substr( $class_name, $last_ns_pos + 1 ); + $dir = \str_replace( self::NS_SEPARATOR, DIRECTORY_SEPARATOR, $namespace ) . DIRECTORY_SEPARATOR; + } + + $path = $this->path . $dir . 'class-' . \str_replace( '_', '-', $class_name ) . '.php'; + + if ( ! \file_exists( $path ) ) { + $path = $this->path . $dir . 'interface-' . \str_replace( '_', '-', $class_name ) . '.php'; + } + + if ( ! \file_exists( $path ) ) { + $path = $this->path . $dir . 'trait-' . \str_replace( '_', '-', $class_name ) . '.php'; + } + + if ( \file_exists( $path ) ) { + require_once $path; + } + } +} diff --git a/includes/class-indieauth-client-discovery.php b/includes/class-client-discovery.php similarity index 78% rename from includes/class-indieauth-client-discovery.php rename to includes/class-client-discovery.php index 35d02c7..08ecdd1 100644 --- a/includes/class-indieauth-client-discovery.php +++ b/includes/class-client-discovery.php @@ -5,10 +5,12 @@ * @package IndieAuth */ +namespace IndieAuth; + /** * Discovers information about an IndieAuth client from its client_id URL. */ -class IndieAuth_Client_Discovery { +class Client_Discovery { /** * Discovered rel values. @@ -78,7 +80,7 @@ public function __construct( $client_id ) { return; } // Validate if this is an IP address. - $ip = filter_var( wp_parse_url( $client_id, PHP_URL_HOST ), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 ); + $ip = filter_var( \wp_parse_url( $client_id, PHP_URL_HOST ), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 ); $donotfetch = array( '127.0.0.1', '0000:0000:0000:0000:0000:0000:0000:0001', @@ -90,13 +92,13 @@ public function __construct( $client_id ) { return; } - if ( 'localhost' === wp_parse_url( $client_id, PHP_URL_HOST ) ) { + if ( 'localhost' === \wp_parse_url( $client_id, PHP_URL_HOST ) ) { return; } $response = self::parse( $client_id ); - if ( is_wp_error( $response ) ) { + if ( \is_wp_error( $response ) ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( __( 'Failed to Retrieve IndieAuth Client Details ', 'indieauth' ) . wp_json_encode( $response ) ); + \error_log( \__( 'Failed to Retrieve IndieAuth Client Details ', 'indieauth' ) . \wp_json_encode( $response ) ); return; } } @@ -123,22 +125,22 @@ public function export() { * Fetches the client URL content. * * @param string $url The URL to fetch. - * @return array|WP_Error The HTTP response or WP_Error on failure. + * @return array|\WP_Error The HTTP response or WP_Error on failure. */ private function fetch( $url ) { - $wp_version = get_bloginfo( 'version' ); - $user_agent = apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ) ); + $wp_version = \get_bloginfo( 'version' ); + $user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) ); $args = array( 'timeout' => 100, 'limit_response_size' => 1048576, 'redirection' => 3, 'user-agent' => "$user_agent; IndieAuth Client Information Discovery", ); - $response = wp_safe_remote_get( $url, $args ); - if ( ! is_wp_error( $response ) ) { - $code = wp_remote_retrieve_response_code( $response ); + $response = \wp_safe_remote_get( $url, $args ); + if ( ! \is_wp_error( $response ) ) { + $code = \wp_remote_retrieve_response_code( $response ); if ( ( $code / 100 ) !== 2 ) { - return new WP_Error( 'retrieval_error', __( 'Failed to Retrieve Client Details', 'indieauth' ), $code ); + return new \WP_Error( 'retrieval_error', \__( 'Failed to Retrieve Client Details', 'indieauth' ), $code ); } } @@ -149,18 +151,18 @@ private function fetch( $url ) { * Parses the client URL to extract client metadata. * * @param string $url The client URL to parse. - * @return void|WP_Error Void on success, WP_Error on failure. + * @return void|\WP_Error Void on success, WP_Error on failure. */ private function parse( $url ) { $response = self::fetch( $url ); - if ( is_wp_error( $response ) ) { + if ( \is_wp_error( $response ) ) { return $response; } - $content_type = wp_remote_retrieve_header( $response, 'content-type' ); + $content_type = \wp_remote_retrieve_header( $response, 'content-type' ); if ( 'application/json' === $content_type ) { - $this->json = json_decode( wp_remote_retrieve_body( $response ), true ); + $this->json = json_decode( \wp_remote_retrieve_body( $response ), true ); /** * Expected format is per the IndieAuth standard as revised 2024-06-23 to include a JSON Client Metadata File * @@ -175,10 +177,10 @@ private function parse( $url ) { * } */ if ( ! is_array( $this->json ) || empty( $this->json ) ) { - return new WP_Error( 'empty_json', __( 'Discovery Has Returned an Empty JSON Document', 'indieauth' ) ); + return new \WP_Error( 'empty_json', \__( 'Discovery Has Returned an Empty JSON Document', 'indieauth' ) ); } if ( ! array_key_exists( 'client_id', $this->json ) ) { - return new WP_Error( 'missing_client_id', __( 'No Client ID Found in JSON Client Metadata', 'indieauth' ) ); + return new \WP_Error( 'missing_client_id', \__( 'No Client ID Found in JSON Client Metadata', 'indieauth' ) ); } $this->client_id = $this->json['client_id']; if ( array_key_exists( 'client_name', $this->json ) ) { @@ -191,7 +193,7 @@ private function parse( $url ) { $this->client_uri = $this->json['client_uri']; } } elseif ( 'text/html' === $content_type ) { - $content = wp_remote_retrieve_body( $response ); + $content = \wp_remote_retrieve_body( $response ); $this->get_mf2( $content, $url ); if ( ! empty( $this->mf2 ) ) { if ( array_key_exists( 'name', $this->mf2 ) ) { @@ -205,14 +207,14 @@ private function parse( $url ) { } } } else { - $domdocument = new DOMDocument( wp_remote_retrieve_body( $response ) ); + $domdocument = new \DOMDocument( \wp_remote_retrieve_body( $response ) ); $this->client_icon = $this->determine_icon( $this->rels ); $this->get_html( $domdocument ); $this->client_name = $this->html['title']; } if ( ! empty( $this->client_icon ) ) { - $this->client_icon = WP_Http::make_absolute_url( $this->client_icon, $url ); + $this->client_icon = \WP_Http::make_absolute_url( $this->client_icon, $url ); } } } @@ -225,11 +227,11 @@ private function parse( $url ) { */ private function get_mf2( $input, $url ) { if ( ! class_exists( 'Mf2\Parser' ) ) { - require_once plugin_dir_path( __DIR__ ) . 'lib/mf2/Parser.php'; + require_once \plugin_dir_path( __DIR__ ) . 'lib/mf2/Parser.php'; } $mf = Mf2\parse( $input, $url ); if ( array_key_exists( 'rels', $mf ) ) { - $this->rels = wp_array_slice_assoc( $mf['rels'], array( 'apple-touch-icon', 'icon', 'mask-icon' ) ); + $this->rels = \wp_array_slice_assoc( $mf['rels'], array( 'apple-touch-icon', 'icon', 'mask-icon' ) ); } if ( array_key_exists( 'items', $mf ) ) { foreach ( $mf['items'] as $item ) { @@ -244,10 +246,10 @@ private function get_mf2( $input, $url ) { /** * Extracts HTML metadata from a DOMDocument. * - * @param DOMDocument $input The parsed DOM document. + * @param \DOMDocument $input The parsed DOM document. */ private function get_html( $input ) { - $xpath = new DOMXPath( $input ); + $xpath = new \DOMXPath( $input ); if ( ! empty( $xpath ) ) { $title = $xpath->query( '//title' ); if ( ! empty( $title ) ) { @@ -319,7 +321,7 @@ private function determine_icon( $input ) { $icons = $input['icon']; } - if ( is_array( $icons ) && ! wp_is_numeric_array( $icons ) && isset( $icons['url'] ) ) { + if ( is_array( $icons ) && ! \wp_is_numeric_array( $icons ) && isset( $icons['url'] ) ) { return $icons['url']; } elseif ( is_string( $icons[0] ) ) { return $icons[0]; diff --git a/includes/class-indieauth-client-taxonomy.php b/includes/class-client-taxonomy.php old mode 100755 new mode 100644 similarity index 68% rename from includes/class-indieauth-client-taxonomy.php rename to includes/class-client-taxonomy.php index ee71335..5c32739 --- a/includes/class-indieauth-client-taxonomy.php +++ b/includes/class-client-taxonomy.php @@ -5,7 +5,7 @@ * @package IndieAuth */ -add_action( 'init', array( 'IndieAuth_Client_Taxonomy', 'init' ) ); +namespace IndieAuth; /** * Class that handles the client taxonomy functions. @@ -14,7 +14,7 @@ * * @since 1.0.0 */ -final class IndieAuth_Client_Taxonomy { +final class Client_Taxonomy { /** * Initialize the taxonomy. @@ -22,7 +22,7 @@ final class IndieAuth_Client_Taxonomy { public static function init() { self::register(); - add_filter( 'terms_clauses', array( __CLASS__, 'terms_clauses' ), 11, 3 ); + \add_filter( 'terms_clauses', array( __CLASS__, 'terms_clauses' ), 11, 3 ); } /** @@ -48,18 +48,18 @@ public static function terms_clauses( $clauses, $taxonomies, $args ) { */ public static function register() { $labels = array( - 'name' => _x( 'IndieAuth Applications', 'taxonomy general name', 'indieauth' ), - 'singular_name' => _x( 'IndieAuth Applications', 'taxonomy singular name', 'indieauth' ), - 'search_items' => _x( 'Search IndieAuth Applications', 'search locations', 'indieauth' ), - 'popular_items' => _x( 'Popular Applications', 'popular locations', 'indieauth' ), - 'all_items' => _x( 'All Applications', 'all taxonomy items', 'indieauth' ), - 'edit_item' => _x( 'Edit Application', 'edit taxonomy item', 'indieauth' ), - 'view_item' => _x( 'View Application Archive', 'view taxonomy item', 'indieauth' ), - 'update_item' => _x( 'Update Application', 'update taxonomy item', 'indieauth' ), - 'add_new_item' => _x( 'Add New Application', 'add taxonomy item', 'indieauth' ), - 'new_item_name' => _x( 'New Application', 'new taxonomy item', 'indieauth' ), - 'not found' => _x( 'No applications found', 'no clients found', 'indieauth' ), - 'no_terms' => _x( 'No applications', 'no locations', 'indieauth' ), + 'name' => \_x( 'IndieAuth Applications', 'taxonomy general name', 'indieauth' ), + 'singular_name' => \_x( 'IndieAuth Applications', 'taxonomy singular name', 'indieauth' ), + 'search_items' => \_x( 'Search IndieAuth Applications', 'search locations', 'indieauth' ), + 'popular_items' => \_x( 'Popular Applications', 'popular locations', 'indieauth' ), + 'all_items' => \_x( 'All Applications', 'all taxonomy items', 'indieauth' ), + 'edit_item' => \_x( 'Edit Application', 'edit taxonomy item', 'indieauth' ), + 'view_item' => \_x( 'View Application Archive', 'view taxonomy item', 'indieauth' ), + 'update_item' => \_x( 'Update Application', 'update taxonomy item', 'indieauth' ), + 'add_new_item' => \_x( 'Add New Application', 'add taxonomy item', 'indieauth' ), + 'new_item_name' => \_x( 'New Application', 'new taxonomy item', 'indieauth' ), + 'not found' => \_x( 'No applications found', 'no clients found', 'indieauth' ), + 'no_terms' => \_x( 'No applications', 'no locations', 'indieauth' ), ); $args = array( @@ -74,44 +74,44 @@ public static function register() { 'show_tagcloud' => false, 'show_in_quick_edit' => false, 'show_admin_column' => false, - 'description' => __( 'Stores information in IndieAuth Client Applications', 'indieauth' ), + 'description' => \__( 'Stores information in IndieAuth Client Applications', 'indieauth' ), ); - $object_types = apply_filters( 'indieauth_client_taxonomy_object_types', array( 'post', 'page', 'attachment' ) ); + $object_types = \apply_filters( 'indieauth_client_taxonomy_object_types', array( 'post', 'page', 'attachment' ) ); - register_taxonomy( 'indieauth_client', $object_types, $args ); + \register_taxonomy( 'indieauth_client', $object_types, $args ); - register_meta( + \register_meta( 'term', 'icon', array( 'object_subtype' => 'indieauth_client', 'type' => 'string', - 'description' => __( 'IndieAuth Client Application Icon', 'indieauth' ), + 'description' => \__( 'IndieAuth Client Application Icon', 'indieauth' ), 'single' => true, 'sanitize_callback' => 'esc_url_raw', 'show_in_rest' => true, ) ); - register_meta( + \register_meta( 'term', 'client_uri', array( 'object_subtype' => 'indieauth_client', 'type' => 'string', - 'description' => __( 'IndieAuth Client Application URI', 'indieauth' ), + 'description' => \__( 'IndieAuth Client Application URI', 'indieauth' ), 'single' => true, 'sanitize_callback' => 'esc_url_raw', 'show_in_rest' => true, ) ); - register_meta( + \register_meta( 'term', 'last_modified', array( 'object_subtype' => 'indieauth_client', 'type' => 'integer', - 'description' => __( 'Last Modified Client Timestamp', 'indieauth' ), + 'description' => \__( 'Last Modified Client Timestamp', 'indieauth' ), 'single' => true, 'show_in_rest' => true, ) @@ -130,7 +130,7 @@ public static function update_client_icon_from_discovery( $url ) { return false; } - $client = new IndieAuth_Client_Discovery( $url ); + $client = new Client_Discovery( $url ); if ( ! $client->get_icon() ) { return false; } @@ -146,12 +146,12 @@ public static function update_client_icon_from_discovery( $url ) { * @return string Generated slug. */ public static function generate_slug( $url ) { - $host = wp_parse_url( $url, PHP_URL_HOST ); + $host = \wp_parse_url( $url, PHP_URL_HOST ); // Strip leading www, if any. $host = preg_replace( '/^www\./', '', $host ); - $path = wp_parse_url( $url, PHP_URL_PATH ); + $path = \wp_parse_url( $url, PHP_URL_PATH ); $path = str_replace( '/', '_', $path ); - return sanitize_title( $host . $path ); + return \sanitize_title( $host . $path ); } /** @@ -160,20 +160,20 @@ public static function generate_slug( $url ) { * @param string $url Client URL. * @param string|null $name Client name. * @param string|null $icon Client icon URL. - * @return array|WP_Error Client data or error. + * @return array|\WP_Error Client data or error. */ public static function add_client( $url, $name = null, $icon = null ) { $exists = self::get_client( $url ); // Do Not Overwrite if Already Exists. - if ( ! is_wp_error( $exists ) ) { + if ( ! \is_wp_error( $exists ) ) { return $exists; } $client_uri = ''; if ( empty( $name ) ) { - $client = new IndieAuth_Client_Discovery( $url ); + $client = new Client_Discovery( $url ); if ( defined( 'INDIEAUTH_UNIT_TESTS' ) ) { return array( 'client_id' => $url, @@ -189,25 +189,25 @@ public static function add_client( $url, $name = null, $icon = null ) { $icon = self::sideload_icon( $icon, $url ); - $term = wp_insert_term( + $term = \wp_insert_term( $name, 'indieauth_client', array( 'slug' => self::generate_slug( $url ), - 'description' => esc_url_raw( $url ), + 'description' => \esc_url_raw( $url ), ) ); - if ( is_wp_error( $term ) ) { + if ( \is_wp_error( $term ) ) { return $term; } if ( ! empty( $icon ) ) { - add_term_meta( $term['term_id'], 'icon', $icon ); + \add_term_meta( $term['term_id'], 'icon', $icon ); } if ( ! empty( $client_uri ) ) { - add_term_meta( $term['term_id'], 'client_uri', $client_uri ); + \add_term_meta( $term['term_id'], 'client_uri', $client_uri ); } - add_term_meta( $term['term_id'], 'last_modified', time() ); + \add_term_meta( $term['term_id'], 'last_modified', time() ); return array_filter( array( 'url' => $url, @@ -222,12 +222,12 @@ public static function add_client( $url, $name = null, $icon = null ) { * Get client. * * @param string|int|null $url Client URL, term ID, or null for all. - * @return array|WP_Error Client data or error. + * @return array|\WP_Error Client data or error. */ public static function get_client( $url = null ) { // If URL is null retrieve all clients. if ( is_null( $url ) ) { - $terms = get_terms( + $terms = \get_terms( array( 'taxonomy' => 'indieauth_client', 'hide_empty' => false, @@ -239,19 +239,19 @@ public static function get_client( $url = null ) { 'url' => $term->description, 'name' => $term->name, 'id' => $term->term_id, - 'icon' => get_term_meta( $term->term_id, 'icon', true ), - 'uri' => get_term_meta( $term->term_id, 'client_uri', true ), - 'last_modified' => get_term_meta( $term->term_id, 'last_modified', true ), + 'icon' => \get_term_meta( $term->term_id, 'icon', true ), + 'uri' => \get_term_meta( $term->term_id, 'client_uri', true ), + 'last_modified' => \get_term_meta( $term->term_id, 'last_modified', true ), ); } return $clients; } if ( is_numeric( $url ) ) { - $terms = array( get_term( $url, 'indieauth_client' ) ); + $terms = array( \get_term( $url, 'indieauth_client' ) ); return $terms; } else { - $terms = get_terms( + $terms = \get_terms( array( 'taxonomy' => 'indieauth_client', 'description' => $url, @@ -260,11 +260,11 @@ public static function get_client( $url = null ) { ); } if ( empty( $terms ) ) { - return new WP_Error( 'not_found', __( 'No Term Found', 'indieauth' ) ); + return new \WP_Error( 'not_found', \__( 'No Term Found', 'indieauth' ) ); } if ( 1 !== count( $terms ) ) { - return new WP_Error( 'multiples', __( 'Multiple Terms Found', 'indieauth' ), $terms ); + return new \WP_Error( 'multiples', \__( 'Multiple Terms Found', 'indieauth' ), $terms ); } $term = $terms[0]; @@ -273,9 +273,9 @@ public static function get_client( $url = null ) { 'url' => $term->description, 'name' => $term->name, 'id' => $term->term_id, - 'icon' => get_term_meta( $term->term_id, 'icon', true ), - 'uri' => get_term_meta( $term->term_id, 'client_uri', true ), - 'last_modified' => get_term_meta( $term->term_id, 'last_modified', true ), + 'icon' => \get_term_meta( $term->term_id, 'icon', true ), + 'uri' => \get_term_meta( $term->term_id, 'client_uri', true ), + 'last_modified' => \get_term_meta( $term->term_id, 'last_modified', true ), ); } @@ -283,7 +283,7 @@ public static function get_client( $url = null ) { * Delete a client. * * @param string $url Client URL. - * @return bool|int|WP_Error Term ID or error. + * @return bool|int|\WP_Error Term ID or error. */ public static function delete_client( $url ) { $client = self::get_client( $url ); @@ -293,7 +293,7 @@ public static function delete_client( $url ) { self::delete_icon_file( $client['icon'] ); - return wp_delete_term( + return \wp_delete_term( $client['id'], 'indieauth_client' ); @@ -307,10 +307,10 @@ public static function delete_client( $url ) { * @return string URL or path of upload directory. */ public static function upload_directory( $filepath = '', $url = false ) { - $upload_dir = wp_get_upload_dir(); + $upload_dir = \wp_get_upload_dir(); $upload_dir = $url ? $upload_dir['baseurl'] : $upload_dir['basedir']; $upload_dir .= '/indieauth/icons/'; - $upload_dir = apply_filters( 'indieauth_client_icon_directory', $upload_dir, $url ); + $upload_dir = \apply_filters( 'indieauth_client_icon_directory', $upload_dir, $url ); return $upload_dir . $filepath; } @@ -340,7 +340,7 @@ public static function delete_icon_file( $url ) { return false; } if ( file_exists( $filepath ) ) { - wp_delete_file( $filepath ); + \wp_delete_file( $filepath ); return true; } return false; @@ -369,7 +369,7 @@ public static function sideload_icon( $url, $client_id ) { // Allow for common query parameters in image APIs to get a better quality image. $query = array(); - wp_parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $query ); + \wp_parse_str( \wp_parse_url( $url, PHP_URL_QUERY ), $query ); if ( array_key_exists( 's', $query ) && is_numeric( $query['s'] ) ) { $url = str_replace( 's=' . $query['s'], 's=' . INDIEAUTH_ICON_SIZE, $url ); } @@ -379,12 +379,12 @@ public static function sideload_icon( $url, $client_id ) { } // Download profile picture and add as attachment. - $download = download_url( $url, 300 ); - if ( is_wp_error( $download ) ) { + $download = \download_url( $url, 300 ); + if ( \is_wp_error( $download ) ) { return false; } - $file = wp_get_image_editor( $download ); - if ( is_wp_error( $file ) ) { + $file = \wp_get_image_editor( $download ); + if ( \is_wp_error( $file ) ) { return false; } $file->resize( null, INDIEAUTH_ICON_SIZE, true ); diff --git a/includes/class-indieauth-client.php b/includes/class-client.php similarity index 66% rename from includes/class-indieauth-client.php rename to includes/class-client.php index 414a171..f49c30c 100644 --- a/includes/class-indieauth-client.php +++ b/includes/class-client.php @@ -5,10 +5,12 @@ * @package IndieAuth */ +namespace IndieAuth; + /** * IndieAuth Client class. */ -class IndieAuth_Client { +class Client { /** * Metadata including endpoints. @@ -28,17 +30,17 @@ class IndieAuth_Client { * Constructor. */ public function __construct() { - $this->client_id = trailingslashit( home_url() ); + $this->client_id = \trailingslashit( \home_url() ); } /** * Perform a remote GET request. * * @param string $url URL to request. - * @return array|WP_OAuth_Response Response array or error. + * @return array|OAuth_Response Response array or error. */ public function remote_get( $url ) { - $resp = wp_remote_get( + $resp = \wp_remote_get( $url, array( 'headers' => array( @@ -46,21 +48,21 @@ public function remote_get( $url ) { ), ) ); - if ( is_wp_error( $resp ) ) { + if ( \is_wp_error( $resp ) ) { return wp_error_to_oauth_response( $resp ); } - $code = (int) wp_remote_retrieve_response_code( $resp ); - $body = wp_remote_retrieve_body( $resp ); + $code = (int) \wp_remote_retrieve_response_code( $resp ); + $body = \wp_remote_retrieve_body( $resp ); if ( ( $code / 100 ) !== 2 ) { - return new WP_OAuth_Response( 'unable_retrieve', __( 'Unable to Retrieve', 'indieauth' ), $code, $body ); + return new OAuth_Response( 'unable_retrieve', \__( 'Unable to Retrieve', 'indieauth' ), $code, $body ); } $body = json_decode( $body, true ); if ( ! is_array( $body ) ) { - return new WP_OAuth_Response( 'server_error', __( 'The endpoint did not return a JSON response', 'indieauth' ), 500 ); + return new OAuth_Response( 'server_error', \__( 'The endpoint did not return a JSON response', 'indieauth' ), 500 ); } return $body; @@ -71,10 +73,10 @@ public function remote_get( $url ) { * * @param string $url URL to request. * @param array $post_args POST body arguments. - * @return array|WP_OAuth_Response Response array or error. + * @return array|OAuth_Response Response array or error. */ public function remote_post( $url, $post_args ) { - $resp = wp_remote_post( + $resp = \wp_remote_post( $url, array( 'headers' => array( @@ -92,17 +94,17 @@ public function remote_post( $url, $post_args ) { return $error; } - $code = (int) wp_remote_retrieve_response_code( $resp ); - $body = wp_remote_retrieve_body( $resp ); + $code = (int) \wp_remote_retrieve_response_code( $resp ); + $body = \wp_remote_retrieve_body( $resp ); if ( ( $code / 100 ) !== 2 ) { - return new WP_OAuth_Response( 'unable_retrieve', __( 'Unable to Retrieve', 'indieauth' ), $code, $body ); + return new OAuth_Response( 'unable_retrieve', \__( 'Unable to Retrieve', 'indieauth' ), $code, $body ); } $body = json_decode( $body, true ); if ( ! is_array( $body ) ) { - return new WP_OAuth_Response( 'server_error', __( 'The endpoint did not return a JSON response', 'indieauth' ), 500 ); + return new OAuth_Response( 'server_error', \__( 'The endpoint did not return a JSON response', 'indieauth' ), 500 ); } return $body; @@ -112,10 +114,10 @@ public function remote_post( $url, $post_args ) { * Discover IndieAuth Metadata either from a Metadata Endpoint or Otherwise. * * @param string $url URL. - * @return bool|WP_OAuth_Response True on success, false or error on failure. + * @return bool|OAuth_Response True on success, false or error on failure. */ public function discover_endpoints( $url ) { - $endpoints = get_transient( 'indieauth_discovery_' . base64_urlencode( $url ) ); + $endpoints = \get_transient( 'indieauth_discovery_' . base64_urlencode( $url ) ); if ( $endpoints ) { $this->meta = $endpoints; return true; @@ -135,12 +137,12 @@ public function discover_endpoints( $url ) { $this->meta = $resp; // Store endpoint discovery results for this URL for 3 hours. - set_transient( 'indieauth_discovery_' . base64_urlencode( $url ), $this->meta, 10800 ); + \set_transient( 'indieauth_discovery_' . base64_urlencode( $url ), $this->meta, 10800 ); return true; } elseif ( array_key_exists( 'authorization_endpoint', $endpoints ) && array_key_exists( 'token_endpoint', $endpoints ) ) { $this->meta = $endpoints; // Store endpoint discovery results for this URL for 3 hours. - set_transient( 'indieauth_discovery_' . base64_urlencode( $url ), $this->meta, 10800 ); + \set_transient( 'indieauth_discovery_' . base64_urlencode( $url ), $this->meta, 10800 ); return true; } return false; @@ -156,11 +158,11 @@ public function discover_endpoints( $url ) { * @type string $code_verifier The code verifier. * } * @param boolean $token Redeem For a Token or User Profile. - * @return WP_OAuth_Response|array Return Error or Response Array. + * @return OAuth_Response|array Return Error or Response Array. */ public function redeem_authorization_code( $post_args, $token = true ) { if ( empty( $this->meta ) ) { - return new WP_OAuth_Response( 'server_error', __( 'Valid Endpoint Not Provided', 'indieauth' ), 500 ); + return new OAuth_Response( 'server_error', \__( 'Valid Endpoint Not Provided', 'indieauth' ), 500 ); } $endpoint = $token ? $this->meta['token_endpoint'] : $this->meta['authorization_endpoint']; @@ -170,10 +172,10 @@ public function redeem_authorization_code( $post_args, $token = true ) { 'grant_type' => 'authorization_code', ); - $post_args = wp_parse_args( $post_args, $defaults ); + $post_args = \wp_parse_args( $post_args, $defaults ); if ( ! empty( array_diff( array( 'redirect_uri', 'code', 'code_verifier', 'client_id', 'grant_type' ), array_keys( $post_args ) ) ) ) { - return new WP_OAuth_Response( 'missing_arguments', __( 'Arguments are missing from redemption flow', 'indieauth' ), 500 ); + return new OAuth_Response( 'missing_arguments', \__( 'Arguments are missing from redemption flow', 'indieauth' ), 500 ); } $response = $this->remote_post( $endpoint, $post_args ); @@ -187,13 +189,13 @@ public function redeem_authorization_code( $post_args, $token = true ) { // If this redemption is at the token endpoint. if ( $token ) { if ( ! array_key_exists( 'access_token', $response ) ) { - return new WP_OAuth_Response( 'unknown_error', __( 'Token Endpoint did Not Return a Token', 'indieauth' ), 500 ); + return new OAuth_Response( 'unknown_error', \__( 'Token Endpoint did Not Return a Token', 'indieauth' ), 500 ); } } return $response; } - $error = new WP_OAuth_Response( 'server_error', __( 'There was an error verifying the authorization code, the authorization server returned an expected response', 'indieauth' ), 500 ); + $error = new OAuth_Response( 'server_error', \__( 'There was an error verifying the authorization code, the authorization server returned an expected response', 'indieauth' ), 500 ); $error->set_debug( array( 'debug' => $response ) ); return $error; } diff --git a/includes/class-indieauth-debug.php b/includes/class-debug.php similarity index 65% rename from includes/class-indieauth-debug.php rename to includes/class-debug.php index f5d34d4..b2a8b8c 100644 --- a/includes/class-indieauth-debug.php +++ b/includes/class-debug.php @@ -5,18 +5,20 @@ * @package IndieAuth */ +namespace IndieAuth; + /** * Class for debugging IndieAuth requests and responses. */ -class IndieAuth_Debug { +class Debug { /** * Constructor. Registers hooks for debugging. */ public function __construct() { - add_filter( 'http_request_args', array( $this, 'indieauth_allow_localhost' ), 10, 2 ); - add_filter( 'rest_post_dispatch', array( $this, 'log_rest_api_errors' ), 10, 3 ); - add_action( 'rest_api_init', array( $this, 'register_routes' ) ); + \add_filter( 'http_request_args', array( $this, 'indieauth_allow_localhost' ), 10, 2 ); + \add_filter( 'rest_post_dispatch', array( $this, 'log_rest_api_errors' ), 10, 3 ); + \add_action( 'rest_api_init', array( $this, 'register_routes' ) ); } /** @@ -35,10 +37,10 @@ public function indieauth_allow_localhost( $r, $url ) { // phpcs:ignore Generic. /** * Log REST API errors. * - * @param WP_REST_Response $result Result that will be sent to the client. - * @param WP_REST_Server $server The API server instance. - * @param WP_REST_Request $request The request used to generate the response. - * @return WP_REST_Response The result. + * @param \WP_REST_Response $result Result that will be sent to the client. + * @param \WP_REST_Server $server The API server instance. + * @param \WP_REST_Request $request The request used to generate the response. + * @return \WP_REST_Response The result. */ public function log_rest_api_errors( $result, $server, $request ) { $request_route = $request->get_route(); @@ -65,23 +67,23 @@ public function log_rest_api_errors( $result, $server, $request ) { $data['access_token'] = 'XXXX'; } // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( + \error_log( sprintf( 'REST request: %s: %s(Header %s)', $request->get_route(), - wp_json_encode( $params ), + \wp_json_encode( $params ), $token ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( + \error_log( sprintf( 'REST result: %s: %s(%s) - %s(User ID: %s)', $result->get_matched_route(), - wp_json_encode( $data ), + \wp_json_encode( $data ), $result->get_status(), - wp_json_encode( $result->get_headers() ), - get_current_user_id() + \wp_json_encode( $result->get_headers() ), + \get_current_user_id() ) ); } @@ -92,12 +94,12 @@ public function log_rest_api_errors( $result, $server, $request ) { * Register test route for authorization. */ public function register_routes() { - register_rest_route( + \register_rest_route( 'indieauth/1.0', '/test', array( array( - 'methods' => WP_REST_Server::READABLE, + 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'test' ), 'permission_callback' => array( $this, 'permissions_test' ), ), @@ -108,27 +110,27 @@ public function register_routes() { /** * Permission callback for the test route. * - * @param WP_REST_Request $request The request object. - * @return true|WP_Error True if authorized, WP_Error otherwise. + * @param \WP_REST_Request $request The request object. + * @return true|\WP_Error True if authorized, WP_Error otherwise. */ public function permissions_test( $request ) { $access_token = $request->get_param( 'access_token' ); $header = $request->get_header( 'authorization' ); if ( ! $access_token && ! $header ) { - return new WP_Error( 'forbidden', __( 'Could Not Find Token', 'indieauth' ), array( 'status' => 403 ) ); + return new \WP_Error( 'forbidden', \__( 'Could Not Find Token', 'indieauth' ), array( 'status' => 403 ) ); } - if ( 0 === get_current_user_id() ) { + if ( 0 === \get_current_user_id() ) { if ( empty( $this->response ) ) { - return new WP_Error( + return new \WP_Error( 'forbidden', - __( 'No User is Currently Set', 'indieauth' ), + \__( 'No User is Currently Set', 'indieauth' ), array( 'status' => 403, 'request' => $request, ) ); } else { - return new WP_Error( 'forbidden', __( 'A Successful Auth Response was Given yet No User is Currently Set', 'indieauth' ), array( 'status' => 403 ) ); + return new \WP_Error( 'forbidden', \__( 'A Successful Auth Response was Given yet No User is Currently Set', 'indieauth' ), array( 'status' => 403 ) ); } } return true; @@ -137,12 +139,12 @@ public function permissions_test( $request ) { /** * Callback for the test route. * - * @param WP_REST_Request $request The request object. - * @return array|WP_Error The IndieAuth response or error. + * @param \WP_REST_Request $request The request object. + * @return array|\WP_Error The IndieAuth response or error. */ public function test( $request ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable - if ( 0 === get_current_user_id() ) { - return new WP_Error( 'forbidden', __( 'You have passed a permissions test but somehow the system is still not showing you as logged in', 'indieauth' ) ); + if ( 0 === \get_current_user_id() ) { + return new \WP_Error( 'forbidden', \__( 'You have passed a permissions test but somehow the system is still not showing you as logged in', 'indieauth' ) ); } return indieauth_get_response(); } diff --git a/includes/class-indieauth-admin.php b/includes/class-indieauth-admin.php deleted file mode 100644 index db3c069..0000000 --- a/includes/class-indieauth-admin.php +++ /dev/null @@ -1,372 +0,0 @@ - __( 'IndieAuth Test', 'indieauth' ), - 'test' => array( $this, 'site_health_header_test' ), - ); - $tests['direct']['indieauth_https'] = array( - 'label' => __( 'SSL Test', 'indieauth' ), - 'test' => array( $this, 'site_health_https_test' ), - ); - return $tests; - } - - - /** - * Site health test for HTTPS. - * - * @return array Test result. - */ - public function site_health_https_test() { - $result = array( - 'label' => __( 'HTTPS Check Passed', 'indieauth' ), - 'status' => 'good', - 'badge' => array( - 'label' => __( 'IndieAuth', 'indieauth' ), - 'color' => 'green', - ), - 'description' => sprintf( - '

%s

', - __( 'You are using HTTPS and IndieAuth will be secure', 'indieauth' ) - ), - 'actions' => '', - 'test' => 'indieauth_https', - ); - - if ( ! is_ssl() ) { - $result['status'] = 'critical'; - $result['label'] = __( 'HTTPS Test Failed', 'indieauth' ); - $result['description'] = sprintf( - '

%s

', - __( 'You are not serving your site via HTTPS. This is a security risk if running IndieAuth.', 'indieauth' ) - ); - $result['actions'] = __( 'We recommend you acquire an SSL Certificate. You can do this for free through Lets Encrypt', 'indieauth' ); - } - - return $result; - } - - /** - * Site health test for authorization headers. - * - * @return array Test result. - */ - public function site_health_header_test() { - $result = array( - 'label' => __( 'Authorization Header Passed', 'indieauth' ), - 'status' => 'good', - 'badge' => array( - 'label' => __( 'IndieAuth', 'indieauth' ), - 'color' => 'green', - ), - 'description' => sprintf( - '

%s

', - __( 'Your hosting provider allows authorization headers to pass so IndieAuth should work', 'indieauth' ) - ), - 'actions' => '', - 'test' => 'indieauth_headers', - ); - - if ( ! self::test_auth() ) { - $result['status'] = 'critical'; - $result['label'] = __( 'Authorization Test Failed', 'indieauth' ); - ob_start(); - include plugin_dir_path( __DIR__ ) . 'templates/authdiagfail.php'; - $result['description'] = ob_get_contents(); - ob_end_clean(); - $result['actions'] = sprintf( '%2$s', 'https://github.com/indieweb/wordpress-indieauth/issues', __( 'If contacting your hosting provider does not work you can open an issue on GitHub and we will try to assist', 'indieauth' ) ); - } - - return $result; - } - - /** - * Handle the auth diagnostic login form. - */ - public function login_form_authdiag() { - $return = ''; - if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] ) { - if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) && 'Bearer SjdWwSPRi9rdNzyKVDiZRkXhm0fxP0lAmksJXNOgwc7SYREqJnDpXky1MCbIW6UNAFqCwXHswKGaps2lSZfwpYEZnIdREikjiKKSE6UJNlJ3NLXyvyFSQdzUiRg531uG' === $_SERVER['HTTP_AUTHORIZATION'] ) { - $return = '

' . esc_html__( 'Authorization Header Found. You should be able to use all clients.', 'indieauth' ) . '

'; - } elseif ( ! empty( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) && 'Bearer SjdWwSPRi9rdNzyKVDiZRkXhm0fxP0lAmksJXNOgwc7SYREqJnDpXky1MCbIW6UNAFqCwXHswKGaps2lSZfwpYEZnIdREikjiKKSE6UJNlJ3NLXyvyFSQdzUiRg531uG' === $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) { - $return = '

' . esc_html__( 'Alternate Header Found. You should be able to use all clients.', 'indieauth' ) . '

'; - } - if ( empty( $return ) ) { - ob_start(); - include plugin_dir_path( __DIR__ ) . 'templates/authdiagfail.php'; - $return = ob_get_contents(); - ob_end_clean(); - } - if ( isset( $_SERVER['HTTP_ACCEPT'] ) && 'application/json' === $_SERVER['HTTP_ACCEPT'] ) { - header( 'Content-Type: application/json' ); - echo wp_json_encode( array( 'message' => esc_html( $return ) ) ); - exit; - } - echo wp_kses( - $return, - array( - 'div' => array( - 'class' => array(), - ), - 'p' => array(), - ) - ); - exit; - } - $args = array( - 'action' => 'authdiag', - ); - $url = add_query_params_to_url( $args, wp_login_url() ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Used in included template. - include plugin_dir_path( __DIR__ ) . 'templates/authdiagtest.php'; - exit; - } - - /** - * Register plugin settings. - */ - public function settings() { - register_setting( - 'indieauth', - 'indieauth_config', - array( - 'type' => 'string', - 'description' => __( 'Configuration option for IndieAuth Plugin', 'indieauth' ), - 'show_in_rest' => true, - 'default' => 'local', - ) - ); - register_setting( - 'indieauth', - 'indieauth_root_user', - array( - 'type' => 'int', - 'description' => __( 'User Who is Represented by the Site URL', 'indieauth' ), - 'show_in_rest' => true, - ) - ); - register_setting( - 'indieauth', - 'indieauth_expires_in', - array( - 'type' => 'number', - 'description' => __( 'IndieAuth Default Expiry Time', 'indieauth' ), - 'show_in_rest' => true, - 'default' => 1209600, // Two Weeks. - ) - ); - } - - - /** - * Initialize admin settings fields. - */ - public function admin_init() { - add_settings_field( 'indieauth_general_settings', __( 'IndieAuth Settings', 'indieauth' ), array( $this, 'general_settings' ), 'general', 'default' ); - - add_settings_section( - 'indieauth', - 'IndieAuth Endpoint Settings', - array( $this, 'endpoint_settings' ), - 'indieauth' - ); - add_settings_field( - 'indieauth_expires_in', - __( 'Default Token Expiration Time', 'indieauth' ), - array( $this, 'numeric_field' ), - 'indieauth', - 'indieauth', - array( - 'label_for' => 'indieauth_expires_in', - 'class' => 'widefat', - 'description' => __( 'Set the Number of Seconds until a Token expires (Default is Two Weeks). 0 to Disable Expiration.', 'indieauth' ), - 'default' => '', - 'min' => 0, - ) - ); - } - - /** - * Render endpoint settings section description. - */ - public static function endpoint_settings() { - esc_html_e( 'These settings control the behavior of the endpoints', 'indieauth' ); - } - - - /** - * Render a numeric settings field. - * - * @param array $args Field arguments. - */ - public static function numeric_field( $args ) { - $props = array(); - if ( array_key_exists( 'min', $args ) && is_numeric( $args['min'] ) ) { - $props[] = 'min=' . $args['min']; - } - if ( array_key_exists( 'max', $args ) && is_numeric( $args['max'] ) ) { - $props[] = 'max=' . $args['max']; - } - if ( array_key_exists( 'step', $args ) && is_numeric( $args['step'] ) ) { - $props[] = 'step=' . $args['step']; - } - $props = implode( ' ', $props ); - printf( '