Hello
should be removed. * @param int $priority Optional. The priority of the handler to be removed (default: 10). */ public function unregister_handler( $id, $priority = 10 ) { unset( $this->handlers[ $priority ][ $id ] ); } /** * Returns embed HTML for a given URL from embed handlers. * * Attempts to convert a URL into embed HTML by checking the URL * against the regex of the registered embed handlers. * * @since 5.5.0 * * @param array $attr { * Shortcode attributes. Optional. * * @type int $width Width of the embed in pixels. * @type int $height Height of the embed in pixels. * } * @param string $url The URL attempting to be embedded. * @return string|false The embed HTML on success, false otherwise. */ public function get_embed_handler_html( $attr, $url ) { $rawattr = $attr; $attr = wp_parse_args( $attr, wp_embed_defaults( $url ) ); ksort( $this->handlers ); foreach ( $this->handlers as $priority => $handlers ) { foreach ( $handlers as $id => $handler ) { if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ); if ( false !== $return ) { /** * Filters the returned embed HTML. * * @since 2.9.0 * * @see WP_Embed::shortcode() * * @param string|false $return The HTML result of the shortcode, or false on failure. * @param string $url The embed URL. * @param array $attr An array of shortcode attributes. */ return apply_filters( 'embed_handler_html', $return, $url, $attr ); } } } } return false; } /** * The do_shortcode() callback function. * * Attempts to convert a URL into embed HTML. Starts by checking the URL against the regex of * the registered embed handlers. If none of the regex matches and it's enabled, then the URL * will be given to the WP_oEmbed class. * * @param array $attr { * Shortcode attributes. Optional. * * @type int $width Width of the embed in pixels. * @type int $height Height of the embed in pixels. * } * @param string $url The URL attempting to be embedded. * @return string|false The embed HTML on success, otherwise the original URL. * `->maybe_make_link()` can return false on failure. */ public function shortcode( $attr, $url = '' ) { $post = get_post(); if ( empty( $url ) && ! empty( $attr['src'] ) ) { $url = $attr['src']; } $this->last_url = $url; if ( empty( $url ) ) { $this->last_attr = $attr; return ''; } $rawattr = $attr; $attr = wp_parse_args( $attr, wp_embed_defaults( $url ) ); $this->last_attr = $attr; /* * KSES converts & into & and we need to undo this. * See https://core.trac.wordpress.org/ticket/11311 */ $url = str_replace( '&', '&', $url ); // Look for known internal handlers. $embed_handler_html = $this->get_embed_handler_html( $rawattr, $url ); if ( false !== $embed_handler_html ) { return $embed_handler_html; } $post_id = ( ! empty( $post->ID ) ) ? $post->ID : null; // Potentially set by WP_Embed::cache_oembed(). if ( ! empty( $this->post_ID ) ) { $post_id = $this->post_ID; } // Check for a cached result (stored as custom post or in the post meta). $key_suffix = md5( $url . serialize( $attr ) ); $cachekey = '_oembed_' . $key_suffix; $cachekey_time = '_oembed_time_' . $key_suffix; /** * Filters the oEmbed TTL value (time to live). * * @since 4.0.0 * * @param int $time Time to live (in seconds). * @param string $url The attempted embed URL. * @param array $attr An array of shortcode attributes. * @param int $post_id Post ID. */ $ttl = apply_filters( 'oembed_ttl', DAY_IN_SECONDS, $url, $attr, $post_id ); $cache = ''; $cache_time = 0; $cached_post_id = $this->find_oembed_post_id( $key_suffix ); if ( $post_id ) { $cache = get_post_meta( $post_id, $cachekey, true ); $cache_time = get_post_meta( $post_id, $cachekey_time, true ); if ( ! $cache_time ) { $cache_time = 0; } } elseif ( $cached_post_id ) { $cached_post = get_post( $cached_post_id ); $cache = $cached_post->post_content; $cache_time = strtotime( $cached_post->post_modified_gmt ); } $cached_recently = ( time() - $cache_time ) < $ttl; if ( $this->usecache || $cached_recently ) { // Failures are cached. Serve one if we're using the cache. if ( '{{unknown}}' === $cache ) { return $this->maybe_make_link( $url ); } if ( ! empty( $cache ) ) { /** * Filters the cached oEmbed HTML. * * @since 2.9.0 * * @see WP_Embed::shortcode() * * @param string|false $cache The cached HTML result, stored in post meta. * @param string $url The attempted embed URL. * @param array $attr An array of shortcode attributes. * @param int $post_id Post ID. */ return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_id ); } } /** * Filters whether to inspect the given URL for discoverable link tags. * * @since 2.9.0 * @since 4.4.0 The default value changed to true. * * @see WP_oEmbed::discover() * * @param bool $enable Whether to enable `` tag discovery. Default true. */ $attr['discover'] = apply_filters( 'embed_oembed_discover', true ); // Use oEmbed to get the HTML. $html = wp_oembed_get( $url, $attr ); if ( $post_id ) { if ( $html ) { update_post_meta( $post_id, $cachekey, $html ); update_post_meta( $post_id, $cachekey_time, time() ); } elseif ( ! $cache ) { update_post_meta( $post_id, $cachekey, '{{unknown}}' ); } } else { $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ); if ( $has_kses ) { // Prevent KSES from corrupting JSON in post_content. kses_remove_filters(); } $insert_post_args = array( 'post_name' => $key_suffix, 'post_status' => 'publish', 'post_type' => 'oembed_cache', ); if ( $html ) { if ( $cached_post_id ) { wp_update_post( wp_slash( array( 'ID' => $cached_post_id, 'post_content' => $html, ) ) ); } else { wp_insert_post( wp_slash( array_merge( $insert_post_args, array( 'post_content' => $html, ) ) ) ); } } elseif ( ! $cache ) { wp_insert_post( wp_slash( array_merge( $insert_post_args, array( 'post_content' => '{{unknown}}', ) ) ) ); } if ( $has_kses ) { kses_init_filters(); } } // If there was a result, return it. if ( $html ) { /** This filter is documented in wp-includes/class-wp-embed.php */ return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_id ); } // Still unknown. return $this->maybe_make_link( $url ); } /** * Deletes all oEmbed caches. Unused by core as of 4.0.0. * * @param int $post_id Post ID to delete the caches for. */ public function delete_oembed_caches( $post_id ) { $post_metas = get_post_custom_keys( $post_id ); if ( empty( $post_metas ) ) { return; } foreach ( $post_metas as $post_meta_key ) { if ( str_starts_with( $post_meta_key, '_oembed_' ) ) { delete_post_meta( $post_id, $post_meta_key ); } } } /** * Triggers a caching of all oEmbed results. * * @param int $post_id Post ID to do the caching for. */ public function cache_oembed( $post_id ) { $post = get_post( $post_id ); $post_types = get_post_types( array( 'show_ui' => true ) ); /** * Filters the array of post types to cache oEmbed results for. * * @since 2.9.0 * * @param string[] $post_types Array of post type names to cache oEmbed results for. Defaults to post types with `show_ui` set to true. */ $cache_oembed_types = apply_filters( 'embed_cache_oembed_types', $post_types ); if ( empty( $post->ID ) || ! in_array( $post->post_type, $cache_oembed_types, true ) ) { return; } // Trigger a caching. if ( ! empty( $post->post_content ) ) { $this->post_ID = $post->ID; $this->usecache = false; $content = $this->run_shortcode( $post->post_content ); $this->autoembed( $content ); $this->usecache = true; } } /** * Passes any unlinked URLs that are on their own line to WP_Embed::shortcode() for potential embedding. * * @see WP_Embed::autoembed_callback() * * @param string $content The content to be searched. * @return string Potentially modified $content. */ public function autoembed( $content ) { // Replace line breaks from all HTML elements with placeholders. $content = wp_replace_in_html_tags( $content, array( "\n" => '' ) ); if ( preg_match( '#(^|\s|>)https?://#i', $content ) ) { // Find URLs on their own line. $content = preg_replace_callback( '|^(\s*)(https?://[^\s<>"]+)(\s*)$|im', array( $this, 'autoembed_callback' ), $content ); // Find URLs in their own paragraph. $content = preg_replace_callback( '|(
]*)?>\s*)(https?://[^\s<>"]+)(\s*<\/p>)|i', array( $this, 'autoembed_callback' ), $content );
}
// Put the line breaks back.
return str_replace( '', "\n", $content );
}
/**
* Callback function for WP_Embed::autoembed().
*
* @param array $matches A regex match array.
* @return string The embed HTML on success, otherwise the original URL.
*/
public function autoembed_callback( $matches ) {
$oldval = $this->linkifunknown;
$this->linkifunknown = false;
$return = $this->shortcode( array(), $matches[2] );
$this->linkifunknown = $oldval;
return $matches[1] . $return . $matches[3];
}
/**
* Conditionally makes a hyperlink based on an internal class variable.
*
* @param string $url URL to potentially be linked.
* @return string|false Linked URL or the original URL. False if 'return_false_on_fail' is true.
*/
public function maybe_make_link( $url ) {
if ( $this->return_false_on_fail ) {
return false;
}
$output = ( $this->linkifunknown ) ? '' . esc_html( $url ) . '' : $url;
/**
* Filters the returned, maybe-linked embed URL.
*
* @since 2.9.0
*
* @param string $output The linked or original URL.
* @param string $url The original URL.
*/
return apply_filters( 'embed_maybe_make_link', $output, $url );
}
/**
* Finds the oEmbed cache post ID for a given cache key.
*
* @since 4.9.0
*
* @param string $cache_key oEmbed cache key.
* @return int|null Post ID on success, null on failure.
*/
public function find_oembed_post_id( $cache_key ) {
$cache_group = 'oembed_cache_post';
$oembed_post_id = wp_cache_get( $cache_key, $cache_group );
if ( $oembed_post_id && 'oembed_cache' === get_post_type( $oembed_post_id ) ) {
return $oembed_post_id;
}
$oembed_post_query = new WP_Query(
array(
'post_type' => 'oembed_cache',
'post_status' => 'publish',
'name' => $cache_key,
'posts_per_page' => 1,
'no_found_rows' => true,
'cache_results' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'lazy_load_term_meta' => false,
)
);
if ( ! empty( $oembed_post_query->posts ) ) {
// Note: 'fields' => 'ids' is not being used in order to cache the post object as it will be needed.
$oembed_post_id = $oembed_post_query->posts[0]->ID;
wp_cache_set( $cache_key, $oembed_post_id, $cache_group );
return $oembed_post_id;
}
return null;
}
}
or other layouts.' ),
)
);
register_block_pattern_category(
'footer',
array(
'label' => _x( 'Footers', 'Block pattern category' ),
'description' => __( 'A variety of footer designs displaying information and site navigation.' ),
)
);
register_block_pattern_category(
'header',
array(
'label' => _x( 'Headers', 'Block pattern category' ),
'description' => __( 'A variety of header designs displaying your site title and navigation.' ),
)
);
}
/**
* Normalize the pattern properties to camelCase.
*
* The API's format is snake_case, `register_block_pattern()` expects camelCase.
*
* @since 6.2.0
* @access private
*
* @param array $pattern Pattern as returned from the Pattern Directory API.
* @return array Normalized pattern.
*/
function wp_normalize_remote_block_pattern( $pattern ) {
if ( isset( $pattern['block_types'] ) ) {
$pattern['blockTypes'] = $pattern['block_types'];
unset( $pattern['block_types'] );
}
if ( isset( $pattern['viewport_width'] ) ) {
$pattern['viewportWidth'] = $pattern['viewport_width'];
unset( $pattern['viewport_width'] );
}
return (array) $pattern;
}
/**
* Register Core's official patterns from wordpress.org/patterns.
*
* @since 5.8.0
* @since 5.9.0 The $current_screen argument was removed.
* @since 6.2.0 Normalize the pattern from the API (snake_case) to the
* format expected by `register_block_pattern` (camelCase).
* @since 6.3.0 Add 'pattern-directory/core' to the pattern's 'source'.
*
* @param WP_Screen $deprecated Unused. Formerly the screen that the current request was triggered from.
*/
function _load_remote_block_patterns( $deprecated = null ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '5.9.0' );
$current_screen = $deprecated;
if ( ! $current_screen->is_block_editor ) {
return;
}
}
$supports_core_patterns = get_theme_support( 'core-block-patterns' );
/**
* Filter to disable remote block patterns.
*
* @since 5.8.0
*
* @param bool $should_load_remote
*/
$should_load_remote = apply_filters( 'should_load_remote_block_patterns', true );
if ( $supports_core_patterns && $should_load_remote ) {
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
$core_keyword_id = 11; // 11 is the ID for "core".
$request->set_param( 'keyword', $core_keyword_id );
$response = rest_do_request( $request );
if ( $response->is_error() ) {
return;
}
$patterns = $response->get_data();
foreach ( $patterns as $pattern ) {
$pattern['source'] = 'pattern-directory/core';
$normalized_pattern = wp_normalize_remote_block_pattern( $pattern );
$pattern_name = 'core/' . sanitize_title( $normalized_pattern['title'] );
register_block_pattern( $pattern_name, $normalized_pattern );
}
}
}
/**
* Register `Featured` (category) patterns from wordpress.org/patterns.
*
* @since 5.9.0
* @since 6.2.0 Normalized the pattern from the API (snake_case) to the
* format expected by `register_block_pattern()` (camelCase).
* @since 6.3.0 Add 'pattern-directory/featured' to the pattern's 'source'.
*/
function _load_remote_featured_patterns() {
$supports_core_patterns = get_theme_support( 'core-block-patterns' );
/** This filter is documented in wp-includes/block-patterns.php */
$should_load_remote = apply_filters( 'should_load_remote_block_patterns', true );
if ( ! $should_load_remote || ! $supports_core_patterns ) {
return;
}
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
$featured_cat_id = 26; // This is the `Featured` category id from pattern directory.
$request->set_param( 'category', $featured_cat_id );
$response = rest_do_request( $request );
if ( $response->is_error() ) {
return;
}
$patterns = $response->get_data();
$registry = WP_Block_Patterns_Registry::get_instance();
foreach ( $patterns as $pattern ) {
$pattern['source'] = 'pattern-directory/featured';
$normalized_pattern = wp_normalize_remote_block_pattern( $pattern );
$pattern_name = sanitize_title( $normalized_pattern['title'] );
// Some patterns might be already registered as core patterns with the `core` prefix.
$is_registered = $registry->is_registered( $pattern_name ) || $registry->is_registered( "core/$pattern_name" );
if ( ! $is_registered ) {
register_block_pattern( $pattern_name, $normalized_pattern );
}
}
}
/**
* Registers patterns from Pattern Directory provided by a theme's
* `theme.json` file.
*
* @since 6.0.0
* @since 6.2.0 Normalized the pattern from the API (snake_case) to the
* format expected by `register_block_pattern()` (camelCase).
* @since 6.3.0 Add 'pattern-directory/theme' to the pattern's 'source'.
* @access private
*/
function _register_remote_theme_patterns() {
/** This filter is documented in wp-includes/block-patterns.php */
if ( ! apply_filters( 'should_load_remote_block_patterns', true ) ) {
return;
}
if ( ! wp_theme_has_theme_json() ) {
return;
}
$pattern_settings = wp_get_theme_directory_pattern_slugs();
if ( empty( $pattern_settings ) ) {
return;
}
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
$request['slug'] = $pattern_settings;
$response = rest_do_request( $request );
if ( $response->is_error() ) {
return;
}
$patterns = $response->get_data();
$patterns_registry = WP_Block_Patterns_Registry::get_instance();
foreach ( $patterns as $pattern ) {
$pattern['source'] = 'pattern-directory/theme';
$normalized_pattern = wp_normalize_remote_block_pattern( $pattern );
$pattern_name = sanitize_title( $normalized_pattern['title'] );
// Some patterns might be already registered as core patterns with the `core` prefix.
$is_registered = $patterns_registry->is_registered( $pattern_name ) || $patterns_registry->is_registered( "core/$pattern_name" );
if ( ! $is_registered ) {
register_block_pattern( $pattern_name, $normalized_pattern );
}
}
}
/**
* Register any patterns that the active theme may provide under its
* `./patterns/` directory. Each pattern is defined as a PHP file and defines
* its metadata using plugin-style headers. The minimum required definition is:
*
* /**
* * Title: My Pattern
* * Slug: my-theme/my-pattern
* *
*
* The output of the PHP source corresponds to the content of the pattern, e.g.:
*
* Hello