will not be wrapped with unordered list `
` tags. Default 'Pages'.
* @type string $item_spacing Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'.
* Default 'preserve'.
* @type Walker $walker Walker instance to use for listing pages. Default empty which results in a
* Walker_Page instance being used.
* }
* @return void|string Void if 'echo' argument is true, HTML list of pages if 'echo' is false.
*/
function wp_list_pages( $args = '' ) {
$defaults = array(
'depth' => 0,
'show_date' => '',
'date_format' => get_option( 'date_format' ),
'child_of' => 0,
'exclude' => '',
'title_li' => __( 'Pages' ),
'echo' => 1,
'authors' => '',
'sort_column' => 'menu_order, post_title',
'link_before' => '',
'link_after' => '',
'item_spacing' => 'preserve',
'walker' => '',
);
$parsed_args = wp_parse_args( $args, $defaults );
if ( ! in_array( $parsed_args['item_spacing'], array( 'preserve', 'discard' ), true ) ) {
// Invalid value, fall back to default.
$parsed_args['item_spacing'] = $defaults['item_spacing'];
}
$output = '';
$current_page = 0;
// Sanitize, mostly to keep spaces out.
$parsed_args['exclude'] = preg_replace( '/[^0-9,]/', '', $parsed_args['exclude'] );
// Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array).
$exclude_array = ( $parsed_args['exclude'] ) ? explode( ',', $parsed_args['exclude'] ) : array();
/**
* Filters the array of pages to exclude from the pages list.
*
* @since 2.1.0
*
* @param string[] $exclude_array An array of page IDs to exclude.
*/
$parsed_args['exclude'] = implode( ',', apply_filters( 'wp_list_pages_excludes', $exclude_array ) );
$parsed_args['hierarchical'] = 0;
// Query pages.
$pages = get_pages( $parsed_args );
if ( ! empty( $pages ) ) {
if ( $parsed_args['title_li'] ) {
$output .= '- ' . $parsed_args['title_li'] . '
';
}
global $wp_query;
if ( is_page() || is_attachment() || $wp_query->is_posts_page ) {
$current_page = get_queried_object_id();
} elseif ( is_singular() ) {
$queried_object = get_queried_object();
if ( is_post_type_hierarchical( $queried_object->post_type ) ) {
$current_page = $queried_object->ID;
}
}
$output .= walk_page_tree( $pages, $parsed_args['depth'], $current_page, $parsed_args );
if ( $parsed_args['title_li'] ) {
$output .= '
';
}
}
/**
* Filters the HTML output of the pages to list.
*
* @since 1.5.1
* @since 4.4.0 `$pages` added as arguments.
*
* @see wp_list_pages()
*
* @param string $output HTML output of the pages list.
* @param array $parsed_args An array of page-listing arguments. See wp_list_pages()
* for information on accepted arguments.
* @param WP_Post[] $pages Array of the page objects.
*/
$html = apply_filters( 'wp_list_pages', $output, $parsed_args, $pages );
if ( $parsed_args['echo'] ) {
echo $html;
} else {
return $html;
}
}
/**
* Displays or retrieves a list of pages with an optional home link.
*
* The arguments are listed below and part of the arguments are for wp_list_pages() function.
* Check that function for more info on those arguments.
*
* @since 2.7.0
* @since 4.4.0 Added `menu_id`, `container`, `before`, `after`, and `walker` arguments.
* @since 4.7.0 Added the `item_spacing` argument.
*
* @param array|string $args {
* Optional. Array or string of arguments to generate a page menu. See `wp_list_pages()` for additional arguments.
*
* @type string $sort_column How to sort the list of pages. Accepts post column names.
* Default 'menu_order, post_title'.
* @type string $menu_id ID for the div containing the page list. Default is empty string.
* @type string $menu_class Class to use for the element containing the page list. Default 'menu'.
* @type string $container Element to use for the element containing the page list. Default 'div'.
* @type bool $echo Whether to echo the list or return it. Accepts true (echo) or false (return).
* Default true.
* @type int|bool|string $show_home Whether to display the link to the home page. Can just enter the text
* you'd like shown for the home link. 1|true defaults to 'Home'.
* @type string $link_before The HTML or text to prepend to $show_home text. Default empty.
* @type string $link_after The HTML or text to append to $show_home text. Default empty.
* @type string $before The HTML or text to prepend to the menu. Default is ''.
* @type string $after The HTML or text to append to the menu. Default is '
'.
* @type string $item_spacing Whether to preserve whitespace within the menu's HTML. Accepts 'preserve'
* or 'discard'. Default 'discard'.
* @type Walker $walker Walker instance to use for listing pages. Default empty which results in a
* Walker_Page instance being used.
* }
* @return void|string Void if 'echo' argument is true, HTML menu if 'echo' is false.
*/
function wp_page_menu( $args = array() ) {
$defaults = array(
'sort_column' => 'menu_order, post_title',
'menu_id' => '',
'menu_class' => 'menu',
'container' => 'div',
'echo' => true,
'link_before' => '',
'link_after' => '',
'before' => '',
'item_spacing' => 'discard',
'walker' => '',
);
$args = wp_parse_args( $args, $defaults );
if ( ! in_array( $args['item_spacing'], array( 'preserve', 'discard' ), true ) ) {
// Invalid value, fall back to default.
$args['item_spacing'] = $defaults['item_spacing'];
}
if ( 'preserve' === $args['item_spacing'] ) {
$t = "\t";
$n = "\n";
} else {
$t = '';
$n = '';
}
/**
* Filters the arguments used to generate a page-based menu.
*
* @since 2.7.0
*
* @see wp_page_menu()
*
* @param array $args An array of page menu arguments. See wp_page_menu()
* for information on accepted arguments.
*/
$args = apply_filters( 'wp_page_menu_args', $args );
$menu = '';
$list_args = $args;
// Show Home in the menu.
if ( ! empty( $args['show_home'] ) ) {
if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] ) {
$text = __( 'Home' );
} else {
$text = $args['show_home'];
}
$class = '';
if ( is_front_page() && ! is_paged() ) {
$class = 'class="current_page_item"';
}
$menu .= '- ' . $args['link_before'] . $text . $args['link_after'] . '
';
// If the front page is a page, add it to the exclude list.
if ( 'page' === get_option( 'show_on_front' ) ) {
if ( ! empty( $list_args['exclude'] ) ) {
$list_args['exclude'] .= ',';
} else {
$list_args['exclude'] = '';
}
$list_args['exclude'] .= get_option( 'page_on_front' );
}
}
$list_args['echo'] = false;
$list_args['title_li'] = '';
$menu .= wp_list_pages( $list_args );
$container = sanitize_text_field( $args['container'] );
// Fallback in case `wp_nav_menu()` was called without a container.
if ( empty( $container ) ) {
$container = 'div';
}
if ( $menu ) {
// wp_nav_menu() doesn't set before and after.
if ( isset( $args['fallback_cb'] ) &&
'wp_page_menu' === $args['fallback_cb'] &&
'ul' !== $container ) {
$args['before'] = "{$n}";
$args['after'] = '
';
}
$menu = $args['before'] . $menu . $args['after'];
}
$attrs = '';
if ( ! empty( $args['menu_id'] ) ) {
$attrs .= ' id="' . esc_attr( $args['menu_id'] ) . '"';
}
if ( ! empty( $args['menu_class'] ) ) {
$attrs .= ' class="' . esc_attr( $args['menu_class'] ) . '"';
}
$menu = "<{$container}{$attrs}>" . $menu . "{$container}>{$n}";
/**
* Filters the HTML output of a page-based menu.
*
* @since 2.7.0
*
* @see wp_page_menu()
*
* @param string $menu The HTML output.
* @param array $args An array of arguments. See wp_page_menu()
* for information on accepted arguments.
*/
$menu = apply_filters( 'wp_page_menu', $menu, $args );
if ( $args['echo'] ) {
echo $menu;
} else {
return $menu;
}
}
//
// Page helpers.
//
/**
* Retrieves HTML list content for page list.
*
* @uses Walker_Page to create HTML list content.
* @since 2.1.0
*
* @param array $pages
* @param int $depth
* @param int $current_page
* @param array $args
* @return string
*/
function walk_page_tree( $pages, $depth, $current_page, $args ) {
if ( empty( $args['walker'] ) ) {
$walker = new Walker_Page;
} else {
/**
* @var Walker $walker
*/
$walker = $args['walker'];
}
foreach ( (array) $pages as $page ) {
if ( $page->post_parent ) {
$args['pages_with_children'][ $page->post_parent ] = true;
}
}
return $walker->walk( $pages, $depth, $args, $current_page );
}
/**
* Retrieves HTML dropdown (select) content for page list.
*
* @since 2.1.0
* @since 5.3.0 Formalized the existing `...$args` parameter by adding it
* to the function signature.
*
* @uses Walker_PageDropdown to create HTML dropdown content.
* @see Walker_PageDropdown::walk() for parameters and return description.
*
* @param mixed ...$args Elements array, maximum hierarchical depth and optional additional arguments.
* @return string
*/
function walk_page_dropdown_tree( ...$args ) {
if ( empty( $args[2]['walker'] ) ) { // The user's options are the third parameter.
$walker = new Walker_PageDropdown;
} else {
/**
* @var Walker $walker
*/
$walker = $args[2]['walker'];
}
return $walker->walk( ...$args );
}
//
// Attachments.
//
/**
* Displays an attachment page link using an image or icon.
*
* @since 2.0.0
*
* @param int|WP_Post $id Optional. Post ID or post object.
* @param bool $fullsize Optional. Whether to use full size. Default false.
* @param bool $deprecated Deprecated. Not used.
* @param bool $permalink Optional. Whether to include permalink. Default false.
*/
function the_attachment_link( $id = 0, $fullsize = false, $deprecated = false, $permalink = false ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.5.0' );
}
if ( $fullsize ) {
echo wp_get_attachment_link( $id, 'full', $permalink );
} else {
echo wp_get_attachment_link( $id, 'thumbnail', $permalink );
}
}
/**
* Retrieves an attachment page link using an image or icon, if possible.
*
* @since 2.5.0
* @since 4.4.0 The `$id` parameter can now accept either a post ID or `WP_Post` object.
*
* @param int|WP_Post $id Optional. Post ID or post object.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $permalink Optional. Whether to add permalink to image. Default false.
* @param bool $icon Optional. Whether the attachment is an icon. Default false.
* @param string|false $text Optional. Link text to use. Activated by passing a string, false otherwise.
* Default false.
* @param array|string $attr Optional. Array or string of attributes. Default empty.
* @return string HTML content.
*/
function wp_get_attachment_link( $id = 0, $size = 'thumbnail', $permalink = false, $icon = false, $text = false, $attr = '' ) {
$_post = get_post( $id );
if ( empty( $_post ) || ( 'attachment' !== $_post->post_type ) || ! wp_get_attachment_url( $_post->ID ) ) {
return __( 'Missing Attachment' );
}
$url = wp_get_attachment_url( $_post->ID );
if ( $permalink ) {
$url = get_attachment_link( $_post->ID );
}
if ( $text ) {
$link_text = $text;
} elseif ( $size && 'none' !== $size ) {
$link_text = wp_get_attachment_image( $_post->ID, $size, $icon, $attr );
} else {
$link_text = '';
}
if ( '' === trim( $link_text ) ) {
$link_text = $_post->post_title;
}
if ( '' === trim( $link_text ) ) {
$link_text = esc_html( pathinfo( get_attached_file( $_post->ID ), PATHINFO_FILENAME ) );
}
/**
* Filters a retrieved attachment page link.
*
* @since 2.7.0
* @since 5.1.0 Added the `$attr` parameter.
*
* @param string $link_html The page link HTML output.
* @param int|WP_Post $id Post ID or object. Can be 0 for the current global post.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param bool $permalink Whether to add permalink to image. Default false.
* @param bool $icon Whether to include an icon.
* @param string|false $text If string, will be link text.
* @param array|string $attr Array or string of attributes.
*/
return apply_filters( 'wp_get_attachment_link', "$link_text", $id, $size, $permalink, $icon, $text, $attr );
}
/**
* Wraps attachment in paragraph tag before content.
*
* @since 2.0.0
*
* @param string $content
* @return string
*/
function prepend_attachment( $content ) {
$post = get_post();
if ( empty( $post->post_type ) || 'attachment' !== $post->post_type ) {
return $content;
}
if ( wp_attachment_is( 'video', $post ) ) {
$meta = wp_get_attachment_metadata( get_the_ID() );
$atts = array( 'src' => wp_get_attachment_url() );
if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
$atts['width'] = (int) $meta['width'];
$atts['height'] = (int) $meta['height'];
}
if ( has_post_thumbnail() ) {
$atts['poster'] = wp_get_attachment_url( get_post_thumbnail_id() );
}
$p = wp_video_shortcode( $atts );
} elseif ( wp_attachment_is( 'audio', $post ) ) {
$p = wp_audio_shortcode( array( 'src' => wp_get_attachment_url() ) );
} else {
$p = '';
// Show the medium sized image representation of the attachment if available, and link to the raw file.
$p .= wp_get_attachment_link( 0, 'medium', false );
$p .= '
';
}
/**
* Filters the attachment markup to be prepended to the post content.
*
* @since 2.0.0
*
* @see prepend_attachment()
*
* @param string $p The attachment HTML output.
*/
$p = apply_filters( 'prepend_attachment', $p );
return "$p\n$content";
}
//
// Misc.
//
/**
* Retrieves protected post password form content.
*
* @since 1.0.0
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string HTML content for password form for password protected post.
*/
function get_the_password_form( $post = 0 ) {
$post = get_post( $post );
$label = 'pwbox-' . ( empty( $post->ID ) ? rand() : $post->ID );
$output = '
';
/**
* Filters the HTML output for the protected post password form.
*
* If modifying the password field, please note that the core database schema
* limits the password field to 20 characters regardless of the value of the
* size attribute in the form input.
*
* @since 2.7.0
* @since 5.8.0 Added the `$post` parameter.
*
* @param string $output The password form HTML output.
* @param WP_Post $post Post object.
*/
return apply_filters( 'the_password_form', $output, $post );
}
/**
* Determines whether the current post uses a page template.
*
* This template tag allows you to determine if you are in a page template.
* You can optionally provide a template filename or array of template filenames
* and then the check will be specific to that template.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 2.5.0
* @since 4.2.0 The `$template` parameter was changed to also accept an array of page templates.
* @since 4.7.0 Now works with any post type, not just pages.
*
* @param string|string[] $template The specific template filename or array of templates to match.
* @return bool True on success, false on failure.
*/
function is_page_template( $template = '' ) {
if ( ! is_singular() ) {
return false;
}
$page_template = get_page_template_slug( get_queried_object_id() );
if ( empty( $template ) ) {
return (bool) $page_template;
}
if ( $template == $page_template ) {
return true;
}
if ( is_array( $template ) ) {
if ( ( in_array( 'default', $template, true ) && ! $page_template )
|| in_array( $page_template, $template, true )
) {
return true;
}
}
return ( 'default' === $template && ! $page_template );
}
/**
* Gets the specific template filename for a given post.
*
* @since 3.4.0
* @since 4.7.0 Now works with any post type, not just pages.
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string|false Page template filename. Returns an empty string when the default page template
* is in use. Returns false if the post does not exist.
*/
function get_page_template_slug( $post = null ) {
$post = get_post( $post );
if ( ! $post ) {
return false;
}
$template = get_post_meta( $post->ID, '_wp_page_template', true );
if ( ! $template || 'default' === $template ) {
return '';
}
return $template;
}
/**
* Retrieves formatted date timestamp of a revision (linked to that revisions's page).
*
* @since 2.6.0
*
* @param int|object $revision Revision ID or revision object.
* @param bool $link Optional. Whether to link to revision's page. Default true.
* @return string|false i18n formatted datetimestamp or localized 'Current Revision'.
*/
function wp_post_revision_title( $revision, $link = true ) {
$revision = get_post( $revision );
if ( ! $revision ) {
return $revision;
}
if ( ! in_array( $revision->post_type, array( 'post', 'page', 'revision' ), true ) ) {
return false;
}
/* translators: Revision date format, see https://www.php.net/manual/datetime.format.php */
$datef = _x( 'F j, Y @ H:i:s', 'revision date format' );
/* translators: %s: Revision date. */
$autosavef = __( '%s [Autosave]' );
/* translators: %s: Revision date. */
$currentf = __( '%s [Current Revision]' );
$date = date_i18n( $datef, strtotime( $revision->post_modified ) );
$edit_link = get_edit_post_link( $revision->ID );
if ( $link && current_user_can( 'edit_post', $revision->ID ) && $edit_link ) {
$date = "$date";
}
if ( ! wp_is_post_revision( $revision ) ) {
$date = sprintf( $currentf, $date );
} elseif ( wp_is_post_autosave( $revision ) ) {
$date = sprintf( $autosavef, $date );
}
return $date;
}
/**
* Retrieves formatted date timestamp of a revision (linked to that revisions's page).
*
* @since 3.6.0
*
* @param int|object $revision Revision ID or revision object.
* @param bool $link Optional. Whether to link to revision's page. Default true.
* @return string|false gravatar, user, i18n formatted datetimestamp or localized 'Current Revision'.
*/
function wp_post_revision_title_expanded( $revision, $link = true ) {
$revision = get_post( $revision );
if ( ! $revision ) {
return $revision;
}
if ( ! in_array( $revision->post_type, array( 'post', 'page', 'revision' ), true ) ) {
return false;
}
$author = get_the_author_meta( 'display_name', $revision->post_author );
/* translators: Revision date format, see https://www.php.net/manual/datetime.format.php */
$datef = _x( 'F j, Y @ H:i:s', 'revision date format' );
$gravatar = get_avatar( $revision->post_author, 24 );
$date = date_i18n( $datef, strtotime( $revision->post_modified ) );
$edit_link = get_edit_post_link( $revision->ID );
if ( $link && current_user_can( 'edit_post', $revision->ID ) && $edit_link ) {
$date = "$date";
}
$revision_date_author = sprintf(
/* translators: Post revision title. 1: Author avatar, 2: Author name, 3: Time ago, 4: Date. */
__( '%1$s %2$s, %3$s ago (%4$s)' ),
$gravatar,
$author,
human_time_diff( strtotime( $revision->post_modified_gmt ) ),
$date
);
/* translators: %s: Revision date with author avatar. */
$autosavef = __( '%s [Autosave]' );
/* translators: %s: Revision date with author avatar. */
$currentf = __( '%s [Current Revision]' );
if ( ! wp_is_post_revision( $revision ) ) {
$revision_date_author = sprintf( $currentf, $revision_date_author );
} elseif ( wp_is_post_autosave( $revision ) ) {
$revision_date_author = sprintf( $autosavef, $revision_date_author );
}
/**
* Filters the formatted author and date for a revision.
*
* @since 4.4.0
*
* @param string $revision_date_author The formatted string.
* @param WP_Post $revision The revision object.
* @param bool $link Whether to link to the revisions page, as passed into
* wp_post_revision_title_expanded().
*/
return apply_filters( 'wp_post_revision_title_expanded', $revision_date_author, $revision, $link );
}
/**
* Displays a list of a post's revisions.
*
* Can output either a UL with edit links or a TABLE with diff interface, and
* restore action links.
*
* @since 2.6.0
*
* @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post.
* @param string $type 'all' (default), 'revision' or 'autosave'
*/
function wp_list_post_revisions( $post_id = 0, $type = 'all' ) {
$post = get_post( $post_id );
if ( ! $post ) {
return;
}
// $args array with (parent, format, right, left, type) deprecated since 3.6.
if ( is_array( $type ) ) {
$type = ! empty( $type['type'] ) ? $type['type'] : $type;
_deprecated_argument( __FUNCTION__, '3.6.0' );
}
$revisions = wp_get_post_revisions( $post->ID );
if ( ! $revisions ) {
return;
}
$rows = '';
foreach ( $revisions as $revision ) {
if ( ! current_user_can( 'read_post', $revision->ID ) ) {
continue;
}
$is_autosave = wp_is_post_autosave( $revision );
if ( ( 'revision' === $type && $is_autosave ) || ( 'autosave' === $type && ! $is_autosave ) ) {
continue;
}
$rows .= "\t" . wp_post_revision_title_expanded( $revision ) . "\n";
}
echo "" . __( 'JavaScript must be enabled to use this feature.' ) . "
\n";
echo "';
}
/**
* Retrieves the parent post object for the given post.
*
* @since 5.7.0
*
* @param int|WP_Post|null $post Optional. Post ID or WP_Post object. Default is global $post.
* @return WP_Post|null Parent post object, or null if there isn't one.
*/
function get_post_parent( $post = null ) {
$wp_post = get_post( $post );
return ! empty( $wp_post->post_parent ) ? get_post( $wp_post->post_parent ) : null;
}
/**
* Returns whether the given post has a parent post.
*
* @since 5.7.0
*
* @param int|WP_Post|null $post Optional. Post ID or WP_Post object. Default is global $post.
* @return bool Whether the post has a parent post.
*/
function has_post_parent( $post = null ) {
return (bool) get_post_parent( $post );
}