ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

general-template.php (158208B)


      1 <?php
      2 /**
      3  * General template tags that can go anywhere in a template.
      4  *
      5  * @package WordPress
      6  * @subpackage Template
      7  */
      8 
      9 /**
     10  * Load header template.
     11  *
     12  * Includes the header template for a theme or if a name is specified then a
     13  * specialised header will be included.
     14  *
     15  * For the parameter, if the file is called "header-special.php" then specify
     16  * "special".
     17  *
     18  * @since 1.5.0
     19  * @since 5.5.0 A return value was added.
     20  * @since 5.5.0 The `$args` parameter was added.
     21  *
     22  * @param string $name The name of the specialised header.
     23  * @param array  $args Optional. Additional arguments passed to the header template.
     24  *                     Default empty array.
     25  * @return void|false Void on success, false if the template does not exist.
     26  */
     27 function get_header( $name = null, $args = array() ) {
     28 	/**
     29 	 * Fires before the header template file is loaded.
     30 	 *
     31 	 * @since 2.1.0
     32 	 * @since 2.8.0 The `$name` parameter was added.
     33 	 * @since 5.5.0 The `$args` parameter was added.
     34 	 *
     35 	 * @param string|null $name Name of the specific header file to use. Null for the default header.
     36 	 * @param array       $args Additional arguments passed to the header template.
     37 	 */
     38 	do_action( 'get_header', $name, $args );
     39 
     40 	$templates = array();
     41 	$name      = (string) $name;
     42 	if ( '' !== $name ) {
     43 		$templates[] = "header-{$name}.php";
     44 	}
     45 
     46 	$templates[] = 'header.php';
     47 
     48 	if ( ! locate_template( $templates, true, true, $args ) ) {
     49 		return false;
     50 	}
     51 }
     52 
     53 /**
     54  * Load footer template.
     55  *
     56  * Includes the footer template for a theme or if a name is specified then a
     57  * specialised footer will be included.
     58  *
     59  * For the parameter, if the file is called "footer-special.php" then specify
     60  * "special".
     61  *
     62  * @since 1.5.0
     63  * @since 5.5.0 A return value was added.
     64  * @since 5.5.0 The `$args` parameter was added.
     65  *
     66  * @param string $name The name of the specialised footer.
     67  * @param array  $args Optional. Additional arguments passed to the footer template.
     68  *                     Default empty array.
     69  * @return void|false Void on success, false if the template does not exist.
     70  */
     71 function get_footer( $name = null, $args = array() ) {
     72 	/**
     73 	 * Fires before the footer template file is loaded.
     74 	 *
     75 	 * @since 2.1.0
     76 	 * @since 2.8.0 The `$name` parameter was added.
     77 	 * @since 5.5.0 The `$args` parameter was added.
     78 	 *
     79 	 * @param string|null $name Name of the specific footer file to use. Null for the default footer.
     80 	 * @param array       $args Additional arguments passed to the footer template.
     81 	 */
     82 	do_action( 'get_footer', $name, $args );
     83 
     84 	$templates = array();
     85 	$name      = (string) $name;
     86 	if ( '' !== $name ) {
     87 		$templates[] = "footer-{$name}.php";
     88 	}
     89 
     90 	$templates[] = 'footer.php';
     91 
     92 	if ( ! locate_template( $templates, true, true, $args ) ) {
     93 		return false;
     94 	}
     95 }
     96 
     97 /**
     98  * Load sidebar template.
     99  *
    100  * Includes the sidebar template for a theme or if a name is specified then a
    101  * specialised sidebar will be included.
    102  *
    103  * For the parameter, if the file is called "sidebar-special.php" then specify
    104  * "special".
    105  *
    106  * @since 1.5.0
    107  * @since 5.5.0 A return value was added.
    108  * @since 5.5.0 The `$args` parameter was added.
    109  *
    110  * @param string $name The name of the specialised sidebar.
    111  * @param array  $args Optional. Additional arguments passed to the sidebar template.
    112  *                     Default empty array.
    113  * @return void|false Void on success, false if the template does not exist.
    114  */
    115 function get_sidebar( $name = null, $args = array() ) {
    116 	/**
    117 	 * Fires before the sidebar template file is loaded.
    118 	 *
    119 	 * @since 2.2.0
    120 	 * @since 2.8.0 The `$name` parameter was added.
    121 	 * @since 5.5.0 The `$args` parameter was added.
    122 	 *
    123 	 * @param string|null $name Name of the specific sidebar file to use. Null for the default sidebar.
    124 	 * @param array       $args Additional arguments passed to the sidebar template.
    125 	 */
    126 	do_action( 'get_sidebar', $name, $args );
    127 
    128 	$templates = array();
    129 	$name      = (string) $name;
    130 	if ( '' !== $name ) {
    131 		$templates[] = "sidebar-{$name}.php";
    132 	}
    133 
    134 	$templates[] = 'sidebar.php';
    135 
    136 	if ( ! locate_template( $templates, true, true, $args ) ) {
    137 		return false;
    138 	}
    139 }
    140 
    141 /**
    142  * Loads a template part into a template.
    143  *
    144  * Provides a simple mechanism for child themes to overload reusable sections of code
    145  * in the theme.
    146  *
    147  * Includes the named template part for a theme or if a name is specified then a
    148  * specialised part will be included. If the theme contains no {slug}.php file
    149  * then no template will be included.
    150  *
    151  * The template is included using require, not require_once, so you may include the
    152  * same template part multiple times.
    153  *
    154  * For the $name parameter, if the file is called "{slug}-special.php" then specify
    155  * "special".
    156  *
    157  * @since 3.0.0
    158  * @since 5.5.0 A return value was added.
    159  * @since 5.5.0 The `$args` parameter was added.
    160  *
    161  * @param string $slug The slug name for the generic template.
    162  * @param string $name The name of the specialised template.
    163  * @param array  $args Optional. Additional arguments passed to the template.
    164  *                     Default empty array.
    165  * @return void|false Void on success, false if the template does not exist.
    166  */
    167 function get_template_part( $slug, $name = null, $args = array() ) {
    168 	/**
    169 	 * Fires before the specified template part file is loaded.
    170 	 *
    171 	 * The dynamic portion of the hook name, `$slug`, refers to the slug name
    172 	 * for the generic template part.
    173 	 *
    174 	 * @since 3.0.0
    175 	 * @since 5.5.0 The `$args` parameter was added.
    176 	 *
    177 	 * @param string      $slug The slug name for the generic template.
    178 	 * @param string|null $name The name of the specialized template.
    179 	 * @param array       $args Additional arguments passed to the template.
    180 	 */
    181 	do_action( "get_template_part_{$slug}", $slug, $name, $args );
    182 
    183 	$templates = array();
    184 	$name      = (string) $name;
    185 	if ( '' !== $name ) {
    186 		$templates[] = "{$slug}-{$name}.php";
    187 	}
    188 
    189 	$templates[] = "{$slug}.php";
    190 
    191 	/**
    192 	 * Fires before a template part is loaded.
    193 	 *
    194 	 * @since 5.2.0
    195 	 * @since 5.5.0 The `$args` parameter was added.
    196 	 *
    197 	 * @param string   $slug      The slug name for the generic template.
    198 	 * @param string   $name      The name of the specialized template.
    199 	 * @param string[] $templates Array of template files to search for, in order.
    200 	 * @param array    $args      Additional arguments passed to the template.
    201 	 */
    202 	do_action( 'get_template_part', $slug, $name, $templates, $args );
    203 
    204 	if ( ! locate_template( $templates, true, false, $args ) ) {
    205 		return false;
    206 	}
    207 }
    208 
    209 /**
    210  * Display search form.
    211  *
    212  * Will first attempt to locate the searchform.php file in either the child or
    213  * the parent, then load it. If it doesn't exist, then the default search form
    214  * will be displayed. The default search form is HTML, which will be displayed.
    215  * There is a filter applied to the search form HTML in order to edit or replace
    216  * it. The filter is {@see 'get_search_form'}.
    217  *
    218  * This function is primarily used by themes which want to hardcode the search
    219  * form into the sidebar and also by the search widget in WordPress.
    220  *
    221  * There is also an action that is called whenever the function is run called,
    222  * {@see 'pre_get_search_form'}. This can be useful for outputting JavaScript that the
    223  * search relies on or various formatting that applies to the beginning of the
    224  * search. To give a few examples of what it can be used for.
    225  *
    226  * @since 2.7.0
    227  * @since 5.2.0 The `$args` array parameter was added in place of an `$echo` boolean flag.
    228  *
    229  * @param array $args {
    230  *     Optional. Array of display arguments.
    231  *
    232  *     @type bool   $echo       Whether to echo or return the form. Default true.
    233  *     @type string $aria_label ARIA label for the search form. Useful to distinguish
    234  *                              multiple search forms on the same page and improve
    235  *                              accessibility. Default empty.
    236  * }
    237  * @return void|string Void if 'echo' argument is true, search form HTML if 'echo' is false.
    238  */
    239 function get_search_form( $args = array() ) {
    240 	/**
    241 	 * Fires before the search form is retrieved, at the start of get_search_form().
    242 	 *
    243 	 * @since 2.7.0 as 'get_search_form' action.
    244 	 * @since 3.6.0
    245 	 * @since 5.5.0 The `$args` parameter was added.
    246 	 *
    247 	 * @link https://core.trac.wordpress.org/ticket/19321
    248 	 *
    249 	 * @param array $args The array of arguments for building the search form.
    250 	 *                    See get_search_form() for information on accepted arguments.
    251 	 */
    252 	do_action( 'pre_get_search_form', $args );
    253 
    254 	$echo = true;
    255 
    256 	if ( ! is_array( $args ) ) {
    257 		/*
    258 		 * Back compat: to ensure previous uses of get_search_form() continue to
    259 		 * function as expected, we handle a value for the boolean $echo param removed
    260 		 * in 5.2.0. Then we deal with the $args array and cast its defaults.
    261 		 */
    262 		$echo = (bool) $args;
    263 
    264 		// Set an empty array and allow default arguments to take over.
    265 		$args = array();
    266 	}
    267 
    268 	// Defaults are to echo and to output no custom label on the form.
    269 	$defaults = array(
    270 		'echo'       => $echo,
    271 		'aria_label' => '',
    272 	);
    273 
    274 	$args = wp_parse_args( $args, $defaults );
    275 
    276 	/**
    277 	 * Filters the array of arguments used when generating the search form.
    278 	 *
    279 	 * @since 5.2.0
    280 	 *
    281 	 * @param array $args The array of arguments for building the search form.
    282 	 *                    See get_search_form() for information on accepted arguments.
    283 	 */
    284 	$args = apply_filters( 'search_form_args', $args );
    285 
    286 	// Ensure that the filtered arguments contain all required default values.
    287 	$args = array_merge( $defaults, $args );
    288 
    289 	$format = current_theme_supports( 'html5', 'search-form' ) ? 'html5' : 'xhtml';
    290 
    291 	/**
    292 	 * Filters the HTML format of the search form.
    293 	 *
    294 	 * @since 3.6.0
    295 	 * @since 5.5.0 The `$args` parameter was added.
    296 	 *
    297 	 * @param string $format The type of markup to use in the search form.
    298 	 *                       Accepts 'html5', 'xhtml'.
    299 	 * @param array  $args   The array of arguments for building the search form.
    300 	 *                       See get_search_form() for information on accepted arguments.
    301 	 */
    302 	$format = apply_filters( 'search_form_format', $format, $args );
    303 
    304 	$search_form_template = locate_template( 'searchform.php' );
    305 
    306 	if ( '' !== $search_form_template ) {
    307 		ob_start();
    308 		require $search_form_template;
    309 		$form = ob_get_clean();
    310 	} else {
    311 		// Build a string containing an aria-label to use for the search form.
    312 		if ( $args['aria_label'] ) {
    313 			$aria_label = 'aria-label="' . esc_attr( $args['aria_label'] ) . '" ';
    314 		} else {
    315 			/*
    316 			 * If there's no custom aria-label, we can set a default here. At the
    317 			 * moment it's empty as there's uncertainty about what the default should be.
    318 			 */
    319 			$aria_label = '';
    320 		}
    321 
    322 		if ( 'html5' === $format ) {
    323 			$form = '<form role="search" ' . $aria_label . 'method="get" class="search-form" action="' . esc_url( home_url( '/' ) ) . '">
    324 				<label>
    325 					<span class="screen-reader-text">' . _x( 'Search for:', 'label' ) . '</span>
    326 					<input type="search" class="search-field" placeholder="' . esc_attr_x( 'Search &hellip;', 'placeholder' ) . '" value="' . get_search_query() . '" name="s" />
    327 				</label>
    328 				<input type="submit" class="search-submit" value="' . esc_attr_x( 'Search', 'submit button' ) . '" />
    329 			</form>';
    330 		} else {
    331 			$form = '<form role="search" ' . $aria_label . 'method="get" id="searchform" class="searchform" action="' . esc_url( home_url( '/' ) ) . '">
    332 				<div>
    333 					<label class="screen-reader-text" for="s">' . _x( 'Search for:', 'label' ) . '</label>
    334 					<input type="text" value="' . get_search_query() . '" name="s" id="s" />
    335 					<input type="submit" id="searchsubmit" value="' . esc_attr_x( 'Search', 'submit button' ) . '" />
    336 				</div>
    337 			</form>';
    338 		}
    339 	}
    340 
    341 	/**
    342 	 * Filters the HTML output of the search form.
    343 	 *
    344 	 * @since 2.7.0
    345 	 * @since 5.5.0 The `$args` parameter was added.
    346 	 *
    347 	 * @param string $form The search form HTML output.
    348 	 * @param array  $args The array of arguments for building the search form.
    349 	 *                     See get_search_form() for information on accepted arguments.
    350 	 */
    351 	$result = apply_filters( 'get_search_form', $form, $args );
    352 
    353 	if ( null === $result ) {
    354 		$result = $form;
    355 	}
    356 
    357 	if ( $args['echo'] ) {
    358 		echo $result;
    359 	} else {
    360 		return $result;
    361 	}
    362 }
    363 
    364 /**
    365  * Display the Log In/Out link.
    366  *
    367  * Displays a link, which allows users to navigate to the Log In page to log in
    368  * or log out depending on whether they are currently logged in.
    369  *
    370  * @since 1.5.0
    371  *
    372  * @param string $redirect Optional path to redirect to on login/logout.
    373  * @param bool   $echo     Default to echo and not return the link.
    374  * @return void|string Void if `$echo` argument is true, log in/out link if `$echo` is false.
    375  */
    376 function wp_loginout( $redirect = '', $echo = true ) {
    377 	if ( ! is_user_logged_in() ) {
    378 		$link = '<a href="' . esc_url( wp_login_url( $redirect ) ) . '">' . __( 'Log in' ) . '</a>';
    379 	} else {
    380 		$link = '<a href="' . esc_url( wp_logout_url( $redirect ) ) . '">' . __( 'Log out' ) . '</a>';
    381 	}
    382 
    383 	if ( $echo ) {
    384 		/**
    385 		 * Filters the HTML output for the Log In/Log Out link.
    386 		 *
    387 		 * @since 1.5.0
    388 		 *
    389 		 * @param string $link The HTML link content.
    390 		 */
    391 		echo apply_filters( 'loginout', $link );
    392 	} else {
    393 		/** This filter is documented in wp-includes/general-template.php */
    394 		return apply_filters( 'loginout', $link );
    395 	}
    396 }
    397 
    398 /**
    399  * Retrieves the logout URL.
    400  *
    401  * Returns the URL that allows the user to log out of the site.
    402  *
    403  * @since 2.7.0
    404  *
    405  * @param string $redirect Path to redirect to on logout.
    406  * @return string The logout URL. Note: HTML-encoded via esc_html() in wp_nonce_url().
    407  */
    408 function wp_logout_url( $redirect = '' ) {
    409 	$args = array();
    410 	if ( ! empty( $redirect ) ) {
    411 		$args['redirect_to'] = urlencode( $redirect );
    412 	}
    413 
    414 	$logout_url = add_query_arg( $args, site_url( 'wp-login.php?action=logout', 'login' ) );
    415 	$logout_url = wp_nonce_url( $logout_url, 'log-out' );
    416 
    417 	/**
    418 	 * Filters the logout URL.
    419 	 *
    420 	 * @since 2.8.0
    421 	 *
    422 	 * @param string $logout_url The HTML-encoded logout URL.
    423 	 * @param string $redirect   Path to redirect to on logout.
    424 	 */
    425 	return apply_filters( 'logout_url', $logout_url, $redirect );
    426 }
    427 
    428 /**
    429  * Retrieves the login URL.
    430  *
    431  * @since 2.7.0
    432  *
    433  * @param string $redirect     Path to redirect to on log in.
    434  * @param bool   $force_reauth Whether to force reauthorization, even if a cookie is present.
    435  *                             Default false.
    436  * @return string The login URL. Not HTML-encoded.
    437  */
    438 function wp_login_url( $redirect = '', $force_reauth = false ) {
    439 	$login_url = site_url( 'wp-login.php', 'login' );
    440 
    441 	if ( ! empty( $redirect ) ) {
    442 		$login_url = add_query_arg( 'redirect_to', urlencode( $redirect ), $login_url );
    443 	}
    444 
    445 	if ( $force_reauth ) {
    446 		$login_url = add_query_arg( 'reauth', '1', $login_url );
    447 	}
    448 
    449 	/**
    450 	 * Filters the login URL.
    451 	 *
    452 	 * @since 2.8.0
    453 	 * @since 4.2.0 The `$force_reauth` parameter was added.
    454 	 *
    455 	 * @param string $login_url    The login URL. Not HTML-encoded.
    456 	 * @param string $redirect     The path to redirect to on login, if supplied.
    457 	 * @param bool   $force_reauth Whether to force reauthorization, even if a cookie is present.
    458 	 */
    459 	return apply_filters( 'login_url', $login_url, $redirect, $force_reauth );
    460 }
    461 
    462 /**
    463  * Returns the URL that allows the user to register on the site.
    464  *
    465  * @since 3.6.0
    466  *
    467  * @return string User registration URL.
    468  */
    469 function wp_registration_url() {
    470 	/**
    471 	 * Filters the user registration URL.
    472 	 *
    473 	 * @since 3.6.0
    474 	 *
    475 	 * @param string $register The user registration URL.
    476 	 */
    477 	return apply_filters( 'register_url', site_url( 'wp-login.php?action=register', 'login' ) );
    478 }
    479 
    480 /**
    481  * Provides a simple login form for use anywhere within WordPress.
    482  *
    483  * The login form HTML is echoed by default. Pass a false value for `$echo` to return it instead.
    484  *
    485  * @since 3.0.0
    486  *
    487  * @param array $args {
    488  *     Optional. Array of options to control the form output. Default empty array.
    489  *
    490  *     @type bool   $echo           Whether to display the login form or return the form HTML code.
    491  *                                  Default true (echo).
    492  *     @type string $redirect       URL to redirect to. Must be absolute, as in "https://example.com/mypage/".
    493  *                                  Default is to redirect back to the request URI.
    494  *     @type string $form_id        ID attribute value for the form. Default 'loginform'.
    495  *     @type string $label_username Label for the username or email address field. Default 'Username or Email Address'.
    496  *     @type string $label_password Label for the password field. Default 'Password'.
    497  *     @type string $label_remember Label for the remember field. Default 'Remember Me'.
    498  *     @type string $label_log_in   Label for the submit button. Default 'Log In'.
    499  *     @type string $id_username    ID attribute value for the username field. Default 'user_login'.
    500  *     @type string $id_password    ID attribute value for the password field. Default 'user_pass'.
    501  *     @type string $id_remember    ID attribute value for the remember field. Default 'rememberme'.
    502  *     @type string $id_submit      ID attribute value for the submit button. Default 'wp-submit'.
    503  *     @type bool   $remember       Whether to display the "rememberme" checkbox in the form.
    504  *     @type string $value_username Default value for the username field. Default empty.
    505  *     @type bool   $value_remember Whether the "Remember Me" checkbox should be checked by default.
    506  *                                  Default false (unchecked).
    507  *
    508  * }
    509  * @return void|string Void if 'echo' argument is true, login form HTML if 'echo' is false.
    510  */
    511 function wp_login_form( $args = array() ) {
    512 	$defaults = array(
    513 		'echo'           => true,
    514 		// Default 'redirect' value takes the user back to the request URI.
    515 		'redirect'       => ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'],
    516 		'form_id'        => 'loginform',
    517 		'label_username' => __( 'Username or Email Address' ),
    518 		'label_password' => __( 'Password' ),
    519 		'label_remember' => __( 'Remember Me' ),
    520 		'label_log_in'   => __( 'Log In' ),
    521 		'id_username'    => 'user_login',
    522 		'id_password'    => 'user_pass',
    523 		'id_remember'    => 'rememberme',
    524 		'id_submit'      => 'wp-submit',
    525 		'remember'       => true,
    526 		'value_username' => '',
    527 		// Set 'value_remember' to true to default the "Remember me" checkbox to checked.
    528 		'value_remember' => false,
    529 	);
    530 
    531 	/**
    532 	 * Filters the default login form output arguments.
    533 	 *
    534 	 * @since 3.0.0
    535 	 *
    536 	 * @see wp_login_form()
    537 	 *
    538 	 * @param array $defaults An array of default login form arguments.
    539 	 */
    540 	$args = wp_parse_args( $args, apply_filters( 'login_form_defaults', $defaults ) );
    541 
    542 	/**
    543 	 * Filters content to display at the top of the login form.
    544 	 *
    545 	 * The filter evaluates just following the opening form tag element.
    546 	 *
    547 	 * @since 3.0.0
    548 	 *
    549 	 * @param string $content Content to display. Default empty.
    550 	 * @param array  $args    Array of login form arguments.
    551 	 */
    552 	$login_form_top = apply_filters( 'login_form_top', '', $args );
    553 
    554 	/**
    555 	 * Filters content to display in the middle of the login form.
    556 	 *
    557 	 * The filter evaluates just following the location where the 'login-password'
    558 	 * field is displayed.
    559 	 *
    560 	 * @since 3.0.0
    561 	 *
    562 	 * @param string $content Content to display. Default empty.
    563 	 * @param array  $args    Array of login form arguments.
    564 	 */
    565 	$login_form_middle = apply_filters( 'login_form_middle', '', $args );
    566 
    567 	/**
    568 	 * Filters content to display at the bottom of the login form.
    569 	 *
    570 	 * The filter evaluates just preceding the closing form tag element.
    571 	 *
    572 	 * @since 3.0.0
    573 	 *
    574 	 * @param string $content Content to display. Default empty.
    575 	 * @param array  $args    Array of login form arguments.
    576 	 */
    577 	$login_form_bottom = apply_filters( 'login_form_bottom', '', $args );
    578 
    579 	$form = '
    580 		<form name="' . $args['form_id'] . '" id="' . $args['form_id'] . '" action="' . esc_url( site_url( 'wp-login.php', 'login_post' ) ) . '" method="post">
    581 			' . $login_form_top . '
    582 			<p class="login-username">
    583 				<label for="' . esc_attr( $args['id_username'] ) . '">' . esc_html( $args['label_username'] ) . '</label>
    584 				<input type="text" name="log" id="' . esc_attr( $args['id_username'] ) . '" class="input" value="' . esc_attr( $args['value_username'] ) . '" size="20" />
    585 			</p>
    586 			<p class="login-password">
    587 				<label for="' . esc_attr( $args['id_password'] ) . '">' . esc_html( $args['label_password'] ) . '</label>
    588 				<input type="password" name="pwd" id="' . esc_attr( $args['id_password'] ) . '" class="input" value="" size="20" />
    589 			</p>
    590 			' . $login_form_middle . '
    591 			' . ( $args['remember'] ? '<p class="login-remember"><label><input name="rememberme" type="checkbox" id="' . esc_attr( $args['id_remember'] ) . '" value="forever"' . ( $args['value_remember'] ? ' checked="checked"' : '' ) . ' /> ' . esc_html( $args['label_remember'] ) . '</label></p>' : '' ) . '
    592 			<p class="login-submit">
    593 				<input type="submit" name="wp-submit" id="' . esc_attr( $args['id_submit'] ) . '" class="button button-primary" value="' . esc_attr( $args['label_log_in'] ) . '" />
    594 				<input type="hidden" name="redirect_to" value="' . esc_url( $args['redirect'] ) . '" />
    595 			</p>
    596 			' . $login_form_bottom . '
    597 		</form>';
    598 
    599 	if ( $args['echo'] ) {
    600 		echo $form;
    601 	} else {
    602 		return $form;
    603 	}
    604 }
    605 
    606 /**
    607  * Returns the URL that allows the user to retrieve the lost password
    608  *
    609  * @since 2.8.0
    610  *
    611  * @param string $redirect Path to redirect to on login.
    612  * @return string Lost password URL.
    613  */
    614 function wp_lostpassword_url( $redirect = '' ) {
    615 	$args = array(
    616 		'action' => 'lostpassword',
    617 	);
    618 
    619 	if ( ! empty( $redirect ) ) {
    620 		$args['redirect_to'] = urlencode( $redirect );
    621 	}
    622 
    623 	if ( is_multisite() ) {
    624 		$blog_details  = get_blog_details();
    625 		$wp_login_path = $blog_details->path . 'wp-login.php';
    626 	} else {
    627 		$wp_login_path = 'wp-login.php';
    628 	}
    629 
    630 	$lostpassword_url = add_query_arg( $args, network_site_url( $wp_login_path, 'login' ) );
    631 
    632 	/**
    633 	 * Filters the Lost Password URL.
    634 	 *
    635 	 * @since 2.8.0
    636 	 *
    637 	 * @param string $lostpassword_url The lost password page URL.
    638 	 * @param string $redirect         The path to redirect to on login.
    639 	 */
    640 	return apply_filters( 'lostpassword_url', $lostpassword_url, $redirect );
    641 }
    642 
    643 /**
    644  * Display the Registration or Admin link.
    645  *
    646  * Display a link which allows the user to navigate to the registration page if
    647  * not logged in and registration is enabled or to the dashboard if logged in.
    648  *
    649  * @since 1.5.0
    650  *
    651  * @param string $before Text to output before the link. Default `<li>`.
    652  * @param string $after  Text to output after the link. Default `</li>`.
    653  * @param bool   $echo   Default to echo and not return the link.
    654  * @return void|string Void if `$echo` argument is true, registration or admin link
    655  *                     if `$echo` is false.
    656  */
    657 function wp_register( $before = '<li>', $after = '</li>', $echo = true ) {
    658 	if ( ! is_user_logged_in() ) {
    659 		if ( get_option( 'users_can_register' ) ) {
    660 			$link = $before . '<a href="' . esc_url( wp_registration_url() ) . '">' . __( 'Register' ) . '</a>' . $after;
    661 		} else {
    662 			$link = '';
    663 		}
    664 	} elseif ( current_user_can( 'read' ) ) {
    665 		$link = $before . '<a href="' . admin_url() . '">' . __( 'Site Admin' ) . '</a>' . $after;
    666 	} else {
    667 		$link = '';
    668 	}
    669 
    670 	/**
    671 	 * Filters the HTML link to the Registration or Admin page.
    672 	 *
    673 	 * Users are sent to the admin page if logged-in, or the registration page
    674 	 * if enabled and logged-out.
    675 	 *
    676 	 * @since 1.5.0
    677 	 *
    678 	 * @param string $link The HTML code for the link to the Registration or Admin page.
    679 	 */
    680 	$link = apply_filters( 'register', $link );
    681 
    682 	if ( $echo ) {
    683 		echo $link;
    684 	} else {
    685 		return $link;
    686 	}
    687 }
    688 
    689 /**
    690  * Theme container function for the 'wp_meta' action.
    691  *
    692  * The {@see 'wp_meta'} action can have several purposes, depending on how you use it,
    693  * but one purpose might have been to allow for theme switching.
    694  *
    695  * @since 1.5.0
    696  *
    697  * @link https://core.trac.wordpress.org/ticket/1458 Explanation of 'wp_meta' action.
    698  */
    699 function wp_meta() {
    700 	/**
    701 	 * Fires before displaying echoed content in the sidebar.
    702 	 *
    703 	 * @since 1.5.0
    704 	 */
    705 	do_action( 'wp_meta' );
    706 }
    707 
    708 /**
    709  * Displays information about the current site.
    710  *
    711  * @since 0.71
    712  *
    713  * @see get_bloginfo() For possible `$show` values
    714  *
    715  * @param string $show Optional. Site information to display. Default empty.
    716  */
    717 function bloginfo( $show = '' ) {
    718 	echo get_bloginfo( $show, 'display' );
    719 }
    720 
    721 /**
    722  * Retrieves information about the current site.
    723  *
    724  * Possible values for `$show` include:
    725  *
    726  * - 'name' - Site title (set in Settings > General)
    727  * - 'description' - Site tagline (set in Settings > General)
    728  * - 'wpurl' - The WordPress address (URL) (set in Settings > General)
    729  * - 'url' - The Site address (URL) (set in Settings > General)
    730  * - 'admin_email' - Admin email (set in Settings > General)
    731  * - 'charset' - The "Encoding for pages and feeds"  (set in Settings > Reading)
    732  * - 'version' - The current WordPress version
    733  * - 'html_type' - The content-type (default: "text/html"). Themes and plugins
    734  *   can override the default value using the {@see 'pre_option_html_type'} filter
    735  * - 'text_direction' - The text direction determined by the site's language. is_rtl()
    736  *   should be used instead
    737  * - 'language' - Language code for the current site
    738  * - 'stylesheet_url' - URL to the stylesheet for the active theme. An active child theme
    739  *   will take precedence over this value
    740  * - 'stylesheet_directory' - Directory path for the active theme.  An active child theme
    741  *   will take precedence over this value
    742  * - 'template_url' / 'template_directory' - URL of the active theme's directory. An active
    743  *   child theme will NOT take precedence over this value
    744  * - 'pingback_url' - The pingback XML-RPC file URL (xmlrpc.php)
    745  * - 'atom_url' - The Atom feed URL (/feed/atom)
    746  * - 'rdf_url' - The RDF/RSS 1.0 feed URL (/feed/rdf)
    747  * - 'rss_url' - The RSS 0.92 feed URL (/feed/rss)
    748  * - 'rss2_url' - The RSS 2.0 feed URL (/feed)
    749  * - 'comments_atom_url' - The comments Atom feed URL (/comments/feed)
    750  * - 'comments_rss2_url' - The comments RSS 2.0 feed URL (/comments/feed)
    751  *
    752  * Some `$show` values are deprecated and will be removed in future versions.
    753  * These options will trigger the _deprecated_argument() function.
    754  *
    755  * Deprecated arguments include:
    756  *
    757  * - 'siteurl' - Use 'url' instead
    758  * - 'home' - Use 'url' instead
    759  *
    760  * @since 0.71
    761  *
    762  * @global string $wp_version The WordPress version string.
    763  *
    764  * @param string $show   Optional. Site info to retrieve. Default empty (site name).
    765  * @param string $filter Optional. How to filter what is retrieved. Default 'raw'.
    766  * @return string Mostly string values, might be empty.
    767  */
    768 function get_bloginfo( $show = '', $filter = 'raw' ) {
    769 	switch ( $show ) {
    770 		case 'home':    // Deprecated.
    771 		case 'siteurl': // Deprecated.
    772 			_deprecated_argument(
    773 				__FUNCTION__,
    774 				'2.2.0',
    775 				sprintf(
    776 					/* translators: 1: 'siteurl'/'home' argument, 2: bloginfo() function name, 3: 'url' argument. */
    777 					__( 'The %1$s option is deprecated for the family of %2$s functions. Use the %3$s option instead.' ),
    778 					'<code>' . $show . '</code>',
    779 					'<code>bloginfo()</code>',
    780 					'<code>url</code>'
    781 				)
    782 			);
    783 			// Intentional fall-through to be handled by the 'url' case.
    784 		case 'url':
    785 			$output = home_url();
    786 			break;
    787 		case 'wpurl':
    788 			$output = site_url();
    789 			break;
    790 		case 'description':
    791 			$output = get_option( 'blogdescription' );
    792 			break;
    793 		case 'rdf_url':
    794 			$output = get_feed_link( 'rdf' );
    795 			break;
    796 		case 'rss_url':
    797 			$output = get_feed_link( 'rss' );
    798 			break;
    799 		case 'rss2_url':
    800 			$output = get_feed_link( 'rss2' );
    801 			break;
    802 		case 'atom_url':
    803 			$output = get_feed_link( 'atom' );
    804 			break;
    805 		case 'comments_atom_url':
    806 			$output = get_feed_link( 'comments_atom' );
    807 			break;
    808 		case 'comments_rss2_url':
    809 			$output = get_feed_link( 'comments_rss2' );
    810 			break;
    811 		case 'pingback_url':
    812 			$output = site_url( 'xmlrpc.php' );
    813 			break;
    814 		case 'stylesheet_url':
    815 			$output = get_stylesheet_uri();
    816 			break;
    817 		case 'stylesheet_directory':
    818 			$output = get_stylesheet_directory_uri();
    819 			break;
    820 		case 'template_directory':
    821 		case 'template_url':
    822 			$output = get_template_directory_uri();
    823 			break;
    824 		case 'admin_email':
    825 			$output = get_option( 'admin_email' );
    826 			break;
    827 		case 'charset':
    828 			$output = get_option( 'blog_charset' );
    829 			if ( '' === $output ) {
    830 				$output = 'UTF-8';
    831 			}
    832 			break;
    833 		case 'html_type':
    834 			$output = get_option( 'html_type' );
    835 			break;
    836 		case 'version':
    837 			global $wp_version;
    838 			$output = $wp_version;
    839 			break;
    840 		case 'language':
    841 			/*
    842 			 * translators: Translate this to the correct language tag for your locale,
    843 			 * see https://www.w3.org/International/articles/language-tags/ for reference.
    844 			 * Do not translate into your own language.
    845 			 */
    846 			$output = __( 'html_lang_attribute' );
    847 			if ( 'html_lang_attribute' === $output || preg_match( '/[^a-zA-Z0-9-]/', $output ) ) {
    848 				$output = determine_locale();
    849 				$output = str_replace( '_', '-', $output );
    850 			}
    851 			break;
    852 		case 'text_direction':
    853 			_deprecated_argument(
    854 				__FUNCTION__,
    855 				'2.2.0',
    856 				sprintf(
    857 					/* translators: 1: 'text_direction' argument, 2: bloginfo() function name, 3: is_rtl() function name. */
    858 					__( 'The %1$s option is deprecated for the family of %2$s functions. Use the %3$s function instead.' ),
    859 					'<code>' . $show . '</code>',
    860 					'<code>bloginfo()</code>',
    861 					'<code>is_rtl()</code>'
    862 				)
    863 			);
    864 			if ( function_exists( 'is_rtl' ) ) {
    865 				$output = is_rtl() ? 'rtl' : 'ltr';
    866 			} else {
    867 				$output = 'ltr';
    868 			}
    869 			break;
    870 		case 'name':
    871 		default:
    872 			$output = get_option( 'blogname' );
    873 			break;
    874 	}
    875 
    876 	$url = true;
    877 	if ( strpos( $show, 'url' ) === false &&
    878 		strpos( $show, 'directory' ) === false &&
    879 		strpos( $show, 'home' ) === false ) {
    880 		$url = false;
    881 	}
    882 
    883 	if ( 'display' === $filter ) {
    884 		if ( $url ) {
    885 			/**
    886 			 * Filters the URL returned by get_bloginfo().
    887 			 *
    888 			 * @since 2.0.5
    889 			 *
    890 			 * @param string $output The URL returned by bloginfo().
    891 			 * @param string $show   Type of information requested.
    892 			 */
    893 			$output = apply_filters( 'bloginfo_url', $output, $show );
    894 		} else {
    895 			/**
    896 			 * Filters the site information returned by get_bloginfo().
    897 			 *
    898 			 * @since 0.71
    899 			 *
    900 			 * @param mixed  $output The requested non-URL site information.
    901 			 * @param string $show   Type of information requested.
    902 			 */
    903 			$output = apply_filters( 'bloginfo', $output, $show );
    904 		}
    905 	}
    906 
    907 	return $output;
    908 }
    909 
    910 /**
    911  * Returns the Site Icon URL.
    912  *
    913  * @since 4.3.0
    914  *
    915  * @param int    $size    Optional. Size of the site icon. Default 512 (pixels).
    916  * @param string $url     Optional. Fallback url if no site icon is found. Default empty.
    917  * @param int    $blog_id Optional. ID of the blog to get the site icon for. Default current blog.
    918  * @return string Site Icon URL.
    919  */
    920 function get_site_icon_url( $size = 512, $url = '', $blog_id = 0 ) {
    921 	$switched_blog = false;
    922 
    923 	if ( is_multisite() && ! empty( $blog_id ) && get_current_blog_id() !== (int) $blog_id ) {
    924 		switch_to_blog( $blog_id );
    925 		$switched_blog = true;
    926 	}
    927 
    928 	$site_icon_id = get_option( 'site_icon' );
    929 
    930 	if ( $site_icon_id ) {
    931 		if ( $size >= 512 ) {
    932 			$size_data = 'full';
    933 		} else {
    934 			$size_data = array( $size, $size );
    935 		}
    936 		$url = wp_get_attachment_image_url( $site_icon_id, $size_data );
    937 	}
    938 
    939 	if ( $switched_blog ) {
    940 		restore_current_blog();
    941 	}
    942 
    943 	/**
    944 	 * Filters the site icon URL.
    945 	 *
    946 	 * @since 4.4.0
    947 	 *
    948 	 * @param string $url     Site icon URL.
    949 	 * @param int    $size    Size of the site icon.
    950 	 * @param int    $blog_id ID of the blog to get the site icon for.
    951 	 */
    952 	return apply_filters( 'get_site_icon_url', $url, $size, $blog_id );
    953 }
    954 
    955 /**
    956  * Displays the Site Icon URL.
    957  *
    958  * @since 4.3.0
    959  *
    960  * @param int    $size    Optional. Size of the site icon. Default 512 (pixels).
    961  * @param string $url     Optional. Fallback url if no site icon is found. Default empty.
    962  * @param int    $blog_id Optional. ID of the blog to get the site icon for. Default current blog.
    963  */
    964 function site_icon_url( $size = 512, $url = '', $blog_id = 0 ) {
    965 	echo esc_url( get_site_icon_url( $size, $url, $blog_id ) );
    966 }
    967 
    968 /**
    969  * Whether the site has a Site Icon.
    970  *
    971  * @since 4.3.0
    972  *
    973  * @param int $blog_id Optional. ID of the blog in question. Default current blog.
    974  * @return bool Whether the site has a site icon or not.
    975  */
    976 function has_site_icon( $blog_id = 0 ) {
    977 	return (bool) get_site_icon_url( 512, '', $blog_id );
    978 }
    979 
    980 /**
    981  * Determines whether the site has a custom logo.
    982  *
    983  * @since 4.5.0
    984  *
    985  * @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog.
    986  * @return bool Whether the site has a custom logo or not.
    987  */
    988 function has_custom_logo( $blog_id = 0 ) {
    989 	$switched_blog = false;
    990 
    991 	if ( is_multisite() && ! empty( $blog_id ) && get_current_blog_id() !== (int) $blog_id ) {
    992 		switch_to_blog( $blog_id );
    993 		$switched_blog = true;
    994 	}
    995 
    996 	$custom_logo_id = get_theme_mod( 'custom_logo' );
    997 
    998 	if ( $switched_blog ) {
    999 		restore_current_blog();
   1000 	}
   1001 
   1002 	return (bool) $custom_logo_id;
   1003 }
   1004 
   1005 /**
   1006  * Returns a custom logo, linked to home unless the theme supports removing the link on the home page.
   1007  *
   1008  * @since 4.5.0
   1009  * @since 5.5.0 Added option to remove the link on the home page with `unlink-homepage-logo` theme support
   1010  *              for the `custom-logo` theme feature.
   1011  * @since 5.5.1 Disabled lazy-loading by default.
   1012  *
   1013  * @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog.
   1014  * @return string Custom logo markup.
   1015  */
   1016 function get_custom_logo( $blog_id = 0 ) {
   1017 	$html          = '';
   1018 	$switched_blog = false;
   1019 
   1020 	if ( is_multisite() && ! empty( $blog_id ) && get_current_blog_id() !== (int) $blog_id ) {
   1021 		switch_to_blog( $blog_id );
   1022 		$switched_blog = true;
   1023 	}
   1024 
   1025 	$custom_logo_id = get_theme_mod( 'custom_logo' );
   1026 
   1027 	// We have a logo. Logo is go.
   1028 	if ( $custom_logo_id ) {
   1029 		$custom_logo_attr = array(
   1030 			'class'   => 'custom-logo',
   1031 			'loading' => false,
   1032 		);
   1033 
   1034 		$unlink_homepage_logo = (bool) get_theme_support( 'custom-logo', 'unlink-homepage-logo' );
   1035 
   1036 		if ( $unlink_homepage_logo && is_front_page() && ! is_paged() ) {
   1037 			/*
   1038 			 * If on the home page, set the logo alt attribute to an empty string,
   1039 			 * as the image is decorative and doesn't need its purpose to be described.
   1040 			 */
   1041 			$custom_logo_attr['alt'] = '';
   1042 		} else {
   1043 			/*
   1044 			 * If the logo alt attribute is empty, get the site title and explicitly pass it
   1045 			 * to the attributes used by wp_get_attachment_image().
   1046 			 */
   1047 			$image_alt = get_post_meta( $custom_logo_id, '_wp_attachment_image_alt', true );
   1048 			if ( empty( $image_alt ) ) {
   1049 				$custom_logo_attr['alt'] = get_bloginfo( 'name', 'display' );
   1050 			}
   1051 		}
   1052 
   1053 		/**
   1054 		 * Filters the list of custom logo image attributes.
   1055 		 *
   1056 		 * @since 5.5.0
   1057 		 *
   1058 		 * @param array $custom_logo_attr Custom logo image attributes.
   1059 		 * @param int   $custom_logo_id   Custom logo attachment ID.
   1060 		 * @param int   $blog_id          ID of the blog to get the custom logo for.
   1061 		 */
   1062 		$custom_logo_attr = apply_filters( 'get_custom_logo_image_attributes', $custom_logo_attr, $custom_logo_id, $blog_id );
   1063 
   1064 		/*
   1065 		 * If the alt attribute is not empty, there's no need to explicitly pass it
   1066 		 * because wp_get_attachment_image() already adds the alt attribute.
   1067 		 */
   1068 		$image = wp_get_attachment_image( $custom_logo_id, 'full', false, $custom_logo_attr );
   1069 
   1070 		if ( $unlink_homepage_logo && is_front_page() && ! is_paged() ) {
   1071 			// If on the home page, don't link the logo to home.
   1072 			$html = sprintf(
   1073 				'<span class="custom-logo-link">%1$s</span>',
   1074 				$image
   1075 			);
   1076 		} else {
   1077 			$aria_current = is_front_page() && ! is_paged() ? ' aria-current="page"' : '';
   1078 
   1079 			$html = sprintf(
   1080 				'<a href="%1$s" class="custom-logo-link" rel="home"%2$s>%3$s</a>',
   1081 				esc_url( home_url( '/' ) ),
   1082 				$aria_current,
   1083 				$image
   1084 			);
   1085 		}
   1086 	} elseif ( is_customize_preview() ) {
   1087 		// If no logo is set but we're in the Customizer, leave a placeholder (needed for the live preview).
   1088 		$html = sprintf(
   1089 			'<a href="%1$s" class="custom-logo-link" style="display:none;"><img class="custom-logo" alt="" /></a>',
   1090 			esc_url( home_url( '/' ) )
   1091 		);
   1092 	}
   1093 
   1094 	if ( $switched_blog ) {
   1095 		restore_current_blog();
   1096 	}
   1097 
   1098 	/**
   1099 	 * Filters the custom logo output.
   1100 	 *
   1101 	 * @since 4.5.0
   1102 	 * @since 4.6.0 Added the `$blog_id` parameter.
   1103 	 *
   1104 	 * @param string $html    Custom logo HTML output.
   1105 	 * @param int    $blog_id ID of the blog to get the custom logo for.
   1106 	 */
   1107 	return apply_filters( 'get_custom_logo', $html, $blog_id );
   1108 }
   1109 
   1110 /**
   1111  * Displays a custom logo, linked to home unless the theme supports removing the link on the home page.
   1112  *
   1113  * @since 4.5.0
   1114  *
   1115  * @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog.
   1116  */
   1117 function the_custom_logo( $blog_id = 0 ) {
   1118 	echo get_custom_logo( $blog_id );
   1119 }
   1120 
   1121 /**
   1122  * Returns document title for the current page.
   1123  *
   1124  * @since 4.4.0
   1125  *
   1126  * @global int $page  Page number of a single post.
   1127  * @global int $paged Page number of a list of posts.
   1128  *
   1129  * @return string Tag with the document title.
   1130  */
   1131 function wp_get_document_title() {
   1132 
   1133 	/**
   1134 	 * Filters the document title before it is generated.
   1135 	 *
   1136 	 * Passing a non-empty value will short-circuit wp_get_document_title(),
   1137 	 * returning that value instead.
   1138 	 *
   1139 	 * @since 4.4.0
   1140 	 *
   1141 	 * @param string $title The document title. Default empty string.
   1142 	 */
   1143 	$title = apply_filters( 'pre_get_document_title', '' );
   1144 	if ( ! empty( $title ) ) {
   1145 		return $title;
   1146 	}
   1147 
   1148 	global $page, $paged;
   1149 
   1150 	$title = array(
   1151 		'title' => '',
   1152 	);
   1153 
   1154 	// If it's a 404 page, use a "Page not found" title.
   1155 	if ( is_404() ) {
   1156 		$title['title'] = __( 'Page not found' );
   1157 
   1158 		// If it's a search, use a dynamic search results title.
   1159 	} elseif ( is_search() ) {
   1160 		/* translators: %s: Search query. */
   1161 		$title['title'] = sprintf( __( 'Search Results for &#8220;%s&#8221;' ), get_search_query() );
   1162 
   1163 		// If on the front page, use the site title.
   1164 	} elseif ( is_front_page() ) {
   1165 		$title['title'] = get_bloginfo( 'name', 'display' );
   1166 
   1167 		// If on a post type archive, use the post type archive title.
   1168 	} elseif ( is_post_type_archive() ) {
   1169 		$title['title'] = post_type_archive_title( '', false );
   1170 
   1171 		// If on a taxonomy archive, use the term title.
   1172 	} elseif ( is_tax() ) {
   1173 		$title['title'] = single_term_title( '', false );
   1174 
   1175 		/*
   1176 		* If we're on the blog page that is not the homepage
   1177 		* or a single post of any post type, use the post title.
   1178 		*/
   1179 	} elseif ( is_home() || is_singular() ) {
   1180 		$title['title'] = single_post_title( '', false );
   1181 
   1182 		// If on a category or tag archive, use the term title.
   1183 	} elseif ( is_category() || is_tag() ) {
   1184 		$title['title'] = single_term_title( '', false );
   1185 
   1186 		// If on an author archive, use the author's display name.
   1187 	} elseif ( is_author() && get_queried_object() ) {
   1188 		$author         = get_queried_object();
   1189 		$title['title'] = $author->display_name;
   1190 
   1191 		// If it's a date archive, use the date as the title.
   1192 	} elseif ( is_year() ) {
   1193 		$title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) );
   1194 
   1195 	} elseif ( is_month() ) {
   1196 		$title['title'] = get_the_date( _x( 'F Y', 'monthly archives date format' ) );
   1197 
   1198 	} elseif ( is_day() ) {
   1199 		$title['title'] = get_the_date();
   1200 	}
   1201 
   1202 	// Add a page number if necessary.
   1203 	if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
   1204 		/* translators: %s: Page number. */
   1205 		$title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) );
   1206 	}
   1207 
   1208 	// Append the description or site title to give context.
   1209 	if ( is_front_page() ) {
   1210 		$title['tagline'] = get_bloginfo( 'description', 'display' );
   1211 	} else {
   1212 		$title['site'] = get_bloginfo( 'name', 'display' );
   1213 	}
   1214 
   1215 	/**
   1216 	 * Filters the separator for the document title.
   1217 	 *
   1218 	 * @since 4.4.0
   1219 	 *
   1220 	 * @param string $sep Document title separator. Default '-'.
   1221 	 */
   1222 	$sep = apply_filters( 'document_title_separator', '-' );
   1223 
   1224 	/**
   1225 	 * Filters the parts of the document title.
   1226 	 *
   1227 	 * @since 4.4.0
   1228 	 *
   1229 	 * @param array $title {
   1230 	 *     The document title parts.
   1231 	 *
   1232 	 *     @type string $title   Title of the viewed page.
   1233 	 *     @type string $page    Optional. Page number if paginated.
   1234 	 *     @type string $tagline Optional. Site description when on home page.
   1235 	 *     @type string $site    Optional. Site title when not on home page.
   1236 	 * }
   1237 	 */
   1238 	$title = apply_filters( 'document_title_parts', $title );
   1239 
   1240 	$title = implode( " $sep ", array_filter( $title ) );
   1241 
   1242 	/**
   1243 	 * Filters the document title.
   1244 	 *
   1245 	 * @since 5.8.0
   1246 	 *
   1247 	 * @param string $title Document title.
   1248 	 */
   1249 	$title = apply_filters( 'document_title', $title );
   1250 
   1251 	return $title;
   1252 }
   1253 
   1254 /**
   1255  * Displays title tag with content.
   1256  *
   1257  * @ignore
   1258  * @since 4.1.0
   1259  * @since 4.4.0 Improved title output replaced `wp_title()`.
   1260  * @access private
   1261  */
   1262 function _wp_render_title_tag() {
   1263 	if ( ! current_theme_supports( 'title-tag' ) ) {
   1264 		return;
   1265 	}
   1266 
   1267 	echo '<title>' . wp_get_document_title() . '</title>' . "\n";
   1268 }
   1269 
   1270 /**
   1271  * Display or retrieve page title for all areas of blog.
   1272  *
   1273  * By default, the page title will display the separator before the page title,
   1274  * so that the blog title will be before the page title. This is not good for
   1275  * title display, since the blog title shows up on most tabs and not what is
   1276  * important, which is the page that the user is looking at.
   1277  *
   1278  * There are also SEO benefits to having the blog title after or to the 'right'
   1279  * of the page title. However, it is mostly common sense to have the blog title
   1280  * to the right with most browsers supporting tabs. You can achieve this by
   1281  * using the seplocation parameter and setting the value to 'right'. This change
   1282  * was introduced around 2.5.0, in case backward compatibility of themes is
   1283  * important.
   1284  *
   1285  * @since 1.0.0
   1286  *
   1287  * @global WP_Locale $wp_locale WordPress date and time locale object.
   1288  *
   1289  * @param string $sep         Optional. How to separate the various items within the page title.
   1290  *                            Default '&raquo;'.
   1291  * @param bool   $display     Optional. Whether to display or retrieve title. Default true.
   1292  * @param string $seplocation Optional. Location of the separator ('left' or 'right').
   1293  * @return string|null String on retrieve, null when displaying.
   1294  */
   1295 function wp_title( $sep = '&raquo;', $display = true, $seplocation = '' ) {
   1296 	global $wp_locale;
   1297 
   1298 	$m        = get_query_var( 'm' );
   1299 	$year     = get_query_var( 'year' );
   1300 	$monthnum = get_query_var( 'monthnum' );
   1301 	$day      = get_query_var( 'day' );
   1302 	$search   = get_query_var( 's' );
   1303 	$title    = '';
   1304 
   1305 	$t_sep = '%WP_TITLE_SEP%'; // Temporary separator, for accurate flipping, if necessary.
   1306 
   1307 	// If there is a post.
   1308 	if ( is_single() || ( is_home() && ! is_front_page() ) || ( is_page() && ! is_front_page() ) ) {
   1309 		$title = single_post_title( '', false );
   1310 	}
   1311 
   1312 	// If there's a post type archive.
   1313 	if ( is_post_type_archive() ) {
   1314 		$post_type = get_query_var( 'post_type' );
   1315 		if ( is_array( $post_type ) ) {
   1316 			$post_type = reset( $post_type );
   1317 		}
   1318 		$post_type_object = get_post_type_object( $post_type );
   1319 		if ( ! $post_type_object->has_archive ) {
   1320 			$title = post_type_archive_title( '', false );
   1321 		}
   1322 	}
   1323 
   1324 	// If there's a category or tag.
   1325 	if ( is_category() || is_tag() ) {
   1326 		$title = single_term_title( '', false );
   1327 	}
   1328 
   1329 	// If there's a taxonomy.
   1330 	if ( is_tax() ) {
   1331 		$term = get_queried_object();
   1332 		if ( $term ) {
   1333 			$tax   = get_taxonomy( $term->taxonomy );
   1334 			$title = single_term_title( $tax->labels->name . $t_sep, false );
   1335 		}
   1336 	}
   1337 
   1338 	// If there's an author.
   1339 	if ( is_author() && ! is_post_type_archive() ) {
   1340 		$author = get_queried_object();
   1341 		if ( $author ) {
   1342 			$title = $author->display_name;
   1343 		}
   1344 	}
   1345 
   1346 	// Post type archives with has_archive should override terms.
   1347 	if ( is_post_type_archive() && $post_type_object->has_archive ) {
   1348 		$title = post_type_archive_title( '', false );
   1349 	}
   1350 
   1351 	// If there's a month.
   1352 	if ( is_archive() && ! empty( $m ) ) {
   1353 		$my_year  = substr( $m, 0, 4 );
   1354 		$my_month = $wp_locale->get_month( substr( $m, 4, 2 ) );
   1355 		$my_day   = (int) substr( $m, 6, 2 );
   1356 		$title    = $my_year . ( $my_month ? $t_sep . $my_month : '' ) . ( $my_day ? $t_sep . $my_day : '' );
   1357 	}
   1358 
   1359 	// If there's a year.
   1360 	if ( is_archive() && ! empty( $year ) ) {
   1361 		$title = $year;
   1362 		if ( ! empty( $monthnum ) ) {
   1363 			$title .= $t_sep . $wp_locale->get_month( $monthnum );
   1364 		}
   1365 		if ( ! empty( $day ) ) {
   1366 			$title .= $t_sep . zeroise( $day, 2 );
   1367 		}
   1368 	}
   1369 
   1370 	// If it's a search.
   1371 	if ( is_search() ) {
   1372 		/* translators: 1: Separator, 2: Search query. */
   1373 		$title = sprintf( __( 'Search Results %1$s %2$s' ), $t_sep, strip_tags( $search ) );
   1374 	}
   1375 
   1376 	// If it's a 404 page.
   1377 	if ( is_404() ) {
   1378 		$title = __( 'Page not found' );
   1379 	}
   1380 
   1381 	$prefix = '';
   1382 	if ( ! empty( $title ) ) {
   1383 		$prefix = " $sep ";
   1384 	}
   1385 
   1386 	/**
   1387 	 * Filters the parts of the page title.
   1388 	 *
   1389 	 * @since 4.0.0
   1390 	 *
   1391 	 * @param string[] $title_array Array of parts of the page title.
   1392 	 */
   1393 	$title_array = apply_filters( 'wp_title_parts', explode( $t_sep, $title ) );
   1394 
   1395 	// Determines position of the separator and direction of the breadcrumb.
   1396 	if ( 'right' === $seplocation ) { // Separator on right, so reverse the order.
   1397 		$title_array = array_reverse( $title_array );
   1398 		$title       = implode( " $sep ", $title_array ) . $prefix;
   1399 	} else {
   1400 		$title = $prefix . implode( " $sep ", $title_array );
   1401 	}
   1402 
   1403 	/**
   1404 	 * Filters the text of the page title.
   1405 	 *
   1406 	 * @since 2.0.0
   1407 	 *
   1408 	 * @param string $title       Page title.
   1409 	 * @param string $sep         Title separator.
   1410 	 * @param string $seplocation Location of the separator ('left' or 'right').
   1411 	 */
   1412 	$title = apply_filters( 'wp_title', $title, $sep, $seplocation );
   1413 
   1414 	// Send it out.
   1415 	if ( $display ) {
   1416 		echo $title;
   1417 	} else {
   1418 		return $title;
   1419 	}
   1420 }
   1421 
   1422 /**
   1423  * Display or retrieve page title for post.
   1424  *
   1425  * This is optimized for single.php template file for displaying the post title.
   1426  *
   1427  * It does not support placing the separator after the title, but by leaving the
   1428  * prefix parameter empty, you can set the title separator manually. The prefix
   1429  * does not automatically place a space between the prefix, so if there should
   1430  * be a space, the parameter value will need to have it at the end.
   1431  *
   1432  * @since 0.71
   1433  *
   1434  * @param string $prefix  Optional. What to display before the title.
   1435  * @param bool   $display Optional. Whether to display or retrieve title. Default true.
   1436  * @return string|void Title when retrieving.
   1437  */
   1438 function single_post_title( $prefix = '', $display = true ) {
   1439 	$_post = get_queried_object();
   1440 
   1441 	if ( ! isset( $_post->post_title ) ) {
   1442 		return;
   1443 	}
   1444 
   1445 	/**
   1446 	 * Filters the page title for a single post.
   1447 	 *
   1448 	 * @since 0.71
   1449 	 *
   1450 	 * @param string  $_post_title The single post page title.
   1451 	 * @param WP_Post $_post       The current post.
   1452 	 */
   1453 	$title = apply_filters( 'single_post_title', $_post->post_title, $_post );
   1454 	if ( $display ) {
   1455 		echo $prefix . $title;
   1456 	} else {
   1457 		return $prefix . $title;
   1458 	}
   1459 }
   1460 
   1461 /**
   1462  * Display or retrieve title for a post type archive.
   1463  *
   1464  * This is optimized for archive.php and archive-{$post_type}.php template files
   1465  * for displaying the title of the post type.
   1466  *
   1467  * @since 3.1.0
   1468  *
   1469  * @param string $prefix  Optional. What to display before the title.
   1470  * @param bool   $display Optional. Whether to display or retrieve title. Default true.
   1471  * @return string|void Title when retrieving, null when displaying or failure.
   1472  */
   1473 function post_type_archive_title( $prefix = '', $display = true ) {
   1474 	if ( ! is_post_type_archive() ) {
   1475 		return;
   1476 	}
   1477 
   1478 	$post_type = get_query_var( 'post_type' );
   1479 	if ( is_array( $post_type ) ) {
   1480 		$post_type = reset( $post_type );
   1481 	}
   1482 
   1483 	$post_type_obj = get_post_type_object( $post_type );
   1484 
   1485 	/**
   1486 	 * Filters the post type archive title.
   1487 	 *
   1488 	 * @since 3.1.0
   1489 	 *
   1490 	 * @param string $post_type_name Post type 'name' label.
   1491 	 * @param string $post_type      Post type.
   1492 	 */
   1493 	$title = apply_filters( 'post_type_archive_title', $post_type_obj->labels->name, $post_type );
   1494 
   1495 	if ( $display ) {
   1496 		echo $prefix . $title;
   1497 	} else {
   1498 		return $prefix . $title;
   1499 	}
   1500 }
   1501 
   1502 /**
   1503  * Display or retrieve page title for category archive.
   1504  *
   1505  * Useful for category template files for displaying the category page title.
   1506  * The prefix does not automatically place a space between the prefix, so if
   1507  * there should be a space, the parameter value will need to have it at the end.
   1508  *
   1509  * @since 0.71
   1510  *
   1511  * @param string $prefix  Optional. What to display before the title.
   1512  * @param bool   $display Optional. Whether to display or retrieve title. Default true.
   1513  * @return string|void Title when retrieving.
   1514  */
   1515 function single_cat_title( $prefix = '', $display = true ) {
   1516 	return single_term_title( $prefix, $display );
   1517 }
   1518 
   1519 /**
   1520  * Display or retrieve page title for tag post archive.
   1521  *
   1522  * Useful for tag template files for displaying the tag page title. The prefix
   1523  * does not automatically place a space between the prefix, so if there should
   1524  * be a space, the parameter value will need to have it at the end.
   1525  *
   1526  * @since 2.3.0
   1527  *
   1528  * @param string $prefix  Optional. What to display before the title.
   1529  * @param bool   $display Optional. Whether to display or retrieve title. Default true.
   1530  * @return string|void Title when retrieving.
   1531  */
   1532 function single_tag_title( $prefix = '', $display = true ) {
   1533 	return single_term_title( $prefix, $display );
   1534 }
   1535 
   1536 /**
   1537  * Display or retrieve page title for taxonomy term archive.
   1538  *
   1539  * Useful for taxonomy term template files for displaying the taxonomy term page title.
   1540  * The prefix does not automatically place a space between the prefix, so if there should
   1541  * be a space, the parameter value will need to have it at the end.
   1542  *
   1543  * @since 3.1.0
   1544  *
   1545  * @param string $prefix  Optional. What to display before the title.
   1546  * @param bool   $display Optional. Whether to display or retrieve title. Default true.
   1547  * @return string|void Title when retrieving.
   1548  */
   1549 function single_term_title( $prefix = '', $display = true ) {
   1550 	$term = get_queried_object();
   1551 
   1552 	if ( ! $term ) {
   1553 		return;
   1554 	}
   1555 
   1556 	if ( is_category() ) {
   1557 		/**
   1558 		 * Filters the category archive page title.
   1559 		 *
   1560 		 * @since 2.0.10
   1561 		 *
   1562 		 * @param string $term_name Category name for archive being displayed.
   1563 		 */
   1564 		$term_name = apply_filters( 'single_cat_title', $term->name );
   1565 	} elseif ( is_tag() ) {
   1566 		/**
   1567 		 * Filters the tag archive page title.
   1568 		 *
   1569 		 * @since 2.3.0
   1570 		 *
   1571 		 * @param string $term_name Tag name for archive being displayed.
   1572 		 */
   1573 		$term_name = apply_filters( 'single_tag_title', $term->name );
   1574 	} elseif ( is_tax() ) {
   1575 		/**
   1576 		 * Filters the custom taxonomy archive page title.
   1577 		 *
   1578 		 * @since 3.1.0
   1579 		 *
   1580 		 * @param string $term_name Term name for archive being displayed.
   1581 		 */
   1582 		$term_name = apply_filters( 'single_term_title', $term->name );
   1583 	} else {
   1584 		return;
   1585 	}
   1586 
   1587 	if ( empty( $term_name ) ) {
   1588 		return;
   1589 	}
   1590 
   1591 	if ( $display ) {
   1592 		echo $prefix . $term_name;
   1593 	} else {
   1594 		return $prefix . $term_name;
   1595 	}
   1596 }
   1597 
   1598 /**
   1599  * Display or retrieve page title for post archive based on date.
   1600  *
   1601  * Useful for when the template only needs to display the month and year,
   1602  * if either are available. The prefix does not automatically place a space
   1603  * between the prefix, so if there should be a space, the parameter value
   1604  * will need to have it at the end.
   1605  *
   1606  * @since 0.71
   1607  *
   1608  * @global WP_Locale $wp_locale WordPress date and time locale object.
   1609  *
   1610  * @param string $prefix  Optional. What to display before the title.
   1611  * @param bool   $display Optional. Whether to display or retrieve title. Default true.
   1612  * @return string|void Title when retrieving.
   1613  */
   1614 function single_month_title( $prefix = '', $display = true ) {
   1615 	global $wp_locale;
   1616 
   1617 	$m        = get_query_var( 'm' );
   1618 	$year     = get_query_var( 'year' );
   1619 	$monthnum = get_query_var( 'monthnum' );
   1620 
   1621 	if ( ! empty( $monthnum ) && ! empty( $year ) ) {
   1622 		$my_year  = $year;
   1623 		$my_month = $wp_locale->get_month( $monthnum );
   1624 	} elseif ( ! empty( $m ) ) {
   1625 		$my_year  = substr( $m, 0, 4 );
   1626 		$my_month = $wp_locale->get_month( substr( $m, 4, 2 ) );
   1627 	}
   1628 
   1629 	if ( empty( $my_month ) ) {
   1630 		return false;
   1631 	}
   1632 
   1633 	$result = $prefix . $my_month . $prefix . $my_year;
   1634 
   1635 	if ( ! $display ) {
   1636 		return $result;
   1637 	}
   1638 	echo $result;
   1639 }
   1640 
   1641 /**
   1642  * Display the archive title based on the queried object.
   1643  *
   1644  * @since 4.1.0
   1645  *
   1646  * @see get_the_archive_title()
   1647  *
   1648  * @param string $before Optional. Content to prepend to the title. Default empty.
   1649  * @param string $after  Optional. Content to append to the title. Default empty.
   1650  */
   1651 function the_archive_title( $before = '', $after = '' ) {
   1652 	$title = get_the_archive_title();
   1653 
   1654 	if ( ! empty( $title ) ) {
   1655 		echo $before . $title . $after;
   1656 	}
   1657 }
   1658 
   1659 /**
   1660  * Retrieve the archive title based on the queried object.
   1661  *
   1662  * @since 4.1.0
   1663  * @since 5.5.0 The title part is wrapped in a `<span>` element.
   1664  *
   1665  * @return string Archive title.
   1666  */
   1667 function get_the_archive_title() {
   1668 	$title  = __( 'Archives' );
   1669 	$prefix = '';
   1670 
   1671 	if ( is_category() ) {
   1672 		$title  = single_cat_title( '', false );
   1673 		$prefix = _x( 'Category:', 'category archive title prefix' );
   1674 	} elseif ( is_tag() ) {
   1675 		$title  = single_tag_title( '', false );
   1676 		$prefix = _x( 'Tag:', 'tag archive title prefix' );
   1677 	} elseif ( is_author() ) {
   1678 		$title  = get_the_author();
   1679 		$prefix = _x( 'Author:', 'author archive title prefix' );
   1680 	} elseif ( is_year() ) {
   1681 		$title  = get_the_date( _x( 'Y', 'yearly archives date format' ) );
   1682 		$prefix = _x( 'Year:', 'date archive title prefix' );
   1683 	} elseif ( is_month() ) {
   1684 		$title  = get_the_date( _x( 'F Y', 'monthly archives date format' ) );
   1685 		$prefix = _x( 'Month:', 'date archive title prefix' );
   1686 	} elseif ( is_day() ) {
   1687 		$title  = get_the_date( _x( 'F j, Y', 'daily archives date format' ) );
   1688 		$prefix = _x( 'Day:', 'date archive title prefix' );
   1689 	} elseif ( is_tax( 'post_format' ) ) {
   1690 		if ( is_tax( 'post_format', 'post-format-aside' ) ) {
   1691 			$title = _x( 'Asides', 'post format archive title' );
   1692 		} elseif ( is_tax( 'post_format', 'post-format-gallery' ) ) {
   1693 			$title = _x( 'Galleries', 'post format archive title' );
   1694 		} elseif ( is_tax( 'post_format', 'post-format-image' ) ) {
   1695 			$title = _x( 'Images', 'post format archive title' );
   1696 		} elseif ( is_tax( 'post_format', 'post-format-video' ) ) {
   1697 			$title = _x( 'Videos', 'post format archive title' );
   1698 		} elseif ( is_tax( 'post_format', 'post-format-quote' ) ) {
   1699 			$title = _x( 'Quotes', 'post format archive title' );
   1700 		} elseif ( is_tax( 'post_format', 'post-format-link' ) ) {
   1701 			$title = _x( 'Links', 'post format archive title' );
   1702 		} elseif ( is_tax( 'post_format', 'post-format-status' ) ) {
   1703 			$title = _x( 'Statuses', 'post format archive title' );
   1704 		} elseif ( is_tax( 'post_format', 'post-format-audio' ) ) {
   1705 			$title = _x( 'Audio', 'post format archive title' );
   1706 		} elseif ( is_tax( 'post_format', 'post-format-chat' ) ) {
   1707 			$title = _x( 'Chats', 'post format archive title' );
   1708 		}
   1709 	} elseif ( is_post_type_archive() ) {
   1710 		$title  = post_type_archive_title( '', false );
   1711 		$prefix = _x( 'Archives:', 'post type archive title prefix' );
   1712 	} elseif ( is_tax() ) {
   1713 		$queried_object = get_queried_object();
   1714 		if ( $queried_object ) {
   1715 			$tax    = get_taxonomy( $queried_object->taxonomy );
   1716 			$title  = single_term_title( '', false );
   1717 			$prefix = sprintf(
   1718 				/* translators: %s: Taxonomy singular name. */
   1719 				_x( '%s:', 'taxonomy term archive title prefix' ),
   1720 				$tax->labels->singular_name
   1721 			);
   1722 		}
   1723 	}
   1724 
   1725 	$original_title = $title;
   1726 
   1727 	/**
   1728 	 * Filters the archive title prefix.
   1729 	 *
   1730 	 * @since 5.5.0
   1731 	 *
   1732 	 * @param string $prefix Archive title prefix.
   1733 	 */
   1734 	$prefix = apply_filters( 'get_the_archive_title_prefix', $prefix );
   1735 	if ( $prefix ) {
   1736 		$title = sprintf(
   1737 			/* translators: 1: Title prefix. 2: Title. */
   1738 			_x( '%1$s %2$s', 'archive title' ),
   1739 			$prefix,
   1740 			'<span>' . $title . '</span>'
   1741 		);
   1742 	}
   1743 
   1744 	/**
   1745 	 * Filters the archive title.
   1746 	 *
   1747 	 * @since 4.1.0
   1748 	 * @since 5.5.0 Added the `$prefix` and `$original_title` parameters.
   1749 	 *
   1750 	 * @param string $title          Archive title to be displayed.
   1751 	 * @param string $original_title Archive title without prefix.
   1752 	 * @param string $prefix         Archive title prefix.
   1753 	 */
   1754 	return apply_filters( 'get_the_archive_title', $title, $original_title, $prefix );
   1755 }
   1756 
   1757 /**
   1758  * Display category, tag, term, or author description.
   1759  *
   1760  * @since 4.1.0
   1761  *
   1762  * @see get_the_archive_description()
   1763  *
   1764  * @param string $before Optional. Content to prepend to the description. Default empty.
   1765  * @param string $after  Optional. Content to append to the description. Default empty.
   1766  */
   1767 function the_archive_description( $before = '', $after = '' ) {
   1768 	$description = get_the_archive_description();
   1769 	if ( $description ) {
   1770 		echo $before . $description . $after;
   1771 	}
   1772 }
   1773 
   1774 /**
   1775  * Retrieves the description for an author, post type, or term archive.
   1776  *
   1777  * @since 4.1.0
   1778  * @since 4.7.0 Added support for author archives.
   1779  * @since 4.9.0 Added support for post type archives.
   1780  *
   1781  * @see term_description()
   1782  *
   1783  * @return string Archive description.
   1784  */
   1785 function get_the_archive_description() {
   1786 	if ( is_author() ) {
   1787 		$description = get_the_author_meta( 'description' );
   1788 	} elseif ( is_post_type_archive() ) {
   1789 		$description = get_the_post_type_description();
   1790 	} else {
   1791 		$description = term_description();
   1792 	}
   1793 
   1794 	/**
   1795 	 * Filters the archive description.
   1796 	 *
   1797 	 * @since 4.1.0
   1798 	 *
   1799 	 * @param string $description Archive description to be displayed.
   1800 	 */
   1801 	return apply_filters( 'get_the_archive_description', $description );
   1802 }
   1803 
   1804 /**
   1805  * Retrieves the description for a post type archive.
   1806  *
   1807  * @since 4.9.0
   1808  *
   1809  * @return string The post type description.
   1810  */
   1811 function get_the_post_type_description() {
   1812 	$post_type = get_query_var( 'post_type' );
   1813 
   1814 	if ( is_array( $post_type ) ) {
   1815 		$post_type = reset( $post_type );
   1816 	}
   1817 
   1818 	$post_type_obj = get_post_type_object( $post_type );
   1819 
   1820 	// Check if a description is set.
   1821 	if ( isset( $post_type_obj->description ) ) {
   1822 		$description = $post_type_obj->description;
   1823 	} else {
   1824 		$description = '';
   1825 	}
   1826 
   1827 	/**
   1828 	 * Filters the description for a post type archive.
   1829 	 *
   1830 	 * @since 4.9.0
   1831 	 *
   1832 	 * @param string       $description   The post type description.
   1833 	 * @param WP_Post_Type $post_type_obj The post type object.
   1834 	 */
   1835 	return apply_filters( 'get_the_post_type_description', $description, $post_type_obj );
   1836 }
   1837 
   1838 /**
   1839  * Retrieve archive link content based on predefined or custom code.
   1840  *
   1841  * The format can be one of four styles. The 'link' for head element, 'option'
   1842  * for use in the select element, 'html' for use in list (either ol or ul HTML
   1843  * elements). Custom content is also supported using the before and after
   1844  * parameters.
   1845  *
   1846  * The 'link' format uses the `<link>` HTML element with the **archives**
   1847  * relationship. The before and after parameters are not used. The text
   1848  * parameter is used to describe the link.
   1849  *
   1850  * The 'option' format uses the option HTML element for use in select element.
   1851  * The value is the url parameter and the before and after parameters are used
   1852  * between the text description.
   1853  *
   1854  * The 'html' format, which is the default, uses the li HTML element for use in
   1855  * the list HTML elements. The before parameter is before the link and the after
   1856  * parameter is after the closing link.
   1857  *
   1858  * The custom format uses the before parameter before the link ('a' HTML
   1859  * element) and the after parameter after the closing link tag. If the above
   1860  * three values for the format are not used, then custom format is assumed.
   1861  *
   1862  * @since 1.0.0
   1863  * @since 5.2.0 Added the `$selected` parameter.
   1864  *
   1865  * @param string $url      URL to archive.
   1866  * @param string $text     Archive text description.
   1867  * @param string $format   Optional. Can be 'link', 'option', 'html', or custom. Default 'html'.
   1868  * @param string $before   Optional. Content to prepend to the description. Default empty.
   1869  * @param string $after    Optional. Content to append to the description. Default empty.
   1870  * @param bool   $selected Optional. Set to true if the current page is the selected archive page.
   1871  * @return string HTML link content for archive.
   1872  */
   1873 function get_archives_link( $url, $text, $format = 'html', $before = '', $after = '', $selected = false ) {
   1874 	$text         = wptexturize( $text );
   1875 	$url          = esc_url( $url );
   1876 	$aria_current = $selected ? ' aria-current="page"' : '';
   1877 
   1878 	if ( 'link' === $format ) {
   1879 		$link_html = "\t<link rel='archives' title='" . esc_attr( $text ) . "' href='$url' />\n";
   1880 	} elseif ( 'option' === $format ) {
   1881 		$selected_attr = $selected ? " selected='selected'" : '';
   1882 		$link_html     = "\t<option value='$url'$selected_attr>$before $text $after</option>\n";
   1883 	} elseif ( 'html' === $format ) {
   1884 		$link_html = "\t<li>$before<a href='$url'$aria_current>$text</a>$after</li>\n";
   1885 	} else { // Custom.
   1886 		$link_html = "\t$before<a href='$url'$aria_current>$text</a>$after\n";
   1887 	}
   1888 
   1889 	/**
   1890 	 * Filters the archive link content.
   1891 	 *
   1892 	 * @since 2.6.0
   1893 	 * @since 4.5.0 Added the `$url`, `$text`, `$format`, `$before`, and `$after` parameters.
   1894 	 * @since 5.2.0 Added the `$selected` parameter.
   1895 	 *
   1896 	 * @param string $link_html The archive HTML link content.
   1897 	 * @param string $url       URL to archive.
   1898 	 * @param string $text      Archive text description.
   1899 	 * @param string $format    Link format. Can be 'link', 'option', 'html', or custom.
   1900 	 * @param string $before    Content to prepend to the description.
   1901 	 * @param string $after     Content to append to the description.
   1902 	 * @param bool   $selected  True if the current page is the selected archive.
   1903 	 */
   1904 	return apply_filters( 'get_archives_link', $link_html, $url, $text, $format, $before, $after, $selected );
   1905 }
   1906 
   1907 /**
   1908  * Display archive links based on type and format.
   1909  *
   1910  * @since 1.2.0
   1911  * @since 4.4.0 The `$post_type` argument was added.
   1912  * @since 5.2.0 The `$year`, `$monthnum`, `$day`, and `$w` arguments were added.
   1913  *
   1914  * @see get_archives_link()
   1915  *
   1916  * @global wpdb      $wpdb      WordPress database abstraction object.
   1917  * @global WP_Locale $wp_locale WordPress date and time locale object.
   1918  *
   1919  * @param string|array $args {
   1920  *     Default archive links arguments. Optional.
   1921  *
   1922  *     @type string     $type            Type of archive to retrieve. Accepts 'daily', 'weekly', 'monthly',
   1923  *                                       'yearly', 'postbypost', or 'alpha'. Both 'postbypost' and 'alpha'
   1924  *                                       display the same archive link list as well as post titles instead
   1925  *                                       of displaying dates. The difference between the two is that 'alpha'
   1926  *                                       will order by post title and 'postbypost' will order by post date.
   1927  *                                       Default 'monthly'.
   1928  *     @type string|int $limit           Number of links to limit the query to. Default empty (no limit).
   1929  *     @type string     $format          Format each link should take using the $before and $after args.
   1930  *                                       Accepts 'link' (`<link>` tag), 'option' (`<option>` tag), 'html'
   1931  *                                       (`<li>` tag), or a custom format, which generates a link anchor
   1932  *                                       with $before preceding and $after succeeding. Default 'html'.
   1933  *     @type string     $before          Markup to prepend to the beginning of each link. Default empty.
   1934  *     @type string     $after           Markup to append to the end of each link. Default empty.
   1935  *     @type bool       $show_post_count Whether to display the post count alongside the link. Default false.
   1936  *     @type bool|int   $echo            Whether to echo or return the links list. Default 1|true to echo.
   1937  *     @type string     $order           Whether to use ascending or descending order. Accepts 'ASC', or 'DESC'.
   1938  *                                       Default 'DESC'.
   1939  *     @type string     $post_type       Post type. Default 'post'.
   1940  *     @type string     $year            Year. Default current year.
   1941  *     @type string     $monthnum        Month number. Default current month number.
   1942  *     @type string     $day             Day. Default current day.
   1943  *     @type string     $w               Week. Default current week.
   1944  * }
   1945  * @return void|string Void if 'echo' argument is true, archive links if 'echo' is false.
   1946  */
   1947 function wp_get_archives( $args = '' ) {
   1948 	global $wpdb, $wp_locale;
   1949 
   1950 	$defaults = array(
   1951 		'type'            => 'monthly',
   1952 		'limit'           => '',
   1953 		'format'          => 'html',
   1954 		'before'          => '',
   1955 		'after'           => '',
   1956 		'show_post_count' => false,
   1957 		'echo'            => 1,
   1958 		'order'           => 'DESC',
   1959 		'post_type'       => 'post',
   1960 		'year'            => get_query_var( 'year' ),
   1961 		'monthnum'        => get_query_var( 'monthnum' ),
   1962 		'day'             => get_query_var( 'day' ),
   1963 		'w'               => get_query_var( 'w' ),
   1964 	);
   1965 
   1966 	$parsed_args = wp_parse_args( $args, $defaults );
   1967 
   1968 	$post_type_object = get_post_type_object( $parsed_args['post_type'] );
   1969 	if ( ! is_post_type_viewable( $post_type_object ) ) {
   1970 		return;
   1971 	}
   1972 
   1973 	$parsed_args['post_type'] = $post_type_object->name;
   1974 
   1975 	if ( '' === $parsed_args['type'] ) {
   1976 		$parsed_args['type'] = 'monthly';
   1977 	}
   1978 
   1979 	if ( ! empty( $parsed_args['limit'] ) ) {
   1980 		$parsed_args['limit'] = absint( $parsed_args['limit'] );
   1981 		$parsed_args['limit'] = ' LIMIT ' . $parsed_args['limit'];
   1982 	}
   1983 
   1984 	$order = strtoupper( $parsed_args['order'] );
   1985 	if ( 'ASC' !== $order ) {
   1986 		$order = 'DESC';
   1987 	}
   1988 
   1989 	// This is what will separate dates on weekly archive links.
   1990 	$archive_week_separator = '&#8211;';
   1991 
   1992 	$sql_where = $wpdb->prepare( "WHERE post_type = %s AND post_status = 'publish'", $parsed_args['post_type'] );
   1993 
   1994 	/**
   1995 	 * Filters the SQL WHERE clause for retrieving archives.
   1996 	 *
   1997 	 * @since 2.2.0
   1998 	 *
   1999 	 * @param string $sql_where   Portion of SQL query containing the WHERE clause.
   2000 	 * @param array  $parsed_args An array of default arguments.
   2001 	 */
   2002 	$where = apply_filters( 'getarchives_where', $sql_where, $parsed_args );
   2003 
   2004 	/**
   2005 	 * Filters the SQL JOIN clause for retrieving archives.
   2006 	 *
   2007 	 * @since 2.2.0
   2008 	 *
   2009 	 * @param string $sql_join    Portion of SQL query containing JOIN clause.
   2010 	 * @param array  $parsed_args An array of default arguments.
   2011 	 */
   2012 	$join = apply_filters( 'getarchives_join', '', $parsed_args );
   2013 
   2014 	$output = '';
   2015 
   2016 	$last_changed = wp_cache_get_last_changed( 'posts' );
   2017 
   2018 	$limit = $parsed_args['limit'];
   2019 
   2020 	if ( 'monthly' === $parsed_args['type'] ) {
   2021 		$query   = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date $order $limit";
   2022 		$key     = md5( $query );
   2023 		$key     = "wp_get_archives:$key:$last_changed";
   2024 		$results = wp_cache_get( $key, 'posts' );
   2025 		if ( ! $results ) {
   2026 			$results = $wpdb->get_results( $query );
   2027 			wp_cache_set( $key, $results, 'posts' );
   2028 		}
   2029 		if ( $results ) {
   2030 			$after = $parsed_args['after'];
   2031 			foreach ( (array) $results as $result ) {
   2032 				$url = get_month_link( $result->year, $result->month );
   2033 				if ( 'post' !== $parsed_args['post_type'] ) {
   2034 					$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
   2035 				}
   2036 				/* translators: 1: Month name, 2: 4-digit year. */
   2037 				$text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $result->month ), $result->year );
   2038 				if ( $parsed_args['show_post_count'] ) {
   2039 					$parsed_args['after'] = '&nbsp;(' . $result->posts . ')' . $after;
   2040 				}
   2041 				$selected = is_archive() && (string) $parsed_args['year'] === $result->year && (string) $parsed_args['monthnum'] === $result->month;
   2042 				$output  .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
   2043 			}
   2044 		}
   2045 	} elseif ( 'yearly' === $parsed_args['type'] ) {
   2046 		$query   = "SELECT YEAR(post_date) AS `year`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date) ORDER BY post_date $order $limit";
   2047 		$key     = md5( $query );
   2048 		$key     = "wp_get_archives:$key:$last_changed";
   2049 		$results = wp_cache_get( $key, 'posts' );
   2050 		if ( ! $results ) {
   2051 			$results = $wpdb->get_results( $query );
   2052 			wp_cache_set( $key, $results, 'posts' );
   2053 		}
   2054 		if ( $results ) {
   2055 			$after = $parsed_args['after'];
   2056 			foreach ( (array) $results as $result ) {
   2057 				$url = get_year_link( $result->year );
   2058 				if ( 'post' !== $parsed_args['post_type'] ) {
   2059 					$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
   2060 				}
   2061 				$text = sprintf( '%d', $result->year );
   2062 				if ( $parsed_args['show_post_count'] ) {
   2063 					$parsed_args['after'] = '&nbsp;(' . $result->posts . ')' . $after;
   2064 				}
   2065 				$selected = is_archive() && (string) $parsed_args['year'] === $result->year;
   2066 				$output  .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
   2067 			}
   2068 		}
   2069 	} elseif ( 'daily' === $parsed_args['type'] ) {
   2070 		$query   = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, DAYOFMONTH(post_date) AS `dayofmonth`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date), DAYOFMONTH(post_date) ORDER BY post_date $order $limit";
   2071 		$key     = md5( $query );
   2072 		$key     = "wp_get_archives:$key:$last_changed";
   2073 		$results = wp_cache_get( $key, 'posts' );
   2074 		if ( ! $results ) {
   2075 			$results = $wpdb->get_results( $query );
   2076 			wp_cache_set( $key, $results, 'posts' );
   2077 		}
   2078 		if ( $results ) {
   2079 			$after = $parsed_args['after'];
   2080 			foreach ( (array) $results as $result ) {
   2081 				$url = get_day_link( $result->year, $result->month, $result->dayofmonth );
   2082 				if ( 'post' !== $parsed_args['post_type'] ) {
   2083 					$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
   2084 				}
   2085 				$date = sprintf( '%1$d-%2$02d-%3$02d 00:00:00', $result->year, $result->month, $result->dayofmonth );
   2086 				$text = mysql2date( get_option( 'date_format' ), $date );
   2087 				if ( $parsed_args['show_post_count'] ) {
   2088 					$parsed_args['after'] = '&nbsp;(' . $result->posts . ')' . $after;
   2089 				}
   2090 				$selected = is_archive() && (string) $parsed_args['year'] === $result->year && (string) $parsed_args['monthnum'] === $result->month && (string) $parsed_args['day'] === $result->dayofmonth;
   2091 				$output  .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
   2092 			}
   2093 		}
   2094 	} elseif ( 'weekly' === $parsed_args['type'] ) {
   2095 		$week    = _wp_mysql_week( '`post_date`' );
   2096 		$query   = "SELECT DISTINCT $week AS `week`, YEAR( `post_date` ) AS `yr`, DATE_FORMAT( `post_date`, '%Y-%m-%d' ) AS `yyyymmdd`, count( `ID` ) AS `posts` FROM `$wpdb->posts` $join $where GROUP BY $week, YEAR( `post_date` ) ORDER BY `post_date` $order $limit";
   2097 		$key     = md5( $query );
   2098 		$key     = "wp_get_archives:$key:$last_changed";
   2099 		$results = wp_cache_get( $key, 'posts' );
   2100 		if ( ! $results ) {
   2101 			$results = $wpdb->get_results( $query );
   2102 			wp_cache_set( $key, $results, 'posts' );
   2103 		}
   2104 		$arc_w_last = '';
   2105 		if ( $results ) {
   2106 			$after = $parsed_args['after'];
   2107 			foreach ( (array) $results as $result ) {
   2108 				if ( $result->week != $arc_w_last ) {
   2109 					$arc_year       = $result->yr;
   2110 					$arc_w_last     = $result->week;
   2111 					$arc_week       = get_weekstartend( $result->yyyymmdd, get_option( 'start_of_week' ) );
   2112 					$arc_week_start = date_i18n( get_option( 'date_format' ), $arc_week['start'] );
   2113 					$arc_week_end   = date_i18n( get_option( 'date_format' ), $arc_week['end'] );
   2114 					$url            = add_query_arg(
   2115 						array(
   2116 							'm' => $arc_year,
   2117 							'w' => $result->week,
   2118 						),
   2119 						home_url( '/' )
   2120 					);
   2121 					if ( 'post' !== $parsed_args['post_type'] ) {
   2122 						$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
   2123 					}
   2124 					$text = $arc_week_start . $archive_week_separator . $arc_week_end;
   2125 					if ( $parsed_args['show_post_count'] ) {
   2126 						$parsed_args['after'] = '&nbsp;(' . $result->posts . ')' . $after;
   2127 					}
   2128 					$selected = is_archive() && (string) $parsed_args['year'] === $result->yr && (string) $parsed_args['w'] === $result->week;
   2129 					$output  .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
   2130 				}
   2131 			}
   2132 		}
   2133 	} elseif ( ( 'postbypost' === $parsed_args['type'] ) || ( 'alpha' === $parsed_args['type'] ) ) {
   2134 		$orderby = ( 'alpha' === $parsed_args['type'] ) ? 'post_title ASC ' : 'post_date DESC, ID DESC ';
   2135 		$query   = "SELECT * FROM $wpdb->posts $join $where ORDER BY $orderby $limit";
   2136 		$key     = md5( $query );
   2137 		$key     = "wp_get_archives:$key:$last_changed";
   2138 		$results = wp_cache_get( $key, 'posts' );
   2139 		if ( ! $results ) {
   2140 			$results = $wpdb->get_results( $query );
   2141 			wp_cache_set( $key, $results, 'posts' );
   2142 		}
   2143 		if ( $results ) {
   2144 			foreach ( (array) $results as $result ) {
   2145 				if ( '0000-00-00 00:00:00' !== $result->post_date ) {
   2146 					$url = get_permalink( $result );
   2147 					if ( $result->post_title ) {
   2148 						/** This filter is documented in wp-includes/post-template.php */
   2149 						$text = strip_tags( apply_filters( 'the_title', $result->post_title, $result->ID ) );
   2150 					} else {
   2151 						$text = $result->ID;
   2152 					}
   2153 					$selected = get_the_ID() === $result->ID;
   2154 					$output  .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
   2155 				}
   2156 			}
   2157 		}
   2158 	}
   2159 
   2160 	if ( $parsed_args['echo'] ) {
   2161 		echo $output;
   2162 	} else {
   2163 		return $output;
   2164 	}
   2165 }
   2166 
   2167 /**
   2168  * Get number of days since the start of the week.
   2169  *
   2170  * @since 1.5.0
   2171  *
   2172  * @param int $num Number of day.
   2173  * @return float Days since the start of the week.
   2174  */
   2175 function calendar_week_mod( $num ) {
   2176 	$base = 7;
   2177 	return ( $num - $base * floor( $num / $base ) );
   2178 }
   2179 
   2180 /**
   2181  * Display calendar with days that have posts as links.
   2182  *
   2183  * The calendar is cached, which will be retrieved, if it exists. If there are
   2184  * no posts for the month, then it will not be displayed.
   2185  *
   2186  * @since 1.0.0
   2187  *
   2188  * @global wpdb      $wpdb      WordPress database abstraction object.
   2189  * @global int       $m
   2190  * @global int       $monthnum
   2191  * @global int       $year
   2192  * @global WP_Locale $wp_locale WordPress date and time locale object.
   2193  * @global array     $posts
   2194  *
   2195  * @param bool $initial Optional. Whether to use initial calendar names. Default true.
   2196  * @param bool $echo    Optional. Whether to display the calendar output. Default true.
   2197  * @return void|string Void if `$echo` argument is true, calendar HTML if `$echo` is false.
   2198  */
   2199 function get_calendar( $initial = true, $echo = true ) {
   2200 	global $wpdb, $m, $monthnum, $year, $wp_locale, $posts;
   2201 
   2202 	$key   = md5( $m . $monthnum . $year );
   2203 	$cache = wp_cache_get( 'get_calendar', 'calendar' );
   2204 
   2205 	if ( $cache && is_array( $cache ) && isset( $cache[ $key ] ) ) {
   2206 		/** This filter is documented in wp-includes/general-template.php */
   2207 		$output = apply_filters( 'get_calendar', $cache[ $key ] );
   2208 
   2209 		if ( $echo ) {
   2210 			echo $output;
   2211 			return;
   2212 		}
   2213 
   2214 		return $output;
   2215 	}
   2216 
   2217 	if ( ! is_array( $cache ) ) {
   2218 		$cache = array();
   2219 	}
   2220 
   2221 	// Quick check. If we have no posts at all, abort!
   2222 	if ( ! $posts ) {
   2223 		$gotsome = $wpdb->get_var( "SELECT 1 as test FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' LIMIT 1" );
   2224 		if ( ! $gotsome ) {
   2225 			$cache[ $key ] = '';
   2226 			wp_cache_set( 'get_calendar', $cache, 'calendar' );
   2227 			return;
   2228 		}
   2229 	}
   2230 
   2231 	if ( isset( $_GET['w'] ) ) {
   2232 		$w = (int) $_GET['w'];
   2233 	}
   2234 	// week_begins = 0 stands for Sunday.
   2235 	$week_begins = (int) get_option( 'start_of_week' );
   2236 
   2237 	// Let's figure out when we are.
   2238 	if ( ! empty( $monthnum ) && ! empty( $year ) ) {
   2239 		$thismonth = zeroise( (int) $monthnum, 2 );
   2240 		$thisyear  = (int) $year;
   2241 	} elseif ( ! empty( $w ) ) {
   2242 		// We need to get the month from MySQL.
   2243 		$thisyear = (int) substr( $m, 0, 4 );
   2244 		// It seems MySQL's weeks disagree with PHP's.
   2245 		$d         = ( ( $w - 1 ) * 7 ) + 6;
   2246 		$thismonth = $wpdb->get_var( "SELECT DATE_FORMAT((DATE_ADD('{$thisyear}0101', INTERVAL $d DAY) ), '%m')" );
   2247 	} elseif ( ! empty( $m ) ) {
   2248 		$thisyear = (int) substr( $m, 0, 4 );
   2249 		if ( strlen( $m ) < 6 ) {
   2250 			$thismonth = '01';
   2251 		} else {
   2252 			$thismonth = zeroise( (int) substr( $m, 4, 2 ), 2 );
   2253 		}
   2254 	} else {
   2255 		$thisyear  = current_time( 'Y' );
   2256 		$thismonth = current_time( 'm' );
   2257 	}
   2258 
   2259 	$unixmonth = mktime( 0, 0, 0, $thismonth, 1, $thisyear );
   2260 	$last_day  = gmdate( 't', $unixmonth );
   2261 
   2262 	// Get the next and previous month and year with at least one post.
   2263 	$previous = $wpdb->get_row(
   2264 		"SELECT MONTH(post_date) AS month, YEAR(post_date) AS year
   2265 		FROM $wpdb->posts
   2266 		WHERE post_date < '$thisyear-$thismonth-01'
   2267 		AND post_type = 'post' AND post_status = 'publish'
   2268 			ORDER BY post_date DESC
   2269 			LIMIT 1"
   2270 	);
   2271 	$next     = $wpdb->get_row(
   2272 		"SELECT MONTH(post_date) AS month, YEAR(post_date) AS year
   2273 		FROM $wpdb->posts
   2274 		WHERE post_date > '$thisyear-$thismonth-{$last_day} 23:59:59'
   2275 		AND post_type = 'post' AND post_status = 'publish'
   2276 			ORDER BY post_date ASC
   2277 			LIMIT 1"
   2278 	);
   2279 
   2280 	/* translators: Calendar caption: 1: Month name, 2: 4-digit year. */
   2281 	$calendar_caption = _x( '%1$s %2$s', 'calendar caption' );
   2282 	$calendar_output  = '<table id="wp-calendar" class="wp-calendar-table">
   2283 	<caption>' . sprintf(
   2284 		$calendar_caption,
   2285 		$wp_locale->get_month( $thismonth ),
   2286 		gmdate( 'Y', $unixmonth )
   2287 	) . '</caption>
   2288 	<thead>
   2289 	<tr>';
   2290 
   2291 	$myweek = array();
   2292 
   2293 	for ( $wdcount = 0; $wdcount <= 6; $wdcount++ ) {
   2294 		$myweek[] = $wp_locale->get_weekday( ( $wdcount + $week_begins ) % 7 );
   2295 	}
   2296 
   2297 	foreach ( $myweek as $wd ) {
   2298 		$day_name         = $initial ? $wp_locale->get_weekday_initial( $wd ) : $wp_locale->get_weekday_abbrev( $wd );
   2299 		$wd               = esc_attr( $wd );
   2300 		$calendar_output .= "\n\t\t<th scope=\"col\" title=\"$wd\">$day_name</th>";
   2301 	}
   2302 
   2303 	$calendar_output .= '
   2304 	</tr>
   2305 	</thead>
   2306 	<tbody>
   2307 	<tr>';
   2308 
   2309 	$daywithpost = array();
   2310 
   2311 	// Get days with posts.
   2312 	$dayswithposts = $wpdb->get_results(
   2313 		"SELECT DISTINCT DAYOFMONTH(post_date)
   2314 		FROM $wpdb->posts WHERE post_date >= '{$thisyear}-{$thismonth}-01 00:00:00'
   2315 		AND post_type = 'post' AND post_status = 'publish'
   2316 		AND post_date <= '{$thisyear}-{$thismonth}-{$last_day} 23:59:59'",
   2317 		ARRAY_N
   2318 	);
   2319 
   2320 	if ( $dayswithposts ) {
   2321 		foreach ( (array) $dayswithposts as $daywith ) {
   2322 			$daywithpost[] = (int) $daywith[0];
   2323 		}
   2324 	}
   2325 
   2326 	// See how much we should pad in the beginning.
   2327 	$pad = calendar_week_mod( gmdate( 'w', $unixmonth ) - $week_begins );
   2328 	if ( 0 != $pad ) {
   2329 		$calendar_output .= "\n\t\t" . '<td colspan="' . esc_attr( $pad ) . '" class="pad">&nbsp;</td>';
   2330 	}
   2331 
   2332 	$newrow      = false;
   2333 	$daysinmonth = (int) gmdate( 't', $unixmonth );
   2334 
   2335 	for ( $day = 1; $day <= $daysinmonth; ++$day ) {
   2336 		if ( isset( $newrow ) && $newrow ) {
   2337 			$calendar_output .= "\n\t</tr>\n\t<tr>\n\t\t";
   2338 		}
   2339 		$newrow = false;
   2340 
   2341 		if ( current_time( 'j' ) == $day &&
   2342 			current_time( 'm' ) == $thismonth &&
   2343 			current_time( 'Y' ) == $thisyear ) {
   2344 			$calendar_output .= '<td id="today">';
   2345 		} else {
   2346 			$calendar_output .= '<td>';
   2347 		}
   2348 
   2349 		if ( in_array( $day, $daywithpost, true ) ) {
   2350 			// Any posts today?
   2351 			$date_format = gmdate( _x( 'F j, Y', 'daily archives date format' ), strtotime( "{$thisyear}-{$thismonth}-{$day}" ) );
   2352 			/* translators: Post calendar label. %s: Date. */
   2353 			$label            = sprintf( __( 'Posts published on %s' ), $date_format );
   2354 			$calendar_output .= sprintf(
   2355 				'<a href="%s" aria-label="%s">%s</a>',
   2356 				get_day_link( $thisyear, $thismonth, $day ),
   2357 				esc_attr( $label ),
   2358 				$day
   2359 			);
   2360 		} else {
   2361 			$calendar_output .= $day;
   2362 		}
   2363 
   2364 		$calendar_output .= '</td>';
   2365 
   2366 		if ( 6 == calendar_week_mod( gmdate( 'w', mktime( 0, 0, 0, $thismonth, $day, $thisyear ) ) - $week_begins ) ) {
   2367 			$newrow = true;
   2368 		}
   2369 	}
   2370 
   2371 	$pad = 7 - calendar_week_mod( gmdate( 'w', mktime( 0, 0, 0, $thismonth, $day, $thisyear ) ) - $week_begins );
   2372 	if ( 0 != $pad && 7 != $pad ) {
   2373 		$calendar_output .= "\n\t\t" . '<td class="pad" colspan="' . esc_attr( $pad ) . '">&nbsp;</td>';
   2374 	}
   2375 
   2376 	$calendar_output .= "\n\t</tr>\n\t</tbody>";
   2377 
   2378 	$calendar_output .= "\n\t</table>";
   2379 
   2380 	$calendar_output .= '<nav aria-label="' . __( 'Previous and next months' ) . '" class="wp-calendar-nav">';
   2381 
   2382 	if ( $previous ) {
   2383 		$calendar_output .= "\n\t\t" . '<span class="wp-calendar-nav-prev"><a href="' . get_month_link( $previous->year, $previous->month ) . '">&laquo; ' .
   2384 			$wp_locale->get_month_abbrev( $wp_locale->get_month( $previous->month ) ) .
   2385 		'</a></span>';
   2386 	} else {
   2387 		$calendar_output .= "\n\t\t" . '<span class="wp-calendar-nav-prev">&nbsp;</span>';
   2388 	}
   2389 
   2390 	$calendar_output .= "\n\t\t" . '<span class="pad">&nbsp;</span>';
   2391 
   2392 	if ( $next ) {
   2393 		$calendar_output .= "\n\t\t" . '<span class="wp-calendar-nav-next"><a href="' . get_month_link( $next->year, $next->month ) . '">' .
   2394 			$wp_locale->get_month_abbrev( $wp_locale->get_month( $next->month ) ) .
   2395 		' &raquo;</a></span>';
   2396 	} else {
   2397 		$calendar_output .= "\n\t\t" . '<span class="wp-calendar-nav-next">&nbsp;</span>';
   2398 	}
   2399 
   2400 	$calendar_output .= '
   2401 	</nav>';
   2402 
   2403 	$cache[ $key ] = $calendar_output;
   2404 	wp_cache_set( 'get_calendar', $cache, 'calendar' );
   2405 
   2406 	if ( $echo ) {
   2407 		/**
   2408 		 * Filters the HTML calendar output.
   2409 		 *
   2410 		 * @since 3.0.0
   2411 		 *
   2412 		 * @param string $calendar_output HTML output of the calendar.
   2413 		 */
   2414 		echo apply_filters( 'get_calendar', $calendar_output );
   2415 		return;
   2416 	}
   2417 	/** This filter is documented in wp-includes/general-template.php */
   2418 	return apply_filters( 'get_calendar', $calendar_output );
   2419 }
   2420 
   2421 /**
   2422  * Purge the cached results of get_calendar.
   2423  *
   2424  * @see get_calendar()
   2425  * @since 2.1.0
   2426  */
   2427 function delete_get_calendar_cache() {
   2428 	wp_cache_delete( 'get_calendar', 'calendar' );
   2429 }
   2430 
   2431 /**
   2432  * Display all of the allowed tags in HTML format with attributes.
   2433  *
   2434  * This is useful for displaying in the comment area, which elements and
   2435  * attributes are supported. As well as any plugins which want to display it.
   2436  *
   2437  * @since 1.0.1
   2438  *
   2439  * @global array $allowedtags
   2440  *
   2441  * @return string HTML allowed tags entity encoded.
   2442  */
   2443 function allowed_tags() {
   2444 	global $allowedtags;
   2445 	$allowed = '';
   2446 	foreach ( (array) $allowedtags as $tag => $attributes ) {
   2447 		$allowed .= '<' . $tag;
   2448 		if ( 0 < count( $attributes ) ) {
   2449 			foreach ( $attributes as $attribute => $limits ) {
   2450 				$allowed .= ' ' . $attribute . '=""';
   2451 			}
   2452 		}
   2453 		$allowed .= '> ';
   2454 	}
   2455 	return htmlentities( $allowed );
   2456 }
   2457 
   2458 /***** Date/Time tags */
   2459 
   2460 /**
   2461  * Outputs the date in iso8601 format for xml files.
   2462  *
   2463  * @since 1.0.0
   2464  */
   2465 function the_date_xml() {
   2466 	echo mysql2date( 'Y-m-d', get_post()->post_date, false );
   2467 }
   2468 
   2469 /**
   2470  * Display or Retrieve the date the current post was written (once per date)
   2471  *
   2472  * Will only output the date if the current post's date is different from the
   2473  * previous one output.
   2474  *
   2475  * i.e. Only one date listing will show per day worth of posts shown in the loop, even if the
   2476  * function is called several times for each post.
   2477  *
   2478  * HTML output can be filtered with 'the_date'.
   2479  * Date string output can be filtered with 'get_the_date'.
   2480  *
   2481  * @since 0.71
   2482  *
   2483  * @global string $currentday  The day of the current post in the loop.
   2484  * @global string $previousday The day of the previous post in the loop.
   2485  *
   2486  * @param string $format Optional. PHP date format. Defaults to the 'date_format' option.
   2487  * @param string $before Optional. Output before the date. Default empty.
   2488  * @param string $after  Optional. Output after the date. Default empty.
   2489  * @param bool   $echo   Optional. Whether to echo the date or return it. Default true.
   2490  * @return string|void String if retrieving.
   2491  */
   2492 function the_date( $format = '', $before = '', $after = '', $echo = true ) {
   2493 	global $currentday, $previousday;
   2494 
   2495 	$the_date = '';
   2496 
   2497 	if ( is_new_day() ) {
   2498 		$the_date    = $before . get_the_date( $format ) . $after;
   2499 		$previousday = $currentday;
   2500 	}
   2501 
   2502 	/**
   2503 	 * Filters the date a post was published for display.
   2504 	 *
   2505 	 * @since 0.71
   2506 	 *
   2507 	 * @param string $the_date The formatted date string.
   2508 	 * @param string $format   PHP date format.
   2509 	 * @param string $before   HTML output before the date.
   2510 	 * @param string $after    HTML output after the date.
   2511 	 */
   2512 	$the_date = apply_filters( 'the_date', $the_date, $format, $before, $after );
   2513 
   2514 	if ( $echo ) {
   2515 		echo $the_date;
   2516 	} else {
   2517 		return $the_date;
   2518 	}
   2519 }
   2520 
   2521 /**
   2522  * Retrieve the date on which the post was written.
   2523  *
   2524  * Unlike the_date() this function will always return the date.
   2525  * Modify output with the {@see 'get_the_date'} filter.
   2526  *
   2527  * @since 3.0.0
   2528  *
   2529  * @param string      $format Optional. PHP date format. Defaults to the 'date_format' option.
   2530  * @param int|WP_Post $post   Optional. Post ID or WP_Post object. Default current post.
   2531  * @return string|false Date the current post was written. False on failure.
   2532  */
   2533 function get_the_date( $format = '', $post = null ) {
   2534 	$post = get_post( $post );
   2535 
   2536 	if ( ! $post ) {
   2537 		return false;
   2538 	}
   2539 
   2540 	$_format = ! empty( $format ) ? $format : get_option( 'date_format' );
   2541 
   2542 	$the_date = get_post_time( $_format, false, $post, true );
   2543 
   2544 	/**
   2545 	 * Filters the date a post was published.
   2546 	 *
   2547 	 * @since 3.0.0
   2548 	 *
   2549 	 * @param string      $the_date The formatted date.
   2550 	 * @param string      $format   PHP date format.
   2551 	 * @param int|WP_Post $post     The post object or ID.
   2552 	 */
   2553 	return apply_filters( 'get_the_date', $the_date, $format, $post );
   2554 }
   2555 
   2556 /**
   2557  * Display the date on which the post was last modified.
   2558  *
   2559  * @since 2.1.0
   2560  *
   2561  * @param string $format Optional. PHP date format. Defaults to the 'date_format' option.
   2562  * @param string $before Optional. Output before the date. Default empty.
   2563  * @param string $after  Optional. Output after the date. Default empty.
   2564  * @param bool   $echo   Optional. Whether to echo the date or return it. Default true.
   2565  * @return string|void String if retrieving.
   2566  */
   2567 function the_modified_date( $format = '', $before = '', $after = '', $echo = true ) {
   2568 	$the_modified_date = $before . get_the_modified_date( $format ) . $after;
   2569 
   2570 	/**
   2571 	 * Filters the date a post was last modified for display.
   2572 	 *
   2573 	 * @since 2.1.0
   2574 	 *
   2575 	 * @param string|false $the_modified_date The last modified date or false if no post is found.
   2576 	 * @param string       $format            PHP date format.
   2577 	 * @param string       $before            HTML output before the date.
   2578 	 * @param string       $after             HTML output after the date.
   2579 	 */
   2580 	$the_modified_date = apply_filters( 'the_modified_date', $the_modified_date, $format, $before, $after );
   2581 
   2582 	if ( $echo ) {
   2583 		echo $the_modified_date;
   2584 	} else {
   2585 		return $the_modified_date;
   2586 	}
   2587 
   2588 }
   2589 
   2590 /**
   2591  * Retrieve the date on which the post was last modified.
   2592  *
   2593  * @since 2.1.0
   2594  * @since 4.6.0 Added the `$post` parameter.
   2595  *
   2596  * @param string      $format Optional. PHP date format. Defaults to the 'date_format' option.
   2597  * @param int|WP_Post $post   Optional. Post ID or WP_Post object. Default current post.
   2598  * @return string|int|false Date the current post was modified. False on failure.
   2599  */
   2600 function get_the_modified_date( $format = '', $post = null ) {
   2601 	$post = get_post( $post );
   2602 
   2603 	if ( ! $post ) {
   2604 		// For backward compatibility, failures go through the filter below.
   2605 		$the_time = false;
   2606 	} else {
   2607 		$_format = ! empty( $format ) ? $format : get_option( 'date_format' );
   2608 
   2609 		$the_time = get_post_modified_time( $_format, false, $post, true );
   2610 	}
   2611 
   2612 	/**
   2613 	 * Filters the date a post was last modified.
   2614 	 *
   2615 	 * @since 2.1.0
   2616 	 * @since 4.6.0 Added the `$post` parameter.
   2617 	 *
   2618 	 * @param string|int|false $the_time The formatted date or false if no post is found.
   2619 	 * @param string           $format   PHP date format.
   2620 	 * @param WP_Post|null     $post     WP_Post object or null if no post is found.
   2621 	 */
   2622 	return apply_filters( 'get_the_modified_date', $the_time, $format, $post );
   2623 }
   2624 
   2625 /**
   2626  * Display the time at which the post was written.
   2627  *
   2628  * @since 0.71
   2629  *
   2630  * @param string $format Optional. Format to use for retrieving the time the post
   2631  *                       was written. Accepts 'G', 'U', or PHP date format.
   2632  *                       Defaults to the 'time_format' option.
   2633  */
   2634 function the_time( $format = '' ) {
   2635 	/**
   2636 	 * Filters the time a post was written for display.
   2637 	 *
   2638 	 * @since 0.71
   2639 	 *
   2640 	 * @param string $get_the_time The formatted time.
   2641 	 * @param string $format       Format to use for retrieving the time the post
   2642 	 *                             was written. Accepts 'G', 'U', or PHP date format.
   2643 	 */
   2644 	echo apply_filters( 'the_time', get_the_time( $format ), $format );
   2645 }
   2646 
   2647 /**
   2648  * Retrieve the time at which the post was written.
   2649  *
   2650  * @since 1.5.0
   2651  *
   2652  * @param string      $format Optional. Format to use for retrieving the time the post
   2653  *                            was written. Accepts 'G', 'U', or PHP date format.
   2654  *                            Defaults to the 'time_format' option.
   2655  * @param int|WP_Post $post   WP_Post object or ID. Default is global `$post` object.
   2656  * @return string|int|false Formatted date string or Unix timestamp if `$format` is 'U' or 'G'.
   2657  *                          False on failure.
   2658  */
   2659 function get_the_time( $format = '', $post = null ) {
   2660 	$post = get_post( $post );
   2661 
   2662 	if ( ! $post ) {
   2663 		return false;
   2664 	}
   2665 
   2666 	$_format = ! empty( $format ) ? $format : get_option( 'time_format' );
   2667 
   2668 	$the_time = get_post_time( $_format, false, $post, true );
   2669 
   2670 	/**
   2671 	 * Filters the time a post was written.
   2672 	 *
   2673 	 * @since 1.5.0
   2674 	 *
   2675 	 * @param string      $the_time The formatted time.
   2676 	 * @param string      $format   Format to use for retrieving the time the post
   2677 	 *                              was written. Accepts 'G', 'U', or PHP date format.
   2678 	 * @param int|WP_Post $post     WP_Post object or ID.
   2679 	 */
   2680 	return apply_filters( 'get_the_time', $the_time, $format, $post );
   2681 }
   2682 
   2683 /**
   2684  * Retrieve the time at which the post was written.
   2685  *
   2686  * @since 2.0.0
   2687  *
   2688  * @param string      $format    Optional. Format to use for retrieving the time the post
   2689  *                               was written. Accepts 'G', 'U', or PHP date format. Default 'U'.
   2690  * @param bool        $gmt       Optional. Whether to retrieve the GMT time. Default false.
   2691  * @param int|WP_Post $post      WP_Post object or ID. Default is global `$post` object.
   2692  * @param bool        $translate Whether to translate the time string. Default false.
   2693  * @return string|int|false Formatted date string or Unix timestamp if `$format` is 'U' or 'G'.
   2694  *                          False on failure.
   2695  */
   2696 function get_post_time( $format = 'U', $gmt = false, $post = null, $translate = false ) {
   2697 	$post = get_post( $post );
   2698 
   2699 	if ( ! $post ) {
   2700 		return false;
   2701 	}
   2702 
   2703 	$source   = ( $gmt ) ? 'gmt' : 'local';
   2704 	$datetime = get_post_datetime( $post, 'date', $source );
   2705 
   2706 	if ( false === $datetime ) {
   2707 		return false;
   2708 	}
   2709 
   2710 	if ( 'U' === $format || 'G' === $format ) {
   2711 		$time = $datetime->getTimestamp();
   2712 
   2713 		// Returns a sum of timestamp with timezone offset. Ideally should never be used.
   2714 		if ( ! $gmt ) {
   2715 			$time += $datetime->getOffset();
   2716 		}
   2717 	} elseif ( $translate ) {
   2718 		$time = wp_date( $format, $datetime->getTimestamp(), $gmt ? new DateTimeZone( 'UTC' ) : null );
   2719 	} else {
   2720 		if ( $gmt ) {
   2721 			$datetime = $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
   2722 		}
   2723 
   2724 		$time = $datetime->format( $format );
   2725 	}
   2726 
   2727 	/**
   2728 	 * Filters the localized time a post was written.
   2729 	 *
   2730 	 * @since 2.6.0
   2731 	 *
   2732 	 * @param string $time   The formatted time.
   2733 	 * @param string $format Format to use for retrieving the time the post was written.
   2734 	 *                       Accepts 'G', 'U', or PHP date format. Default 'U'.
   2735 	 * @param bool   $gmt    Whether to retrieve the GMT time. Default false.
   2736 	 */
   2737 	return apply_filters( 'get_post_time', $time, $format, $gmt );
   2738 }
   2739 
   2740 /**
   2741  * Retrieve post published or modified time as a `DateTimeImmutable` object instance.
   2742  *
   2743  * The object will be set to the timezone from WordPress settings.
   2744  *
   2745  * For legacy reasons, this function allows to choose to instantiate from local or UTC time in database.
   2746  * Normally this should make no difference to the result. However, the values might get out of sync in database,
   2747  * typically because of timezone setting changes. The parameter ensures the ability to reproduce backwards
   2748  * compatible behaviors in such cases.
   2749  *
   2750  * @since 5.3.0
   2751  *
   2752  * @param int|WP_Post $post   Optional. WP_Post object or ID. Default is global `$post` object.
   2753  * @param string      $field  Optional. Published or modified time to use from database. Accepts 'date' or 'modified'.
   2754  *                            Default 'date'.
   2755  * @param string      $source Optional. Local or UTC time to use from database. Accepts 'local' or 'gmt'.
   2756  *                            Default 'local'.
   2757  * @return DateTimeImmutable|false Time object on success, false on failure.
   2758  */
   2759 function get_post_datetime( $post = null, $field = 'date', $source = 'local' ) {
   2760 	$post = get_post( $post );
   2761 
   2762 	if ( ! $post ) {
   2763 		return false;
   2764 	}
   2765 
   2766 	$wp_timezone = wp_timezone();
   2767 
   2768 	if ( 'gmt' === $source ) {
   2769 		$time     = ( 'modified' === $field ) ? $post->post_modified_gmt : $post->post_date_gmt;
   2770 		$timezone = new DateTimeZone( 'UTC' );
   2771 	} else {
   2772 		$time     = ( 'modified' === $field ) ? $post->post_modified : $post->post_date;
   2773 		$timezone = $wp_timezone;
   2774 	}
   2775 
   2776 	if ( empty( $time ) || '0000-00-00 00:00:00' === $time ) {
   2777 		return false;
   2778 	}
   2779 
   2780 	$datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', $time, $timezone );
   2781 
   2782 	if ( false === $datetime ) {
   2783 		return false;
   2784 	}
   2785 
   2786 	return $datetime->setTimezone( $wp_timezone );
   2787 }
   2788 
   2789 /**
   2790  * Retrieve post published or modified time as a Unix timestamp.
   2791  *
   2792  * Note that this function returns a true Unix timestamp, not summed with timezone offset
   2793  * like older WP functions.
   2794  *
   2795  * @since 5.3.0
   2796  *
   2797  * @param int|WP_Post $post  Optional. WP_Post object or ID. Default is global `$post` object.
   2798  * @param string      $field Optional. Published or modified time to use from database. Accepts 'date' or 'modified'.
   2799  *                           Default 'date'.
   2800  * @return int|false Unix timestamp on success, false on failure.
   2801  */
   2802 function get_post_timestamp( $post = null, $field = 'date' ) {
   2803 	$datetime = get_post_datetime( $post, $field );
   2804 
   2805 	if ( false === $datetime ) {
   2806 		return false;
   2807 	}
   2808 
   2809 	return $datetime->getTimestamp();
   2810 }
   2811 
   2812 /**
   2813  * Display the time at which the post was last modified.
   2814  *
   2815  * @since 2.0.0
   2816  *
   2817  * @param string $format Optional. Format to use for retrieving the time the post
   2818  *                       was modified. Accepts 'G', 'U', or PHP date format.
   2819  *                       Defaults to the 'time_format' option.
   2820  */
   2821 function the_modified_time( $format = '' ) {
   2822 	/**
   2823 	 * Filters the localized time a post was last modified, for display.
   2824 	 *
   2825 	 * @since 2.0.0
   2826 	 *
   2827 	 * @param string|false $get_the_modified_time The formatted time or false if no post is found.
   2828 	 * @param string       $format                Format to use for retrieving the time the post
   2829 	 *                                            was modified. Accepts 'G', 'U', or PHP date format.
   2830 	 */
   2831 	echo apply_filters( 'the_modified_time', get_the_modified_time( $format ), $format );
   2832 }
   2833 
   2834 /**
   2835  * Retrieve the time at which the post was last modified.
   2836  *
   2837  * @since 2.0.0
   2838  * @since 4.6.0 Added the `$post` parameter.
   2839  *
   2840  * @param string      $format Optional. Format to use for retrieving the time the post
   2841  *                            was modified. Accepts 'G', 'U', or PHP date format.
   2842  *                            Defaults to the 'time_format' option.
   2843  * @param int|WP_Post $post   Optional. Post ID or WP_Post object. Default current post.
   2844  * @return string|int|false Formatted date string or Unix timestamp. False on failure.
   2845  */
   2846 function get_the_modified_time( $format = '', $post = null ) {
   2847 	$post = get_post( $post );
   2848 
   2849 	if ( ! $post ) {
   2850 		// For backward compatibility, failures go through the filter below.
   2851 		$the_time = false;
   2852 	} else {
   2853 		$_format = ! empty( $format ) ? $format : get_option( 'time_format' );
   2854 
   2855 		$the_time = get_post_modified_time( $_format, false, $post, true );
   2856 	}
   2857 
   2858 	/**
   2859 	 * Filters the localized time a post was last modified.
   2860 	 *
   2861 	 * @since 2.0.0
   2862 	 * @since 4.6.0 Added the `$post` parameter.
   2863 	 *
   2864 	 * @param string|int|false $the_time The formatted time or false if no post is found.
   2865 	 * @param string           $format   Format to use for retrieving the time the post
   2866 	 *                                   was modified. Accepts 'G', 'U', or PHP date format.
   2867 	 * @param WP_Post|null     $post     WP_Post object or null if no post is found.
   2868 	 */
   2869 	return apply_filters( 'get_the_modified_time', $the_time, $format, $post );
   2870 }
   2871 
   2872 /**
   2873  * Retrieve the time at which the post was last modified.
   2874  *
   2875  * @since 2.0.0
   2876  *
   2877  * @param string      $format    Optional. Format to use for retrieving the time the post
   2878  *                               was modified. Accepts 'G', 'U', or PHP date format. Default 'U'.
   2879  * @param bool        $gmt       Optional. Whether to retrieve the GMT time. Default false.
   2880  * @param int|WP_Post $post      WP_Post object or ID. Default is global `$post` object.
   2881  * @param bool        $translate Whether to translate the time string. Default false.
   2882  * @return string|int|false Formatted date string or Unix timestamp if `$format` is 'U' or 'G'.
   2883  *                          False on failure.
   2884  */
   2885 function get_post_modified_time( $format = 'U', $gmt = false, $post = null, $translate = false ) {
   2886 	$post = get_post( $post );
   2887 
   2888 	if ( ! $post ) {
   2889 		return false;
   2890 	}
   2891 
   2892 	$source   = ( $gmt ) ? 'gmt' : 'local';
   2893 	$datetime = get_post_datetime( $post, 'modified', $source );
   2894 
   2895 	if ( false === $datetime ) {
   2896 		return false;
   2897 	}
   2898 
   2899 	if ( 'U' === $format || 'G' === $format ) {
   2900 		$time = $datetime->getTimestamp();
   2901 
   2902 		// Returns a sum of timestamp with timezone offset. Ideally should never be used.
   2903 		if ( ! $gmt ) {
   2904 			$time += $datetime->getOffset();
   2905 		}
   2906 	} elseif ( $translate ) {
   2907 		$time = wp_date( $format, $datetime->getTimestamp(), $gmt ? new DateTimeZone( 'UTC' ) : null );
   2908 	} else {
   2909 		if ( $gmt ) {
   2910 			$datetime = $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
   2911 		}
   2912 
   2913 		$time = $datetime->format( $format );
   2914 	}
   2915 
   2916 	/**
   2917 	 * Filters the localized time a post was last modified.
   2918 	 *
   2919 	 * @since 2.8.0
   2920 	 *
   2921 	 * @param string|int $time   Formatted date string or Unix timestamp if `$format` is 'U' or 'G'.
   2922 	 * @param string     $format Format to use for retrieving the time the post was modified.
   2923 	 *                           Accepts 'G', 'U', or PHP date format. Default 'U'.
   2924 	 * @param bool       $gmt    Whether to retrieve the GMT time. Default false.
   2925 	 */
   2926 	return apply_filters( 'get_post_modified_time', $time, $format, $gmt );
   2927 }
   2928 
   2929 /**
   2930  * Display the weekday on which the post was written.
   2931  *
   2932  * @since 0.71
   2933  *
   2934  * @global WP_Locale $wp_locale WordPress date and time locale object.
   2935  */
   2936 function the_weekday() {
   2937 	global $wp_locale;
   2938 
   2939 	$post = get_post();
   2940 
   2941 	if ( ! $post ) {
   2942 		return;
   2943 	}
   2944 
   2945 	$the_weekday = $wp_locale->get_weekday( get_post_time( 'w', false, $post ) );
   2946 
   2947 	/**
   2948 	 * Filters the weekday on which the post was written, for display.
   2949 	 *
   2950 	 * @since 0.71
   2951 	 *
   2952 	 * @param string $the_weekday
   2953 	 */
   2954 	echo apply_filters( 'the_weekday', $the_weekday );
   2955 }
   2956 
   2957 /**
   2958  * Display the weekday on which the post was written.
   2959  *
   2960  * Will only output the weekday if the current post's weekday is different from
   2961  * the previous one output.
   2962  *
   2963  * @since 0.71
   2964  *
   2965  * @global WP_Locale $wp_locale       WordPress date and time locale object.
   2966  * @global string    $currentday      The day of the current post in the loop.
   2967  * @global string    $previousweekday The day of the previous post in the loop.
   2968  *
   2969  * @param string $before Optional. Output before the date. Default empty.
   2970  * @param string $after  Optional. Output after the date. Default empty.
   2971  */
   2972 function the_weekday_date( $before = '', $after = '' ) {
   2973 	global $wp_locale, $currentday, $previousweekday;
   2974 
   2975 	$post = get_post();
   2976 
   2977 	if ( ! $post ) {
   2978 		return;
   2979 	}
   2980 
   2981 	$the_weekday_date = '';
   2982 
   2983 	if ( $currentday !== $previousweekday ) {
   2984 		$the_weekday_date .= $before;
   2985 		$the_weekday_date .= $wp_locale->get_weekday( get_post_time( 'w', false, $post ) );
   2986 		$the_weekday_date .= $after;
   2987 		$previousweekday   = $currentday;
   2988 	}
   2989 
   2990 	/**
   2991 	 * Filters the localized date on which the post was written, for display.
   2992 	 *
   2993 	 * @since 0.71
   2994 	 *
   2995 	 * @param string $the_weekday_date The weekday on which the post was written.
   2996 	 * @param string $before           The HTML to output before the date.
   2997 	 * @param string $after            The HTML to output after the date.
   2998 	 */
   2999 	echo apply_filters( 'the_weekday_date', $the_weekday_date, $before, $after );
   3000 }
   3001 
   3002 /**
   3003  * Fire the wp_head action.
   3004  *
   3005  * See {@see 'wp_head'}.
   3006  *
   3007  * @since 1.2.0
   3008  */
   3009 function wp_head() {
   3010 	/**
   3011 	 * Prints scripts or data in the head tag on the front end.
   3012 	 *
   3013 	 * @since 1.5.0
   3014 	 */
   3015 	do_action( 'wp_head' );
   3016 }
   3017 
   3018 /**
   3019  * Fire the wp_footer action.
   3020  *
   3021  * See {@see 'wp_footer'}.
   3022  *
   3023  * @since 1.5.1
   3024  */
   3025 function wp_footer() {
   3026 	/**
   3027 	 * Prints scripts or data before the closing body tag on the front end.
   3028 	 *
   3029 	 * @since 1.5.1
   3030 	 */
   3031 	do_action( 'wp_footer' );
   3032 }
   3033 
   3034 /**
   3035  * Fire the wp_body_open action.
   3036  *
   3037  * See {@see 'wp_body_open'}.
   3038  *
   3039  * @since 5.2.0
   3040  */
   3041 function wp_body_open() {
   3042 	/**
   3043 	 * Triggered after the opening body tag.
   3044 	 *
   3045 	 * @since 5.2.0
   3046 	 */
   3047 	do_action( 'wp_body_open' );
   3048 }
   3049 
   3050 /**
   3051  * Display the links to the general feeds.
   3052  *
   3053  * @since 2.8.0
   3054  *
   3055  * @param array $args Optional arguments.
   3056  */
   3057 function feed_links( $args = array() ) {
   3058 	if ( ! current_theme_supports( 'automatic-feed-links' ) ) {
   3059 		return;
   3060 	}
   3061 
   3062 	$defaults = array(
   3063 		/* translators: Separator between blog name and feed type in feed links. */
   3064 		'separator' => _x( '&raquo;', 'feed link' ),
   3065 		/* translators: 1: Blog title, 2: Separator (raquo). */
   3066 		'feedtitle' => __( '%1$s %2$s Feed' ),
   3067 		/* translators: 1: Blog title, 2: Separator (raquo). */
   3068 		'comstitle' => __( '%1$s %2$s Comments Feed' ),
   3069 	);
   3070 
   3071 	$args = wp_parse_args( $args, $defaults );
   3072 
   3073 	/**
   3074 	 * Filters whether to display the posts feed link.
   3075 	 *
   3076 	 * @since 4.4.0
   3077 	 *
   3078 	 * @param bool $show Whether to display the posts feed link. Default true.
   3079 	 */
   3080 	if ( apply_filters( 'feed_links_show_posts_feed', true ) ) {
   3081 		echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr( sprintf( $args['feedtitle'], get_bloginfo( 'name' ), $args['separator'] ) ) . '" href="' . esc_url( get_feed_link() ) . "\" />\n";
   3082 	}
   3083 
   3084 	/**
   3085 	 * Filters whether to display the comments feed link.
   3086 	 *
   3087 	 * @since 4.4.0
   3088 	 *
   3089 	 * @param bool $show Whether to display the comments feed link. Default true.
   3090 	 */
   3091 	if ( apply_filters( 'feed_links_show_comments_feed', true ) ) {
   3092 		echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr( sprintf( $args['comstitle'], get_bloginfo( 'name' ), $args['separator'] ) ) . '" href="' . esc_url( get_feed_link( 'comments_' . get_default_feed() ) ) . "\" />\n";
   3093 	}
   3094 }
   3095 
   3096 /**
   3097  * Display the links to the extra feeds such as category feeds.
   3098  *
   3099  * @since 2.8.0
   3100  *
   3101  * @param array $args Optional arguments.
   3102  */
   3103 function feed_links_extra( $args = array() ) {
   3104 	$defaults = array(
   3105 		/* translators: Separator between blog name and feed type in feed links. */
   3106 		'separator'     => _x( '&raquo;', 'feed link' ),
   3107 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Post title. */
   3108 		'singletitle'   => __( '%1$s %2$s %3$s Comments Feed' ),
   3109 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Category name. */
   3110 		'cattitle'      => __( '%1$s %2$s %3$s Category Feed' ),
   3111 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Tag name. */
   3112 		'tagtitle'      => __( '%1$s %2$s %3$s Tag Feed' ),
   3113 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Term name, 4: Taxonomy singular name. */
   3114 		'taxtitle'      => __( '%1$s %2$s %3$s %4$s Feed' ),
   3115 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Author name. */
   3116 		'authortitle'   => __( '%1$s %2$s Posts by %3$s Feed' ),
   3117 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Search query. */
   3118 		'searchtitle'   => __( '%1$s %2$s Search Results for &#8220;%3$s&#8221; Feed' ),
   3119 		/* translators: 1: Blog name, 2: Separator (raquo), 3: Post type name. */
   3120 		'posttypetitle' => __( '%1$s %2$s %3$s Feed' ),
   3121 	);
   3122 
   3123 	$args = wp_parse_args( $args, $defaults );
   3124 
   3125 	if ( is_singular() ) {
   3126 		$id   = 0;
   3127 		$post = get_post( $id );
   3128 
   3129 		if ( comments_open() || pings_open() || $post->comment_count > 0 ) {
   3130 			$title = sprintf( $args['singletitle'], get_bloginfo( 'name' ), $args['separator'], the_title_attribute( array( 'echo' => false ) ) );
   3131 			$href  = get_post_comments_feed_link( $post->ID );
   3132 		}
   3133 	} elseif ( is_post_type_archive() ) {
   3134 		$post_type = get_query_var( 'post_type' );
   3135 		if ( is_array( $post_type ) ) {
   3136 			$post_type = reset( $post_type );
   3137 		}
   3138 
   3139 		$post_type_obj = get_post_type_object( $post_type );
   3140 		$title         = sprintf( $args['posttypetitle'], get_bloginfo( 'name' ), $args['separator'], $post_type_obj->labels->name );
   3141 		$href          = get_post_type_archive_feed_link( $post_type_obj->name );
   3142 	} elseif ( is_category() ) {
   3143 		$term = get_queried_object();
   3144 
   3145 		if ( $term ) {
   3146 			$title = sprintf( $args['cattitle'], get_bloginfo( 'name' ), $args['separator'], $term->name );
   3147 			$href  = get_category_feed_link( $term->term_id );
   3148 		}
   3149 	} elseif ( is_tag() ) {
   3150 		$term = get_queried_object();
   3151 
   3152 		if ( $term ) {
   3153 			$title = sprintf( $args['tagtitle'], get_bloginfo( 'name' ), $args['separator'], $term->name );
   3154 			$href  = get_tag_feed_link( $term->term_id );
   3155 		}
   3156 	} elseif ( is_tax() ) {
   3157 		$term = get_queried_object();
   3158 
   3159 		if ( $term ) {
   3160 			$tax   = get_taxonomy( $term->taxonomy );
   3161 			$title = sprintf( $args['taxtitle'], get_bloginfo( 'name' ), $args['separator'], $term->name, $tax->labels->singular_name );
   3162 			$href  = get_term_feed_link( $term->term_id, $term->taxonomy );
   3163 		}
   3164 	} elseif ( is_author() ) {
   3165 		$author_id = (int) get_query_var( 'author' );
   3166 
   3167 		$title = sprintf( $args['authortitle'], get_bloginfo( 'name' ), $args['separator'], get_the_author_meta( 'display_name', $author_id ) );
   3168 		$href  = get_author_feed_link( $author_id );
   3169 	} elseif ( is_search() ) {
   3170 		$title = sprintf( $args['searchtitle'], get_bloginfo( 'name' ), $args['separator'], get_search_query( false ) );
   3171 		$href  = get_search_feed_link();
   3172 	}
   3173 
   3174 	if ( isset( $title ) && isset( $href ) ) {
   3175 		echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr( $title ) . '" href="' . esc_url( $href ) . '" />' . "\n";
   3176 	}
   3177 }
   3178 
   3179 /**
   3180  * Display the link to the Really Simple Discovery service endpoint.
   3181  *
   3182  * @link http://archipelago.phrasewise.com/rsd
   3183  * @since 2.0.0
   3184  */
   3185 function rsd_link() {
   3186 	echo '<link rel="EditURI" type="application/rsd+xml" title="RSD" href="' . esc_url( site_url( 'xmlrpc.php?rsd', 'rpc' ) ) . '" />' . "\n";
   3187 }
   3188 
   3189 /**
   3190  * Display the link to the Windows Live Writer manifest file.
   3191  *
   3192  * @link https://msdn.microsoft.com/en-us/library/bb463265.aspx
   3193  * @since 2.3.1
   3194  */
   3195 function wlwmanifest_link() {
   3196 	echo '<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="' . includes_url( 'wlwmanifest.xml' ) . '" /> ' . "\n";
   3197 }
   3198 
   3199 /**
   3200  * Displays a referrer strict-origin-when-cross-origin meta tag.
   3201  *
   3202  * Outputs a referrer origin-when-cross-origin meta tag that tells the browser not to send the full
   3203  * url as a referrer to other sites when cross-origin assets are loaded.
   3204  *
   3205  * Typical usage is as a wp_head callback. add_action( 'wp_head', 'wp_strict_cross_origin_referrer' );
   3206  *
   3207  * @since 5.7.0
   3208  */
   3209 function wp_strict_cross_origin_referrer() {
   3210 	?>
   3211 	<meta name='referrer' content='strict-origin-when-cross-origin' />
   3212 	<?php
   3213 }
   3214 
   3215 /**
   3216  * Display site icon meta tags.
   3217  *
   3218  * @since 4.3.0
   3219  *
   3220  * @link https://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#rel-icon HTML5 specification link icon.
   3221  */
   3222 function wp_site_icon() {
   3223 	if ( ! has_site_icon() && ! is_customize_preview() ) {
   3224 		return;
   3225 	}
   3226 
   3227 	$meta_tags = array();
   3228 	$icon_32   = get_site_icon_url( 32 );
   3229 	if ( empty( $icon_32 ) && is_customize_preview() ) {
   3230 		$icon_32 = '/favicon.ico'; // Serve default favicon URL in customizer so element can be updated for preview.
   3231 	}
   3232 	if ( $icon_32 ) {
   3233 		$meta_tags[] = sprintf( '<link rel="icon" href="%s" sizes="32x32" />', esc_url( $icon_32 ) );
   3234 	}
   3235 	$icon_192 = get_site_icon_url( 192 );
   3236 	if ( $icon_192 ) {
   3237 		$meta_tags[] = sprintf( '<link rel="icon" href="%s" sizes="192x192" />', esc_url( $icon_192 ) );
   3238 	}
   3239 	$icon_180 = get_site_icon_url( 180 );
   3240 	if ( $icon_180 ) {
   3241 		$meta_tags[] = sprintf( '<link rel="apple-touch-icon" href="%s" />', esc_url( $icon_180 ) );
   3242 	}
   3243 	$icon_270 = get_site_icon_url( 270 );
   3244 	if ( $icon_270 ) {
   3245 		$meta_tags[] = sprintf( '<meta name="msapplication-TileImage" content="%s" />', esc_url( $icon_270 ) );
   3246 	}
   3247 
   3248 	/**
   3249 	 * Filters the site icon meta tags, so plugins can add their own.
   3250 	 *
   3251 	 * @since 4.3.0
   3252 	 *
   3253 	 * @param string[] $meta_tags Array of Site Icon meta tags.
   3254 	 */
   3255 	$meta_tags = apply_filters( 'site_icon_meta_tags', $meta_tags );
   3256 	$meta_tags = array_filter( $meta_tags );
   3257 
   3258 	foreach ( $meta_tags as $meta_tag ) {
   3259 		echo "$meta_tag\n";
   3260 	}
   3261 }
   3262 
   3263 /**
   3264  * Prints resource hints to browsers for pre-fetching, pre-rendering
   3265  * and pre-connecting to web sites.
   3266  *
   3267  * Gives hints to browsers to prefetch specific pages or render them
   3268  * in the background, to perform DNS lookups or to begin the connection
   3269  * handshake (DNS, TCP, TLS) in the background.
   3270  *
   3271  * These performance improving indicators work by using `<link rel"…">`.
   3272  *
   3273  * @since 4.6.0
   3274  */
   3275 function wp_resource_hints() {
   3276 	$hints = array(
   3277 		'dns-prefetch' => wp_dependencies_unique_hosts(),
   3278 		'preconnect'   => array(),
   3279 		'prefetch'     => array(),
   3280 		'prerender'    => array(),
   3281 	);
   3282 
   3283 	/*
   3284 	 * Add DNS prefetch for the Emoji CDN.
   3285 	 * The path is removed in the foreach loop below.
   3286 	 */
   3287 	/** This filter is documented in wp-includes/formatting.php */
   3288 	$hints['dns-prefetch'][] = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/13.0.0/svg/' );
   3289 
   3290 	foreach ( $hints as $relation_type => $urls ) {
   3291 		$unique_urls = array();
   3292 
   3293 		/**
   3294 		 * Filters domains and URLs for resource hints of relation type.
   3295 		 *
   3296 		 * @since 4.6.0
   3297 		 * @since 4.7.0 The `$urls` parameter accepts arrays of specific HTML attributes
   3298 		 *              as its child elements.
   3299 		 *
   3300 		 * @param array  $urls {
   3301 		 *     Array of resources and their attributes, or URLs to print for resource hints.
   3302 		 *
   3303 		 *     @type array|string ...$0 {
   3304 		 *         Array of resource attributes, or a URL string.
   3305 		 *
   3306 		 *         @type string $href        URL to include in resource hints. Required.
   3307 		 *         @type string $as          How the browser should treat the resource
   3308 		 *                                   (`script`, `style`, `image`, `document`, etc).
   3309 		 *         @type string $crossorigin Indicates the CORS policy of the specified resource.
   3310 		 *         @type float  $pr          Expected probability that the resource hint will be used.
   3311 		 *         @type string $type        Type of the resource (`text/html`, `text/css`, etc).
   3312 		 *     }
   3313 		 * }
   3314 		 * @param string $relation_type The relation type the URLs are printed for,
   3315 		 *                              e.g. 'preconnect' or 'prerender'.
   3316 		 */
   3317 		$urls = apply_filters( 'wp_resource_hints', $urls, $relation_type );
   3318 
   3319 		foreach ( $urls as $key => $url ) {
   3320 			$atts = array();
   3321 
   3322 			if ( is_array( $url ) ) {
   3323 				if ( isset( $url['href'] ) ) {
   3324 					$atts = $url;
   3325 					$url  = $url['href'];
   3326 				} else {
   3327 					continue;
   3328 				}
   3329 			}
   3330 
   3331 			$url = esc_url( $url, array( 'http', 'https' ) );
   3332 
   3333 			if ( ! $url ) {
   3334 				continue;
   3335 			}
   3336 
   3337 			if ( isset( $unique_urls[ $url ] ) ) {
   3338 				continue;
   3339 			}
   3340 
   3341 			if ( in_array( $relation_type, array( 'preconnect', 'dns-prefetch' ), true ) ) {
   3342 				$parsed = wp_parse_url( $url );
   3343 
   3344 				if ( empty( $parsed['host'] ) ) {
   3345 					continue;
   3346 				}
   3347 
   3348 				if ( 'preconnect' === $relation_type && ! empty( $parsed['scheme'] ) ) {
   3349 					$url = $parsed['scheme'] . '://' . $parsed['host'];
   3350 				} else {
   3351 					// Use protocol-relative URLs for dns-prefetch or if scheme is missing.
   3352 					$url = '//' . $parsed['host'];
   3353 				}
   3354 			}
   3355 
   3356 			$atts['rel']  = $relation_type;
   3357 			$atts['href'] = $url;
   3358 
   3359 			$unique_urls[ $url ] = $atts;
   3360 		}
   3361 
   3362 		foreach ( $unique_urls as $atts ) {
   3363 			$html = '';
   3364 
   3365 			foreach ( $atts as $attr => $value ) {
   3366 				if ( ! is_scalar( $value )
   3367 					|| ( ! in_array( $attr, array( 'as', 'crossorigin', 'href', 'pr', 'rel', 'type' ), true ) && ! is_numeric( $attr ) )
   3368 				) {
   3369 
   3370 					continue;
   3371 				}
   3372 
   3373 				$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
   3374 
   3375 				if ( ! is_string( $attr ) ) {
   3376 					$html .= " $value";
   3377 				} else {
   3378 					$html .= " $attr='$value'";
   3379 				}
   3380 			}
   3381 
   3382 			$html = trim( $html );
   3383 
   3384 			echo "<link $html />\n";
   3385 		}
   3386 	}
   3387 }
   3388 
   3389 /**
   3390  * Retrieves a list of unique hosts of all enqueued scripts and styles.
   3391  *
   3392  * @since 4.6.0
   3393  *
   3394  * @return string[] A list of unique hosts of enqueued scripts and styles.
   3395  */
   3396 function wp_dependencies_unique_hosts() {
   3397 	global $wp_scripts, $wp_styles;
   3398 
   3399 	$unique_hosts = array();
   3400 
   3401 	foreach ( array( $wp_scripts, $wp_styles ) as $dependencies ) {
   3402 		if ( $dependencies instanceof WP_Dependencies && ! empty( $dependencies->queue ) ) {
   3403 			foreach ( $dependencies->queue as $handle ) {
   3404 				if ( ! isset( $dependencies->registered[ $handle ] ) ) {
   3405 					continue;
   3406 				}
   3407 
   3408 				/* @var _WP_Dependency $dependency */
   3409 				$dependency = $dependencies->registered[ $handle ];
   3410 				$parsed     = wp_parse_url( $dependency->src );
   3411 
   3412 				if ( ! empty( $parsed['host'] )
   3413 					&& ! in_array( $parsed['host'], $unique_hosts, true ) && $parsed['host'] !== $_SERVER['SERVER_NAME']
   3414 				) {
   3415 					$unique_hosts[] = $parsed['host'];
   3416 				}
   3417 			}
   3418 		}
   3419 	}
   3420 
   3421 	return $unique_hosts;
   3422 }
   3423 
   3424 /**
   3425  * Whether the user can access the visual editor.
   3426  *
   3427  * Checks if the user can access the visual editor and that it's supported by the user's browser.
   3428  *
   3429  * @since 2.0.0
   3430  *
   3431  * @global bool $wp_rich_edit Whether the user can access the visual editor.
   3432  * @global bool $is_gecko     Whether the browser is Gecko-based.
   3433  * @global bool $is_opera     Whether the browser is Opera.
   3434  * @global bool $is_safari    Whether the browser is Safari.
   3435  * @global bool $is_chrome    Whether the browser is Chrome.
   3436  * @global bool $is_IE        Whether the browser is Internet Explorer.
   3437  * @global bool $is_edge      Whether the browser is Microsoft Edge.
   3438  *
   3439  * @return bool True if the user can access the visual editor, false otherwise.
   3440  */
   3441 function user_can_richedit() {
   3442 	global $wp_rich_edit, $is_gecko, $is_opera, $is_safari, $is_chrome, $is_IE, $is_edge;
   3443 
   3444 	if ( ! isset( $wp_rich_edit ) ) {
   3445 		$wp_rich_edit = false;
   3446 
   3447 		if ( 'true' === get_user_option( 'rich_editing' ) || ! is_user_logged_in() ) { // Default to 'true' for logged out users.
   3448 			if ( $is_safari ) {
   3449 				$wp_rich_edit = ! wp_is_mobile() || ( preg_match( '!AppleWebKit/(\d+)!', $_SERVER['HTTP_USER_AGENT'], $match ) && (int) $match[1] >= 534 );
   3450 			} elseif ( $is_IE ) {
   3451 				$wp_rich_edit = ( strpos( $_SERVER['HTTP_USER_AGENT'], 'Trident/7.0;' ) !== false );
   3452 			} elseif ( $is_gecko || $is_chrome || $is_edge || ( $is_opera && ! wp_is_mobile() ) ) {
   3453 				$wp_rich_edit = true;
   3454 			}
   3455 		}
   3456 	}
   3457 
   3458 	/**
   3459 	 * Filters whether the user can access the visual editor.
   3460 	 *
   3461 	 * @since 2.1.0
   3462 	 *
   3463 	 * @param bool $wp_rich_edit Whether the user can access the visual editor.
   3464 	 */
   3465 	return apply_filters( 'user_can_richedit', $wp_rich_edit );
   3466 }
   3467 
   3468 /**
   3469  * Find out which editor should be displayed by default.
   3470  *
   3471  * Works out which of the two editors to display as the current editor for a
   3472  * user. The 'html' setting is for the "Text" editor tab.
   3473  *
   3474  * @since 2.5.0
   3475  *
   3476  * @return string Either 'tinymce', or 'html', or 'test'
   3477  */
   3478 function wp_default_editor() {
   3479 	$r = user_can_richedit() ? 'tinymce' : 'html'; // Defaults.
   3480 	if ( wp_get_current_user() ) { // Look for cookie.
   3481 		$ed = get_user_setting( 'editor', 'tinymce' );
   3482 		$r  = ( in_array( $ed, array( 'tinymce', 'html', 'test' ), true ) ) ? $ed : $r;
   3483 	}
   3484 
   3485 	/**
   3486 	 * Filters which editor should be displayed by default.
   3487 	 *
   3488 	 * @since 2.5.0
   3489 	 *
   3490 	 * @param string $r Which editor should be displayed by default. Either 'tinymce', 'html', or 'test'.
   3491 	 */
   3492 	return apply_filters( 'wp_default_editor', $r );
   3493 }
   3494 
   3495 /**
   3496  * Renders an editor.
   3497  *
   3498  * Using this function is the proper way to output all needed components for both TinyMCE and Quicktags.
   3499  * _WP_Editors should not be used directly. See https://core.trac.wordpress.org/ticket/17144.
   3500  *
   3501  * NOTE: Once initialized the TinyMCE editor cannot be safely moved in the DOM. For that reason
   3502  * running wp_editor() inside of a meta box is not a good idea unless only Quicktags is used.
   3503  * On the post edit screen several actions can be used to include additional editors
   3504  * containing TinyMCE: 'edit_page_form', 'edit_form_advanced' and 'dbx_post_sidebar'.
   3505  * See https://core.trac.wordpress.org/ticket/19173 for more information.
   3506  *
   3507  * @see _WP_Editors::editor()
   3508  * @see _WP_Editors::parse_settings()
   3509  * @since 3.3.0
   3510  *
   3511  * @param string $content   Initial content for the editor.
   3512  * @param string $editor_id HTML ID attribute value for the textarea and TinyMCE.
   3513  *                          Should not contain square brackets.
   3514  * @param array  $settings  See _WP_Editors::parse_settings() for description.
   3515  */
   3516 function wp_editor( $content, $editor_id, $settings = array() ) {
   3517 	if ( ! class_exists( '_WP_Editors', false ) ) {
   3518 		require ABSPATH . WPINC . '/class-wp-editor.php';
   3519 	}
   3520 	_WP_Editors::editor( $content, $editor_id, $settings );
   3521 }
   3522 
   3523 /**
   3524  * Outputs the editor scripts, stylesheets, and default settings.
   3525  *
   3526  * The editor can be initialized when needed after page load.
   3527  * See wp.editor.initialize() in wp-admin/js/editor.js for initialization options.
   3528  *
   3529  * @uses _WP_Editors
   3530  * @since 4.8.0
   3531  */
   3532 function wp_enqueue_editor() {
   3533 	if ( ! class_exists( '_WP_Editors', false ) ) {
   3534 		require ABSPATH . WPINC . '/class-wp-editor.php';
   3535 	}
   3536 
   3537 	_WP_Editors::enqueue_default_editor();
   3538 }
   3539 
   3540 /**
   3541  * Enqueue assets needed by the code editor for the given settings.
   3542  *
   3543  * @since 4.9.0
   3544  *
   3545  * @see wp_enqueue_editor()
   3546  * @see wp_get_code_editor_settings();
   3547  * @see _WP_Editors::parse_settings()
   3548  *
   3549  * @param array $args {
   3550  *     Args.
   3551  *
   3552  *     @type string   $type       The MIME type of the file to be edited.
   3553  *     @type string   $file       Filename to be edited. Extension is used to sniff the type. Can be supplied as alternative to `$type` param.
   3554  *     @type WP_Theme $theme      Theme being edited when on theme editor.
   3555  *     @type string   $plugin     Plugin being edited when on plugin editor.
   3556  *     @type array    $codemirror Additional CodeMirror setting overrides.
   3557  *     @type array    $csslint    CSSLint rule overrides.
   3558  *     @type array    $jshint     JSHint rule overrides.
   3559  *     @type array    $htmlhint   HTMLHint rule overrides.
   3560  * }
   3561  * @return array|false Settings for the enqueued code editor, or false if the editor was not enqueued.
   3562  */
   3563 function wp_enqueue_code_editor( $args ) {
   3564 	if ( is_user_logged_in() && 'false' === wp_get_current_user()->syntax_highlighting ) {
   3565 		return false;
   3566 	}
   3567 
   3568 	$settings = wp_get_code_editor_settings( $args );
   3569 
   3570 	if ( empty( $settings ) || empty( $settings['codemirror'] ) ) {
   3571 		return false;
   3572 	}
   3573 
   3574 	wp_enqueue_script( 'code-editor' );
   3575 	wp_enqueue_style( 'code-editor' );
   3576 
   3577 	if ( isset( $settings['codemirror']['mode'] ) ) {
   3578 		$mode = $settings['codemirror']['mode'];
   3579 		if ( is_string( $mode ) ) {
   3580 			$mode = array(
   3581 				'name' => $mode,
   3582 			);
   3583 		}
   3584 
   3585 		if ( ! empty( $settings['codemirror']['lint'] ) ) {
   3586 			switch ( $mode['name'] ) {
   3587 				case 'css':
   3588 				case 'text/css':
   3589 				case 'text/x-scss':
   3590 				case 'text/x-less':
   3591 					wp_enqueue_script( 'csslint' );
   3592 					break;
   3593 				case 'htmlmixed':
   3594 				case 'text/html':
   3595 				case 'php':
   3596 				case 'application/x-httpd-php':
   3597 				case 'text/x-php':
   3598 					wp_enqueue_script( 'htmlhint' );
   3599 					wp_enqueue_script( 'csslint' );
   3600 					wp_enqueue_script( 'jshint' );
   3601 					if ( ! current_user_can( 'unfiltered_html' ) ) {
   3602 						wp_enqueue_script( 'htmlhint-kses' );
   3603 					}
   3604 					break;
   3605 				case 'javascript':
   3606 				case 'application/ecmascript':
   3607 				case 'application/json':
   3608 				case 'application/javascript':
   3609 				case 'application/ld+json':
   3610 				case 'text/typescript':
   3611 				case 'application/typescript':
   3612 					wp_enqueue_script( 'jshint' );
   3613 					wp_enqueue_script( 'jsonlint' );
   3614 					break;
   3615 			}
   3616 		}
   3617 	}
   3618 
   3619 	wp_add_inline_script( 'code-editor', sprintf( 'jQuery.extend( wp.codeEditor.defaultSettings, %s );', wp_json_encode( $settings ) ) );
   3620 
   3621 	/**
   3622 	 * Fires when scripts and styles are enqueued for the code editor.
   3623 	 *
   3624 	 * @since 4.9.0
   3625 	 *
   3626 	 * @param array $settings Settings for the enqueued code editor.
   3627 	 */
   3628 	do_action( 'wp_enqueue_code_editor', $settings );
   3629 
   3630 	return $settings;
   3631 }
   3632 
   3633 /**
   3634  * Generate and return code editor settings.
   3635  *
   3636  * @since 5.0.0
   3637  *
   3638  * @see wp_enqueue_code_editor()
   3639  *
   3640  * @param array $args {
   3641  *     Args.
   3642  *
   3643  *     @type string   $type       The MIME type of the file to be edited.
   3644  *     @type string   $file       Filename to be edited. Extension is used to sniff the type. Can be supplied as alternative to `$type` param.
   3645  *     @type WP_Theme $theme      Theme being edited when on theme editor.
   3646  *     @type string   $plugin     Plugin being edited when on plugin editor.
   3647  *     @type array    $codemirror Additional CodeMirror setting overrides.
   3648  *     @type array    $csslint    CSSLint rule overrides.
   3649  *     @type array    $jshint     JSHint rule overrides.
   3650  *     @type array    $htmlhint   HTMLHint rule overrides.
   3651  * }
   3652  * @return array|false Settings for the code editor.
   3653  */
   3654 function wp_get_code_editor_settings( $args ) {
   3655 	$settings = array(
   3656 		'codemirror' => array(
   3657 			'indentUnit'       => 4,
   3658 			'indentWithTabs'   => true,
   3659 			'inputStyle'       => 'contenteditable',
   3660 			'lineNumbers'      => true,
   3661 			'lineWrapping'     => true,
   3662 			'styleActiveLine'  => true,
   3663 			'continueComments' => true,
   3664 			'extraKeys'        => array(
   3665 				'Ctrl-Space' => 'autocomplete',
   3666 				'Ctrl-/'     => 'toggleComment',
   3667 				'Cmd-/'      => 'toggleComment',
   3668 				'Alt-F'      => 'findPersistent',
   3669 				'Ctrl-F'     => 'findPersistent',
   3670 				'Cmd-F'      => 'findPersistent',
   3671 			),
   3672 			'direction'        => 'ltr', // Code is shown in LTR even in RTL languages.
   3673 			'gutters'          => array(),
   3674 		),
   3675 		'csslint'    => array(
   3676 			'errors'                    => true, // Parsing errors.
   3677 			'box-model'                 => true,
   3678 			'display-property-grouping' => true,
   3679 			'duplicate-properties'      => true,
   3680 			'known-properties'          => true,
   3681 			'outline-none'              => true,
   3682 		),
   3683 		'jshint'     => array(
   3684 			// The following are copied from <https://github.com/WordPress/wordpress-develop/blob/4.8.1/.jshintrc>.
   3685 			'boss'     => true,
   3686 			'curly'    => true,
   3687 			'eqeqeq'   => true,
   3688 			'eqnull'   => true,
   3689 			'es3'      => true,
   3690 			'expr'     => true,
   3691 			'immed'    => true,
   3692 			'noarg'    => true,
   3693 			'nonbsp'   => true,
   3694 			'onevar'   => true,
   3695 			'quotmark' => 'single',
   3696 			'trailing' => true,
   3697 			'undef'    => true,
   3698 			'unused'   => true,
   3699 
   3700 			'browser'  => true,
   3701 
   3702 			'globals'  => array(
   3703 				'_'        => false,
   3704 				'Backbone' => false,
   3705 				'jQuery'   => false,
   3706 				'JSON'     => false,
   3707 				'wp'       => false,
   3708 			),
   3709 		),
   3710 		'htmlhint'   => array(
   3711 			'tagname-lowercase'        => true,
   3712 			'attr-lowercase'           => true,
   3713 			'attr-value-double-quotes' => false,
   3714 			'doctype-first'            => false,
   3715 			'tag-pair'                 => true,
   3716 			'spec-char-escape'         => true,
   3717 			'id-unique'                => true,
   3718 			'src-not-empty'            => true,
   3719 			'attr-no-duplication'      => true,
   3720 			'alt-require'              => true,
   3721 			'space-tab-mixed-disabled' => 'tab',
   3722 			'attr-unsafe-chars'        => true,
   3723 		),
   3724 	);
   3725 
   3726 	$type = '';
   3727 	if ( isset( $args['type'] ) ) {
   3728 		$type = $args['type'];
   3729 
   3730 		// Remap MIME types to ones that CodeMirror modes will recognize.
   3731 		if ( 'application/x-patch' === $type || 'text/x-patch' === $type ) {
   3732 			$type = 'text/x-diff';
   3733 		}
   3734 	} elseif ( isset( $args['file'] ) && false !== strpos( basename( $args['file'] ), '.' ) ) {
   3735 		$extension = strtolower( pathinfo( $args['file'], PATHINFO_EXTENSION ) );
   3736 		foreach ( wp_get_mime_types() as $exts => $mime ) {
   3737 			if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
   3738 				$type = $mime;
   3739 				break;
   3740 			}
   3741 		}
   3742 
   3743 		// Supply any types that are not matched by wp_get_mime_types().
   3744 		if ( empty( $type ) ) {
   3745 			switch ( $extension ) {
   3746 				case 'conf':
   3747 					$type = 'text/nginx';
   3748 					break;
   3749 				case 'css':
   3750 					$type = 'text/css';
   3751 					break;
   3752 				case 'diff':
   3753 				case 'patch':
   3754 					$type = 'text/x-diff';
   3755 					break;
   3756 				case 'html':
   3757 				case 'htm':
   3758 					$type = 'text/html';
   3759 					break;
   3760 				case 'http':
   3761 					$type = 'message/http';
   3762 					break;
   3763 				case 'js':
   3764 					$type = 'text/javascript';
   3765 					break;
   3766 				case 'json':
   3767 					$type = 'application/json';
   3768 					break;
   3769 				case 'jsx':
   3770 					$type = 'text/jsx';
   3771 					break;
   3772 				case 'less':
   3773 					$type = 'text/x-less';
   3774 					break;
   3775 				case 'md':
   3776 					$type = 'text/x-gfm';
   3777 					break;
   3778 				case 'php':
   3779 				case 'phtml':
   3780 				case 'php3':
   3781 				case 'php4':
   3782 				case 'php5':
   3783 				case 'php7':
   3784 				case 'phps':
   3785 					$type = 'application/x-httpd-php';
   3786 					break;
   3787 				case 'scss':
   3788 					$type = 'text/x-scss';
   3789 					break;
   3790 				case 'sass':
   3791 					$type = 'text/x-sass';
   3792 					break;
   3793 				case 'sh':
   3794 				case 'bash':
   3795 					$type = 'text/x-sh';
   3796 					break;
   3797 				case 'sql':
   3798 					$type = 'text/x-sql';
   3799 					break;
   3800 				case 'svg':
   3801 					$type = 'application/svg+xml';
   3802 					break;
   3803 				case 'xml':
   3804 					$type = 'text/xml';
   3805 					break;
   3806 				case 'yml':
   3807 				case 'yaml':
   3808 					$type = 'text/x-yaml';
   3809 					break;
   3810 				case 'txt':
   3811 				default:
   3812 					$type = 'text/plain';
   3813 					break;
   3814 			}
   3815 		}
   3816 	}
   3817 
   3818 	if ( in_array( $type, array( 'text/css', 'text/x-scss', 'text/x-less', 'text/x-sass' ), true ) ) {
   3819 		$settings['codemirror'] = array_merge(
   3820 			$settings['codemirror'],
   3821 			array(
   3822 				'mode'              => $type,
   3823 				'lint'              => false,
   3824 				'autoCloseBrackets' => true,
   3825 				'matchBrackets'     => true,
   3826 			)
   3827 		);
   3828 	} elseif ( 'text/x-diff' === $type ) {
   3829 		$settings['codemirror'] = array_merge(
   3830 			$settings['codemirror'],
   3831 			array(
   3832 				'mode' => 'diff',
   3833 			)
   3834 		);
   3835 	} elseif ( 'text/html' === $type ) {
   3836 		$settings['codemirror'] = array_merge(
   3837 			$settings['codemirror'],
   3838 			array(
   3839 				'mode'              => 'htmlmixed',
   3840 				'lint'              => true,
   3841 				'autoCloseBrackets' => true,
   3842 				'autoCloseTags'     => true,
   3843 				'matchTags'         => array(
   3844 					'bothTags' => true,
   3845 				),
   3846 			)
   3847 		);
   3848 
   3849 		if ( ! current_user_can( 'unfiltered_html' ) ) {
   3850 			$settings['htmlhint']['kses'] = wp_kses_allowed_html( 'post' );
   3851 		}
   3852 	} elseif ( 'text/x-gfm' === $type ) {
   3853 		$settings['codemirror'] = array_merge(
   3854 			$settings['codemirror'],
   3855 			array(
   3856 				'mode'                => 'gfm',
   3857 				'highlightFormatting' => true,
   3858 			)
   3859 		);
   3860 	} elseif ( 'application/javascript' === $type || 'text/javascript' === $type ) {
   3861 		$settings['codemirror'] = array_merge(
   3862 			$settings['codemirror'],
   3863 			array(
   3864 				'mode'              => 'javascript',
   3865 				'lint'              => true,
   3866 				'autoCloseBrackets' => true,
   3867 				'matchBrackets'     => true,
   3868 			)
   3869 		);
   3870 	} elseif ( false !== strpos( $type, 'json' ) ) {
   3871 		$settings['codemirror'] = array_merge(
   3872 			$settings['codemirror'],
   3873 			array(
   3874 				'mode'              => array(
   3875 					'name' => 'javascript',
   3876 				),
   3877 				'lint'              => true,
   3878 				'autoCloseBrackets' => true,
   3879 				'matchBrackets'     => true,
   3880 			)
   3881 		);
   3882 		if ( 'application/ld+json' === $type ) {
   3883 			$settings['codemirror']['mode']['jsonld'] = true;
   3884 		} else {
   3885 			$settings['codemirror']['mode']['json'] = true;
   3886 		}
   3887 	} elseif ( false !== strpos( $type, 'jsx' ) ) {
   3888 		$settings['codemirror'] = array_merge(
   3889 			$settings['codemirror'],
   3890 			array(
   3891 				'mode'              => 'jsx',
   3892 				'autoCloseBrackets' => true,
   3893 				'matchBrackets'     => true,
   3894 			)
   3895 		);
   3896 	} elseif ( 'text/x-markdown' === $type ) {
   3897 		$settings['codemirror'] = array_merge(
   3898 			$settings['codemirror'],
   3899 			array(
   3900 				'mode'                => 'markdown',
   3901 				'highlightFormatting' => true,
   3902 			)
   3903 		);
   3904 	} elseif ( 'text/nginx' === $type ) {
   3905 		$settings['codemirror'] = array_merge(
   3906 			$settings['codemirror'],
   3907 			array(
   3908 				'mode' => 'nginx',
   3909 			)
   3910 		);
   3911 	} elseif ( 'application/x-httpd-php' === $type ) {
   3912 		$settings['codemirror'] = array_merge(
   3913 			$settings['codemirror'],
   3914 			array(
   3915 				'mode'              => 'php',
   3916 				'autoCloseBrackets' => true,
   3917 				'autoCloseTags'     => true,
   3918 				'matchBrackets'     => true,
   3919 				'matchTags'         => array(
   3920 					'bothTags' => true,
   3921 				),
   3922 			)
   3923 		);
   3924 	} elseif ( 'text/x-sql' === $type || 'text/x-mysql' === $type ) {
   3925 		$settings['codemirror'] = array_merge(
   3926 			$settings['codemirror'],
   3927 			array(
   3928 				'mode'              => 'sql',
   3929 				'autoCloseBrackets' => true,
   3930 				'matchBrackets'     => true,
   3931 			)
   3932 		);
   3933 	} elseif ( false !== strpos( $type, 'xml' ) ) {
   3934 		$settings['codemirror'] = array_merge(
   3935 			$settings['codemirror'],
   3936 			array(
   3937 				'mode'              => 'xml',
   3938 				'autoCloseBrackets' => true,
   3939 				'autoCloseTags'     => true,
   3940 				'matchTags'         => array(
   3941 					'bothTags' => true,
   3942 				),
   3943 			)
   3944 		);
   3945 	} elseif ( 'text/x-yaml' === $type ) {
   3946 		$settings['codemirror'] = array_merge(
   3947 			$settings['codemirror'],
   3948 			array(
   3949 				'mode' => 'yaml',
   3950 			)
   3951 		);
   3952 	} else {
   3953 		$settings['codemirror']['mode'] = $type;
   3954 	}
   3955 
   3956 	if ( ! empty( $settings['codemirror']['lint'] ) ) {
   3957 		$settings['codemirror']['gutters'][] = 'CodeMirror-lint-markers';
   3958 	}
   3959 
   3960 	// Let settings supplied via args override any defaults.
   3961 	foreach ( wp_array_slice_assoc( $args, array( 'codemirror', 'csslint', 'jshint', 'htmlhint' ) ) as $key => $value ) {
   3962 		$settings[ $key ] = array_merge(
   3963 			$settings[ $key ],
   3964 			$value
   3965 		);
   3966 	}
   3967 
   3968 	/**
   3969 	 * Filters settings that are passed into the code editor.
   3970 	 *
   3971 	 * Returning a falsey value will disable the syntax-highlighting code editor.
   3972 	 *
   3973 	 * @since 4.9.0
   3974 	 *
   3975 	 * @param array $settings The array of settings passed to the code editor.
   3976 	 *                        A falsey value disables the editor.
   3977 	 * @param array $args {
   3978 	 *     Args passed when calling `get_code_editor_settings()`.
   3979 	 *
   3980 	 *     @type string   $type       The MIME type of the file to be edited.
   3981 	 *     @type string   $file       Filename being edited.
   3982 	 *     @type WP_Theme $theme      Theme being edited when on theme editor.
   3983 	 *     @type string   $plugin     Plugin being edited when on plugin editor.
   3984 	 *     @type array    $codemirror Additional CodeMirror setting overrides.
   3985 	 *     @type array    $csslint    CSSLint rule overrides.
   3986 	 *     @type array    $jshint     JSHint rule overrides.
   3987 	 *     @type array    $htmlhint   HTMLHint rule overrides.
   3988 	 * }
   3989 	 */
   3990 	return apply_filters( 'wp_code_editor_settings', $settings, $args );
   3991 }
   3992 
   3993 /**
   3994  * Retrieves the contents of the search WordPress query variable.
   3995  *
   3996  * The search query string is passed through esc_attr() to ensure that it is safe
   3997  * for placing in an HTML attribute.
   3998  *
   3999  * @since 2.3.0
   4000  *
   4001  * @param bool $escaped Whether the result is escaped. Default true.
   4002  *                      Only use when you are later escaping it. Do not use unescaped.
   4003  * @return string
   4004  */
   4005 function get_search_query( $escaped = true ) {
   4006 	/**
   4007 	 * Filters the contents of the search query variable.
   4008 	 *
   4009 	 * @since 2.3.0
   4010 	 *
   4011 	 * @param mixed $search Contents of the search query variable.
   4012 	 */
   4013 	$query = apply_filters( 'get_search_query', get_query_var( 's' ) );
   4014 
   4015 	if ( $escaped ) {
   4016 		$query = esc_attr( $query );
   4017 	}
   4018 	return $query;
   4019 }
   4020 
   4021 /**
   4022  * Displays the contents of the search query variable.
   4023  *
   4024  * The search query string is passed through esc_attr() to ensure that it is safe
   4025  * for placing in an HTML attribute.
   4026  *
   4027  * @since 2.1.0
   4028  */
   4029 function the_search_query() {
   4030 	/**
   4031 	 * Filters the contents of the search query variable for display.
   4032 	 *
   4033 	 * @since 2.3.0
   4034 	 *
   4035 	 * @param mixed $search Contents of the search query variable.
   4036 	 */
   4037 	echo esc_attr( apply_filters( 'the_search_query', get_search_query( false ) ) );
   4038 }
   4039 
   4040 /**
   4041  * Gets the language attributes for the 'html' tag.
   4042  *
   4043  * Builds up a set of HTML attributes containing the text direction and language
   4044  * information for the page.
   4045  *
   4046  * @since 4.3.0
   4047  *
   4048  * @param string $doctype Optional. The type of HTML document. Accepts 'xhtml' or 'html'. Default 'html'.
   4049  */
   4050 function get_language_attributes( $doctype = 'html' ) {
   4051 	$attributes = array();
   4052 
   4053 	if ( function_exists( 'is_rtl' ) && is_rtl() ) {
   4054 		$attributes[] = 'dir="rtl"';
   4055 	}
   4056 
   4057 	$lang = get_bloginfo( 'language' );
   4058 	if ( $lang ) {
   4059 		if ( 'text/html' === get_option( 'html_type' ) || 'html' === $doctype ) {
   4060 			$attributes[] = 'lang="' . esc_attr( $lang ) . '"';
   4061 		}
   4062 
   4063 		if ( 'text/html' !== get_option( 'html_type' ) || 'xhtml' === $doctype ) {
   4064 			$attributes[] = 'xml:lang="' . esc_attr( $lang ) . '"';
   4065 		}
   4066 	}
   4067 
   4068 	$output = implode( ' ', $attributes );
   4069 
   4070 	/**
   4071 	 * Filters the language attributes for display in the 'html' tag.
   4072 	 *
   4073 	 * @since 2.5.0
   4074 	 * @since 4.3.0 Added the `$doctype` parameter.
   4075 	 *
   4076 	 * @param string $output A space-separated list of language attributes.
   4077 	 * @param string $doctype The type of HTML document (xhtml|html).
   4078 	 */
   4079 	return apply_filters( 'language_attributes', $output, $doctype );
   4080 }
   4081 
   4082 /**
   4083  * Displays the language attributes for the 'html' tag.
   4084  *
   4085  * Builds up a set of HTML attributes containing the text direction and language
   4086  * information for the page.
   4087  *
   4088  * @since 2.1.0
   4089  * @since 4.3.0 Converted into a wrapper for get_language_attributes().
   4090  *
   4091  * @param string $doctype Optional. The type of HTML document. Accepts 'xhtml' or 'html'. Default 'html'.
   4092  */
   4093 function language_attributes( $doctype = 'html' ) {
   4094 	echo get_language_attributes( $doctype );
   4095 }
   4096 
   4097 /**
   4098  * Retrieves paginated links for archive post pages.
   4099  *
   4100  * Technically, the function can be used to create paginated link list for any
   4101  * area. The 'base' argument is used to reference the url, which will be used to
   4102  * create the paginated links. The 'format' argument is then used for replacing
   4103  * the page number. It is however, most likely and by default, to be used on the
   4104  * archive post pages.
   4105  *
   4106  * The 'type' argument controls format of the returned value. The default is
   4107  * 'plain', which is just a string with the links separated by a newline
   4108  * character. The other possible values are either 'array' or 'list'. The
   4109  * 'array' value will return an array of the paginated link list to offer full
   4110  * control of display. The 'list' value will place all of the paginated links in
   4111  * an unordered HTML list.
   4112  *
   4113  * The 'total' argument is the total amount of pages and is an integer. The
   4114  * 'current' argument is the current page number and is also an integer.
   4115  *
   4116  * An example of the 'base' argument is "http://example.com/all_posts.php%_%"
   4117  * and the '%_%' is required. The '%_%' will be replaced by the contents of in
   4118  * the 'format' argument. An example for the 'format' argument is "?page=%#%"
   4119  * and the '%#%' is also required. The '%#%' will be replaced with the page
   4120  * number.
   4121  *
   4122  * You can include the previous and next links in the list by setting the
   4123  * 'prev_next' argument to true, which it is by default. You can set the
   4124  * previous text, by using the 'prev_text' argument. You can set the next text
   4125  * by setting the 'next_text' argument.
   4126  *
   4127  * If the 'show_all' argument is set to true, then it will show all of the pages
   4128  * instead of a short list of the pages near the current page. By default, the
   4129  * 'show_all' is set to false and controlled by the 'end_size' and 'mid_size'
   4130  * arguments. The 'end_size' argument is how many numbers on either the start
   4131  * and the end list edges, by default is 1. The 'mid_size' argument is how many
   4132  * numbers to either side of current page, but not including current page.
   4133  *
   4134  * It is possible to add query vars to the link by using the 'add_args' argument
   4135  * and see add_query_arg() for more information.
   4136  *
   4137  * The 'before_page_number' and 'after_page_number' arguments allow users to
   4138  * augment the links themselves. Typically this might be to add context to the
   4139  * numbered links so that screen reader users understand what the links are for.
   4140  * The text strings are added before and after the page number - within the
   4141  * anchor tag.
   4142  *
   4143  * @since 2.1.0
   4144  * @since 4.9.0 Added the `aria_current` argument.
   4145  *
   4146  * @global WP_Query   $wp_query   WordPress Query object.
   4147  * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
   4148  *
   4149  * @param string|array $args {
   4150  *     Optional. Array or string of arguments for generating paginated links for archives.
   4151  *
   4152  *     @type string $base               Base of the paginated url. Default empty.
   4153  *     @type string $format             Format for the pagination structure. Default empty.
   4154  *     @type int    $total              The total amount of pages. Default is the value WP_Query's
   4155  *                                      `max_num_pages` or 1.
   4156  *     @type int    $current            The current page number. Default is 'paged' query var or 1.
   4157  *     @type string $aria_current       The value for the aria-current attribute. Possible values are 'page',
   4158  *                                      'step', 'location', 'date', 'time', 'true', 'false'. Default is 'page'.
   4159  *     @type bool   $show_all           Whether to show all pages. Default false.
   4160  *     @type int    $end_size           How many numbers on either the start and the end list edges.
   4161  *                                      Default 1.
   4162  *     @type int    $mid_size           How many numbers to either side of the current pages. Default 2.
   4163  *     @type bool   $prev_next          Whether to include the previous and next links in the list. Default true.
   4164  *     @type bool   $prev_text          The previous page text. Default '&laquo; Previous'.
   4165  *     @type bool   $next_text          The next page text. Default 'Next &raquo;'.
   4166  *     @type string $type               Controls format of the returned value. Possible values are 'plain',
   4167  *                                      'array' and 'list'. Default is 'plain'.
   4168  *     @type array  $add_args           An array of query args to add. Default false.
   4169  *     @type string $add_fragment       A string to append to each link. Default empty.
   4170  *     @type string $before_page_number A string to appear before the page number. Default empty.
   4171  *     @type string $after_page_number  A string to append after the page number. Default empty.
   4172  * }
   4173  * @return string|array|void String of page links or array of page links, depending on 'type' argument.
   4174  *                           Void if total number of pages is less than 2.
   4175  */
   4176 function paginate_links( $args = '' ) {
   4177 	global $wp_query, $wp_rewrite;
   4178 
   4179 	// Setting up default values based on the current URL.
   4180 	$pagenum_link = html_entity_decode( get_pagenum_link() );
   4181 	$url_parts    = explode( '?', $pagenum_link );
   4182 
   4183 	// Get max pages and current page out of the current query, if available.
   4184 	$total   = isset( $wp_query->max_num_pages ) ? $wp_query->max_num_pages : 1;
   4185 	$current = get_query_var( 'paged' ) ? (int) get_query_var( 'paged' ) : 1;
   4186 
   4187 	// Append the format placeholder to the base URL.
   4188 	$pagenum_link = trailingslashit( $url_parts[0] ) . '%_%';
   4189 
   4190 	// URL base depends on permalink settings.
   4191 	$format  = $wp_rewrite->using_index_permalinks() && ! strpos( $pagenum_link, 'index.php' ) ? 'index.php/' : '';
   4192 	$format .= $wp_rewrite->using_permalinks() ? user_trailingslashit( $wp_rewrite->pagination_base . '/%#%', 'paged' ) : '?paged=%#%';
   4193 
   4194 	$defaults = array(
   4195 		'base'               => $pagenum_link, // http://example.com/all_posts.php%_% : %_% is replaced by format (below).
   4196 		'format'             => $format, // ?page=%#% : %#% is replaced by the page number.
   4197 		'total'              => $total,
   4198 		'current'            => $current,
   4199 		'aria_current'       => 'page',
   4200 		'show_all'           => false,
   4201 		'prev_next'          => true,
   4202 		'prev_text'          => __( '&laquo; Previous' ),
   4203 		'next_text'          => __( 'Next &raquo;' ),
   4204 		'end_size'           => 1,
   4205 		'mid_size'           => 2,
   4206 		'type'               => 'plain',
   4207 		'add_args'           => array(), // Array of query args to add.
   4208 		'add_fragment'       => '',
   4209 		'before_page_number' => '',
   4210 		'after_page_number'  => '',
   4211 	);
   4212 
   4213 	$args = wp_parse_args( $args, $defaults );
   4214 
   4215 	if ( ! is_array( $args['add_args'] ) ) {
   4216 		$args['add_args'] = array();
   4217 	}
   4218 
   4219 	// Merge additional query vars found in the original URL into 'add_args' array.
   4220 	if ( isset( $url_parts[1] ) ) {
   4221 		// Find the format argument.
   4222 		$format       = explode( '?', str_replace( '%_%', $args['format'], $args['base'] ) );
   4223 		$format_query = isset( $format[1] ) ? $format[1] : '';
   4224 		wp_parse_str( $format_query, $format_args );
   4225 
   4226 		// Find the query args of the requested URL.
   4227 		wp_parse_str( $url_parts[1], $url_query_args );
   4228 
   4229 		// Remove the format argument from the array of query arguments, to avoid overwriting custom format.
   4230 		foreach ( $format_args as $format_arg => $format_arg_value ) {
   4231 			unset( $url_query_args[ $format_arg ] );
   4232 		}
   4233 
   4234 		$args['add_args'] = array_merge( $args['add_args'], urlencode_deep( $url_query_args ) );
   4235 	}
   4236 
   4237 	// Who knows what else people pass in $args.
   4238 	$total = (int) $args['total'];
   4239 	if ( $total < 2 ) {
   4240 		return;
   4241 	}
   4242 	$current  = (int) $args['current'];
   4243 	$end_size = (int) $args['end_size']; // Out of bounds? Make it the default.
   4244 	if ( $end_size < 1 ) {
   4245 		$end_size = 1;
   4246 	}
   4247 	$mid_size = (int) $args['mid_size'];
   4248 	if ( $mid_size < 0 ) {
   4249 		$mid_size = 2;
   4250 	}
   4251 
   4252 	$add_args   = $args['add_args'];
   4253 	$r          = '';
   4254 	$page_links = array();
   4255 	$dots       = false;
   4256 
   4257 	if ( $args['prev_next'] && $current && 1 < $current ) :
   4258 		$link = str_replace( '%_%', 2 == $current ? '' : $args['format'], $args['base'] );
   4259 		$link = str_replace( '%#%', $current - 1, $link );
   4260 		if ( $add_args ) {
   4261 			$link = add_query_arg( $add_args, $link );
   4262 		}
   4263 		$link .= $args['add_fragment'];
   4264 
   4265 		$page_links[] = sprintf(
   4266 			'<a class="prev page-numbers" href="%s">%s</a>',
   4267 			/**
   4268 			 * Filters the paginated links for the given archive pages.
   4269 			 *
   4270 			 * @since 3.0.0
   4271 			 *
   4272 			 * @param string $link The paginated link URL.
   4273 			 */
   4274 			esc_url( apply_filters( 'paginate_links', $link ) ),
   4275 			$args['prev_text']
   4276 		);
   4277 	endif;
   4278 
   4279 	for ( $n = 1; $n <= $total; $n++ ) :
   4280 		if ( $n == $current ) :
   4281 			$page_links[] = sprintf(
   4282 				'<span aria-current="%s" class="page-numbers current">%s</span>',
   4283 				esc_attr( $args['aria_current'] ),
   4284 				$args['before_page_number'] . number_format_i18n( $n ) . $args['after_page_number']
   4285 			);
   4286 
   4287 			$dots = true;
   4288 		else :
   4289 			if ( $args['show_all'] || ( $n <= $end_size || ( $current && $n >= $current - $mid_size && $n <= $current + $mid_size ) || $n > $total - $end_size ) ) :
   4290 				$link = str_replace( '%_%', 1 == $n ? '' : $args['format'], $args['base'] );
   4291 				$link = str_replace( '%#%', $n, $link );
   4292 				if ( $add_args ) {
   4293 					$link = add_query_arg( $add_args, $link );
   4294 				}
   4295 				$link .= $args['add_fragment'];
   4296 
   4297 				$page_links[] = sprintf(
   4298 					'<a class="page-numbers" href="%s">%s</a>',
   4299 					/** This filter is documented in wp-includes/general-template.php */
   4300 					esc_url( apply_filters( 'paginate_links', $link ) ),
   4301 					$args['before_page_number'] . number_format_i18n( $n ) . $args['after_page_number']
   4302 				);
   4303 
   4304 				$dots = true;
   4305 			elseif ( $dots && ! $args['show_all'] ) :
   4306 				$page_links[] = '<span class="page-numbers dots">' . __( '&hellip;' ) . '</span>';
   4307 
   4308 				$dots = false;
   4309 			endif;
   4310 		endif;
   4311 	endfor;
   4312 
   4313 	if ( $args['prev_next'] && $current && $current < $total ) :
   4314 		$link = str_replace( '%_%', $args['format'], $args['base'] );
   4315 		$link = str_replace( '%#%', $current + 1, $link );
   4316 		if ( $add_args ) {
   4317 			$link = add_query_arg( $add_args, $link );
   4318 		}
   4319 		$link .= $args['add_fragment'];
   4320 
   4321 		$page_links[] = sprintf(
   4322 			'<a class="next page-numbers" href="%s">%s</a>',
   4323 			/** This filter is documented in wp-includes/general-template.php */
   4324 			esc_url( apply_filters( 'paginate_links', $link ) ),
   4325 			$args['next_text']
   4326 		);
   4327 	endif;
   4328 
   4329 	switch ( $args['type'] ) {
   4330 		case 'array':
   4331 			return $page_links;
   4332 
   4333 		case 'list':
   4334 			$r .= "<ul class='page-numbers'>\n\t<li>";
   4335 			$r .= implode( "</li>\n\t<li>", $page_links );
   4336 			$r .= "</li>\n</ul>\n";
   4337 			break;
   4338 
   4339 		default:
   4340 			$r = implode( "\n", $page_links );
   4341 			break;
   4342 	}
   4343 
   4344 	/**
   4345 	 * Filters the HTML output of paginated links for archives.
   4346 	 *
   4347 	 * @since 5.7.0
   4348 	 *
   4349 	 * @param string $r    HTML output.
   4350 	 * @param array  $args An array of arguments. See paginate_links()
   4351 	 *                     for information on accepted arguments.
   4352 	 */
   4353 	$r = apply_filters( 'paginate_links_output', $r, $args );
   4354 
   4355 	return $r;
   4356 }
   4357 
   4358 /**
   4359  * Registers an admin color scheme css file.
   4360  *
   4361  * Allows a plugin to register a new admin color scheme. For example:
   4362  *
   4363  *     wp_admin_css_color( 'classic', __( 'Classic' ), admin_url( "css/colors-classic.css" ), array(
   4364  *         '#07273E', '#14568A', '#D54E21', '#2683AE'
   4365  *     ) );
   4366  *
   4367  * @since 2.5.0
   4368  *
   4369  * @global array $_wp_admin_css_colors
   4370  *
   4371  * @param string $key    The unique key for this theme.
   4372  * @param string $name   The name of the theme.
   4373  * @param string $url    The URL of the CSS file containing the color scheme.
   4374  * @param array  $colors Optional. An array of CSS color definition strings which are used
   4375  *                       to give the user a feel for the theme.
   4376  * @param array  $icons {
   4377  *     Optional. CSS color definitions used to color any SVG icons.
   4378  *
   4379  *     @type string $base    SVG icon base color.
   4380  *     @type string $focus   SVG icon color on focus.
   4381  *     @type string $current SVG icon color of current admin menu link.
   4382  * }
   4383  */
   4384 function wp_admin_css_color( $key, $name, $url, $colors = array(), $icons = array() ) {
   4385 	global $_wp_admin_css_colors;
   4386 
   4387 	if ( ! isset( $_wp_admin_css_colors ) ) {
   4388 		$_wp_admin_css_colors = array();
   4389 	}
   4390 
   4391 	$_wp_admin_css_colors[ $key ] = (object) array(
   4392 		'name'        => $name,
   4393 		'url'         => $url,
   4394 		'colors'      => $colors,
   4395 		'icon_colors' => $icons,
   4396 	);
   4397 }
   4398 
   4399 /**
   4400  * Registers the default admin color schemes.
   4401  *
   4402  * Registers the initial set of eight color schemes in the Profile section
   4403  * of the dashboard which allows for styling the admin menu and toolbar.
   4404  *
   4405  * @see wp_admin_css_color()
   4406  *
   4407  * @since 3.0.0
   4408  */
   4409 function register_admin_color_schemes() {
   4410 	$suffix  = is_rtl() ? '-rtl' : '';
   4411 	$suffix .= SCRIPT_DEBUG ? '' : '.min';
   4412 
   4413 	wp_admin_css_color(
   4414 		'fresh',
   4415 		_x( 'Default', 'admin color scheme' ),
   4416 		false,
   4417 		array( '#1d2327', '#2c3338', '#2271b1', '#72aee6' ),
   4418 		array(
   4419 			'base'    => '#a7aaad',
   4420 			'focus'   => '#72aee6',
   4421 			'current' => '#fff',
   4422 		)
   4423 	);
   4424 
   4425 	wp_admin_css_color(
   4426 		'light',
   4427 		_x( 'Light', 'admin color scheme' ),
   4428 		admin_url( "css/colors/light/colors$suffix.css" ),
   4429 		array( '#e5e5e5', '#999', '#d64e07', '#04a4cc' ),
   4430 		array(
   4431 			'base'    => '#999',
   4432 			'focus'   => '#ccc',
   4433 			'current' => '#ccc',
   4434 		)
   4435 	);
   4436 
   4437 	wp_admin_css_color(
   4438 		'modern',
   4439 		_x( 'Modern', 'admin color scheme' ),
   4440 		admin_url( "css/colors/modern/colors$suffix.css" ),
   4441 		array( '#1e1e1e', '#3858e9', '#33f078' ),
   4442 		array(
   4443 			'base'    => '#f3f1f1',
   4444 			'focus'   => '#fff',
   4445 			'current' => '#fff',
   4446 		)
   4447 	);
   4448 
   4449 	wp_admin_css_color(
   4450 		'blue',
   4451 		_x( 'Blue', 'admin color scheme' ),
   4452 		admin_url( "css/colors/blue/colors$suffix.css" ),
   4453 		array( '#096484', '#4796b3', '#52accc', '#74B6CE' ),
   4454 		array(
   4455 			'base'    => '#e5f8ff',
   4456 			'focus'   => '#fff',
   4457 			'current' => '#fff',
   4458 		)
   4459 	);
   4460 
   4461 	wp_admin_css_color(
   4462 		'midnight',
   4463 		_x( 'Midnight', 'admin color scheme' ),
   4464 		admin_url( "css/colors/midnight/colors$suffix.css" ),
   4465 		array( '#25282b', '#363b3f', '#69a8bb', '#e14d43' ),
   4466 		array(
   4467 			'base'    => '#f1f2f3',
   4468 			'focus'   => '#fff',
   4469 			'current' => '#fff',
   4470 		)
   4471 	);
   4472 
   4473 	wp_admin_css_color(
   4474 		'sunrise',
   4475 		_x( 'Sunrise', 'admin color scheme' ),
   4476 		admin_url( "css/colors/sunrise/colors$suffix.css" ),
   4477 		array( '#b43c38', '#cf4944', '#dd823b', '#ccaf0b' ),
   4478 		array(
   4479 			'base'    => '#f3f1f1',
   4480 			'focus'   => '#fff',
   4481 			'current' => '#fff',
   4482 		)
   4483 	);
   4484 
   4485 	wp_admin_css_color(
   4486 		'ectoplasm',
   4487 		_x( 'Ectoplasm', 'admin color scheme' ),
   4488 		admin_url( "css/colors/ectoplasm/colors$suffix.css" ),
   4489 		array( '#413256', '#523f6d', '#a3b745', '#d46f15' ),
   4490 		array(
   4491 			'base'    => '#ece6f6',
   4492 			'focus'   => '#fff',
   4493 			'current' => '#fff',
   4494 		)
   4495 	);
   4496 
   4497 	wp_admin_css_color(
   4498 		'ocean',
   4499 		_x( 'Ocean', 'admin color scheme' ),
   4500 		admin_url( "css/colors/ocean/colors$suffix.css" ),
   4501 		array( '#627c83', '#738e96', '#9ebaa0', '#aa9d88' ),
   4502 		array(
   4503 			'base'    => '#f2fcff',
   4504 			'focus'   => '#fff',
   4505 			'current' => '#fff',
   4506 		)
   4507 	);
   4508 
   4509 	wp_admin_css_color(
   4510 		'coffee',
   4511 		_x( 'Coffee', 'admin color scheme' ),
   4512 		admin_url( "css/colors/coffee/colors$suffix.css" ),
   4513 		array( '#46403c', '#59524c', '#c7a589', '#9ea476' ),
   4514 		array(
   4515 			'base'    => '#f3f2f1',
   4516 			'focus'   => '#fff',
   4517 			'current' => '#fff',
   4518 		)
   4519 	);
   4520 
   4521 }
   4522 
   4523 /**
   4524  * Displays the URL of a WordPress admin CSS file.
   4525  *
   4526  * @see WP_Styles::_css_href and its {@see 'style_loader_src'} filter.
   4527  *
   4528  * @since 2.3.0
   4529  *
   4530  * @param string $file file relative to wp-admin/ without its ".css" extension.
   4531  * @return string
   4532  */
   4533 function wp_admin_css_uri( $file = 'wp-admin' ) {
   4534 	if ( defined( 'WP_INSTALLING' ) ) {
   4535 		$_file = "./$file.css";
   4536 	} else {
   4537 		$_file = admin_url( "$file.css" );
   4538 	}
   4539 	$_file = add_query_arg( 'version', get_bloginfo( 'version' ), $_file );
   4540 
   4541 	/**
   4542 	 * Filters the URI of a WordPress admin CSS file.
   4543 	 *
   4544 	 * @since 2.3.0
   4545 	 *
   4546 	 * @param string $_file Relative path to the file with query arguments attached.
   4547 	 * @param string $file  Relative path to the file, minus its ".css" extension.
   4548 	 */
   4549 	return apply_filters( 'wp_admin_css_uri', $_file, $file );
   4550 }
   4551 
   4552 /**
   4553  * Enqueues or directly prints a stylesheet link to the specified CSS file.
   4554  *
   4555  * "Intelligently" decides to enqueue or to print the CSS file. If the
   4556  * {@see 'wp_print_styles'} action has *not* yet been called, the CSS file will be
   4557  * enqueued. If the {@see 'wp_print_styles'} action has been called, the CSS link will
   4558  * be printed. Printing may be forced by passing true as the $force_echo
   4559  * (second) parameter.
   4560  *
   4561  * For backward compatibility with WordPress 2.3 calling method: If the $file
   4562  * (first) parameter does not correspond to a registered CSS file, we assume
   4563  * $file is a file relative to wp-admin/ without its ".css" extension. A
   4564  * stylesheet link to that generated URL is printed.
   4565  *
   4566  * @since 2.3.0
   4567  *
   4568  * @param string $file       Optional. Style handle name or file name (without ".css" extension) relative
   4569  *                           to wp-admin/. Defaults to 'wp-admin'.
   4570  * @param bool   $force_echo Optional. Force the stylesheet link to be printed rather than enqueued.
   4571  */
   4572 function wp_admin_css( $file = 'wp-admin', $force_echo = false ) {
   4573 	// For backward compatibility.
   4574 	$handle = 0 === strpos( $file, 'css/' ) ? substr( $file, 4 ) : $file;
   4575 
   4576 	if ( wp_styles()->query( $handle ) ) {
   4577 		if ( $force_echo || did_action( 'wp_print_styles' ) ) {
   4578 			// We already printed the style queue. Print this one immediately.
   4579 			wp_print_styles( $handle );
   4580 		} else {
   4581 			// Add to style queue.
   4582 			wp_enqueue_style( $handle );
   4583 		}
   4584 		return;
   4585 	}
   4586 
   4587 	$stylesheet_link = sprintf(
   4588 		"<link rel='stylesheet' href='%s' type='text/css' />\n",
   4589 		esc_url( wp_admin_css_uri( $file ) )
   4590 	);
   4591 
   4592 	/**
   4593 	 * Filters the stylesheet link to the specified CSS file.
   4594 	 *
   4595 	 * If the site is set to display right-to-left, the RTL stylesheet link
   4596 	 * will be used instead.
   4597 	 *
   4598 	 * @since 2.3.0
   4599 	 * @param string $stylesheet_link HTML link element for the stylesheet.
   4600 	 * @param string $file            Style handle name or filename (without ".css" extension)
   4601 	 *                                relative to wp-admin/. Defaults to 'wp-admin'.
   4602 	 */
   4603 	echo apply_filters( 'wp_admin_css', $stylesheet_link, $file );
   4604 
   4605 	if ( function_exists( 'is_rtl' ) && is_rtl() ) {
   4606 		$rtl_stylesheet_link = sprintf(
   4607 			"<link rel='stylesheet' href='%s' type='text/css' />\n",
   4608 			esc_url( wp_admin_css_uri( "$file-rtl" ) )
   4609 		);
   4610 
   4611 		/** This filter is documented in wp-includes/general-template.php */
   4612 		echo apply_filters( 'wp_admin_css', $rtl_stylesheet_link, "$file-rtl" );
   4613 	}
   4614 }
   4615 
   4616 /**
   4617  * Enqueues the default ThickBox js and css.
   4618  *
   4619  * If any of the settings need to be changed, this can be done with another js
   4620  * file similar to media-upload.js. That file should
   4621  * require array('thickbox') to ensure it is loaded after.
   4622  *
   4623  * @since 2.5.0
   4624  */
   4625 function add_thickbox() {
   4626 	wp_enqueue_script( 'thickbox' );
   4627 	wp_enqueue_style( 'thickbox' );
   4628 
   4629 	if ( is_network_admin() ) {
   4630 		add_action( 'admin_head', '_thickbox_path_admin_subfolder' );
   4631 	}
   4632 }
   4633 
   4634 /**
   4635  * Displays the XHTML generator that is generated on the wp_head hook.
   4636  *
   4637  * See {@see 'wp_head'}.
   4638  *
   4639  * @since 2.5.0
   4640  */
   4641 function wp_generator() {
   4642 	/**
   4643 	 * Filters the output of the XHTML generator tag.
   4644 	 *
   4645 	 * @since 2.5.0
   4646 	 *
   4647 	 * @param string $generator_type The XHTML generator.
   4648 	 */
   4649 	the_generator( apply_filters( 'wp_generator_type', 'xhtml' ) );
   4650 }
   4651 
   4652 /**
   4653  * Display the generator XML or Comment for RSS, ATOM, etc.
   4654  *
   4655  * Returns the correct generator type for the requested output format. Allows
   4656  * for a plugin to filter generators overall the {@see 'the_generator'} filter.
   4657  *
   4658  * @since 2.5.0
   4659  *
   4660  * @param string $type The type of generator to output - (html|xhtml|atom|rss2|rdf|comment|export).
   4661  */
   4662 function the_generator( $type ) {
   4663 	/**
   4664 	 * Filters the output of the XHTML generator tag for display.
   4665 	 *
   4666 	 * @since 2.5.0
   4667 	 *
   4668 	 * @param string $generator_type The generator output.
   4669 	 * @param string $type           The type of generator to output. Accepts 'html',
   4670 	 *                               'xhtml', 'atom', 'rss2', 'rdf', 'comment', 'export'.
   4671 	 */
   4672 	echo apply_filters( 'the_generator', get_the_generator( $type ), $type ) . "\n";
   4673 }
   4674 
   4675 /**
   4676  * Creates the generator XML or Comment for RSS, ATOM, etc.
   4677  *
   4678  * Returns the correct generator type for the requested output format. Allows
   4679  * for a plugin to filter generators on an individual basis using the
   4680  * {@see 'get_the_generator_$type'} filter.
   4681  *
   4682  * @since 2.5.0
   4683  *
   4684  * @param string $type The type of generator to return - (html|xhtml|atom|rss2|rdf|comment|export).
   4685  * @return string|void The HTML content for the generator.
   4686  */
   4687 function get_the_generator( $type = '' ) {
   4688 	if ( empty( $type ) ) {
   4689 
   4690 		$current_filter = current_filter();
   4691 		if ( empty( $current_filter ) ) {
   4692 			return;
   4693 		}
   4694 
   4695 		switch ( $current_filter ) {
   4696 			case 'rss2_head':
   4697 			case 'commentsrss2_head':
   4698 				$type = 'rss2';
   4699 				break;
   4700 			case 'rss_head':
   4701 			case 'opml_head':
   4702 				$type = 'comment';
   4703 				break;
   4704 			case 'rdf_header':
   4705 				$type = 'rdf';
   4706 				break;
   4707 			case 'atom_head':
   4708 			case 'comments_atom_head':
   4709 			case 'app_head':
   4710 				$type = 'atom';
   4711 				break;
   4712 		}
   4713 	}
   4714 
   4715 	switch ( $type ) {
   4716 		case 'html':
   4717 			$gen = '<meta name="generator" content="WordPress ' . esc_attr( get_bloginfo( 'version' ) ) . '">';
   4718 			break;
   4719 		case 'xhtml':
   4720 			$gen = '<meta name="generator" content="WordPress ' . esc_attr( get_bloginfo( 'version' ) ) . '" />';
   4721 			break;
   4722 		case 'atom':
   4723 			$gen = '<generator uri="https://wordpress.org/" version="' . esc_attr( get_bloginfo_rss( 'version' ) ) . '">WordPress</generator>';
   4724 			break;
   4725 		case 'rss2':
   4726 			$gen = '<generator>' . esc_url_raw( 'https://wordpress.org/?v=' . get_bloginfo_rss( 'version' ) ) . '</generator>';
   4727 			break;
   4728 		case 'rdf':
   4729 			$gen = '<admin:generatorAgent rdf:resource="' . esc_url_raw( 'https://wordpress.org/?v=' . get_bloginfo_rss( 'version' ) ) . '" />';
   4730 			break;
   4731 		case 'comment':
   4732 			$gen = '<!-- generator="WordPress/' . esc_attr( get_bloginfo( 'version' ) ) . '" -->';
   4733 			break;
   4734 		case 'export':
   4735 			$gen = '<!-- generator="WordPress/' . esc_attr( get_bloginfo_rss( 'version' ) ) . '" created="' . gmdate( 'Y-m-d H:i' ) . '" -->';
   4736 			break;
   4737 	}
   4738 
   4739 	/**
   4740 	 * Filters the HTML for the retrieved generator type.
   4741 	 *
   4742 	 * The dynamic portion of the hook name, `$type`, refers to the generator type.
   4743 	 *
   4744 	 * Possible hook names include:
   4745 	 *
   4746 	 *  - `get_the_generator_atom`
   4747 	 *  - `get_the_generator_comment`
   4748 	 *  - `get_the_generator_export`
   4749 	 *  - `get_the_generator_html`
   4750 	 *  - `get_the_generator_rdf`
   4751 	 *  - `get_the_generator_rss2`
   4752 	 *  - `get_the_generator_xhtml`
   4753 	 *
   4754 	 * @since 2.5.0
   4755 	 *
   4756 	 * @param string $gen  The HTML markup output to wp_head().
   4757 	 * @param string $type The type of generator. Accepts 'html', 'xhtml', 'atom',
   4758 	 *                     'rss2', 'rdf', 'comment', 'export'.
   4759 	 */
   4760 	return apply_filters( "get_the_generator_{$type}", $gen, $type );
   4761 }
   4762 
   4763 /**
   4764  * Outputs the HTML checked attribute.
   4765  *
   4766  * Compares the first two arguments and if identical marks as checked
   4767  *
   4768  * @since 1.0.0
   4769  *
   4770  * @param mixed $checked One of the values to compare
   4771  * @param mixed $current (true) The other value to compare if not just true
   4772  * @param bool  $echo    Whether to echo or just return the string
   4773  * @return string HTML attribute or empty string
   4774  */
   4775 function checked( $checked, $current = true, $echo = true ) {
   4776 	return __checked_selected_helper( $checked, $current, $echo, 'checked' );
   4777 }
   4778 
   4779 /**
   4780  * Outputs the HTML selected attribute.
   4781  *
   4782  * Compares the first two arguments and if identical marks as selected
   4783  *
   4784  * @since 1.0.0
   4785  *
   4786  * @param mixed $selected One of the values to compare
   4787  * @param mixed $current  (true) The other value to compare if not just true
   4788  * @param bool  $echo     Whether to echo or just return the string
   4789  * @return string HTML attribute or empty string
   4790  */
   4791 function selected( $selected, $current = true, $echo = true ) {
   4792 	return __checked_selected_helper( $selected, $current, $echo, 'selected' );
   4793 }
   4794 
   4795 /**
   4796  * Outputs the HTML disabled attribute.
   4797  *
   4798  * Compares the first two arguments and if identical marks as disabled
   4799  *
   4800  * @since 3.0.0
   4801  *
   4802  * @param mixed $disabled One of the values to compare
   4803  * @param mixed $current  (true) The other value to compare if not just true
   4804  * @param bool  $echo     Whether to echo or just return the string
   4805  * @return string HTML attribute or empty string
   4806  */
   4807 function disabled( $disabled, $current = true, $echo = true ) {
   4808 	return __checked_selected_helper( $disabled, $current, $echo, 'disabled' );
   4809 }
   4810 
   4811 /**
   4812  * Outputs the HTML readonly attribute.
   4813  *
   4814  * Compares the first two arguments and if identical marks as readonly
   4815  *
   4816  * @since 4.9.0
   4817  *
   4818  * @param mixed $readonly One of the values to compare
   4819  * @param mixed $current  (true) The other value to compare if not just true
   4820  * @param bool  $echo     Whether to echo or just return the string
   4821  * @return string HTML attribute or empty string
   4822  */
   4823 function readonly( $readonly, $current = true, $echo = true ) {
   4824 	return __checked_selected_helper( $readonly, $current, $echo, 'readonly' );
   4825 }
   4826 
   4827 /**
   4828  * Private helper function for checked, selected, disabled and readonly.
   4829  *
   4830  * Compares the first two arguments and if identical marks as $type
   4831  *
   4832  * @since 2.8.0
   4833  * @access private
   4834  *
   4835  * @param mixed  $helper  One of the values to compare
   4836  * @param mixed  $current (true) The other value to compare if not just true
   4837  * @param bool   $echo    Whether to echo or just return the string
   4838  * @param string $type    The type of checked|selected|disabled|readonly we are doing
   4839  * @return string HTML attribute or empty string
   4840  */
   4841 function __checked_selected_helper( $helper, $current, $echo, $type ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
   4842 	if ( (string) $helper === (string) $current ) {
   4843 		$result = " $type='$type'";
   4844 	} else {
   4845 		$result = '';
   4846 	}
   4847 
   4848 	if ( $echo ) {
   4849 		echo $result;
   4850 	}
   4851 
   4852 	return $result;
   4853 }
   4854 
   4855 /**
   4856  * Default settings for heartbeat
   4857  *
   4858  * Outputs the nonce used in the heartbeat XHR
   4859  *
   4860  * @since 3.6.0
   4861  *
   4862  * @param array $settings
   4863  * @return array Heartbeat settings.
   4864  */
   4865 function wp_heartbeat_settings( $settings ) {
   4866 	if ( ! is_admin() ) {
   4867 		$settings['ajaxurl'] = admin_url( 'admin-ajax.php', 'relative' );
   4868 	}
   4869 
   4870 	if ( is_user_logged_in() ) {
   4871 		$settings['nonce'] = wp_create_nonce( 'heartbeat-nonce' );
   4872 	}
   4873 
   4874 	return $settings;
   4875 }