or_block_count' => (int) $plugin['author_block_count'], 'author' => wp_strip_all_tags( $plugin['author'] ), 'icon' => ( isset( $plugin['icons']['1x'] ) ? $plugin['icons']['1x'] : 'block-default' ), 'last_updated' => gmdate( 'Y-m-d\TH:i:s', strtotime( $plugin['last_updated'] ) ), 'humanized_updated' => sprintf( /* translators: %s: Human-readable time difference. */ __( '%s ago' ), human_time_diff( strtotime( $plugin['last_updated'] ) ) ), ); $this->add_additional_fields_to_object( $block, $request ); $response = new WP_REST_Response( $block ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $plugin ) ); } return $response; } /** * Generates a list of links to include in the response for the plugin. * * @since 5.5.0 * * @param array $plugin The plugin data from WordPress.org. * @return array */ protected function prepare_links( $plugin ) { $links = array( 'https://api.w.org/install-plugin' => array( 'href' => add_query_arg( 'slug', urlencode( $plugin['slug'] ), rest_url( 'wp/v2/plugins' ) ), ), ); $plugin_file = $this->find_plugin_for_slug( $plugin['slug'] ); if ( $plugin_file ) { $links['https://api.w.org/plugin'] = array( 'href' => rest_url( 'wp/v2/plugins/' . substr( $plugin_file, 0, - 4 ) ), 'embeddable' => true, ); } return $links; } /** * Finds an installed plugin for the given slug. * * @since 5.5.0 * * @param string $slug The WordPress.org directory slug for a plugin. * @return string The plugin file found matching it. */ protected function find_plugin_for_slug( $slug ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; $plugin_files = get_plugins( '/' . $slug ); if ( ! $plugin_files ) { return ''; } $plugin_files = array_keys( $plugin_files ); return $slug . '/' . reset( $plugin_files ); } /** * Retrieves the theme's schema, conforming to JSON Schema. * * @since 5.5.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'block-directory-item', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The block name, in namespace/block-name format.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'title' => array( 'description' => __( 'The block title, in human readable format.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'description' => array( 'description' => __( 'A short description of the block, in human readable format.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'id' => array( 'description' => __( 'The block slug.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'rating' => array( 'description' => __( 'The star rating of the block.' ), 'type' => 'number', 'context' => array( 'view' ), ), 'rating_count' => array( 'description' => __( 'The number of ratings.' ), 'type' => 'integer', 'context' => array( 'view' ), ), 'active_installs' => array( 'description' => __( 'The number sites that have activated this block.' ), 'type' => 'integer', 'context' => array( 'view' ), ), 'author_block_rating' => array( 'description' => __( 'The average rating of blocks published by the same author.' ), 'type' => 'number', 'context' => array( 'view' ), ), 'author_block_count' => array( 'description' => __( 'The number of blocks published by the same author.' ), 'type' => 'integer', 'context' => array( 'view' ), ), 'author' => array( 'description' => __( 'The WordPress.org username of the block author.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'icon' => array( 'description' => __( 'The block icon.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view' ), ), 'last_updated' => array( 'description' => __( 'The date when the block was last updated.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view' ), ), 'humanized_updated' => array( 'description' => __( 'The date when the block was last updated, in fuzzy human readable format.' ), 'type' => 'string', 'context' => array( 'view' ), ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the search params for the blocks collection. * * @since 5.5.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['term'] = array( 'description' => __( 'Limit result set to blocks matching the search term.' ), 'type' => 'string', 'required' => true, 'minLength' => 1, ); unset( $query_params['search'] ); /** * Filters REST API collection parameters for the block directory controller. * * @since 5.5.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_block_directory_collection_params', $query_params ); } } dd_action( 'admin_init', [ $this, 'list_table_search' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); add_filter( 'set-screen-option', [ $this, 'set_screen_option' ], 11, 3 ); } } /** * Initialize the AJAX redirect files. */ private function initialize_ajax() { // Normal Redirect AJAX. new WPSEO_Redirect_Ajax( WPSEO_Redirect_Formats::PLAIN ); // Regex Redirect AJAX. new WPSEO_Redirect_Ajax( WPSEO_Redirect_Formats::REGEX ); } /** * Getting the current active tab. * * @return string */ private function get_current_tab() { static $current_tab; if ( $current_tab === null ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We're not manipulating the value. if ( isset( $_GET['tab'] ) && is_string( $_GET['tab'] ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended -- value sanitized in the if body, regex filters unwanted values. && in_array( wp_unslash( $_GET['tab'] ), [ WPSEO_Redirect_Formats::PLAIN, WPSEO_Redirect_Formats::REGEX, 'settings' ], true ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- the regex takes care of filtering out unwanted values. $current_tab = sanitize_text_field( wp_unslash( $_GET['tab'] ) ); } else { $current_tab = WPSEO_Redirect_Formats::PLAIN; } } return $current_tab; } /** * Setting redirect manager, based on the current active tab. * * @return WPSEO_Redirect_Manager */ private function get_redirect_manager() { static $redirect_manager; if ( $redirect_manager === null ) { $redirects_format = WPSEO_Redirect_Formats::PLAIN; if ( $this->get_current_tab() === WPSEO_Redirect_Formats::REGEX ) { $redirects_format = WPSEO_Redirect_Formats::REGEX; } $redirect_manager = new WPSEO_Redirect_Manager( $redirects_format ); } return $redirect_manager; } /** * Fetches the bulk action for removing redirects. * * @return void */ private function fetch_bulk_action() { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in wp_verify_none. if ( ! isset( $_POST['wpseo_redirects_ajax_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['wpseo_redirects_ajax_nonce'] ), 'wpseo-redirects-ajax-security' ) ) { return; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We're just strictly comparing the value. if ( ( ! isset( $_POST['action'] ) || ! is_string( $_POST['action'] ) || ! wp_unslash( $_POST['action'] ) === 'delete' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We're just strictly comparing the value. && ( ! isset( $_POST['action2'] ) || ! is_string( $_POST['action2'] ) || ! wp_unslash( $_POST['action2'] ) === 'delete' ) ) { return; } if ( ! isset( $_POST['wpseo_redirects_bulk_delete'] ) || ! is_array( $_POST['wpseo_redirects_bulk_delete'] ) ) { return; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Array elements are sanitized one by one in the foreach loop. $bulk_delete = wp_unslash( $_POST['wpseo_redirects_bulk_delete'] ); $redirects = []; foreach ( $bulk_delete as $origin ) { $redirect = $this->get_redirect_manager()->get_redirect( $origin ); if ( $redirect !== false ) { $redirects[] = $redirect; } } $this->get_redirect_manager()->delete_redirects( $redirects ); } }