Bootstrap/Load: Make handling the /favicon.ico requests more flexible.

Previously, `wp_favicon_request()` was introduced in [13205] to avoid a performance hit of serving a full 404 page on every favicon request.

While working as intended, that implementation did not provide a way for theme or plugin authors to manage the behavior of favicon requests.

This changeset implements the following logic (only applied if WordPress is installed in the root directory):

* If there is a Site Icon set in Customizer, redirect `/favicon.ico` requests to that icon.
* Otherwise, use the WordPress logo as a default icon.
* If a physical `/favicon.ico` file exists, do nothing, let the server handle the request.

Handling `/favicon.ico` is now more consistent with handling `/robots.txt` requests.

New functions and hooks:

* Introduce `is_favicon()` conditional tag to complement `is_robots()`.
* Introduce `do_favicon` action to complement `do_robots` and use it in template loader.
* Introduce `do_favicon()` function, hooked to the above action by default, to complement `do_robots()`.
* Introduce `do_faviconico` action to complement `do_robotstxt`, for plugins to override the default behavior.
* Mark `wp_favicon_request()` as deprecated in favor of `do_favicon()`.

Props jonoaldersonwp, birgire, joostdevalk, mukesh27, SergeyBiryukov.
Fixes #47398.

git-svn-id: https://develop.svn.wordpress.org/trunk@47018 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Sergey Biryukov 2019-12-28 21:18:03 +00:00
parent 85c7a64791
commit ef6973b7f0
13 changed files with 89 additions and 16 deletions

View File

@ -19,8 +19,8 @@
* *
* Prevents redirection for feeds, trackbacks, searches, and * Prevents redirection for feeds, trackbacks, searches, and
* admin URLs. Does not redirect on non-pretty-permalink-supporting IIS 7+, * admin URLs. Does not redirect on non-pretty-permalink-supporting IIS 7+,
* page/post previews, WP admin, Trackbacks, robots.txt, searches, or on POST * page/post previews, WP admin, Trackbacks, robots.txt, favicon.ico, searches,
* requests. * or on POST requests.
* *
* Will also attempt to find the correct link when a user enters a URL that does * Will also attempt to find the correct link when a user enters a URL that does
* not exist based on exact WordPress query. Will instead try to parse the URL * not exist based on exact WordPress query. Will instead try to parse the URL
@ -56,7 +56,7 @@ function redirect_canonical( $requested_url = null, $do_redirect = true ) {
} }
} }
if ( is_trackback() || is_search() || is_admin() || is_preview() || is_robots() || ( $is_IIS && ! iis7_supports_permalinks() ) ) { if ( is_trackback() || is_search() || is_admin() || is_preview() || is_robots() || is_favicon() || ( $is_IIS && ! iis7_supports_permalinks() ) ) {
return; return;
} }

View File

@ -390,6 +390,14 @@ class WP_Query {
*/ */
public $is_robots = false; public $is_robots = false;
/**
* Signifies whether the current query is for the favicon.ico file.
*
* @since 5.4.0
* @var bool
*/
public $is_favicon = false;
/** /**
* Signifies whether the current query is for the page_for_posts page. * Signifies whether the current query is for the page_for_posts page.
* *
@ -478,6 +486,7 @@ class WP_Query {
$this->is_attachment = false; $this->is_attachment = false;
$this->is_singular = false; $this->is_singular = false;
$this->is_robots = false; $this->is_robots = false;
$this->is_favicon = false;
$this->is_posts_page = false; $this->is_posts_page = false;
$this->is_post_type_archive = false; $this->is_post_type_archive = false;
} }
@ -744,6 +753,8 @@ class WP_Query {
if ( ! empty( $qv['robots'] ) ) { if ( ! empty( $qv['robots'] ) ) {
$this->is_robots = true; $this->is_robots = true;
} elseif ( ! empty( $qv['favicon'] ) ) {
$this->is_favicon = true;
} }
if ( ! is_scalar( $qv['p'] ) || $qv['p'] < 0 ) { if ( ! is_scalar( $qv['p'] ) || $qv['p'] < 0 ) {
@ -957,7 +968,9 @@ class WP_Query {
$this->is_comment_feed = true; $this->is_comment_feed = true;
} }
if ( ! ( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots ) ) { if ( ! ( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed
|| ( defined( 'REST_REQUEST' ) && REST_REQUEST )
|| $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots || $this->is_favicon ) ) {
$this->is_home = true; $this->is_home = true;
} }
@ -4007,7 +4020,7 @@ class WP_Query {
} }
/** /**
* Is the query for the robots file? * Is the query for the robots.txt file?
* *
* @since 3.1.0 * @since 3.1.0
* *
@ -4017,6 +4030,17 @@ class WP_Query {
return (bool) $this->is_robots; return (bool) $this->is_robots;
} }
/**
* Is the query for the favicon.ico file?
*
* @since 5.4.0
*
* @return bool
*/
public function is_favicon() {
return (bool) $this->is_favicon;
}
/** /**
* Is the query for a search? * Is the query for a search?
* *

View File

@ -1259,10 +1259,13 @@ class WP_Rewrite {
return $rewrite; return $rewrite;
} }
// robots.txt -only if installed at the root // robots.txt -- only if installed at the root
$home_path = parse_url( home_url() ); $home_path = parse_url( home_url() );
$robots_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'robots\.txt$' => $this->index . '?robots=1' ) : array(); $robots_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'robots\.txt$' => $this->index . '?robots=1' ) : array();
// favicon.ico -- only if installed at the root
$favicon_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'favicon\.ico$' => $this->index . '?favicon=1' ) : array();
// Old feed and service files. // Old feed and service files.
$deprecated_files = array( $deprecated_files = array(
'.*wp-(atom|rdf|rss|rss2|feed|commentsrss2)\.php$' => $this->index . '?feed=old', '.*wp-(atom|rdf|rss|rss2|feed|commentsrss2)\.php$' => $this->index . '?feed=old',
@ -1419,9 +1422,9 @@ class WP_Rewrite {
// Put them together. // Put them together.
if ( $this->use_verbose_page_rules ) { if ( $this->use_verbose_page_rules ) {
$this->rules = array_merge( $this->extra_rules_top, $robots_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $author_rewrite, $date_rewrite, $page_rewrite, $post_rewrite, $this->extra_rules ); $this->rules = array_merge( $this->extra_rules_top, $robots_rewrite, $favicon_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $author_rewrite, $date_rewrite, $page_rewrite, $post_rewrite, $this->extra_rules );
} else { } else {
$this->rules = array_merge( $this->extra_rules_top, $robots_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules ); $this->rules = array_merge( $this->extra_rules_top, $robots_rewrite, $favicon_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules );
} }
/** /**

View File

@ -14,7 +14,7 @@ class WP {
* @since 2.0.0 * @since 2.0.0
* @var string[] * @var string[]
*/ */
public $public_query_vars = array( 'm', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' ); public $public_query_vars = array( 'm', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'favicon', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' );
/** /**
* Private query variables. * Private query variables.
@ -659,8 +659,8 @@ class WP {
return; return;
} }
// Never 404 for the admin, robots, or if we found posts. // Never 404 for the admin, robots, favicon, or if we found posts.
if ( is_admin() || is_robots() || $wp_query->posts ) { if ( is_admin() || is_robots() || is_favicon() || $wp_query->posts ) {
$success = true; $success = true;
if ( is_singular() ) { if ( is_singular() ) {

View File

@ -338,6 +338,7 @@ add_action( 'do_feed_rss2', 'do_feed_rss2', 10, 1 );
add_action( 'do_feed_atom', 'do_feed_atom', 10, 1 ); add_action( 'do_feed_atom', 'do_feed_atom', 10, 1 );
add_action( 'do_pings', 'do_all_pings', 10, 0 ); add_action( 'do_pings', 'do_all_pings', 10, 0 );
add_action( 'do_robots', 'do_robots' ); add_action( 'do_robots', 'do_robots' );
add_action( 'do_favicon', 'do_favicon' );
add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 3 ); add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 3 );
add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' ); add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' );
add_action( 'admin_print_scripts', 'print_emoji_detection_script' ); add_action( 'admin_print_scripts', 'print_emoji_detection_script' );

View File

@ -1636,6 +1636,23 @@ function do_robots() {
echo apply_filters( 'robots_txt', $output, $public ); echo apply_filters( 'robots_txt', $output, $public );
} }
/**
* Display the favicon.ico file content.
*
* @since 5.4.0
*/
function do_favicon() {
/**
* Fires when serving the favicon.ico file.
*
* @since 5.4.0
*/
do_action( 'do_faviconico' );
wp_redirect( get_site_icon_url( 32, admin_url( 'images/w-logo-blue.png' ) ) );
exit;
}
/** /**
* Determines whether WordPress is already installed. * Determines whether WordPress is already installed.
* *

View File

@ -160,6 +160,7 @@ function wp_check_php_mysql_versions() {
* Instead, send the headers for a zero-length favicon and bail. * Instead, send the headers for a zero-length favicon and bail.
* *
* @since 3.0.0 * @since 3.0.0
* @deprecated 5.4.0 Deprecated in favor of do_favicon().
*/ */
function wp_favicon_request() { function wp_favicon_request() {
if ( '/favicon.ico' == $_SERVER['REQUEST_URI'] ) { if ( '/favicon.ico' == $_SERVER['REQUEST_URI'] ) {

View File

@ -623,7 +623,7 @@ function is_preview() {
} }
/** /**
* Is the query for the robots file? * Is the query for the robots.txt file?
* *
* @since 2.1.0 * @since 2.1.0
* *
@ -642,6 +642,26 @@ function is_robots() {
return $wp_query->is_robots(); return $wp_query->is_robots();
} }
/**
* Is the query for the favicon.ico file?
*
* @since 5.4.0
*
* @global WP_Query $wp_query WordPress Query object.
*
* @return bool
*/
function is_favicon() {
global $wp_query;
if ( ! isset( $wp_query ) ) {
_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
return false;
}
return $wp_query->is_favicon();
}
/** /**
* Determines whether the query is for a search. * Determines whether the query is for a search.
* *

View File

@ -36,6 +36,14 @@ if ( is_robots() ) {
*/ */
do_action( 'do_robots' ); do_action( 'do_robots' );
return; return;
} elseif ( is_favicon() ) {
/**
* Fired when the template loader determines a favicon.ico request.
*
* @since 5.4.0
*/
do_action( 'do_favicon' );
return;
} elseif ( is_feed() ) { } elseif ( is_feed() ) {
do_feed(); do_feed();
return; return;

View File

@ -20,7 +20,7 @@ $wp_version = '5.4-alpha-46582-src';
* *
* @global int $wp_db_version * @global int $wp_db_version
*/ */
$wp_db_version = 45805; $wp_db_version = 47018;
/** /**
* Holds the TinyMCE version * Holds the TinyMCE version

View File

@ -63,9 +63,6 @@ wp_unregister_GLOBALS();
// Standardize $_SERVER variables across setups. // Standardize $_SERVER variables across setups.
wp_fix_server_vars(); wp_fix_server_vars();
// Check if we have received a request due to missing favicon.ico
wp_favicon_request();
// Check if we're in maintenance mode. // Check if we're in maintenance mode.
wp_maintenance(); wp_maintenance();

View File

@ -962,6 +962,7 @@ abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase {
'is_posts_page', 'is_posts_page',
'is_preview', 'is_preview',
'is_robots', 'is_robots',
'is_favicon',
'is_search', 'is_search',
'is_single', 'is_single',
'is_singular', 'is_singular',

View File

@ -60,6 +60,7 @@ class Tests_Query_Vars extends WP_UnitTestCase {
'subpost_id', 'subpost_id',
'preview', 'preview',
'robots', 'robots',
'favicon',
'taxonomy', 'taxonomy',
'term', 'term',
'cpage', 'cpage',