#js&&****&……class-wp-recovery-mode-key-service.php000064400000010256150320557470014024 0ustar00HashPassword( $key ); $records = $this->get_keys(); $records[ $token ] = array( 'hashed_key' => $hashed, 'created_at' => time(), ); $this->update_keys( $records ); /** * Fires when a recovery mode key is generated. * * @since 5.2.0 * * @param string $token The recovery data token. * @param string $key The recovery mode key. */ do_action( 'generate_recovery_mode_key', $token, $key ); return $key; } /** * Verifies if the recovery mode key is correct. * * Recovery mode keys can only be used once; the key will be consumed in the process. * * @since 5.2.0 * * @param string $token The token used when generating the given key. * @param string $key The unhashed key. * @param int $ttl Time in seconds for the key to be valid for. * @return true|WP_Error True on success, error object on failure. */ public function validate_recovery_mode_key( $token, $key, $ttl ) { $records = $this->get_keys(); if ( ! isset( $records[ $token ] ) ) { return new WP_Error( 'token_not_found', __( 'Recovery Mode not initialized.' ) ); } $record = $records[ $token ]; $this->remove_key( $token ); if ( ! is_array( $record ) || ! isset( $record['hashed_key'], $record['created_at'] ) ) { return new WP_Error( 'invalid_recovery_key_format', __( 'Invalid recovery key format.' ) ); } if ( ! wp_check_password( $key, $record['hashed_key'] ) ) { return new WP_Error( 'hash_mismatch', __( 'Invalid recovery key.' ) ); } if ( time() > $record['created_at'] + $ttl ) { return new WP_Error( 'key_expired', __( 'Recovery key expired.' ) ); } return true; } /** * Removes expired recovery mode keys. * * @since 5.2.0 * * @param int $ttl Time in seconds for the keys to be valid for. */ public function clean_expired_keys( $ttl ) { $records = $this->get_keys(); foreach ( $records as $key => $record ) { if ( ! isset( $record['created_at'] ) || time() > $record['created_at'] + $ttl ) { unset( $records[ $key ] ); } } $this->update_keys( $records ); } /** * Removes a used recovery key. * * @since 5.2.0 * * @param string $token The token used when generating a recovery mode key. */ private function remove_key( $token ) { $records = $this->get_keys(); if ( ! isset( $records[ $token ] ) ) { return; } unset( $records[ $token ] ); $this->update_keys( $records ); } /** * Gets the recovery key records. * * @since 5.2.0 * * @return array Associative array of $token => $data pairs, where $data has keys 'hashed_key' * and 'created_at'. */ private function get_keys() { return (array) get_option( $this->option_name, array() ); } /** * Updates the recovery key records. * * @since 5.2.0 * * @param array $keys Associative array of $token => $data pairs, where $data has keys 'hashed_key' * and 'created_at'. * @return bool True on success, false on failure. */ private function update_keys( array $keys ) { return update_option( $this->option_name, $keys ); } } class-wp-block.php000064400000013743150320557470010116 0ustar00 testing..." -> "Just testing..." * * @since 5.5.0 * @var string */ public $inner_html = ''; /** * List of string fragments and null markers where inner blocks were found * * @example array( * 'inner_html' => 'BeforeInnerAfter', * 'inner_blocks' => array( block, block ), * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), * ) * * @since 5.5.0 * @var array */ public $inner_content = array(); /** * Constructor. * * Populates object properties from the provided block instance argument. * * The given array of context values will not necessarily be available on * the instance itself, but is treated as the full set of values provided by * the block's ancestry. This is assigned to the private `available_context` * property. Only values which are configured to consumed by the block via * its registered type will be assigned to the block's `context` property. * * @since 5.5.0 * * @param array $block Array of parsed block properties. * @param array $available_context Optional array of ancestry context values. * @param WP_Block_Type_Registry $registry Optional block type registry. */ public function __construct( $block, $available_context = array(), $registry = null ) { $this->parsed_block = $block; $this->name = $block['blockName']; if ( is_null( $registry ) ) { $registry = WP_Block_Type_Registry::get_instance(); } $this->block_type = $registry->get_registered( $this->name ); $this->available_context = $available_context; if ( ! empty( $this->block_type->uses_context ) ) { foreach ( $this->block_type->uses_context as $context_name ) { if ( array_key_exists( $context_name, $this->available_context ) ) { $this->context[ $context_name ] = $this->available_context[ $context_name ]; } } } if ( ! empty( $block['innerBlocks'] ) ) { $child_context = $this->available_context; if ( ! empty( $this->block_type->provides_context ) ) { foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) { if ( array_key_exists( $attribute_name, $this->attributes ) ) { $child_context[ $context_name ] = $this->attributes[ $attribute_name ]; } } } $this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry ); } if ( ! empty( $block['innerHTML'] ) ) { $this->inner_html = $block['innerHTML']; } if ( ! empty( $block['innerContent'] ) ) { $this->inner_content = $block['innerContent']; } } /** * Returns a value from an inaccessible property. * * This is used to lazily initialize the `attributes` property of a block, * such that it is only prepared with default attributes at the time that * the property is accessed. For all other inaccessible properties, a `null` * value is returned. * * @since 5.5.0 * * @param string $name Property name. * @return array|null Prepared attributes, or null. */ public function __get( $name ) { if ( 'attributes' === $name ) { $this->attributes = isset( $this->parsed_block['attrs'] ) ? $this->parsed_block['attrs'] : array(); if ( ! is_null( $this->block_type ) ) { $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes ); } return $this->attributes; } return null; } /** * Generates the render output for the block. * * @since 5.5.0 * * @param array $options { * Optional options object. * * @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback. * } * @return string Rendered block output. */ public function render( $options = array() ) { global $post; $options = wp_parse_args( $options, array( 'dynamic' => true, ) ); $is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); $block_content = ''; if ( ! $options['dynamic'] || empty( $this->block_type->skip_inner_blocks ) ) { $index = 0; foreach ( $this->inner_content as $chunk ) { $block_content .= is_string( $chunk ) ? $chunk : $this->inner_blocks[ $index++ ]->render(); } } if ( $is_dynamic ) { $global_post = $post; $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this ); $post = $global_post; } if ( ! empty( $this->block_type->script ) ) { wp_enqueue_script( $this->block_type->script ); } if ( ! empty( $this->block_type->style ) ) { wp_enqueue_style( $this->block_type->style ); } /** * Filters the content of a single block. * * @since 5.0.0 * * @param string $block_content The block content about to be appended. * @param array $block The full block, including name and attributes. */ return apply_filters( 'render_block', $block_content, $this->parsed_block ); } } class-wp-paused-extensions-storage.php000064400000011473150320557470014142 0ustar00type = $extension_type; } /** * Records an extension error. * * Only one error is stored per extension, with subsequent errors for the same extension overriding the * previously stored error. * * @since 5.2.0 * * @param string $extension Plugin or theme directory name. * @param array $error { * Error that was triggered. * * @type string $type The error type. * @type string $file The name of the file in which the error occurred. * @type string $line The line number in which the error occurred. * @type string $message The error message. * } * @return bool True on success, false on failure. */ public function set( $extension, $error ) { if ( ! $this->is_api_loaded() ) { return false; } $option_name = $this->get_option_name(); if ( ! $option_name ) { return false; } $paused_extensions = (array) get_option( $option_name, array() ); // Do not update if the error is already stored. if ( isset( $paused_extensions[ $this->type ][ $extension ] ) && $paused_extensions[ $this->type ][ $extension ] === $error ) { return true; } $paused_extensions[ $this->type ][ $extension ] = $error; return update_option( $option_name, $paused_extensions ); } /** * Forgets a previously recorded extension error. * * @since 5.2.0 * * @param string $extension Plugin or theme directory name. * @return bool True on success, false on failure. */ public function delete( $extension ) { if ( ! $this->is_api_loaded() ) { return false; } $option_name = $this->get_option_name(); if ( ! $option_name ) { return false; } $paused_extensions = (array) get_option( $option_name, array() ); // Do not delete if no error is stored. if ( ! isset( $paused_extensions[ $this->type ][ $extension ] ) ) { return true; } unset( $paused_extensions[ $this->type ][ $extension ] ); if ( empty( $paused_extensions[ $this->type ] ) ) { unset( $paused_extensions[ $this->type ] ); } // Clean up the entire option if we're removing the only error. if ( ! $paused_extensions ) { return delete_option( $option_name ); } return update_option( $option_name, $paused_extensions ); } /** * Gets the error for an extension, if paused. * * @since 5.2.0 * * @param string $extension Plugin or theme directory name. * @return array|null Error that is stored, or null if the extension is not paused. */ public function get( $extension ) { if ( ! $this->is_api_loaded() ) { return null; } $paused_extensions = $this->get_all(); if ( ! isset( $paused_extensions[ $extension ] ) ) { return null; } return $paused_extensions[ $extension ]; } /** * Gets the paused extensions with their errors. * * @since 5.2.0 * * @return array Associative array of extension slugs to the error recorded. */ public function get_all() { if ( ! $this->is_api_loaded() ) { return array(); } $option_name = $this->get_option_name(); if ( ! $option_name ) { return array(); } $paused_extensions = (array) get_option( $option_name, array() ); return isset( $paused_extensions[ $this->type ] ) ? $paused_extensions[ $this->type ] : array(); } /** * Remove all paused extensions. * * @since 5.2.0 * * @return bool */ public function delete_all() { if ( ! $this->is_api_loaded() ) { return false; } $option_name = $this->get_option_name(); if ( ! $option_name ) { return false; } $paused_extensions = (array) get_option( $option_name, array() ); unset( $paused_extensions[ $this->type ] ); if ( ! $paused_extensions ) { return delete_option( $option_name ); } return update_option( $option_name, $paused_extensions ); } /** * Checks whether the underlying API to store paused extensions is loaded. * * @since 5.2.0 * * @return bool True if the API is loaded, false otherwise. */ protected function is_api_loaded() { return function_exists( 'get_option' ); } /** * Get the option name for storing paused extensions. * * @since 5.2.0 * * @return string */ protected function get_option_name() { if ( ! wp_recovery_mode()->is_active() ) { return ''; } $session_id = wp_recovery_mode()->get_session_id(); if ( empty( $session_id ) ) { return ''; } return "{$session_id}_paused_extensions"; } } feed-rdf.php000064400000005154150320557470006746 0ustar00'; /** This action is documented in wp-includes/feed-rss2.php */ do_action( 'rss_tag_pre', 'rdf' ); ?> > <?php wp_title_rss(); ?> 2000-01-01T12:00+00:00 <?php the_title_rss(); ?> ]]> post_date_gmt, false ); ?> ]]> ]]> ]]> template-loader.php000064400000005704150320557470010352 0ustar00 'get_embed_template', 'is_404' => 'get_404_template', 'is_search' => 'get_search_template', 'is_front_page' => 'get_front_page_template', 'is_home' => 'get_home_template', 'is_privacy_policy' => 'get_privacy_policy_template', 'is_post_type_archive' => 'get_post_type_archive_template', 'is_tax' => 'get_taxonomy_template', 'is_attachment' => 'get_attachment_template', 'is_single' => 'get_single_template', 'is_page' => 'get_page_template', 'is_singular' => 'get_singular_template', 'is_category' => 'get_category_template', 'is_tag' => 'get_tag_template', 'is_author' => 'get_author_template', 'is_date' => 'get_date_template', 'is_archive' => 'get_archive_template', ); $template = false; // Loop through each of the template conditionals, and find the appropriate template file. foreach ( $tag_templates as $tag => $template_getter ) { if ( call_user_func( $tag ) ) { $template = call_user_func( $template_getter ); } if ( $template ) { if ( 'is_attachment' === $tag ) { remove_filter( 'the_content', 'prepend_attachment' ); } break; } } if ( ! $template ) { $template = get_index_template(); } /** * Filters the path of the current template before including it. * * @since 3.0.0 * * @param string $template The path of the template to include. */ $template = apply_filters( 'template_include', $template ); if ( $template ) { include $template; } elseif ( current_user_can( 'switch_themes' ) ) { $theme = wp_get_theme(); if ( $theme->errors() ) { wp_die( $theme->errors() ); } } return; } class-wp-theme.php000064400000144545150320557470010133 0ustar00 'Theme Name', 'ThemeURI' => 'Theme URI', 'Description' => 'Description', 'Author' => 'Author', 'AuthorURI' => 'Author URI', 'Version' => 'Version', 'Template' => 'Template', 'Status' => 'Status', 'Tags' => 'Tags', 'TextDomain' => 'Text Domain', 'DomainPath' => 'Domain Path', 'RequiresWP' => 'Requires at least', 'RequiresPHP' => 'Requires PHP', ); /** * Default themes. * * @var array */ private static $default_themes = array( 'classic' => 'WordPress Classic', 'default' => 'WordPress Default', 'twentyten' => 'Twenty Ten', 'twentyeleven' => 'Twenty Eleven', 'twentytwelve' => 'Twenty Twelve', 'twentythirteen' => 'Twenty Thirteen', 'twentyfourteen' => 'Twenty Fourteen', 'twentyfifteen' => 'Twenty Fifteen', 'twentysixteen' => 'Twenty Sixteen', 'twentyseventeen' => 'Twenty Seventeen', 'twentynineteen' => 'Twenty Nineteen', 'twentytwenty' => 'Twenty Twenty', ); /** * Renamed theme tags. * * @var array */ private static $tag_map = array( 'fixed-width' => 'fixed-layout', 'flexible-width' => 'fluid-layout', ); /** * Absolute path to the theme root, usually wp-content/themes * * @var string */ private $theme_root; /** * Header data from the theme's style.css file. * * @var array */ private $headers = array(); /** * Header data from the theme's style.css file after being sanitized. * * @var array */ private $headers_sanitized; /** * Header name from the theme's style.css after being translated. * * Cached due to sorting functions running over the translated name. * * @var string */ private $name_translated; /** * Errors encountered when initializing the theme. * * @var WP_Error */ private $errors; /** * The directory name of the theme's files, inside the theme root. * * In the case of a child theme, this is directory name of the child theme. * Otherwise, 'stylesheet' is the same as 'template'. * * @var string */ private $stylesheet; /** * The directory name of the theme's files, inside the theme root. * * In the case of a child theme, this is the directory name of the parent theme. * Otherwise, 'template' is the same as 'stylesheet'. * * @var string */ private $template; /** * A reference to the parent theme, in the case of a child theme. * * @var WP_Theme */ private $parent; /** * URL to the theme root, usually an absolute URL to wp-content/themes * * @var string */ private $theme_root_uri; /** * Flag for whether the theme's textdomain is loaded. * * @var bool */ private $textdomain_loaded; /** * Stores an md5 hash of the theme root, to function as the cache key. * * @var string */ private $cache_hash; /** * Flag for whether the themes cache bucket should be persistently cached. * * Default is false. Can be set with the {@see 'wp_cache_themes_persistently'} filter. * * @var bool */ private static $persistently_cache; /** * Expiration time for the themes cache bucket. * * By default the bucket is not cached, so this value is useless. * * @var bool */ private static $cache_expiration = 1800; /** * Constructor for WP_Theme. * * @since 3.4.0 * * @global array $wp_theme_directories * * @param string $theme_dir Directory of the theme within the theme_root. * @param string $theme_root Theme root. * @param WP_Theme|null $_child If this theme is a parent theme, the child may be passed for validation purposes. */ public function __construct( $theme_dir, $theme_root, $_child = null ) { global $wp_theme_directories; // Initialize caching on first run. if ( ! isset( self::$persistently_cache ) ) { /** This action is documented in wp-includes/theme.php */ self::$persistently_cache = apply_filters( 'wp_cache_themes_persistently', false, 'WP_Theme' ); if ( self::$persistently_cache ) { wp_cache_add_global_groups( 'themes' ); if ( is_int( self::$persistently_cache ) ) { self::$cache_expiration = self::$persistently_cache; } } else { wp_cache_add_non_persistent_groups( 'themes' ); } } $this->theme_root = $theme_root; $this->stylesheet = $theme_dir; // Correct a situation where the theme is 'some-directory/some-theme' but 'some-directory' was passed in as part of the theme root instead. if ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) && in_array( dirname( $theme_root ), (array) $wp_theme_directories, true ) ) { $this->stylesheet = basename( $this->theme_root ) . '/' . $this->stylesheet; $this->theme_root = dirname( $theme_root ); } $this->cache_hash = md5( $this->theme_root . '/' . $this->stylesheet ); $theme_file = $this->stylesheet . '/style.css'; $cache = $this->cache_get( 'theme' ); if ( is_array( $cache ) ) { foreach ( array( 'errors', 'headers', 'template' ) as $key ) { if ( isset( $cache[ $key ] ) ) { $this->$key = $cache[ $key ]; } } if ( $this->errors ) { return; } if ( isset( $cache['theme_root_template'] ) ) { $theme_root_template = $cache['theme_root_template']; } } elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) { $this->headers['Name'] = $this->stylesheet; if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) ) { $this->errors = new WP_Error( 'theme_not_found', sprintf( /* translators: %s: Theme directory name. */ __( 'The theme directory "%s" does not exist.' ), esc_html( $this->stylesheet ) ) ); } else { $this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) ); } $this->template = $this->stylesheet; $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template, ) ); if ( ! file_exists( $this->theme_root ) ) { // Don't cache this one. $this->errors->add( 'theme_root_missing', __( 'Error: The themes directory is either empty or doesn’t exist. Please check your installation.' ) ); } return; } elseif ( ! is_readable( $this->theme_root . '/' . $theme_file ) ) { $this->headers['Name'] = $this->stylesheet; $this->errors = new WP_Error( 'theme_stylesheet_not_readable', __( 'Stylesheet is not readable.' ) ); $this->template = $this->stylesheet; $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template, ) ); return; } else { $this->headers = get_file_data( $this->theme_root . '/' . $theme_file, self::$file_headers, 'theme' ); // Default themes always trump their pretenders. // Properly identify default themes that are inside a directory within wp-content/themes. $default_theme_slug = array_search( $this->headers['Name'], self::$default_themes, true ); if ( $default_theme_slug ) { if ( basename( $this->stylesheet ) != $default_theme_slug ) { $this->headers['Name'] .= '/' . $this->stylesheet; } } } if ( ! $this->template && $this->stylesheet === $this->headers['Template'] ) { $this->errors = new WP_Error( 'theme_child_invalid', sprintf( /* translators: %s: Template. */ __( 'The theme defines itself as its parent theme. Please check the %s header.' ), 'Template' ) ); $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, ) ); return; } // (If template is set from cache [and there are no errors], we know it's good.) if ( ! $this->template ) { $this->template = $this->headers['Template']; } if ( ! $this->template ) { $this->template = $this->stylesheet; if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet . '/index.php' ) ) { $error_message = sprintf( /* translators: 1: index.php, 2: Documentation URL, 3: style.css */ __( 'Template is missing. Standalone themes need to have a %1$s template file. Child themes need to have a Template header in the %3$s stylesheet.' ), 'index.php', __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ), 'style.css' ); $this->errors = new WP_Error( 'theme_no_index', $error_message ); $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template, ) ); return; } } // If we got our data from cache, we can assume that 'template' is pointing to the right place. if ( ! is_array( $cache ) && $this->template != $this->stylesheet && ! file_exists( $this->theme_root . '/' . $this->template . '/index.php' ) ) { // If we're in a directory of themes inside /themes, look for the parent nearby. // wp-content/themes/directory-of-themes/* $parent_dir = dirname( $this->stylesheet ); $directories = search_theme_directories(); if ( '.' !== $parent_dir && file_exists( $this->theme_root . '/' . $parent_dir . '/' . $this->template . '/index.php' ) ) { $this->template = $parent_dir . '/' . $this->template; } elseif ( $directories && isset( $directories[ $this->template ] ) ) { // Look for the template in the search_theme_directories() results, in case it is in another theme root. // We don't look into directories of themes, just the theme root. $theme_root_template = $directories[ $this->template ]['theme_root']; } else { // Parent theme is missing. $this->errors = new WP_Error( 'theme_no_parent', sprintf( /* translators: %s: Theme directory name. */ __( 'The parent theme is missing. Please install the "%s" parent theme.' ), esc_html( $this->template ) ) ); $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template, ) ); $this->parent = new WP_Theme( $this->template, $this->theme_root, $this ); return; } } // Set the parent, if we're a child theme. if ( $this->template != $this->stylesheet ) { // If we are a parent, then there is a problem. Only two generations allowed! Cancel things out. if ( $_child instanceof WP_Theme && $_child->template == $this->stylesheet ) { $_child->parent = null; $_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( /* translators: %s: Theme directory name. */ __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $_child->template ) ) ); $_child->cache_add( 'theme', array( 'headers' => $_child->headers, 'errors' => $_child->errors, 'stylesheet' => $_child->stylesheet, 'template' => $_child->template, ) ); // The two themes actually reference each other with the Template header. if ( $_child->stylesheet == $this->template ) { $this->errors = new WP_Error( 'theme_parent_invalid', sprintf( /* translators: %s: Theme directory name. */ __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $this->template ) ) ); $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template, ) ); } return; } // Set the parent. Pass the current instance so we can do the crazy checks above and assess errors. $this->parent = new WP_Theme( $this->template, isset( $theme_root_template ) ? $theme_root_template : $this->theme_root, $this ); } if ( wp_paused_themes()->get( $this->stylesheet ) && ( ! is_wp_error( $this->errors ) || ! isset( $this->errors->errors['theme_paused'] ) ) ) { $this->errors = new WP_Error( 'theme_paused', __( 'This theme failed to load properly and was paused within the admin backend.' ) ); } // We're good. If we didn't retrieve from cache, set it. if ( ! is_array( $cache ) ) { $cache = array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template, ); // If the parent theme is in another root, we'll want to cache this. Avoids an entire branch of filesystem calls above. if ( isset( $theme_root_template ) ) { $cache['theme_root_template'] = $theme_root_template; } $this->cache_add( 'theme', $cache ); } } /** * When converting the object to a string, the theme name is returned. * * @since 3.4.0 * * @return string Theme name, ready for display (translated) */ public function __toString() { return (string) $this->display( 'Name' ); } /** * __isset() magic method for properties formerly returned by current_theme_info() * * @since 3.4.0 * * @param string $offset Property to check if set. * @return bool Whether the given property is set. */ public function __isset( $offset ) { static $properties = array( 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', ); return in_array( $offset, $properties, true ); } /** * __get() magic method for properties formerly returned by current_theme_info() * * @since 3.4.0 * * @param string $offset Property to get. * @return mixed Property value. */ public function __get( $offset ) { switch ( $offset ) { case 'name': case 'title': return $this->get( 'Name' ); case 'version': return $this->get( 'Version' ); case 'parent_theme': return $this->parent() ? $this->parent()->get( 'Name' ) : ''; case 'template_dir': return $this->get_template_directory(); case 'stylesheet_dir': return $this->get_stylesheet_directory(); case 'template': return $this->get_template(); case 'stylesheet': return $this->get_stylesheet(); case 'screenshot': return $this->get_screenshot( 'relative' ); // 'author' and 'description' did not previously return translated data. case 'description': return $this->display( 'Description' ); case 'author': return $this->display( 'Author' ); case 'tags': return $this->get( 'Tags' ); case 'theme_root': return $this->get_theme_root(); case 'theme_root_uri': return $this->get_theme_root_uri(); // For cases where the array was converted to an object. default: return $this->offsetGet( $offset ); } } /** * Method to implement ArrayAccess for keys formerly returned by get_themes() * * @since 3.4.0 * * @param mixed $offset * @param mixed $value */ public function offsetSet( $offset, $value ) {} /** * Method to implement ArrayAccess for keys formerly returned by get_themes() * * @since 3.4.0 * * @param mixed $offset */ public function offsetUnset( $offset ) {} /** * Method to implement ArrayAccess for keys formerly returned by get_themes() * * @since 3.4.0 * * @param mixed $offset * @return bool */ public function offsetExists( $offset ) { static $keys = array( 'Name', 'Version', 'Status', 'Title', 'Author', 'Author Name', 'Author URI', 'Description', 'Template', 'Stylesheet', 'Template Files', 'Stylesheet Files', 'Template Dir', 'Stylesheet Dir', 'Screenshot', 'Tags', 'Theme Root', 'Theme Root URI', 'Parent Theme', ); return in_array( $offset, $keys, true ); } /** * Method to implement ArrayAccess for keys formerly returned by get_themes(). * * Author, Author Name, Author URI, and Description did not previously return * translated data. We are doing so now as it is safe to do. However, as * Name and Title could have been used as the key for get_themes(), both remain * untranslated for back compatibility. This means that ['Name'] is not ideal, * and care should be taken to use `$theme::display( 'Name' )` to get a properly * translated header. * * @since 3.4.0 * * @param mixed $offset * @return mixed */ public function offsetGet( $offset ) { switch ( $offset ) { case 'Name': case 'Title': /* * See note above about using translated data. get() is not ideal. * It is only for backward compatibility. Use display(). */ return $this->get( 'Name' ); case 'Author': return $this->display( 'Author' ); case 'Author Name': return $this->display( 'Author', false ); case 'Author URI': return $this->display( 'AuthorURI' ); case 'Description': return $this->display( 'Description' ); case 'Version': case 'Status': return $this->get( $offset ); case 'Template': return $this->get_template(); case 'Stylesheet': return $this->get_stylesheet(); case 'Template Files': return $this->get_files( 'php', 1, true ); case 'Stylesheet Files': return $this->get_files( 'css', 0, false ); case 'Template Dir': return $this->get_template_directory(); case 'Stylesheet Dir': return $this->get_stylesheet_directory(); case 'Screenshot': return $this->get_screenshot( 'relative' ); case 'Tags': return $this->get( 'Tags' ); case 'Theme Root': return $this->get_theme_root(); case 'Theme Root URI': return $this->get_theme_root_uri(); case 'Parent Theme': return $this->parent() ? $this->parent()->get( 'Name' ) : ''; default: return null; } } /** * Returns errors property. * * @since 3.4.0 * * @return WP_Error|false WP_Error if there are errors, or false. */ public function errors() { return is_wp_error( $this->errors ) ? $this->errors : false; } /** * Whether the theme exists. * * A theme with errors exists. A theme with the error of 'theme_not_found', * meaning that the theme's directory was not found, does not exist. * * @since 3.4.0 * * @return bool Whether the theme exists. */ public function exists() { return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes(), true ) ); } /** * Returns reference to the parent theme. * * @since 3.4.0 * * @return WP_Theme|false Parent theme, or false if the current theme is not a child theme. */ public function parent() { return isset( $this->parent ) ? $this->parent : false; } /** * Perform reinitialization tasks. * * Prevents a callback from being injected during unserialization of an object. * * @return void */ public function __wakeup() { if ( $this->parent && ! $this->parent instanceof self ) { throw new UnexpectedValueException(); } if ( $this->headers && ! is_array( $this->headers ) ) { throw new UnexpectedValueException(); } foreach ( $this->headers as $value ) { if ( ! is_string( $value ) ) { throw new UnexpectedValueException(); } } $this->headers_sanitized = array(); } /** * Adds theme data to cache. * * Cache entries keyed by the theme and the type of data. * * @since 3.4.0 * * @param string $key Type of data to store (theme, screenshot, headers, post_templates) * @param array|string $data Data to store * @return bool Return value from wp_cache_add() */ private function cache_add( $key, $data ) { return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration ); } /** * Gets theme data from cache. * * Cache entries are keyed by the theme and the type of data. * * @since 3.4.0 * * @param string $key Type of data to retrieve (theme, screenshot, headers, post_templates) * @return mixed Retrieved data */ private function cache_get( $key ) { return wp_cache_get( $key . '-' . $this->cache_hash, 'themes' ); } /** * Clears the cache for the theme. * * @since 3.4.0 */ public function cache_delete() { foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key ) { wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' ); } $this->template = null; $this->textdomain_loaded = null; $this->theme_root_uri = null; $this->parent = null; $this->errors = null; $this->headers_sanitized = null; $this->name_translated = null; $this->headers = array(); $this->__construct( $this->stylesheet, $this->theme_root ); } /** * Get a raw, unformatted theme header. * * The header is sanitized, but is not translated, and is not marked up for display. * To get a theme header for display, use the display() method. * * Use the get_template() method, not the 'Template' header, for finding the template. * The 'Template' header is only good for what was written in the style.css, while * get_template() takes into account where WordPress actually located the theme and * whether it is actually valid. * * @since 3.4.0 * * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. * @return string|array|false String or array (for Tags header) on success, false on failure. */ public function get( $header ) { if ( ! isset( $this->headers[ $header ] ) ) { return false; } if ( ! isset( $this->headers_sanitized ) ) { $this->headers_sanitized = $this->cache_get( 'headers' ); if ( ! is_array( $this->headers_sanitized ) ) { $this->headers_sanitized = array(); } } if ( isset( $this->headers_sanitized[ $header ] ) ) { return $this->headers_sanitized[ $header ]; } // If themes are a persistent group, sanitize everything and cache it. One cache add is better than many cache sets. if ( self::$persistently_cache ) { foreach ( array_keys( $this->headers ) as $_header ) { $this->headers_sanitized[ $_header ] = $this->sanitize_header( $_header, $this->headers[ $_header ] ); } $this->cache_add( 'headers', $this->headers_sanitized ); } else { $this->headers_sanitized[ $header ] = $this->sanitize_header( $header, $this->headers[ $header ] ); } return $this->headers_sanitized[ $header ]; } /** * Gets a theme header, formatted and translated for display. * * @since 3.4.0 * * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. * @param bool $markup Optional. Whether to mark up the header. Defaults to true. * @param bool $translate Optional. Whether to translate the header. Defaults to true. * @return string|array|false Processed header. An array for Tags if `$markup` is false, string otherwise. * False on failure. */ public function display( $header, $markup = true, $translate = true ) { $value = $this->get( $header ); if ( false === $value ) { return false; } if ( $translate && ( empty( $value ) || ! $this->load_textdomain() ) ) { $translate = false; } if ( $translate ) { $value = $this->translate_header( $header, $value ); } if ( $markup ) { $value = $this->markup_header( $header, $value, $translate ); } return $value; } /** * Sanitize a theme header. * * @since 3.4.0 * @since 5.4.0 Added support for `Requires at least` and `Requires PHP` headers. * * @param string $header Theme header. Accepts 'Name', 'Description', 'Author', 'Version', * 'ThemeURI', 'AuthorURI', 'Status', 'Tags', 'RequiresWP', 'RequiresPHP'. * @param string $value Value to sanitize. * @return string|array An array for Tags header, string otherwise. */ private function sanitize_header( $header, $value ) { switch ( $header ) { case 'Status': if ( ! $value ) { $value = 'publish'; break; } // Fall through otherwise. case 'Name': static $header_tags = array( 'abbr' => array( 'title' => true ), 'acronym' => array( 'title' => true ), 'code' => true, 'em' => true, 'strong' => true, ); $value = wp_kses( $value, $header_tags ); break; case 'Author': // There shouldn't be anchor tags in Author, but some themes like to be challenging. case 'Description': static $header_tags_with_a = array( 'a' => array( 'href' => true, 'title' => true, ), 'abbr' => array( 'title' => true ), 'acronym' => array( 'title' => true ), 'code' => true, 'em' => true, 'strong' => true, ); $value = wp_kses( $value, $header_tags_with_a ); break; case 'ThemeURI': case 'AuthorURI': $value = esc_url_raw( $value ); break; case 'Tags': $value = array_filter( array_map( 'trim', explode( ',', strip_tags( $value ) ) ) ); break; case 'Version': case 'RequiresWP': case 'RequiresPHP': $value = strip_tags( $value ); break; } return $value; } /** * Mark up a theme header. * * @since 3.4.0 * * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. * @param string|array $value Value to mark up. An array for Tags header, string otherwise. * @param string $translate Whether the header has been translated. * @return string Value, marked up. */ private function markup_header( $header, $value, $translate ) { switch ( $header ) { case 'Name': if ( empty( $value ) ) { $value = esc_html( $this->get_stylesheet() ); } break; case 'Description': $value = wptexturize( $value ); break; case 'Author': if ( $this->get( 'AuthorURI' ) ) { $value = sprintf( '%2$s', $this->display( 'AuthorURI', true, $translate ), $value ); } elseif ( ! $value ) { $value = __( 'Anonymous' ); } break; case 'Tags': static $comma = null; if ( ! isset( $comma ) ) { /* translators: Used between list items, there is a space after the comma. */ $comma = __( ', ' ); } $value = implode( $comma, $value ); break; case 'ThemeURI': case 'AuthorURI': $value = esc_url( $value ); break; } return $value; } /** * Translate a theme header. * * @since 3.4.0 * * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. * @param string|array $value Value to translate. An array for Tags header, string otherwise. * @return string|array Translated value. An array for Tags header, string otherwise. */ private function translate_header( $header, $value ) { switch ( $header ) { case 'Name': // Cached for sorting reasons. if ( isset( $this->name_translated ) ) { return $this->name_translated; } // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain $this->name_translated = translate( $value, $this->get( 'TextDomain' ) ); return $this->name_translated; case 'Tags': if ( empty( $value ) || ! function_exists( 'get_theme_feature_list' ) ) { return $value; } static $tags_list; if ( ! isset( $tags_list ) ) { $tags_list = array( // As of 4.6, deprecated tags which are only used to provide translation for older themes. 'black' => __( 'Black' ), 'blue' => __( 'Blue' ), 'brown' => __( 'Brown' ), 'gray' => __( 'Gray' ), 'green' => __( 'Green' ), 'orange' => __( 'Orange' ), 'pink' => __( 'Pink' ), 'purple' => __( 'Purple' ), 'red' => __( 'Red' ), 'silver' => __( 'Silver' ), 'tan' => __( 'Tan' ), 'white' => __( 'White' ), 'yellow' => __( 'Yellow' ), 'dark' => __( 'Dark' ), 'light' => __( 'Light' ), 'fixed-layout' => __( 'Fixed Layout' ), 'fluid-layout' => __( 'Fluid Layout' ), 'responsive-layout' => __( 'Responsive Layout' ), 'blavatar' => __( 'Blavatar' ), 'photoblogging' => __( 'Photoblogging' ), 'seasonal' => __( 'Seasonal' ), ); $feature_list = get_theme_feature_list( false ); // No API. foreach ( $feature_list as $tags ) { $tags_list += $tags; } } foreach ( $value as &$tag ) { if ( isset( $tags_list[ $tag ] ) ) { $tag = $tags_list[ $tag ]; } elseif ( isset( self::$tag_map[ $tag ] ) ) { $tag = $tags_list[ self::$tag_map[ $tag ] ]; } } return $value; default: // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain $value = translate( $value, $this->get( 'TextDomain' ) ); } return $value; } /** * The directory name of the theme's "stylesheet" files, inside the theme root. * * In the case of a child theme, this is directory name of the child theme. * Otherwise, get_stylesheet() is the same as get_template(). * * @since 3.4.0 * * @return string Stylesheet */ public function get_stylesheet() { return $this->stylesheet; } /** * The directory name of the theme's "template" files, inside the theme root. * * In the case of a child theme, this is the directory name of the parent theme. * Otherwise, the get_template() is the same as get_stylesheet(). * * @since 3.4.0 * * @return string Template */ public function get_template() { return $this->template; } /** * Returns the absolute path to the directory of a theme's "stylesheet" files. * * In the case of a child theme, this is the absolute path to the directory * of the child theme's files. * * @since 3.4.0 * * @return string Absolute path of the stylesheet directory. */ public function get_stylesheet_directory() { if ( $this->errors() && in_array( 'theme_root_missing', $this->errors()->get_error_codes(), true ) ) { return ''; } return $this->theme_root . '/' . $this->stylesheet; } /** * Returns the absolute path to the directory of a theme's "template" files. * * In the case of a child theme, this is the absolute path to the directory * of the parent theme's files. * * @since 3.4.0 * * @return string Absolute path of the template directory. */ public function get_template_directory() { if ( $this->parent() ) { $theme_root = $this->parent()->theme_root; } else { $theme_root = $this->theme_root; } return $theme_root . '/' . $this->template; } /** * Returns the URL to the directory of a theme's "stylesheet" files. * * In the case of a child theme, this is the URL to the directory of the * child theme's files. * * @since 3.4.0 * * @return string URL to the stylesheet directory. */ public function get_stylesheet_directory_uri() { return $this->get_theme_root_uri() . '/' . str_replace( '%2F', '/', rawurlencode( $this->stylesheet ) ); } /** * Returns the URL to the directory of a theme's "template" files. * * In the case of a child theme, this is the URL to the directory of the * parent theme's files. * * @since 3.4.0 * * @return string URL to the template directory. */ public function get_template_directory_uri() { if ( $this->parent() ) { $theme_root_uri = $this->parent()->get_theme_root_uri(); } else { $theme_root_uri = $this->get_theme_root_uri(); } return $theme_root_uri . '/' . str_replace( '%2F', '/', rawurlencode( $this->template ) ); } /** * The absolute path to the directory of the theme root. * * This is typically the absolute path to wp-content/themes. * * @since 3.4.0 * * @return string Theme root. */ public function get_theme_root() { return $this->theme_root; } /** * Returns the URL to the directory of the theme root. * * This is typically the absolute URL to wp-content/themes. This forms the basis * for all other URLs returned by WP_Theme, so we pass it to the public function * get_theme_root_uri() and allow it to run the {@see 'theme_root_uri'} filter. * * @since 3.4.0 * * @return string Theme root URI. */ public function get_theme_root_uri() { if ( ! isset( $this->theme_root_uri ) ) { $this->theme_root_uri = get_theme_root_uri( $this->stylesheet, $this->theme_root ); } return $this->theme_root_uri; } /** * Returns the main screenshot file for the theme. * * The main screenshot is called screenshot.png. gif and jpg extensions are also allowed. * * Screenshots for a theme must be in the stylesheet directory. (In the case of child * themes, parent theme screenshots are not inherited.) * * @since 3.4.0 * * @param string $uri Type of URL to return, either 'relative' or an absolute URI. Defaults to absolute URI. * @return string|false Screenshot file. False if the theme does not have a screenshot. */ public function get_screenshot( $uri = 'uri' ) { $screenshot = $this->cache_get( 'screenshot' ); if ( $screenshot ) { if ( 'relative' === $uri ) { return $screenshot; } return $this->get_stylesheet_directory_uri() . '/' . $screenshot; } elseif ( 0 === $screenshot ) { return false; } foreach ( array( 'png', 'gif', 'jpg', 'jpeg' ) as $ext ) { if ( file_exists( $this->get_stylesheet_directory() . "/screenshot.$ext" ) ) { $this->cache_add( 'screenshot', 'screenshot.' . $ext ); if ( 'relative' === $uri ) { return 'screenshot.' . $ext; } return $this->get_stylesheet_directory_uri() . '/' . 'screenshot.' . $ext; } } $this->cache_add( 'screenshot', 0 ); return false; } /** * Return files in the theme's directory. * * @since 3.4.0 * * @param string[]|string $type Optional. Array of extensions to find, string of a single extension, * or null for all extensions. Default null. * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). * -1 depth is infinite. * @param bool $search_parent Optional. Whether to return parent files. Default false. * @return string[] Array of files, keyed by the path to the file relative to the theme's directory, with the values * being absolute paths. */ public function get_files( $type = null, $depth = 0, $search_parent = false ) { $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth ); if ( $search_parent && $this->parent() ) { $files += (array) self::scandir( $this->get_template_directory(), $type, $depth ); } return $files; } /** * Returns the theme's post templates. * * @since 4.7.0 * * @return string[] Array of page templates, keyed by filename and post type, * with the value of the translated header name. */ public function get_post_templates() { // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide. if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) { return array(); } $post_templates = $this->cache_get( 'post_templates' ); if ( ! is_array( $post_templates ) ) { $post_templates = array(); $files = (array) $this->get_files( 'php', 1, true ); foreach ( $files as $file => $full_path ) { if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) { continue; } $types = array( 'page' ); if ( preg_match( '|Template Post Type:(.*)$|mi', file_get_contents( $full_path ), $type ) ) { $types = explode( ',', _cleanup_header_comment( $type[1] ) ); } foreach ( $types as $type ) { $type = sanitize_key( $type ); if ( ! isset( $post_templates[ $type ] ) ) { $post_templates[ $type ] = array(); } $post_templates[ $type ][ $file ] = _cleanup_header_comment( $header[1] ); } } $this->cache_add( 'post_templates', $post_templates ); } if ( $this->load_textdomain() ) { foreach ( $post_templates as &$post_type ) { foreach ( $post_type as &$post_template ) { $post_template = $this->translate_header( 'Template Name', $post_template ); } } } return $post_templates; } /** * Returns the theme's post templates for a given post type. * * @since 3.4.0 * @since 4.7.0 Added the `$post_type` parameter. * * @param WP_Post|null $post Optional. The post being edited, provided for context. * @param string $post_type Optional. Post type to get the templates for. Default 'page'. * If a post is provided, its post type is used. * @return string[] Array of template header names keyed by the template file name. */ public function get_page_templates( $post = null, $post_type = 'page' ) { if ( $post ) { $post_type = get_post_type( $post ); } $post_templates = $this->get_post_templates(); $post_templates = isset( $post_templates[ $post_type ] ) ? $post_templates[ $post_type ] : array(); /** * Filters list of page templates for a theme. * * @since 4.9.6 * * @param string[] $post_templates Array of template header names keyed by the template file name. * @param WP_Theme $this The theme object. * @param WP_Post|null $post The post being edited, provided for context, or null. * @param string $post_type Post type to get the templates for. */ $post_templates = (array) apply_filters( 'theme_templates', $post_templates, $this, $post, $post_type ); /** * Filters list of page templates for a theme. * * The dynamic portion of the hook name, `$post_type`, refers to the post type. * * @since 3.9.0 * @since 4.4.0 Converted to allow complete control over the `$page_templates` array. * @since 4.7.0 Added the `$post_type` parameter. * * @param string[] $post_templates Array of template header names keyed by the template file name. * @param WP_Theme $this The theme object. * @param WP_Post|null $post The post being edited, provided for context, or null. * @param string $post_type Post type to get the templates for. */ $post_templates = (array) apply_filters( "theme_{$post_type}_templates", $post_templates, $this, $post, $post_type ); return $post_templates; } /** * Scans a directory for files of a certain extension. * * @since 3.4.0 * * @param string $path Absolute path to search. * @param array|string|null $extensions Optional. Array of extensions to find, string of a single extension, * or null for all extensions. Default null. * @param int $depth Optional. How many levels deep to search for files. Accepts 0, 1+, or * -1 (infinite depth). Default 0. * @param string $relative_path Optional. The basename of the absolute path. Used to control the * returned path for the found files, particularly when this function * recurses to lower depths. Default empty. * @return string[]|false Array of files, keyed by the path to the file relative to the `$path` directory prepended * with `$relative_path`, with the values being absolute paths. False otherwise. */ private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) { if ( ! is_dir( $path ) ) { return false; } if ( $extensions ) { $extensions = (array) $extensions; $_extensions = implode( '|', $extensions ); } $relative_path = trailingslashit( $relative_path ); if ( '/' === $relative_path ) { $relative_path = ''; } $results = scandir( $path ); $files = array(); /** * Filters the array of excluded directories and files while scanning theme folder. * * @since 4.7.4 * * @param string[] $exclusions Array of excluded directories and files. */ $exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) ); foreach ( $results as $result ) { if ( '.' === $result[0] || in_array( $result, $exclusions, true ) ) { continue; } if ( is_dir( $path . '/' . $result ) ) { if ( ! $depth ) { continue; } $found = self::scandir( $path . '/' . $result, $extensions, $depth - 1, $relative_path . $result ); $files = array_merge_recursive( $files, $found ); } elseif ( ! $extensions || preg_match( '~\.(' . $_extensions . ')$~', $result ) ) { $files[ $relative_path . $result ] = $path . '/' . $result; } } return $files; } /** * Loads the theme's textdomain. * * Translation files are not inherited from the parent theme. TODO: If this fails for the * child theme, it should probably try to load the parent theme's translations. * * @since 3.4.0 * * @return bool True if the textdomain was successfully loaded or has already been loaded. * False if no textdomain was specified in the file headers, or if the domain could not be loaded. */ public function load_textdomain() { if ( isset( $this->textdomain_loaded ) ) { return $this->textdomain_loaded; } $textdomain = $this->get( 'TextDomain' ); if ( ! $textdomain ) { $this->textdomain_loaded = false; return false; } if ( is_textdomain_loaded( $textdomain ) ) { $this->textdomain_loaded = true; return true; } $path = $this->get_stylesheet_directory(); $domainpath = $this->get( 'DomainPath' ); if ( $domainpath ) { $path .= $domainpath; } else { $path .= '/languages'; } $this->textdomain_loaded = load_theme_textdomain( $textdomain, $path ); return $this->textdomain_loaded; } /** * Whether the theme is allowed (multisite only). * * @since 3.4.0 * * @param string $check Optional. Whether to check only the 'network'-wide settings, the 'site' * settings, or 'both'. Defaults to 'both'. * @param int $blog_id Optional. Ignored if only network-wide settings are checked. Defaults to current site. * @return bool Whether the theme is allowed for the network. Returns true in single-site. */ public function is_allowed( $check = 'both', $blog_id = null ) { if ( ! is_multisite() ) { return true; } if ( 'both' === $check || 'network' === $check ) { $allowed = self::get_allowed_on_network(); if ( ! empty( $allowed[ $this->get_stylesheet() ] ) ) { return true; } } if ( 'both' === $check || 'site' === $check ) { $allowed = self::get_allowed_on_site( $blog_id ); if ( ! empty( $allowed[ $this->get_stylesheet() ] ) ) { return true; } } return false; } /** * Determines the latest WordPress default theme that is installed. * * This hits the filesystem. * * @since 4.4.0 * * @return WP_Theme|false Object, or false if no theme is installed, which would be bad. */ public static function get_core_default_theme() { foreach ( array_reverse( self::$default_themes ) as $slug => $name ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { return $theme; } } return false; } /** * Returns array of stylesheet names of themes allowed on the site or network. * * @since 3.4.0 * * @param int $blog_id Optional. ID of the site. Defaults to the current site. * @return string[] Array of stylesheet names. */ public static function get_allowed( $blog_id = null ) { /** * Filters the array of themes allowed on the network. * * Site is provided as context so that a list of network allowed themes can * be filtered further. * * @since 4.5.0 * * @param string[] $allowed_themes An array of theme stylesheet names. * @param int $blog_id ID of the site. */ $network = (array) apply_filters( 'network_allowed_themes', self::get_allowed_on_network(), $blog_id ); return $network + self::get_allowed_on_site( $blog_id ); } /** * Returns array of stylesheet names of themes allowed on the network. * * @since 3.4.0 * * @return string[] Array of stylesheet names. */ public static function get_allowed_on_network() { static $allowed_themes; if ( ! isset( $allowed_themes ) ) { $allowed_themes = (array) get_site_option( 'allowedthemes' ); } /** * Filters the array of themes allowed on the network. * * @since MU (3.0.0) * * @param string[] $allowed_themes An array of theme stylesheet names. */ $allowed_themes = apply_filters( 'allowed_themes', $allowed_themes ); return $allowed_themes; } /** * Returns array of stylesheet names of themes allowed on the site. * * @since 3.4.0 * * @param int $blog_id Optional. ID of the site. Defaults to the current site. * @return string[] Array of stylesheet names. */ public static function get_allowed_on_site( $blog_id = null ) { static $allowed_themes = array(); if ( ! $blog_id || ! is_multisite() ) { $blog_id = get_current_blog_id(); } if ( isset( $allowed_themes[ $blog_id ] ) ) { /** * Filters the array of themes allowed on the site. * * @since 4.5.0 * * @param string[] $allowed_themes An array of theme stylesheet names. * @param int $blog_id ID of the site. Defaults to current site. */ return (array) apply_filters( 'site_allowed_themes', $allowed_themes[ $blog_id ], $blog_id ); } $current = get_current_blog_id() == $blog_id; if ( $current ) { $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' ); } else { switch_to_blog( $blog_id ); $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' ); restore_current_blog(); } // This is all super old MU back compat joy. // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name. if ( false === $allowed_themes[ $blog_id ] ) { if ( $current ) { $allowed_themes[ $blog_id ] = get_option( 'allowed_themes' ); } else { switch_to_blog( $blog_id ); $allowed_themes[ $blog_id ] = get_option( 'allowed_themes' ); restore_current_blog(); } if ( ! is_array( $allowed_themes[ $blog_id ] ) || empty( $allowed_themes[ $blog_id ] ) ) { $allowed_themes[ $blog_id ] = array(); } else { $converted = array(); $themes = wp_get_themes(); foreach ( $themes as $stylesheet => $theme_data ) { if ( isset( $allowed_themes[ $blog_id ][ $theme_data->get( 'Name' ) ] ) ) { $converted[ $stylesheet ] = true; } } $allowed_themes[ $blog_id ] = $converted; } // Set the option so we never have to go through this pain again. if ( is_admin() && $allowed_themes[ $blog_id ] ) { if ( $current ) { update_option( 'allowedthemes', $allowed_themes[ $blog_id ] ); delete_option( 'allowed_themes' ); } else { switch_to_blog( $blog_id ); update_option( 'allowedthemes', $allowed_themes[ $blog_id ] ); delete_option( 'allowed_themes' ); restore_current_blog(); } } } /** This filter is documented in wp-includes/class-wp-theme.php */ return (array) apply_filters( 'site_allowed_themes', $allowed_themes[ $blog_id ], $blog_id ); } /** * Enables a theme for all sites on the current network. * * @since 4.6.0 * * @param string|string[] $stylesheets Stylesheet name or array of stylesheet names. */ public static function network_enable_theme( $stylesheets ) { if ( ! is_multisite() ) { return; } if ( ! is_array( $stylesheets ) ) { $stylesheets = array( $stylesheets ); } $allowed_themes = get_site_option( 'allowedthemes' ); foreach ( $stylesheets as $stylesheet ) { $allowed_themes[ $stylesheet ] = true; } update_site_option( 'allowedthemes', $allowed_themes ); } /** * Disables a theme for all sites on the current network. * * @since 4.6.0 * * @param string|string[] $stylesheets Stylesheet name or array of stylesheet names. */ public static function network_disable_theme( $stylesheets ) { if ( ! is_multisite() ) { return; } if ( ! is_array( $stylesheets ) ) { $stylesheets = array( $stylesheets ); } $allowed_themes = get_site_option( 'allowedthemes' ); foreach ( $stylesheets as $stylesheet ) { if ( isset( $allowed_themes[ $stylesheet ] ) ) { unset( $allowed_themes[ $stylesheet ] ); } } update_site_option( 'allowedthemes', $allowed_themes ); } /** * Sorts themes by name. * * @since 3.4.0 * * @param WP_Theme[] $themes Array of theme objects to sort (passed by reference). */ public static function sort_by_name( &$themes ) { if ( 0 === strpos( get_user_locale(), 'en_' ) ) { uasort( $themes, array( 'WP_Theme', '_name_sort' ) ); } else { foreach ( $themes as $key => $theme ) { $theme->translate_header( 'Name', $theme->headers['Name'] ); } uasort( $themes, array( 'WP_Theme', '_name_sort_i18n' ) ); } } /** * Callback function for usort() to naturally sort themes by name. * * Accesses the Name header directly from the class for maximum speed. * Would choke on HTML but we don't care enough to slow it down with strip_tags(). * * @since 3.4.0 * * @param WP_Theme $a First theme. * @param WP_Theme $b Second theme. * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). */ private static function _name_sort( $a, $b ) { return strnatcasecmp( $a->headers['Name'], $b->headers['Name'] ); } /** * Callback function for usort() to naturally sort themes by translated name. * * @since 3.4.0 * * @param WP_Theme $a First theme. * @param WP_Theme $b Second theme. * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). */ private static function _name_sort_i18n( $a, $b ) { return strnatcasecmp( $a->name_translated, $b->name_translated ); } private static function _check_headers_property_has_correct_type( $headers ) { if ( ! is_array( $headers ) ) { return false; } foreach ( $headers as $key => $value ) { if ( ! is_string( $key ) || ! is_string( $value ) ) { return false; } } return true; } } comment-template.php000064400000267550150320557470010557 0ustar00comment_author ) ) { $user = $comment->user_id ? get_userdata( $comment->user_id ) : false; if ( $user ) { $author = $user->display_name; } else { $author = __( 'Anonymous' ); } } else { $author = $comment->comment_author; } /** * Filters the returned comment author name. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added. * * @param string $author The comment author's username. * @param int $comment_ID The comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_author', $author, $comment->comment_ID, $comment ); } /** * Displays the author of the current comment. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author. * Default current comment. */ function comment_author( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $author = get_comment_author( $comment ); /** * Filters the comment author's name for display. * * @since 1.2.0 * @since 4.1.0 The `$comment_ID` parameter was added. * * @param string $author The comment author's username. * @param int $comment_ID The comment ID. */ echo apply_filters( 'comment_author', $author, $comment->comment_ID ); } /** * Retrieves the email of the author of the current comment. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's email. * Default current comment. * @return string The current comment author's email */ function get_comment_author_email( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); /** * Filters the comment author's returned email address. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added. * * @param string $comment_author_email The comment author's email address. * @param int $comment_ID The comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_author_email', $comment->comment_author_email, $comment->comment_ID, $comment ); } /** * Displays the email of the author of the current global $comment. * * Care should be taken to protect the email address and assure that email * harvesters do not capture your commenter's email address. Most assume that * their email address will not appear in raw form on the site. Doing so will * enable anyone, including those that people don't want to get the email * address and use it for their own means good and bad. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's email. * Default current comment. */ function comment_author_email( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $author_email = get_comment_author_email( $comment ); /** * Filters the comment author's email for display. * * @since 1.2.0 * @since 4.1.0 The `$comment_ID` parameter was added. * * @param string $author_email The comment author's email address. * @param int $comment_ID The comment ID. */ echo apply_filters( 'author_email', $author_email, $comment->comment_ID ); } /** * Displays the HTML email link to the author of the current comment. * * Care should be taken to protect the email address and assure that email * harvesters do not capture your commenter's email address. Most assume that * their email address will not appear in raw form on the site. Doing so will * enable anyone, including those that people don't want to get the email * address and use it for their own means good and bad. * * @since 0.71 * @since 4.6.0 Added the `$comment` parameter. * * @param string $linktext Optional. Text to display instead of the comment author's email address. * Default empty. * @param string $before Optional. Text or HTML to display before the email link. Default empty. * @param string $after Optional. Text or HTML to display after the email link. Default empty. * @param int|WP_Comment $comment Optional. Comment ID or WP_Comment object. Default is the current comment. */ function comment_author_email_link( $linktext = '', $before = '', $after = '', $comment = null ) { $link = get_comment_author_email_link( $linktext, $before, $after, $comment ); if ( $link ) { echo $link; } } /** * Returns the HTML email link to the author of the current comment. * * Care should be taken to protect the email address and assure that email * harvesters do not capture your commenter's email address. Most assume that * their email address will not appear in raw form on the site. Doing so will * enable anyone, including those that people don't want to get the email * address and use it for their own means good and bad. * * @since 2.7.0 * @since 4.6.0 Added the `$comment` parameter. * * @param string $linktext Optional. Text to display instead of the comment author's email address. * Default empty. * @param string $before Optional. Text or HTML to display before the email link. Default empty. * @param string $after Optional. Text or HTML to display after the email link. Default empty. * @param int|WP_Comment $comment Optional. Comment ID or WP_Comment object. Default is the current comment. * @return string HTML markup for the comment author email link. By default, the email address is obfuscated * via the {@see 'comment_email'} filter with antispambot(). */ function get_comment_author_email_link( $linktext = '', $before = '', $after = '', $comment = null ) { $comment = get_comment( $comment ); /** * Filters the comment author's email for display. * * Care should be taken to protect the email address and assure that email * harvesters do not capture your commenter's email address. * * @since 1.2.0 * @since 4.1.0 The `$comment` parameter was added. * * @param string $comment_author_email The comment author's email address. * @param WP_Comment $comment The comment object. */ $email = apply_filters( 'comment_email', $comment->comment_author_email, $comment ); if ( ( ! empty( $email ) ) && ( '@' !== $email ) ) { $display = ( '' !== $linktext ) ? $linktext : $email; $return = $before; $return .= sprintf( '%2$s', esc_url( 'mailto:' . $email ), esc_html( $display ) ); $return .= $after; return $return; } else { return ''; } } /** * Retrieves the HTML link to the URL of the author of the current comment. * * Both get_comment_author_url() and get_comment_author() rely on get_comment(), * which falls back to the global comment variable if the $comment_ID argument is empty. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's link. * Default current comment. * @return string The comment author name or HTML link for author's URL. */ function get_comment_author_link( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $url = get_comment_author_url( $comment ); $author = get_comment_author( $comment ); if ( empty( $url ) || 'http://' === $url ) { $return = $author; } else { $return = "$author"; } /** * Filters the comment author's link for display. * * @since 1.5.0 * @since 4.1.0 The `$author` and `$comment_ID` parameters were added. * * @param string $return The HTML-formatted comment author link. * Empty for an invalid URL. * @param string $author The comment author's username. * @param int $comment_ID The comment ID. */ return apply_filters( 'get_comment_author_link', $return, $author, $comment->comment_ID ); } /** * Displays the HTML link to the URL of the author of the current comment. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's link. * Default current comment. */ function comment_author_link( $comment_ID = 0 ) { echo get_comment_author_link( $comment_ID ); } /** * Retrieve the IP address of the author of the current comment. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's IP address. * Default current comment. * @return string Comment author's IP address. */ function get_comment_author_IP( $comment_ID = 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid $comment = get_comment( $comment_ID ); /** * Filters the comment author's returned IP address. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added. * * @param string $comment_author_IP The comment author's IP address. * @param int $comment_ID The comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_author_IP', $comment->comment_author_IP, $comment->comment_ID, $comment ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.NotLowercase } /** * Displays the IP address of the author of the current comment. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's IP address. * Default current comment. */ function comment_author_IP( $comment_ID = 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid echo esc_html( get_comment_author_IP( $comment_ID ) ); } /** * Retrieves the URL of the author of the current comment, not linked. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to get the author's URL. * Default current comment. * @return string Comment author URL, if provided, an empty string otherwise. */ function get_comment_author_url( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $url = ''; $id = 0; if ( ! empty( $comment ) ) { $author_url = ( 'http://' === $comment->comment_author_url ) ? '' : $comment->comment_author_url; $url = esc_url( $author_url, array( 'http', 'https' ) ); $id = $comment->comment_ID; } /** * Filters the comment author's URL. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added. * * @param string $url The comment author's URL. * @param int $comment_ID The comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_author_url', $url, $id, $comment ); } /** * Displays the URL of the author of the current comment, not linked. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or the ID of the comment for which to print the author's URL. * Default current comment. */ function comment_author_url( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $author_url = get_comment_author_url( $comment ); /** * Filters the comment author's URL for display. * * @since 1.2.0 * @since 4.1.0 The `$comment_ID` parameter was added. * * @param string $author_url The comment author's URL. * @param int $comment_ID The comment ID. */ echo apply_filters( 'comment_url', $author_url, $comment->comment_ID ); } /** * Retrieves the HTML link of the URL of the author of the current comment. * * $linktext parameter is only used if the URL does not exist for the comment * author. If the URL does exist then the URL will be used and the $linktext * will be ignored. * * Encapsulate the HTML link between the $before and $after. So it will appear * in the order of $before, link, and finally $after. * * @since 1.5.0 * @since 4.6.0 Added the `$comment` parameter. * * @param string $linktext Optional. The text to display instead of the comment * author's email address. Default empty. * @param string $before Optional. The text or HTML to display before the email link. * Default empty. * @param string $after Optional. The text or HTML to display after the email link. * Default empty. * @param int|WP_Comment $comment Optional. Comment ID or WP_Comment object. * Default is the current comment. * @return string The HTML link between the $before and $after parameters. */ function get_comment_author_url_link( $linktext = '', $before = '', $after = '', $comment = 0 ) { $url = get_comment_author_url( $comment ); $display = ( '' !== $linktext ) ? $linktext : $url; $display = str_replace( 'http://www.', '', $display ); $display = str_replace( 'http://', '', $display ); if ( '/' === substr( $display, -1 ) ) { $display = substr( $display, 0, -1 ); } $return = "$before$display$after"; /** * Filters the comment author's returned URL link. * * @since 1.5.0 * * @param string $return The HTML-formatted comment author URL link. */ return apply_filters( 'get_comment_author_url_link', $return ); } /** * Displays the HTML link of the URL of the author of the current comment. * * @since 0.71 * @since 4.6.0 Added the `$comment` parameter. * * @param string $linktext Optional. Text to display instead of the comment author's * email address. Default empty. * @param string $before Optional. Text or HTML to display before the email link. * Default empty. * @param string $after Optional. Text or HTML to display after the email link. * Default empty. * @param int|WP_Comment $comment Optional. Comment ID or WP_Comment object. * Default is the current comment. */ function comment_author_url_link( $linktext = '', $before = '', $after = '', $comment = 0 ) { echo get_comment_author_url_link( $linktext, $before, $after, $comment ); } /** * Generates semantic classes for each comment element. * * @since 2.7.0 * @since 4.4.0 Added the ability for `$comment` to also accept a WP_Comment object. * * @param string|array $class Optional. One or more classes to add to the class list. * Default empty. * @param int|WP_Comment $comment Comment ID or WP_Comment object. Default current comment. * @param int|WP_Post $post_id Post ID or WP_Post object. Default current post. * @param bool $echo Optional. Whether to echo or return the output. * Default true. * @return void|string Void if `$echo` argument is true, comment classes if `$echo` is false. */ function comment_class( $class = '', $comment = null, $post_id = null, $echo = true ) { // Separates classes with a single space, collates classes for comment DIV. $class = 'class="' . join( ' ', get_comment_class( $class, $comment, $post_id ) ) . '"'; if ( $echo ) { echo $class; } else { return $class; } } /** * Returns the classes for the comment div as an array. * * @since 2.7.0 * @since 4.4.0 Added the ability for `$comment_id` to also accept a WP_Comment object. * * @global int $comment_alt * @global int $comment_depth * @global int $comment_thread_alt * * @param string|array $class Optional. One or more classes to add to the class list. Default empty. * @param int|WP_Comment $comment_id Comment ID or WP_Comment object. Default current comment. * @param int|WP_Post $post_id Post ID or WP_Post object. Default current post. * @return string[] An array of classes. */ function get_comment_class( $class = '', $comment_id = null, $post_id = null ) { global $comment_alt, $comment_depth, $comment_thread_alt; $classes = array(); $comment = get_comment( $comment_id ); if ( ! $comment ) { return $classes; } // Get the comment type (comment, trackback). $classes[] = ( empty( $comment->comment_type ) ) ? 'comment' : $comment->comment_type; // Add classes for comment authors that are registered users. $user = $comment->user_id ? get_userdata( $comment->user_id ) : false; if ( $user ) { $classes[] = 'byuser'; $classes[] = 'comment-author-' . sanitize_html_class( $user->user_nicename, $comment->user_id ); // For comment authors who are the author of the post. $post = get_post( $post_id ); if ( $post ) { if ( $comment->user_id === $post->post_author ) { $classes[] = 'bypostauthor'; } } } if ( empty( $comment_alt ) ) { $comment_alt = 0; } if ( empty( $comment_depth ) ) { $comment_depth = 1; } if ( empty( $comment_thread_alt ) ) { $comment_thread_alt = 0; } if ( $comment_alt % 2 ) { $classes[] = 'odd'; $classes[] = 'alt'; } else { $classes[] = 'even'; } $comment_alt++; // Alt for top-level comments. if ( 1 == $comment_depth ) { if ( $comment_thread_alt % 2 ) { $classes[] = 'thread-odd'; $classes[] = 'thread-alt'; } else { $classes[] = 'thread-even'; } $comment_thread_alt++; } $classes[] = "depth-$comment_depth"; if ( ! empty( $class ) ) { if ( ! is_array( $class ) ) { $class = preg_split( '#\s+#', $class ); } $classes = array_merge( $classes, $class ); } $classes = array_map( 'esc_attr', $classes ); /** * Filters the returned CSS classes for the current comment. * * @since 2.7.0 * * @param string[] $classes An array of comment classes. * @param string $class A comma-separated list of additional classes added to the list. * @param int $comment_id The comment ID. * @param WP_Comment $comment The comment object. * @param int|WP_Post $post_id The post ID or WP_Post object. */ return apply_filters( 'comment_class', $classes, $class, $comment->comment_ID, $comment, $post_id ); } /** * Retrieves the comment date of the current comment. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param string $format Optional. The format of the date. Default user's setting. * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to get the date. * Default current comment. * @return string The comment's date. */ function get_comment_date( $format = '', $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $_format = ! empty( $format ) ? $format : get_option( 'date_format' ); $date = mysql2date( $_format, $comment->comment_date ); /** * Filters the returned comment date. * * @since 1.5.0 * * @param string|int $date Formatted date string or Unix timestamp. * @param string $format The format of the date. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_date', $date, $format, $comment ); } /** * Displays the comment date of the current comment. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param string $format Optional. The format of the date. Default user's settings. * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to print the date. * Default current comment. */ function comment_date( $format = '', $comment_ID = 0 ) { echo get_comment_date( $format, $comment_ID ); } /** * Retrieves the excerpt of the given comment. * * Returns a maximum of 20 words with an ellipsis appended if necessary. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to get the excerpt. * Default current comment. * @return string The possibly truncated comment excerpt. */ function get_comment_excerpt( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); if ( ! post_password_required( $comment->comment_post_ID ) ) { $comment_text = strip_tags( str_replace( array( "\n", "\r" ), ' ', $comment->comment_content ) ); } else { $comment_text = __( 'Password protected' ); } /* translators: Maximum number of words used in a comment excerpt. */ $comment_excerpt_length = intval( _x( '20', 'comment_excerpt_length' ) ); /** * Filters the maximum number of words used in the comment excerpt. * * @since 4.4.0 * * @param int $comment_excerpt_length The amount of words you want to display in the comment excerpt. */ $comment_excerpt_length = apply_filters( 'comment_excerpt_length', $comment_excerpt_length ); $excerpt = wp_trim_words( $comment_text, $comment_excerpt_length, '…' ); /** * Filters the retrieved comment excerpt. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added. * * @param string $excerpt The comment excerpt text. * @param int $comment_ID The comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_excerpt', $excerpt, $comment->comment_ID, $comment ); } /** * Displays the excerpt of the current comment. * * @since 1.2.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to print the excerpt. * Default current comment. */ function comment_excerpt( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); $comment_excerpt = get_comment_excerpt( $comment ); /** * Filters the comment excerpt for display. * * @since 1.2.0 * @since 4.1.0 The `$comment_ID` parameter was added. * * @param string $comment_excerpt The comment excerpt text. * @param int $comment_ID The comment ID. */ echo apply_filters( 'comment_excerpt', $comment_excerpt, $comment->comment_ID ); } /** * Retrieves the comment ID of the current comment. * * @since 1.5.0 * * @return int The comment ID. */ function get_comment_ID() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid $comment = get_comment(); /** * Filters the returned comment ID. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` parameter was added. * * @param int $comment_ID The current comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_ID', $comment->comment_ID, $comment ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.NotLowercase } /** * Displays the comment ID of the current comment. * * @since 0.71 */ function comment_ID() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid echo get_comment_ID(); } /** * Retrieves the link to a given comment. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment` to also accept a WP_Comment object. Added `$cpage` argument. * * @see get_page_of_comment() * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. * @global bool $in_comment_loop * * @param WP_Comment|int|null $comment Comment to retrieve. Default current comment. * @param array $args { * An array of optional arguments to override the defaults. * * @type string $type Passed to get_page_of_comment(). * @type int $page Current page of comments, for calculating comment pagination. * @type int $per_page Per-page value for comment pagination. * @type int $max_depth Passed to get_page_of_comment(). * @type int|string $cpage Value to use for the comment's "comment-page" or "cpage" value. * If provided, this value overrides any value calculated from `$page` * and `$per_page`. * } * @return string The permalink to the given comment. */ function get_comment_link( $comment = null, $args = array() ) { global $wp_rewrite, $in_comment_loop; $comment = get_comment( $comment ); // Back-compat. if ( ! is_array( $args ) ) { $args = array( 'page' => $args ); } $defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '', 'cpage' => null, ); $args = wp_parse_args( $args, $defaults ); $link = get_permalink( $comment->comment_post_ID ); // The 'cpage' param takes precedence. if ( ! is_null( $args['cpage'] ) ) { $cpage = $args['cpage']; // No 'cpage' is provided, so we calculate one. } else { if ( '' === $args['per_page'] && get_option( 'page_comments' ) ) { $args['per_page'] = get_option( 'comments_per_page' ); } if ( empty( $args['per_page'] ) ) { $args['per_page'] = 0; $args['page'] = 0; } $cpage = $args['page']; if ( '' == $cpage ) { if ( ! empty( $in_comment_loop ) ) { $cpage = get_query_var( 'cpage' ); } else { // Requires a database hit, so we only do it when we can't figure out from context. $cpage = get_page_of_comment( $comment->comment_ID, $args ); } } /* * If the default page displays the oldest comments, the permalinks for comments on the default page * do not need a 'cpage' query var. */ if ( 'oldest' === get_option( 'default_comments_page' ) && 1 === $cpage ) { $cpage = ''; } } if ( $cpage && get_option( 'page_comments' ) ) { if ( $wp_rewrite->using_permalinks() ) { if ( $cpage ) { $link = trailingslashit( $link ) . $wp_rewrite->comments_pagination_base . '-' . $cpage; } $link = user_trailingslashit( $link, 'comment' ); } elseif ( $cpage ) { $link = add_query_arg( 'cpage', $cpage, $link ); } } if ( $wp_rewrite->using_permalinks() ) { $link = user_trailingslashit( $link, 'comment' ); } $link = $link . '#comment-' . $comment->comment_ID; /** * Filters the returned single comment permalink. * * @since 2.8.0 * @since 4.4.0 Added the `$cpage` parameter. * * @see get_page_of_comment() * * @param string $link The comment permalink with '#comment-$id' appended. * @param WP_Comment $comment The current comment object. * @param array $args An array of arguments to override the defaults. * @param int $cpage The calculated 'cpage' value. */ return apply_filters( 'get_comment_link', $link, $comment, $args, $cpage ); } /** * Retrieves the link to the current post comments. * * @since 1.5.0 * * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post. * @return string The link to the comments. */ function get_comments_link( $post_id = 0 ) { $hash = get_comments_number( $post_id ) ? '#comments' : '#respond'; $comments_link = get_permalink( $post_id ) . $hash; /** * Filters the returned post comments permalink. * * @since 3.6.0 * * @param string $comments_link Post comments permalink with '#comments' appended. * @param int|WP_Post $post_id Post ID or WP_Post object. */ return apply_filters( 'get_comments_link', $comments_link, $post_id ); } /** * Displays the link to the current post comments. * * @since 0.71 * * @param string $deprecated Not Used. * @param string $deprecated_2 Not Used. */ function comments_link( $deprecated = '', $deprecated_2 = '' ) { if ( ! empty( $deprecated ) ) { _deprecated_argument( __FUNCTION__, '0.72' ); } if ( ! empty( $deprecated_2 ) ) { _deprecated_argument( __FUNCTION__, '1.3.0' ); } echo esc_url( get_comments_link() ); } /** * Retrieves the amount of comments a post has. * * @since 1.5.0 * * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is the global `$post`. * @return string|int If the post exists, a numeric string representing the number of comments * the post has, otherwise 0. */ function get_comments_number( $post_id = 0 ) { $post = get_post( $post_id ); if ( ! $post ) { $count = 0; } else { $count = $post->comment_count; $post_id = $post->ID; } /** * Filters the returned comment count for a post. * * @since 1.5.0 * * @param string|int $count A string representing the number of comments a post has, otherwise 0. * @param int $post_id Post ID. */ return apply_filters( 'get_comments_number', $count, $post_id ); } /** * Displays the language string for the number of comments the current post has. * * @since 0.71 * @since 5.4.0 The `$deprecated` parameter was changed to `$post_id`. * * @param string $zero Optional. Text for no comments. Default false. * @param string $one Optional. Text for one comment. Default false. * @param string $more Optional. Text for more than one comment. Default false. * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is the global `$post`. */ function comments_number( $zero = false, $one = false, $more = false, $post_id = 0 ) { echo get_comments_number_text( $zero, $one, $more, $post_id ); } /** * Displays the language string for the number of comments the current post has. * * @since 4.0.0 * @since 5.4.0 Added the `$post_id` parameter to allow using the function outside of the loop. * * @param string $zero Optional. Text for no comments. Default false. * @param string $one Optional. Text for one comment. Default false. * @param string $more Optional. Text for more than one comment. Default false. * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is the global `$post`. * @return string Language string for the number of comments a post has. */ function get_comments_number_text( $zero = false, $one = false, $more = false, $post_id = 0 ) { $number = get_comments_number( $post_id ); if ( $number > 1 ) { if ( false === $more ) { /* translators: %s: Number of comments. */ $output = sprintf( _n( '%s Comment', '%s Comments', $number ), number_format_i18n( $number ) ); } else { // % Comments /* * translators: If comment number in your language requires declension, * translate this to 'on'. Do not translate into your own language. */ if ( 'on' === _x( 'off', 'Comment number declension: on or off' ) ) { $text = preg_replace( '#.+?#', '', $more ); $text = preg_replace( '/&.+?;/', '', $text ); // Kill entities. $text = trim( strip_tags( $text ), '% ' ); // Replace '% Comments' with a proper plural form. if ( $text && ! preg_match( '/[0-9]+/', $text ) && false !== strpos( $more, '%' ) ) { /* translators: %s: Number of comments. */ $new_text = _n( '%s Comment', '%s Comments', $number ); $new_text = trim( sprintf( $new_text, '' ) ); $more = str_replace( $text, $new_text, $more ); if ( false === strpos( $more, '%' ) ) { $more = '% ' . $more; } } } $output = str_replace( '%', number_format_i18n( $number ), $more ); } } elseif ( 0 == $number ) { $output = ( false === $zero ) ? __( 'No Comments' ) : $zero; } else { // Must be one. $output = ( false === $one ) ? __( '1 Comment' ) : $one; } /** * Filters the comments count for display. * * @since 1.5.0 * * @see _n() * * @param string $output A translatable string formatted based on whether the count * is equal to 0, 1, or 1+. * @param int $number The number of post comments. */ return apply_filters( 'comments_number', $output, $number ); } /** * Retrieves the text of the current comment. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * @since 5.4.0 Added 'In reply to %s.' prefix to child comments in comments feed. * * @see Walker_Comment::comment() * * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to get the text. * Default current comment. * @param array $args Optional. An array of arguments. Default empty array. * @return string The comment content. */ function get_comment_text( $comment_ID = 0, $args = array() ) { $comment = get_comment( $comment_ID ); $comment_content = $comment->comment_content; if ( is_comment_feed() && $comment->comment_parent ) { $parent = get_comment( $comment->comment_parent ); if ( $parent ) { $parent_link = esc_url( get_comment_link( $parent ) ); $name = get_comment_author( $parent ); $comment_content = sprintf( /* translators: %s: Comment link. */ ent2ncr( __( 'In reply to %s.' ) ), '' . $name . '' ) . "\n\n" . $comment_content; } } /** * Filters the text of a comment. * * @since 1.5.0 * * @see Walker_Comment::comment() * * @param string $comment_content Text of the comment. * @param WP_Comment $comment The comment object. * @param array $args An array of arguments. */ return apply_filters( 'get_comment_text', $comment_content, $comment, $args ); } /** * Displays the text of the current comment. * * @since 0.71 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @see Walker_Comment::comment() * * @param int|WP_Comment $comment_ID WP_Comment or ID of the comment for which to print the text. * Default current comment. * @param array $args Optional. An array of arguments. Default empty array. */ function comment_text( $comment_ID = 0, $args = array() ) { $comment = get_comment( $comment_ID ); $comment_text = get_comment_text( $comment, $args ); /** * Filters the text of a comment to be displayed. * * @since 1.2.0 * * @see Walker_Comment::comment() * * @param string $comment_text Text of the current comment. * @param WP_Comment|null $comment The comment object. Null if not found. * @param array $args An array of arguments. */ echo apply_filters( 'comment_text', $comment_text, $comment, $args ); } /** * Retrieves the comment time of the current comment. * * @since 1.5.0 * * @param string $format Optional. The format of the time. Default user's settings. * @param bool $gmt Optional. Whether to use the GMT date. Default false. * @param bool $translate Optional. Whether to translate the time (for use in feeds). * Default true. * @return string The formatted time. */ function get_comment_time( $format = '', $gmt = false, $translate = true ) { $comment = get_comment(); $comment_date = $gmt ? $comment->comment_date_gmt : $comment->comment_date; $_format = ! empty( $format ) ? $format : get_option( 'time_format' ); $date = mysql2date( $_format, $comment_date, $translate ); /** * Filters the returned comment time. * * @since 1.5.0 * * @param string|int $date The comment time, formatted as a date string or Unix timestamp. * @param string $format Date format. * @param bool $gmt Whether the GMT date is in use. * @param bool $translate Whether the time is translated. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_time', $date, $format, $gmt, $translate, $comment ); } /** * Displays the comment time of the current comment. * * @since 0.71 * * @param string $format Optional. The format of the time. Default user's settings. */ function comment_time( $format = '' ) { echo get_comment_time( $format ); } /** * Retrieves the comment type of the current comment. * * @since 1.5.0 * @since 4.4.0 Added the ability for `$comment_ID` to also accept a WP_Comment object. * * @param int|WP_Comment $comment_ID Optional. WP_Comment or ID of the comment for which to get the type. * Default current comment. * @return string The comment type. */ function get_comment_type( $comment_ID = 0 ) { $comment = get_comment( $comment_ID ); if ( '' === $comment->comment_type ) { $comment->comment_type = 'comment'; } /** * Filters the returned comment type. * * @since 1.5.0 * @since 4.1.0 The `$comment_ID` and `$comment` parameters were added. * * @param string $comment_type The type of comment, such as 'comment', 'pingback', or 'trackback'. * @param int $comment_ID The comment ID. * @param WP_Comment $comment The comment object. */ return apply_filters( 'get_comment_type', $comment->comment_type, $comment->comment_ID, $comment ); } /** * Displays the comment type of the current comment. * * @since 0.71 * * @param string $commenttxt Optional. String to display for comment type. Default false. * @param string $trackbacktxt Optional. String to display for trackback type. Default false. * @param string $pingbacktxt Optional. String to display for pingback type. Default false. */ function comment_type( $commenttxt = false, $trackbacktxt = false, $pingbacktxt = false ) { if ( false === $commenttxt ) { $commenttxt = _x( 'Comment', 'noun' ); } if ( false === $trackbacktxt ) { $trackbacktxt = __( 'Trackback' ); } if ( false === $pingbacktxt ) { $pingbacktxt = __( 'Pingback' ); } $type = get_comment_type(); switch ( $type ) { case 'trackback': echo $trackbacktxt; break; case 'pingback': echo $pingbacktxt; break; default: echo $commenttxt; } } /** * Retrieves the current post's trackback URL. * * There is a check to see if permalink's have been enabled and if so, will * retrieve the pretty path. If permalinks weren't enabled, the ID of the * current post is used and appended to the correct page to go to. * * @since 1.5.0 * * @return string The trackback URL after being filtered. */ function get_trackback_url() { if ( get_option( 'permalink_structure' ) ) { $tb_url = trailingslashit( get_permalink() ) . user_trailingslashit( 'trackback', 'single_trackback' ); } else { $tb_url = get_option( 'siteurl' ) . '/wp-trackback.php?p=' . get_the_ID(); } /** * Filters the returned trackback URL. * * @since 2.2.0 * * @param string $tb_url The trackback URL. */ return apply_filters( 'trackback_url', $tb_url ); } /** * Displays the current post's trackback URL. * * @since 0.71 * * @param bool $deprecated_echo Not used. * @return void|string Should only be used to echo the trackback URL, use get_trackback_url() * for the result instead. */ function trackback_url( $deprecated_echo = true ) { if ( true !== $deprecated_echo ) { _deprecated_argument( __FUNCTION__, '2.5.0', sprintf( /* translators: %s: get_trackback_url() */ __( 'Use %s instead if you do not want the value echoed.' ), 'get_trackback_url()' ) ); } if ( $deprecated_echo ) { echo get_trackback_url(); } else { return get_trackback_url(); } } /** * Generates and displays the RDF for the trackback information of current post. * * Deprecated in 3.0.0, and restored in 3.0.1. * * @since 0.71 * * @param int $deprecated Not used (Was $timezone = 0). */ function trackback_rdf( $deprecated = '' ) { if ( ! empty( $deprecated ) ) { _deprecated_argument( __FUNCTION__, '2.5.0' ); } if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && false !== stripos( $_SERVER['HTTP_USER_AGENT'], 'W3C_Validator' ) ) { return; } echo ' \n"; echo ''; } /** * Determines whether the current post is open for comments. * * 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 1.5.0 * * @param int|WP_Post $post_id Post ID or WP_Post object. Default current post. * @return bool True if the comments are open. */ function comments_open( $post_id = null ) { $_post = get_post( $post_id ); $post_id = $_post ? $_post->ID : 0; $open = ( 'open' === $_post->comment_status ); /** * Filters whether the current post is open for comments. * * @since 2.5.0 * * @param bool $open Whether the current post is open for comments. * @param int $post_id The post ID. */ return apply_filters( 'comments_open', $open, $post_id ); } /** * Determines whether the current post is open for pings. * * 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 1.5.0 * * @param int|WP_Post $post_id Post ID or WP_Post object. Default current post. * @return bool True if pings are accepted */ function pings_open( $post_id = null ) { $_post = get_post( $post_id ); $post_id = $_post ? $_post->ID : 0; $open = ( 'open' === $_post->ping_status ); /** * Filters whether the current post is open for pings. * * @since 2.5.0 * * @param bool $open Whether the current post is open for pings. * @param int $post_id The post ID. */ return apply_filters( 'pings_open', $open, $post_id ); } /** * Displays form token for unfiltered comments. * * Will only display nonce token if the current user has permissions for * unfiltered html. Won't display the token for other users. * * The function was backported to 2.0.10 and was added to versions 2.1.3 and * above. Does not exist in versions prior to 2.0.10 in the 2.0 branch and in * the 2.1 branch, prior to 2.1.3. Technically added in 2.2.0. * * Backported to 2.0.10. * * @since 2.1.3 */ function wp_comment_form_unfiltered_html_nonce() { $post = get_post(); $post_id = $post ? $post->ID : 0; if ( current_user_can( 'unfiltered_html' ) ) { wp_nonce_field( 'unfiltered-html-comment_' . $post_id, '_wp_unfiltered_html_comment_disabled', false ); echo "\n"; } } /** * Loads the comment template specified in $file. * * Will not display the comments template if not on single post or page, or if * the post does not have comments. * * Uses the WordPress database object to query for the comments. The comments * are passed through the {@see 'comments_array'} filter hook with the list of comments * and the post ID respectively. * * The `$file` path is passed through a filter hook called {@see 'comments_template'}, * which includes the TEMPLATEPATH and $file combined. Tries the $filtered path * first and if it fails it will require the default comment template from the * default theme. If either does not exist, then the WordPress process will be * halted. It is advised for that reason, that the default theme is not deleted. * * Will not try to get the comments if the post has none. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * @global WP_Post $post Global post object. * @global wpdb $wpdb WordPress database abstraction object. * @global int $id * @global WP_Comment $comment Global comment object. * @global string $user_login * @global string $user_identity * @global bool $overridden_cpage * @global bool $withcomments * * @param string $file Optional. The file to load. Default '/comments.php'. * @param bool $separate_comments Optional. Whether to separate the comments by comment type. * Default false. */ function comments_template( $file = '/comments.php', $separate_comments = false ) { global $wp_query, $withcomments, $post, $wpdb, $id, $comment, $user_login, $user_identity, $overridden_cpage; if ( ! ( is_single() || is_page() || $withcomments ) || empty( $post ) ) { return; } if ( empty( $file ) ) { $file = '/comments.php'; } $req = get_option( 'require_name_email' ); /* * Comment author information fetched from the comment cookies. */ $commenter = wp_get_current_commenter(); /* * The name of the current comment author escaped for use in attributes. * Escaped by sanitize_comment_cookies(). */ $comment_author = $commenter['comment_author']; /* * The email address of the current comment author escaped for use in attributes. * Escaped by sanitize_comment_cookies(). */ $comment_author_email = $commenter['comment_author_email']; /* * The URL of the current comment author escaped for use in attributes. */ $comment_author_url = esc_url( $commenter['comment_author_url'] ); $comment_args = array( 'orderby' => 'comment_date_gmt', 'order' => 'ASC', 'status' => 'approve', 'post_id' => $post->ID, 'no_found_rows' => false, 'update_comment_meta_cache' => false, // We lazy-load comment meta for performance. ); if ( get_option( 'thread_comments' ) ) { $comment_args['hierarchical'] = 'threaded'; } else { $comment_args['hierarchical'] = false; } if ( is_user_logged_in() ) { $comment_args['include_unapproved'] = array( get_current_user_id() ); } else { $unapproved_email = wp_get_unapproved_comment_author_email(); if ( $unapproved_email ) { $comment_args['include_unapproved'] = array( $unapproved_email ); } } $per_page = 0; if ( get_option( 'page_comments' ) ) { $per_page = (int) get_query_var( 'comments_per_page' ); if ( 0 === $per_page ) { $per_page = (int) get_option( 'comments_per_page' ); } $comment_args['number'] = $per_page; $page = (int) get_query_var( 'cpage' ); if ( $page ) { $comment_args['offset'] = ( $page - 1 ) * $per_page; } elseif ( 'oldest' === get_option( 'default_comments_page' ) ) { $comment_args['offset'] = 0; } else { // If fetching the first page of 'newest', we need a top-level comment count. $top_level_query = new WP_Comment_Query(); $top_level_args = array( 'count' => true, 'orderby' => false, 'post_id' => $post->ID, 'status' => 'approve', ); if ( $comment_args['hierarchical'] ) { $top_level_args['parent'] = 0; } if ( isset( $comment_args['include_unapproved'] ) ) { $top_level_args['include_unapproved'] = $comment_args['include_unapproved']; } $top_level_count = $top_level_query->query( $top_level_args ); $comment_args['offset'] = ( ceil( $top_level_count / $per_page ) - 1 ) * $per_page; } } /** * Filters the arguments used to query comments in comments_template(). * * @since 4.5.0 * * @see WP_Comment_Query::__construct() * * @param array $comment_args { * Array of WP_Comment_Query arguments. * * @type string|array $orderby Field(s) to order by. * @type string $order Order of results. Accepts 'ASC' or 'DESC'. * @type string $status Comment status. * @type array $include_unapproved Array of IDs or email addresses whose unapproved comments * will be included in results. * @type int $post_id ID of the post. * @type bool $no_found_rows Whether to refrain from querying for found rows. * @type bool $update_comment_meta_cache Whether to prime cache for comment meta. * @type bool|string $hierarchical Whether to query for comments hierarchically. * @type int $offset Comment offset. * @type int $number Number of comments to fetch. * } */ $comment_args = apply_filters( 'comments_template_query_args', $comment_args ); $comment_query = new WP_Comment_Query( $comment_args ); $_comments = $comment_query->comments; // Trees must be flattened before they're passed to the walker. if ( $comment_args['hierarchical'] ) { $comments_flat = array(); foreach ( $_comments as $_comment ) { $comments_flat[] = $_comment; $comment_children = $_comment->get_children( array( 'format' => 'flat', 'status' => $comment_args['status'], 'orderby' => $comment_args['orderby'], ) ); foreach ( $comment_children as $comment_child ) { $comments_flat[] = $comment_child; } } } else { $comments_flat = $_comments; } /** * Filters the comments array. * * @since 2.1.0 * * @param array $comments Array of comments supplied to the comments template. * @param int $post_ID Post ID. */ $wp_query->comments = apply_filters( 'comments_array', $comments_flat, $post->ID ); $comments = &$wp_query->comments; $wp_query->comment_count = count( $wp_query->comments ); $wp_query->max_num_comment_pages = $comment_query->max_num_pages; if ( $separate_comments ) { $wp_query->comments_by_type = separate_comments( $comments ); $comments_by_type = &$wp_query->comments_by_type; } else { $wp_query->comments_by_type = array(); } $overridden_cpage = false; if ( '' == get_query_var( 'cpage' ) && $wp_query->max_num_comment_pages > 1 ) { set_query_var( 'cpage', 'newest' === get_option( 'default_comments_page' ) ? get_comment_pages_count() : 1 ); $overridden_cpage = true; } if ( ! defined( 'COMMENTS_TEMPLATE' ) ) { define( 'COMMENTS_TEMPLATE', true ); } $theme_template = STYLESHEETPATH . $file; /** * Filters the path to the theme template file used for the comments template. * * @since 1.5.1 * * @param string $theme_template The path to the theme template file. */ $include = apply_filters( 'comments_template', $theme_template ); if ( file_exists( $include ) ) { require $include; } elseif ( file_exists( TEMPLATEPATH . $file ) ) { require TEMPLATEPATH . $file; } else { // Backward compat code will be removed in a future release. require ABSPATH . WPINC . '/theme-compat/comments.php'; } } /** * Displays the link to the comments for the current post ID. * * @since 0.71 * * @param false|string $zero Optional. String to display when no comments. Default false. * @param false|string $one Optional. String to display when only one comment is available. Default false. * @param false|string $more Optional. String to display when there are more than one comment. Default false. * @param string $css_class Optional. CSS class to use for comments. Default empty. * @param false|string $none Optional. String to display when comments have been turned off. Default false. */ function comments_popup_link( $zero = false, $one = false, $more = false, $css_class = '', $none = false ) { $post_id = get_the_ID(); $post_title = get_the_title(); $number = get_comments_number( $post_id ); if ( false === $zero ) { /* translators: %s: Post title. */ $zero = sprintf( __( 'No Comments on %s' ), $post_title ); } if ( false === $one ) { /* translators: %s: Post title. */ $one = sprintf( __( '1 Comment on %s' ), $post_title ); } if ( false === $more ) { /* translators: 1: Number of comments, 2: Post title. */ $more = _n( '%1$s Comment on %2$s', '%1$s Comments on %2$s', $number ); $more = sprintf( $more, number_format_i18n( $number ), $post_title ); } if ( false === $none ) { /* translators: %s: Post title. */ $none = sprintf( __( 'Comments Off on %s' ), $post_title ); } if ( 0 == $number && ! comments_open() && ! pings_open() ) { echo '' . $none . ''; return; } if ( post_password_required() ) { _e( 'Enter your password to view comments.' ); return; } echo ''; comments_number( $zero, $one, $more ); echo ''; } /** * Retrieves HTML content for reply to comment link. * * @since 2.7.0 * @since 4.4.0 Added the ability for `$comment` to also accept a WP_Comment object. * * @param array $args { * Optional. Override default arguments. * * @type string $add_below The first part of the selector used to identify the comment to respond below. * The resulting value is passed as the first parameter to addComment.moveForm(), * concatenated as $add_below-$comment->comment_ID. Default 'comment'. * @type string $respond_id The selector identifying the responding comment. Passed as the third parameter * to addComment.moveForm(), and appended to the link URL as a hash value. * Default 'respond'. * @type string $reply_text The text of the Reply link. Default 'Reply'. * @type string $login_text The text of the link to reply if logged out. Default 'Log in to Reply'. * @type int $max_depth The max depth of the comment tree. Default 0. * @type int $depth The depth of the new comment. Must be greater than 0 and less than the value * of the 'thread_comments_depth' option set in Settings > Discussion. Default 0. * @type string $before The text or HTML to add before the reply link. Default empty. * @type string $after The text or HTML to add after the reply link. Default empty. * } * @param int|WP_Comment $comment Comment being replied to. Default current comment. * @param int|WP_Post $post Post ID or WP_Post object the comment is going to be displayed on. * Default current post. * @return string|false|null Link to show comment form, if successful. False, if comments are closed. */ function get_comment_reply_link( $args = array(), $comment = null, $post = null ) { $defaults = array( 'add_below' => 'comment', 'respond_id' => 'respond', 'reply_text' => __( 'Reply' ), /* translators: Comment reply button text. %s: Comment author name. */ 'reply_to_text' => __( 'Reply to %s' ), 'login_text' => __( 'Log in to Reply' ), 'max_depth' => 0, 'depth' => 0, 'before' => '', 'after' => '', ); $args = wp_parse_args( $args, $defaults ); if ( 0 == $args['depth'] || $args['max_depth'] <= $args['depth'] ) { return; } $comment = get_comment( $comment ); if ( empty( $comment ) ) { return; } if ( empty( $post ) ) { $post = $comment->comment_post_ID; } $post = get_post( $post ); if ( ! comments_open( $post->ID ) ) { return false; } /** * Filters the comment reply link arguments. * * @since 4.1.0 * * @param array $args Comment reply link arguments. See get_comment_reply_link() * for more information on accepted arguments. * @param WP_Comment $comment The object of the comment being replied to. * @param WP_Post $post The WP_Post object. */ $args = apply_filters( 'comment_reply_link_args', $args, $comment, $post ); if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) { $link = sprintf( '%s', esc_url( wp_login_url( get_permalink() ) ), $args['login_text'] ); } else { $data_attributes = array( 'commentid' => $comment->comment_ID, 'postid' => $post->ID, 'belowelement' => $args['add_below'] . '-' . $comment->comment_ID, 'respondelement' => $args['respond_id'], 'replyto' => sprintf( $args['reply_to_text'], $comment->comment_author ), ); $data_attribute_string = ''; foreach ( $data_attributes as $name => $value ) { $data_attribute_string .= " data-${name}=\"" . esc_attr( $value ) . '"'; } $data_attribute_string = trim( $data_attribute_string ); $link = sprintf( "%s", esc_url( add_query_arg( array( 'replytocom' => $comment->comment_ID, 'unapproved' => false, 'moderation-hash' => false, ), get_permalink( $post->ID ) ) ) . '#' . $args['respond_id'], $data_attribute_string, esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ), $args['reply_text'] ); } /** * Filters the comment reply link. * * @since 2.7.0 * * @param string $link The HTML markup for the comment reply link. * @param array $args An array of arguments overriding the defaults. * @param WP_Comment $comment The object of the comment being replied. * @param WP_Post $post The WP_Post object. */ return apply_filters( 'comment_reply_link', $args['before'] . $link . $args['after'], $args, $comment, $post ); } /** * Displays the HTML content for reply to comment link. * * @since 2.7.0 * * @see get_comment_reply_link() * * @param array $args Optional. Override default options. Default empty array. * @param int|WP_Comment $comment Comment being replied to. Default current comment. * @param int|WP_Post $post Post ID or WP_Post object the comment is going to be displayed on. * Default current post. */ function comment_reply_link( $args = array(), $comment = null, $post = null ) { echo get_comment_reply_link( $args, $comment, $post ); } /** * Retrieves HTML content for reply to post link. * * @since 2.7.0 * * @param array $args { * Optional. Override default arguments. * * @type string $add_below The first part of the selector used to identify the comment to respond below. * The resulting value is passed as the first parameter to addComment.moveForm(), * concatenated as $add_below-$comment->comment_ID. Default is 'post'. * @type string $respond_id The selector identifying the responding comment. Passed as the third parameter * to addComment.moveForm(), and appended to the link URL as a hash value. * Default 'respond'. * @type string $reply_text Text of the Reply link. Default is 'Leave a Comment'. * @type string $login_text Text of the link to reply if logged out. Default is 'Log in to leave a Comment'. * @type string $before Text or HTML to add before the reply link. Default empty. * @type string $after Text or HTML to add after the reply link. Default empty. * } * @param int|WP_Post $post Optional. Post ID or WP_Post object the comment is going to be displayed on. * Default current post. * @return string|false|null Link to show comment form, if successful. False, if comments are closed. */ function get_post_reply_link( $args = array(), $post = null ) { $defaults = array( 'add_below' => 'post', 'respond_id' => 'respond', 'reply_text' => __( 'Leave a Comment' ), 'login_text' => __( 'Log in to leave a Comment' ), 'before' => '', 'after' => '', ); $args = wp_parse_args( $args, $defaults ); $post = get_post( $post ); if ( ! comments_open( $post->ID ) ) { return false; } if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) { $link = sprintf( '%s', wp_login_url( get_permalink() ), $args['login_text'] ); } else { $onclick = sprintf( 'return addComment.moveForm( "%1$s-%2$s", "0", "%3$s", "%2$s" )', $args['add_below'], $post->ID, $args['respond_id'] ); $link = sprintf( "%s", get_permalink( $post->ID ) . '#' . $args['respond_id'], $onclick, $args['reply_text'] ); } $formatted_link = $args['before'] . $link . $args['after']; /** * Filters the formatted post comments link HTML. * * @since 2.7.0 * * @param string $formatted The HTML-formatted post comments link. * @param int|WP_Post $post The post ID or WP_Post object. */ return apply_filters( 'post_comments_link', $formatted_link, $post ); } /** * Displays the HTML content for reply to post link. * * @since 2.7.0 * * @see get_post_reply_link() * * @param array $args Optional. Override default options. Default empty array. * @param int|WP_Post $post Post ID or WP_Post object the comment is going to be displayed on. * Default current post. */ function post_reply_link( $args = array(), $post = null ) { echo get_post_reply_link( $args, $post ); } /** * Retrieves HTML content for cancel comment reply link. * * @since 2.7.0 * * @param string $text Optional. Text to display for cancel reply link. If empty, * defaults to 'Click here to cancel reply'. Default empty. * @return string */ function get_cancel_comment_reply_link( $text = '' ) { if ( empty( $text ) ) { $text = __( 'Click here to cancel reply.' ); } $style = isset( $_GET['replytocom'] ) ? '' : ' style="display:none;"'; $link = esc_html( remove_query_arg( array( 'replytocom', 'unapproved', 'moderation-hash' ) ) ) . '#respond'; $formatted_link = '' . $text . ''; /** * Filters the cancel comment reply link HTML. * * @since 2.7.0 * * @param string $formatted_link The HTML-formatted cancel comment reply link. * @param string $link Cancel comment reply link URL. * @param string $text Cancel comment reply link text. */ return apply_filters( 'cancel_comment_reply_link', $formatted_link, $link, $text ); } /** * Displays HTML content for cancel comment reply link. * * @since 2.7.0 * * @param string $text Optional. Text to display for cancel reply link. If empty, * defaults to 'Click here to cancel reply'. Default empty. */ function cancel_comment_reply_link( $text = '' ) { echo get_cancel_comment_reply_link( $text ); } /** * Retrieves hidden input HTML for replying to comments. * * @since 3.0.0 * * @param int $post_id Optional. Post ID. Defaults to the current post ID. * @return string Hidden input HTML for replying to comments. */ function get_comment_id_fields( $post_id = 0 ) { if ( empty( $post_id ) ) { $post_id = get_the_ID(); } $reply_to_id = isset( $_GET['replytocom'] ) ? (int) $_GET['replytocom'] : 0; $result = "\n"; $result .= "\n"; /** * Filters the returned comment ID fields. * * @since 3.0.0 * * @param string $result The HTML-formatted hidden ID field comment elements. * @param int $post_id The post ID. * @param int $reply_to_id The ID of the comment being replied to. */ return apply_filters( 'comment_id_fields', $result, $post_id, $reply_to_id ); } /** * Outputs hidden input HTML for replying to comments. * * Adds two hidden inputs to the comment form to identify the `comment_post_ID` * and `comment_parent` values for threaded comments. * * This tag must be within the `
` section of the `comments.php` template. * * @since 2.7.0 * * @see get_comment_id_fields() * * @param int $post_id Optional. Post ID. Defaults to the current post ID. */ function comment_id_fields( $post_id = 0 ) { echo get_comment_id_fields( $post_id ); } /** * Displays text based on comment reply status. * * Only affects users with JavaScript disabled. * * @internal The $comment global must be present to allow template tags access to the current * comment. See https://core.trac.wordpress.org/changeset/36512. * * @since 2.7.0 * * @global WP_Comment $comment Global comment object. * * @param string $no_reply_text Optional. Text to display when not replying to a comment. * Default false. * @param string $reply_text Optional. Text to display when replying to a comment. * Default false. Accepts "%s" for the author of the comment * being replied to. * @param string $link_to_parent Optional. Boolean to control making the author's name a link * to their comment. Default true. */ function comment_form_title( $no_reply_text = false, $reply_text = false, $link_to_parent = true ) { global $comment; if ( false === $no_reply_text ) { $no_reply_text = __( 'Leave a Reply' ); } if ( false === $reply_text ) { /* translators: %s: Author of the comment being replied to. */ $reply_text = __( 'Leave a Reply to %s' ); } $reply_to_id = isset( $_GET['replytocom'] ) ? (int) $_GET['replytocom'] : 0; if ( 0 == $reply_to_id ) { echo $no_reply_text; } else { // Sets the global so that template tags can be used in the comment form. $comment = get_comment( $reply_to_id ); if ( $link_to_parent ) { $author = '' . get_comment_author( $comment ) . ''; } else { $author = get_comment_author( $comment ); } printf( $reply_text, $author ); } } /** * Displays a list of comments. * * Used in the comments.php template to list comments for a particular post. * * @since 2.7.0 * * @see WP_Query->comments * * @global WP_Query $wp_query WordPress Query object. * @global int $comment_alt * @global int $comment_depth * @global int $comment_thread_alt * @global bool $overridden_cpage * @global bool $in_comment_loop * * @param string|array $args { * Optional. Formatting options. * * @type object $walker Instance of a Walker class to list comments. Default null. * @type int $max_depth The maximum comments depth. Default empty. * @type string $style The style of list ordering. Accepts 'ul', 'ol', or 'div'. * 'div' will result in no additional list markup. Default 'ul'. * @type callable $callback Callback function to use. Default null. * @type callable $end-callback Callback function to use at the end. Default null. * @type string $type Type of comments to list. Accepts 'all', 'comment', * 'pingback', 'trackback', 'pings'. Default 'all'. * @type int $page Page ID to list comments for. Default empty. * @type int $per_page Number of comments to list per page. Default empty. * @type int $avatar_size Height and width dimensions of the avatar size. Default 32. * @type bool $reverse_top_level Ordering of the listed comments. If true, will display * newest comments first. Default null. * @type bool $reverse_children Whether to reverse child comments in the list. Default null. * @type string $format How to format the comments list. Accepts 'html5', 'xhtml'. * Default 'html5' if the theme supports it. * @type bool $short_ping Whether to output short pings. Default false. * @type bool $echo Whether to echo the output or return it. Default true. * } * @param WP_Comment[] $comments Optional. Array of WP_Comment objects. * @return void|string Void if 'echo' argument is true, or no comments to list. * Otherwise, HTML list of comments. */ function wp_list_comments( $args = array(), $comments = null ) { global $wp_query, $comment_alt, $comment_depth, $comment_thread_alt, $overridden_cpage, $in_comment_loop; $in_comment_loop = true; $comment_alt = 0; $comment_thread_alt = 0; $comment_depth = 1; $defaults = array( 'walker' => null, 'max_depth' => '', 'style' => 'ul', 'callback' => null, 'end-callback' => null, 'type' => 'all', 'page' => '', 'per_page' => '', 'avatar_size' => 32, 'reverse_top_level' => null, 'reverse_children' => '', 'format' => current_theme_supports( 'html5', 'comment-list' ) ? 'html5' : 'xhtml', 'short_ping' => false, 'echo' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); /** * Filters the arguments used in retrieving the comment list. * * @since 4.0.0 * * @see wp_list_comments() * * @param array $parsed_args An array of arguments for displaying comments. */ $parsed_args = apply_filters( 'wp_list_comments_args', $parsed_args ); // Figure out what comments we'll be looping through ($_comments). if ( null !== $comments ) { $comments = (array) $comments; if ( empty( $comments ) ) { return; } if ( 'all' !== $parsed_args['type'] ) { $comments_by_type = separate_comments( $comments ); if ( empty( $comments_by_type[ $parsed_args['type'] ] ) ) { return; } $_comments = $comments_by_type[ $parsed_args['type'] ]; } else { $_comments = $comments; } } else { /* * If 'page' or 'per_page' has been passed, and does not match what's in $wp_query, * perform a separate comment query and allow Walker_Comment to paginate. */ if ( $parsed_args['page'] || $parsed_args['per_page'] ) { $current_cpage = get_query_var( 'cpage' ); if ( ! $current_cpage ) { $current_cpage = 'newest' === get_option( 'default_comments_page' ) ? 1 : $wp_query->max_num_comment_pages; } $current_per_page = get_query_var( 'comments_per_page' ); if ( $parsed_args['page'] != $current_cpage || $parsed_args['per_page'] != $current_per_page ) { $comment_args = array( 'post_id' => get_the_ID(), 'orderby' => 'comment_date_gmt', 'order' => 'ASC', 'status' => 'approve', ); if ( is_user_logged_in() ) { $comment_args['include_unapproved'] = array( get_current_user_id() ); } else { $unapproved_email = wp_get_unapproved_comment_author_email(); if ( $unapproved_email ) { $comment_args['include_unapproved'] = array( $unapproved_email ); } } $comments = get_comments( $comment_args ); if ( 'all' !== $parsed_args['type'] ) { $comments_by_type = separate_comments( $comments ); if ( empty( $comments_by_type[ $parsed_args['type'] ] ) ) { return; } $_comments = $comments_by_type[ $parsed_args['type'] ]; } else { $_comments = $comments; } } // Otherwise, fall back on the comments from `$wp_query->comments`. } else { if ( empty( $wp_query->comments ) ) { return; } if ( 'all' !== $parsed_args['type'] ) { if ( empty( $wp_query->comments_by_type ) ) { $wp_query->comments_by_type = separate_comments( $wp_query->comments ); } if ( empty( $wp_query->comments_by_type[ $parsed_args['type'] ] ) ) { return; } $_comments = $wp_query->comments_by_type[ $parsed_args['type'] ]; } else { $_comments = $wp_query->comments; } if ( $wp_query->max_num_comment_pages ) { $default_comments_page = get_option( 'default_comments_page' ); $cpage = get_query_var( 'cpage' ); if ( 'newest' === $default_comments_page ) { $parsed_args['cpage'] = $cpage; /* * When first page shows oldest comments, post permalink is the same as * the comment permalink. */ } elseif ( 1 == $cpage ) { $parsed_args['cpage'] = ''; } else { $parsed_args['cpage'] = $cpage; } $parsed_args['page'] = 0; $parsed_args['per_page'] = 0; } } } if ( '' === $parsed_args['per_page'] && get_option( 'page_comments' ) ) { $parsed_args['per_page'] = get_query_var( 'comments_per_page' ); } if ( empty( $parsed_args['per_page'] ) ) { $parsed_args['per_page'] = 0; $parsed_args['page'] = 0; } if ( '' === $parsed_args['max_depth'] ) { if ( get_option( 'thread_comments' ) ) { $parsed_args['max_depth'] = get_option( 'thread_comments_depth' ); } else { $parsed_args['max_depth'] = -1; } } if ( '' === $parsed_args['page'] ) { if ( empty( $overridden_cpage ) ) { $parsed_args['page'] = get_query_var( 'cpage' ); } else { $threaded = ( -1 != $parsed_args['max_depth'] ); $parsed_args['page'] = ( 'newest' === get_option( 'default_comments_page' ) ) ? get_comment_pages_count( $_comments, $parsed_args['per_page'], $threaded ) : 1; set_query_var( 'cpage', $parsed_args['page'] ); } } // Validation check. $parsed_args['page'] = intval( $parsed_args['page'] ); if ( 0 == $parsed_args['page'] && 0 != $parsed_args['per_page'] ) { $parsed_args['page'] = 1; } if ( null === $parsed_args['reverse_top_level'] ) { $parsed_args['reverse_top_level'] = ( 'desc' === get_option( 'comment_order' ) ); } wp_queue_comments_for_comment_meta_lazyload( $_comments ); if ( empty( $parsed_args['walker'] ) ) { $walker = new Walker_Comment; } else { $walker = $parsed_args['walker']; } $output = $walker->paged_walk( $_comments, $parsed_args['max_depth'], $parsed_args['page'], $parsed_args['per_page'], $parsed_args ); $in_comment_loop = false; if ( $parsed_args['echo'] ) { echo $output; } else { return $output; } } /** * Outputs a complete commenting form for use within a template. * * Most strings and form fields may be controlled through the $args array passed * into the function, while you may also choose to use the {@see 'comment_form_default_fields'} * filter to modify the array of default fields if you'd just like to add a new * one or remove a single field. All fields are also individually passed through * a filter of the {@see 'comment_form_field_$name'} where $name is the key used * in the array of fields. * * @since 3.0.0 * @since 4.1.0 Introduced the 'class_submit' argument. * @since 4.2.0 Introduced the 'submit_button' and 'submit_fields' arguments. * @since 4.4.0 Introduced the 'class_form', 'title_reply_before', 'title_reply_after', * 'cancel_reply_before', and 'cancel_reply_after' arguments. * @since 4.5.0 The 'author', 'email', and 'url' form fields are limited to 245, 100, * and 200 characters, respectively. * @since 4.6.0 Introduced the 'action' argument. * @since 4.9.6 Introduced the 'cookies' default comment field. * @since 5.5.0 Introduced the 'class_container' argument. * * @param array $args { * Optional. Default arguments and form fields to override. * * @type array $fields { * Default comment fields, filterable by default via the {@see 'comment_form_default_fields'} hook. * * @type string $author Comment author field HTML. * @type string $email Comment author email field HTML. * @type string $url Comment author URL field HTML. * @type string $cookies Comment cookie opt-in field HTML. * } * @type string $comment_field The comment textarea field HTML. * @type string $must_log_in HTML element for a 'must be logged in to comment' message. * @type string $logged_in_as HTML element for a 'logged in as [user]' message. * @type string $comment_notes_before HTML element for a message displayed before the comment fields * if the user is not logged in. * Default 'Your email address will not be published.'. * @type string $comment_notes_after HTML element for a message displayed after the textarea field. * @type string $action The comment form element action attribute. Default '/wp-comments-post.php'. * @type string $id_form The comment form element id attribute. Default 'commentform'. * @type string $id_submit The comment submit element id attribute. Default 'submit'. * @type string $class_container The comment form container class attribute. Default 'comment-respond'. * @type string $class_form The comment form element class attribute. Default 'comment-form'. * @type string $class_submit The comment submit element class attribute. Default 'submit'. * @type string $name_submit The comment submit element name attribute. Default 'submit'. * @type string $title_reply The translatable 'reply' button label. Default 'Leave a Reply'. * @type string $title_reply_to The translatable 'reply-to' button label. Default 'Leave a Reply to %s', * where %s is the author of the comment being replied to. * @type string $title_reply_before HTML displayed before the comment form title. * Default: '

'. * @type string $title_reply_after HTML displayed after the comment form title. * Default: '

'. * @type string $cancel_reply_before HTML displayed before the cancel reply link. * @type string $cancel_reply_after HTML displayed after the cancel reply link. * @type string $cancel_reply_link The translatable 'cancel reply' button label. Default 'Cancel reply'. * @type string $label_submit The translatable 'submit' button label. Default 'Post a comment'. * @type string $submit_button HTML format for the Submit button. * Default: ''. * @type string $submit_field HTML format for the markup surrounding the Submit button and comment hidden * fields. Default: '

%1$s %2$s

', where %1$s is the * submit button markup and %2$s is the comment hidden fields. * @type string $format The comment form format. Default 'xhtml'. Accepts 'xhtml', 'html5'. * } * @param int|WP_Post $post_id Post ID or WP_Post object to generate the form for. Default current post. */ function comment_form( $args = array(), $post_id = null ) { if ( null === $post_id ) { $post_id = get_the_ID(); } // Exit the function when comments for the post are closed. if ( ! comments_open( $post_id ) ) { /** * Fires after the comment form if comments are closed. * * @since 3.0.0 */ do_action( 'comment_form_comments_closed' ); return; } $commenter = wp_get_current_commenter(); $user = wp_get_current_user(); $user_identity = $user->exists() ? $user->display_name : ''; $args = wp_parse_args( $args ); if ( ! isset( $args['format'] ) ) { $args['format'] = current_theme_supports( 'html5', 'comment-form' ) ? 'html5' : 'xhtml'; } $req = get_option( 'require_name_email' ); $html_req = ( $req ? " required='required'" : '' ); $html5 = 'html5' === $args['format']; $fields = array( 'author' => sprintf( '

%s %s

', sprintf( '', __( 'Name' ), ( $req ? ' *' : '' ) ), sprintf( '', esc_attr( $commenter['comment_author'] ), $html_req ) ), 'email' => sprintf( '', sprintf( '', __( 'Email' ), ( $req ? ' *' : '' ) ), sprintf( '', ( $html5 ? 'type="email"' : 'type="text"' ), esc_attr( $commenter['comment_author_email'] ), $html_req ) ), 'url' => sprintf( '

%s %s

', sprintf( '', __( 'Website' ) ), sprintf( '', ( $html5 ? 'type="url"' : 'type="text"' ), esc_attr( $commenter['comment_author_url'] ) ) ), ); if ( has_action( 'set_comment_cookies', 'wp_set_comment_cookies' ) && get_option( 'show_comments_cookies_opt_in' ) ) { $consent = empty( $commenter['comment_author_email'] ) ? '' : ' checked="checked"'; $fields['cookies'] = sprintf( '', sprintf( '', $consent ), sprintf( '', __( 'Save my name, email, and website in this browser for the next time I comment.' ) ) ); // Ensure that the passed fields include cookies consent. if ( isset( $args['fields'] ) && ! isset( $args['fields']['cookies'] ) ) { $args['fields']['cookies'] = $fields['cookies']; } } $required_text = sprintf( /* translators: %s: Asterisk symbol (*). */ ' ' . __( 'Required fields are marked %s' ), '*' ); /** * Filters the default comment form fields. * * @since 3.0.0 * * @param string[] $fields Array of the default comment fields. */ $fields = apply_filters( 'comment_form_default_fields', $fields ); $defaults = array( 'fields' => $fields, 'comment_field' => sprintf( '

%s %s

', sprintf( '', _x( 'Comment', 'noun' ) ), '' ), 'must_log_in' => sprintf( '', sprintf( /* translators: %s: Login URL. */ __( 'You must be logged in to post a comment.' ), /** This filter is documented in wp-includes/link-template.php */ wp_login_url( apply_filters( 'the_permalink', get_permalink( $post_id ), $post_id ) ) ) ), 'logged_in_as' => sprintf( '

%s

', sprintf( /* translators: 1: Edit user link, 2: Accessibility text, 3: User name, 4: Logout URL. */ __( 'Logged in as %3$s. Log out?' ), get_edit_user_link(), /* translators: %s: User name. */ esc_attr( sprintf( __( 'Logged in as %s. Edit your profile.' ), $user_identity ) ), $user_identity, /** This filter is documented in wp-includes/link-template.php */ wp_logout_url( apply_filters( 'the_permalink', get_permalink( $post_id ), $post_id ) ) ) ), 'comment_notes_before' => sprintf( '

%s%s

', sprintf( '%s', __( 'Your email address will not be published.' ) ), ( $req ? $required_text : '' ) ), 'comment_notes_after' => '', 'action' => site_url( '/wp-comments-post.php' ), 'id_form' => 'commentform', 'id_submit' => 'submit', 'class_container' => 'comment-respond', 'class_form' => 'comment-form', 'class_submit' => 'submit', 'name_submit' => 'submit', 'title_reply' => __( 'Leave a Reply' ), /* translators: %s: Author of the comment being replied to. */ 'title_reply_to' => __( 'Leave a Reply to %s' ), 'title_reply_before' => '

', 'title_reply_after' => '

', 'cancel_reply_before' => ' ', 'cancel_reply_after' => '', 'cancel_reply_link' => __( 'Cancel reply' ), 'label_submit' => __( 'Post Comment' ), 'submit_button' => '', 'submit_field' => '

%1$s %2$s

', 'format' => 'xhtml', ); /** * Filters the comment form default arguments. * * Use {@see 'comment_form_default_fields'} to filter the comment fields. * * @since 3.0.0 * * @param array $defaults The default comment form arguments. */ $args = wp_parse_args( $args, apply_filters( 'comment_form_defaults', $defaults ) ); // Ensure that the filtered arguments contain all required default values. $args = array_merge( $defaults, $args ); // Remove `aria-describedby` from the email field if there's no associated description. if ( isset( $args['fields']['email'] ) && false === strpos( $args['comment_notes_before'], 'id="email-notes"' ) ) { $args['fields']['email'] = str_replace( ' aria-describedby="email-notes"', '', $args['fields']['email'] ); } /** * Fires before the comment form. * * @since 3.0.0 */ do_action( 'comment_form_before' ); ?>
', esc_url( $args['action'] ), esc_attr( $args['id_form'] ), esc_attr( $args['class_form'] ), ( $html5 ? ' novalidate' : '' ) ); /** * Fires at the top of the comment form, inside the form tag. * * @since 3.0.0 */ do_action( 'comment_form_top' ); if ( is_user_logged_in() ) : /** * Filters the 'logged in' message for the comment form for display. * * @since 3.0.0 * * @param string $args_logged_in The logged-in-as HTML-formatted message. * @param array $commenter An array containing the comment author's * username, email, and URL. * @param string $user_identity If the commenter is a registered user, * the display name, blank otherwise. */ echo apply_filters( 'comment_form_logged_in', $args['logged_in_as'], $commenter, $user_identity ); /** * Fires after the is_user_logged_in() check in the comment form. * * @since 3.0.0 * * @param array $commenter An array containing the comment author's * username, email, and URL. * @param string $user_identity If the commenter is a registered user, * the display name, blank otherwise. */ do_action( 'comment_form_logged_in_after', $commenter, $user_identity ); else : echo $args['comment_notes_before']; endif; // Prepare an array of all fields, including the textarea. $comment_fields = array( 'comment' => $args['comment_field'] ) + (array) $args['fields']; /** * Filters the comment form fields, including the textarea. * * @since 4.4.0 * * @param array $comment_fields The comment fields. */ $comment_fields = apply_filters( 'comment_form_fields', $comment_fields ); // Get an array of field names, excluding the textarea. $comment_field_keys = array_diff( array_keys( $comment_fields ), array( 'comment' ) ); // Get the first and the last field name, excluding the textarea. $first_field = reset( $comment_field_keys ); $last_field = end( $comment_field_keys ); foreach ( $comment_fields as $name => $field ) { if ( 'comment' === $name ) { /** * Filters the content of the comment textarea field for display. * * @since 3.0.0 * * @param string $args_comment_field The content of the comment textarea field. */ echo apply_filters( 'comment_form_field_comment', $field ); echo $args['comment_notes_after']; } elseif ( ! is_user_logged_in() ) { if ( $first_field === $name ) { /** * Fires before the comment fields in the comment form, excluding the textarea. * * @since 3.0.0 */ do_action( 'comment_form_before_fields' ); } /** * Filters a comment form field for display. * * The dynamic portion of the filter hook, `$name`, refers to the name * of the comment form field. Such as 'author', 'email', or 'url'. * * @since 3.0.0 * * @param string $field The HTML-formatted output of the comment form field. */ echo apply_filters( "comment_form_field_{$name}", $field ) . "\n"; if ( $last_field === $name ) { /** * Fires after the comment fields in the comment form, excluding the textarea. * * @since 3.0.0 */ do_action( 'comment_form_after_fields' ); } } } $submit_button = sprintf( $args['submit_button'], esc_attr( $args['name_submit'] ), esc_attr( $args['id_submit'] ), esc_attr( $args['class_submit'] ), esc_attr( $args['label_submit'] ) ); /** * Filters the submit button for the comment form to display. * * @since 4.2.0 * * @param string $submit_button HTML markup for the submit button. * @param array $args Arguments passed to comment_form(). */ $submit_button = apply_filters( 'comment_form_submit_button', $submit_button, $args ); $submit_field = sprintf( $args['submit_field'], $submit_button, get_comment_id_fields( $post_id ) ); /** * Filters the submit field for the comment form to display. * * The submit field includes the submit button, hidden fields for the * comment form, and any wrapper markup. * * @since 4.2.0 * * @param string $submit_field HTML markup for the submit field. * @param array $args Arguments passed to comment_form(). */ echo apply_filters( 'comment_form_submit_field', $submit_field, $args ); /** * Fires at the bottom of the comment form, inside the closing form tag. * * @since 1.5.0 * * @param int $post_id The post ID. */ do_action( 'comment_form', $post_id ); echo ''; endif; ?>
get( $var, $default ); } /** * Retrieve the currently-queried object. * * Wrapper for WP_Query::get_queried_object(). * * @since 3.1.0 * * @global WP_Query $wp_query WordPress Query object. * * @return object Queried object. */ function get_queried_object() { global $wp_query; return $wp_query->get_queried_object(); } /** * Retrieve ID of the current queried object. * * Wrapper for WP_Query::get_queried_object_id(). * * @since 3.1.0 * * @global WP_Query $wp_query WordPress Query object. * * @return int ID of the queried object. */ function get_queried_object_id() { global $wp_query; return $wp_query->get_queried_object_id(); } /** * Set query variable. * * @since 2.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @param string $var Query variable key. * @param mixed $value Query variable value. */ function set_query_var( $var, $value ) { global $wp_query; $wp_query->set( $var, $value ); } /** * Sets up The Loop with query parameters. * * Note: This function will completely override the main query and isn't intended for use * by plugins or themes. Its overly-simplistic approach to modifying the main query can be * problematic and should be avoided wherever possible. In most cases, there are better, * more performant options for modifying the main query such as via the {@see 'pre_get_posts'} * action within WP_Query. * * This must not be used within the WordPress Loop. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param array|string $query Array or string of WP_Query arguments. * @return WP_Post[]|int[] Array of post objects or post IDs. */ function query_posts( $query ) { $GLOBALS['wp_query'] = new WP_Query(); return $GLOBALS['wp_query']->query( $query ); } /** * Destroys the previous query and sets up a new query. * * This should be used after query_posts() and before another query_posts(). * This will remove obscure bugs that occur when the previous WP_Query object * is not destroyed properly before another is set up. * * @since 2.3.0 * * @global WP_Query $wp_query WordPress Query object. * @global WP_Query $wp_the_query Copy of the global WP_Query instance created during wp_reset_query(). */ function wp_reset_query() { $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; wp_reset_postdata(); } /** * After looping through a separate query, this function restores * the $post global to the current post in the main query. * * @since 3.0.0 * * @global WP_Query $wp_query WordPress Query object. */ function wp_reset_postdata() { global $wp_query; if ( isset( $wp_query ) ) { $wp_query->reset_postdata(); } } /* * Query type checks. */ /** * Determines whether the query is for an existing archive page. * * Month, Year, Category, Author, Post Type archive... * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for an existing archive page. */ function is_archive() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_archive(); } /** * Determines whether the query is for an existing post type archive page. * * 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 3.1.0 * * @global WP_Query $wp_query WordPress Query object. * * @param string|string[] $post_types Optional. Post type or array of posts types * to check against. Default empty. * @return bool Whether the query is for an existing post type archive page. */ function is_post_type_archive( $post_types = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_post_type_archive( $post_types ); } /** * Determines whether the query is for an existing attachment page. * * 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.0.0 * * @global WP_Query $wp_query WordPress Query object. * * @param int|string|int[]|string[] $attachment Optional. Attachment ID, title, slug, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing attachment page. */ function is_attachment( $attachment = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_attachment( $attachment ); } /** * Determines whether the query is for an existing author archive page. * * If the $author parameter is specified, this function will additionally * check if the query is for one of the authors specified. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param int|string|int[]|string[] $author Optional. User ID, nickname, nicename, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing author archive page. */ function is_author( $author = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_author( $author ); } /** * Determines whether the query is for an existing category archive page. * * If the $category parameter is specified, this function will additionally * check if the query is for one of the categories specified. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param int|string|int[]|string[] $category Optional. Category ID, name, slug, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing category archive page. */ function is_category( $category = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_category( $category ); } /** * Determines whether the query is for an existing tag archive page. * * If the $tag parameter is specified, this function will additionally * check if the query is for one of the tags specified. * * 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.3.0 * * @global WP_Query $wp_query WordPress Query object. * * @param int|string|int[]|string[] $tag Optional. Tag ID, name, slug, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing tag archive page. */ function is_tag( $tag = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_tag( $tag ); } /** * Determines whether the query is for an existing custom taxonomy archive page. * * If the $taxonomy parameter is specified, this function will additionally * check if the query is for that specific $taxonomy. * * If the $term parameter is specified in addition to the $taxonomy parameter, * this function will additionally check if the query is for one of the terms * specified. * * 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 * * @global WP_Query $wp_query WordPress Query object. * * @param string|string[] $taxonomy Optional. Taxonomy slug or slugs to check against. * Default empty. * @param int|string|int[]|string[] $term Optional. Term ID, name, slug, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing custom taxonomy archive page. * True for custom taxonomy archive pages, false for built-in taxonomies * (category and tag archives). */ function is_tax( $taxonomy = '', $term = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_tax( $taxonomy, $term ); } /** * Determines whether the query is for an existing date archive. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for an existing date archive. */ function is_date() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_date(); } /** * Determines whether the query is for an existing day archive. * * A conditional check to test whether the page is a date-based archive page displaying posts for the current day. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for an existing day archive. */ function is_day() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_day(); } /** * Determines whether the query is for a feed. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param string|string[] $feeds Optional. Feed type or array of feed types * to check against. Default empty. * @return bool Whether the query is for a feed. */ function is_feed( $feeds = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_feed( $feeds ); } /** * Is the query for a comments feed? * * @since 3.0.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for a comments feed. */ function is_comment_feed() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_comment_feed(); } /** * Determines whether the query is for the front page of the site. * * This is for what is displayed at your site's main URL. * * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'. * * If you set a static page for the front page of your site, this function will return * true when viewing that page. * * Otherwise the same as @see is_home() * * 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 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for the front page of the site. */ function is_front_page() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_front_page(); } /** * Determines whether the query is for the blog homepage. * * The blog homepage is the page that shows the time-based blog content of the site. * * is_home() is dependent on the site's "Front page displays" Reading Settings 'show_on_front' * and 'page_for_posts'. * * If a static page is set for the front page of the site, this function will return true only * on the page you set as the "Posts page". * * 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 1.5.0 * * @see is_front_page() * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for the blog homepage. */ function is_home() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_home(); } /** * Determines whether the query is for the Privacy Policy page. * * The Privacy Policy page is the page that shows the Privacy Policy content of the site. * * is_privacy_policy() is dependent on the site's "Change your Privacy Policy page" Privacy Settings 'wp_page_for_privacy_policy'. * * This function will return true only on the page you set as the "Privacy Policy page". * * 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 5.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for the Privacy Policy page. */ function is_privacy_policy() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_privacy_policy(); } /** * Determines whether the query is for an existing month archive. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for an existing month archive. */ function is_month() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_month(); } /** * Determines whether the query is for an existing single page. * * If the $page parameter is specified, this function will additionally * check if the query is for one of the pages specified. * * 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. * * @see is_single() * @see is_singular() * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param int|string|int[]|string[] $page Optional. Page ID, title, slug, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing single page. */ function is_page( $page = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_page( $page ); } /** * Determines whether the query is for a paged result and not for the first page. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for a paged result. */ function is_paged() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_paged(); } /** * Determines whether the query is for a post or page preview. * * 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.0.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for a post or page preview. */ function is_preview() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_preview(); } /** * Is the query for the robots.txt file? * * @since 2.1.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for the robots.txt file. */ function is_robots() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_robots(); } /** * Is the query for the favicon.ico file? * * @since 5.4.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for the favicon.ico file. */ function is_favicon() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_favicon(); } /** * Determines whether the query is for a search. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for a search. */ function is_search() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_search(); } /** * Determines whether the query is for an existing single post. * * Works for any post type, except attachments and pages * * If the $post parameter is specified, this function will additionally * check if the query is for one of the Posts specified. * * 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. * * @see is_page() * @see is_singular() * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param int|string|int[]|string[] $post Optional. Post ID, title, slug, or array of such * to check against. Default empty. * @return bool Whether the query is for an existing single post. */ function is_single( $post = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_single( $post ); } /** * Determines whether the query is for an existing single post of any post type * (post, attachment, page, custom post types). * * If the $post_types parameter is specified, this function will additionally * check if the query is for one of the Posts Types specified. * * 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. * * @see is_page() * @see is_single() * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @param string|string[] $post_types Optional. Post type or array of post types * to check against. Default empty. * @return bool Whether the query is for an existing single post * or any of the given post types. */ function is_singular( $post_types = '' ) { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_singular( $post_types ); } /** * Determines whether the query is for a specific time. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for a specific time. */ function is_time() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_time(); } /** * Determines whether the query is for a trackback endpoint call. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for a trackback endpoint call. */ function is_trackback() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_trackback(); } /** * Determines whether the query is for an existing year archive. * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for an existing year archive. */ function is_year() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_year(); } /** * Determines whether the query has resulted in a 404 (returns no results). * * 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 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is a 404 error. */ function is_404() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_404(); } /** * Is the query for an embedded post? * * @since 4.4.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is for an embedded post. */ function is_embed() { global $wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; } return $wp_query->is_embed(); } /** * Determines whether the query is the main query. * * 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 3.3.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool Whether the query is the main query. */ function is_main_query() { if ( 'pre_get_posts' === current_filter() ) { $message = sprintf( /* translators: 1: pre_get_posts, 2: WP_Query->is_main_query(), 3: is_main_query(), 4: Link to codex is_main_query() page. */ __( 'In %1$s, use the %2$s method, not the %3$s function. See %4$s.' ), 'pre_get_posts', 'WP_Query->is_main_query()', 'is_main_query()', __( 'https://codex.wordpress.org/Function_Reference/is_main_query' ) ); _doing_it_wrong( __FUNCTION__, $message, '3.7.0' ); } global $wp_query; return $wp_query->is_main_query(); } /* * The Loop. Post loop control. */ /** * Determines whether current WordPress query has posts to loop over. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool True if posts are available, false if end of the loop. */ function have_posts() { global $wp_query; return $wp_query->have_posts(); } /** * Determines whether the caller is in the Loop. * * 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.0.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool True if caller is within loop, false if loop hasn't started or ended. */ function in_the_loop() { global $wp_query; return $wp_query->in_the_loop; } /** * Rewind the loop posts. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. */ function rewind_posts() { global $wp_query; $wp_query->rewind_posts(); } /** * Iterate the post index in the loop. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. */ function the_post() { global $wp_query; $wp_query->the_post(); } /* * Comments loop. */ /** * Determines whether current WordPress query has comments to loop over. * * @since 2.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool True if comments are available, false if no more comments. */ function have_comments() { global $wp_query; return $wp_query->have_comments(); } /** * Iterate comment index in the comment loop. * * @since 2.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @return object */ function the_comment() { global $wp_query; return $wp_query->the_comment(); } /** * Redirect old slugs to the correct permalink. * * Attempts to find the current slug from the past slugs. * * @since 2.1.0 */ function wp_old_slug_redirect() { if ( is_404() && '' !== get_query_var( 'name' ) ) { // Guess the current post type based on the query vars. if ( get_query_var( 'post_type' ) ) { $post_type = get_query_var( 'post_type' ); } elseif ( get_query_var( 'attachment' ) ) { $post_type = 'attachment'; } elseif ( get_query_var( 'pagename' ) ) { $post_type = 'page'; } else { $post_type = 'post'; } if ( is_array( $post_type ) ) { if ( count( $post_type ) > 1 ) { return; } $post_type = reset( $post_type ); } // Do not attempt redirect for hierarchical post types. if ( is_post_type_hierarchical( $post_type ) ) { return; } $id = _find_post_by_old_slug( $post_type ); if ( ! $id ) { $id = _find_post_by_old_date( $post_type ); } /** * Filters the old slug redirect post ID. * * @since 4.9.3 * * @param int $id The redirect post ID. */ $id = apply_filters( 'old_slug_redirect_post_id', $id ); if ( ! $id ) { return; } $link = get_permalink( $id ); if ( get_query_var( 'paged' ) > 1 ) { $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . get_query_var( 'paged' ) ); } elseif ( is_embed() ) { $link = user_trailingslashit( trailingslashit( $link ) . 'embed' ); } /** * Filters the old slug redirect URL. * * @since 4.4.0 * * @param string $link The redirect URL. */ $link = apply_filters( 'old_slug_redirect_url', $link ); if ( ! $link ) { return; } wp_redirect( $link, 301 ); // Permanent redirect. exit; } } /** * Find the post ID for redirecting an old slug. * * @see wp_old_slug_redirect() * * @since 4.9.3 * @access private * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $post_type The current post type based on the query vars. * @return int The Post ID. */ function _find_post_by_old_slug( $post_type ) { global $wpdb; $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, get_query_var( 'name' ) ); // If year, monthnum, or day have been specified, make our query more precise // just in case there are multiple identical _wp_old_slug values. if ( get_query_var( 'year' ) ) { $query .= $wpdb->prepare( ' AND YEAR(post_date) = %d', get_query_var( 'year' ) ); } if ( get_query_var( 'monthnum' ) ) { $query .= $wpdb->prepare( ' AND MONTH(post_date) = %d', get_query_var( 'monthnum' ) ); } if ( get_query_var( 'day' ) ) { $query .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) ); } $id = (int) $wpdb->get_var( $query ); return $id; } /** * Find the post ID for redirecting an old date. * * @see wp_old_slug_redirect() * * @since 4.9.3 * @access private * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $post_type The current post type based on the query vars. * @return int The Post ID. */ function _find_post_by_old_date( $post_type ) { global $wpdb; $date_query = ''; if ( get_query_var( 'year' ) ) { $date_query .= $wpdb->prepare( ' AND YEAR(pm_date.meta_value) = %d', get_query_var( 'year' ) ); } if ( get_query_var( 'monthnum' ) ) { $date_query .= $wpdb->prepare( ' AND MONTH(pm_date.meta_value) = %d', get_query_var( 'monthnum' ) ); } if ( get_query_var( 'day' ) ) { $date_query .= $wpdb->prepare( ' AND DAYOFMONTH(pm_date.meta_value) = %d', get_query_var( 'day' ) ); } $id = 0; if ( $date_query ) { $id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta AS pm_date, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_date' AND post_name = %s" . $date_query, $post_type, get_query_var( 'name' ) ) ); if ( ! $id ) { // Check to see if an old slug matches the old date. $id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts, $wpdb->postmeta AS pm_slug, $wpdb->postmeta AS pm_date WHERE ID = pm_slug.post_id AND ID = pm_date.post_id AND post_type = %s AND pm_slug.meta_key = '_wp_old_slug' AND pm_slug.meta_value = %s AND pm_date.meta_key = '_wp_old_date'" . $date_query, $post_type, get_query_var( 'name' ) ) ); } } return $id; } /** * Set up global post data. * * @since 1.5.0 * @since 4.4.0 Added the ability to pass a post ID to `$post`. * * @global WP_Query $wp_query WordPress Query object. * * @param WP_Post|object|int $post WP_Post instance or Post ID/object. * @return bool True when finished. */ function setup_postdata( $post ) { global $wp_query; if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { return $wp_query->setup_postdata( $post ); } return false; } /** * Generates post data. * * @since 5.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @param WP_Post|object|int $post WP_Post instance or Post ID/object. * @return array|bool Elements of post, or false on failure. */ function generate_postdata( $post ) { global $wp_query; if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { return $wp_query->generate_postdata( $post ); } return false; } class-wp-customize-section.php000064400000025336150320557470012511 0ustar00$key = $args[ $key ]; } } $this->manager = $manager; $this->id = $id; if ( empty( $this->active_callback ) ) { $this->active_callback = array( $this, 'active_callback' ); } self::$instance_count += 1; $this->instance_number = self::$instance_count; $this->controls = array(); // Users cannot customize the $controls array. } /** * Check whether section is active to current Customizer preview. * * @since 4.1.0 * * @return bool Whether the section is active to the current preview. */ final public function active() { $section = $this; $active = call_user_func( $this->active_callback, $this ); /** * Filters response of WP_Customize_Section::active(). * * @since 4.1.0 * * @param bool $active Whether the Customizer section is active. * @param WP_Customize_Section $section WP_Customize_Section instance. */ $active = apply_filters( 'customize_section_active', $active, $section ); return $active; } /** * Default callback used when invoking WP_Customize_Section::active(). * * Subclasses can override this with their specific logic, or they may provide * an 'active_callback' argument to the constructor. * * @since 4.1.0 * * @return true Always true. */ public function active_callback() { return true; } /** * Gather the parameters passed to client JavaScript via JSON. * * @since 4.1.0 * * @return array The array to be exported to the client as JSON. */ public function json() { $array = wp_array_slice_assoc( (array) $this, array( 'id', 'description', 'priority', 'panel', 'type', 'description_hidden' ) ); $array['title'] = html_entity_decode( $this->title, ENT_QUOTES, get_bloginfo( 'charset' ) ); $array['content'] = $this->get_content(); $array['active'] = $this->active(); $array['instanceNumber'] = $this->instance_number; if ( $this->panel ) { /* translators: ▸ is the unicode right-pointing triangle. %s: Section title in the Customizer. */ $array['customizeAction'] = sprintf( __( 'Customizing ▸ %s' ), esc_html( $this->manager->get_panel( $this->panel )->title ) ); } else { $array['customizeAction'] = __( 'Customizing' ); } return $array; } /** * Checks required user capabilities and whether the theme has the * feature support required by the section. * * @since 3.4.0 * * @return bool False if theme doesn't support the section or user doesn't have the capability. */ final public function check_capabilities() { if ( $this->capability && ! current_user_can( $this->capability ) ) { return false; } if ( $this->theme_supports && ! current_theme_supports( ... (array) $this->theme_supports ) ) { return false; } return true; } /** * Get the section's content for insertion into the Customizer pane. * * @since 4.1.0 * * @return string Contents of the section. */ final public function get_content() { ob_start(); $this->maybe_render(); return trim( ob_get_clean() ); } /** * Check capabilities and render the section. * * @since 3.4.0 */ final public function maybe_render() { if ( ! $this->check_capabilities() ) { return; } /** * Fires before rendering a Customizer section. * * @since 3.4.0 * * @param WP_Customize_Section $this WP_Customize_Section instance. */ do_action( 'customize_render_section', $this ); /** * Fires before rendering a specific Customizer section. * * The dynamic portion of the hook name, `$this->id`, refers to the ID * of the specific Customizer section to be rendered. * * @since 3.4.0 */ do_action( "customize_render_section_{$this->id}" ); $this->render(); } /** * Render the section UI in a subclass. * * Sections are now rendered in JS by default, see WP_Customize_Section::print_template(). * * @since 3.4.0 */ protected function render() {} /** * Render the section's JS template. * * This function is only run for section types that have been registered with * WP_Customize_Manager::register_section_type(). * * @since 4.3.0 * * @see WP_Customize_Manager::render_template() */ public function print_template() { ?>
  • {{ data.title }}

  • link_id, $bookmark, 'bookmark' ); $_bookmark = $bookmark; } else { if ( isset( $GLOBALS['link'] ) && ( $GLOBALS['link']->link_id == $bookmark ) ) { $_bookmark = & $GLOBALS['link']; } else { $_bookmark = wp_cache_get( $bookmark, 'bookmark' ); if ( ! $_bookmark ) { $_bookmark = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->links WHERE link_id = %d LIMIT 1", $bookmark ) ); if ( $_bookmark ) { $_bookmark->link_category = array_unique( wp_get_object_terms( $_bookmark->link_id, 'link_category', array( 'fields' => 'ids' ) ) ); wp_cache_add( $_bookmark->link_id, $_bookmark, 'bookmark' ); } } } } if ( ! $_bookmark ) { return $_bookmark; } $_bookmark = sanitize_bookmark( $_bookmark, $filter ); if ( OBJECT == $output ) { return $_bookmark; } elseif ( ARRAY_A == $output ) { return get_object_vars( $_bookmark ); } elseif ( ARRAY_N == $output ) { return array_values( get_object_vars( $_bookmark ) ); } else { return $_bookmark; } } /** * Retrieve single bookmark data item or field. * * @since 2.3.0 * * @param string $field The name of the data field to return. * @param int $bookmark The bookmark ID to get field. * @param string $context Optional. The context of how the field will be used. * @return string|WP_Error */ function get_bookmark_field( $field, $bookmark, $context = 'display' ) { $bookmark = (int) $bookmark; $bookmark = get_bookmark( $bookmark ); if ( is_wp_error( $bookmark ) ) { return $bookmark; } if ( ! is_object( $bookmark ) ) { return ''; } if ( ! isset( $bookmark->$field ) ) { return ''; } return sanitize_bookmark_field( $field, $bookmark->$field, $bookmark->link_id, $context ); } /** * Retrieves the list of bookmarks * * Attempts to retrieve from the cache first based on MD5 hash of arguments. If * that fails, then the query will be built from the arguments and executed. The * results will be stored to the cache. * * @since 2.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string|array $args { * Optional. String or array of arguments to retrieve bookmarks. * * @type string $orderby How to order the links by. Accepts 'id', 'link_id', 'name', 'link_name', * 'url', 'link_url', 'visible', 'link_visible', 'rating', 'link_rating', * 'owner', 'link_owner', 'updated', 'link_updated', 'notes', 'link_notes', * 'description', 'link_description', 'length' and 'rand'. * When `$orderby` is 'length', orders by the character length of * 'link_name'. Default 'name'. * @type string $order Whether to order bookmarks in ascending or descending order. * Accepts 'ASC' (ascending) or 'DESC' (descending). Default 'ASC'. * @type int $limit Amount of bookmarks to display. Accepts any positive number or * -1 for all. Default -1. * @type string $category Comma-separated list of category IDs to include links from. * Default empty. * @type string $category_name Category to retrieve links for by name. Default empty. * @type int|bool $hide_invisible Whether to show or hide links marked as 'invisible'. Accepts * 1|true or 0|false. Default 1|true. * @type int|bool $show_updated Whether to display the time the bookmark was last updated. * Accepts 1|true or 0|false. Default 0|false. * @type string $include Comma-separated list of bookmark IDs to include. Default empty. * @type string $exclude Comma-separated list of bookmark IDs to exclude. Default empty. * @type string $search Search terms. Will be SQL-formatted with wildcards before and after * and searched in 'link_url', 'link_name' and 'link_description'. * Default empty. * } * @return object[] List of bookmark row objects. */ function get_bookmarks( $args = '' ) { global $wpdb; $defaults = array( 'orderby' => 'name', 'order' => 'ASC', 'limit' => -1, 'category' => '', 'category_name' => '', 'hide_invisible' => 1, 'show_updated' => 0, 'include' => '', 'exclude' => '', 'search' => '', ); $parsed_args = wp_parse_args( $args, $defaults ); $key = md5( serialize( $parsed_args ) ); $cache = wp_cache_get( 'get_bookmarks', 'bookmark' ); if ( 'rand' !== $parsed_args['orderby'] && $cache ) { if ( is_array( $cache ) && isset( $cache[ $key ] ) ) { $bookmarks = $cache[ $key ]; /** * Filters the returned list of bookmarks. * * The first time the hook is evaluated in this file, it returns the cached * bookmarks list. The second evaluation returns a cached bookmarks list if the * link category is passed but does not exist. The third evaluation returns * the full cached results. * * @since 2.1.0 * * @see get_bookmarks() * * @param array $bookmarks List of the cached bookmarks. * @param array $parsed_args An array of bookmark query arguments. */ return apply_filters( 'get_bookmarks', $bookmarks, $parsed_args ); } } if ( ! is_array( $cache ) ) { $cache = array(); } $inclusions = ''; if ( ! empty( $parsed_args['include'] ) ) { $parsed_args['exclude'] = ''; // Ignore exclude, category, and category_name params if using include. $parsed_args['category'] = ''; $parsed_args['category_name'] = ''; $inclinks = wp_parse_id_list( $parsed_args['include'] ); if ( count( $inclinks ) ) { foreach ( $inclinks as $inclink ) { if ( empty( $inclusions ) ) { $inclusions = ' AND ( link_id = ' . $inclink . ' '; } else { $inclusions .= ' OR link_id = ' . $inclink . ' '; } } } } if ( ! empty( $inclusions ) ) { $inclusions .= ')'; } $exclusions = ''; if ( ! empty( $parsed_args['exclude'] ) ) { $exlinks = wp_parse_id_list( $parsed_args['exclude'] ); if ( count( $exlinks ) ) { foreach ( $exlinks as $exlink ) { if ( empty( $exclusions ) ) { $exclusions = ' AND ( link_id <> ' . $exlink . ' '; } else { $exclusions .= ' AND link_id <> ' . $exlink . ' '; } } } } if ( ! empty( $exclusions ) ) { $exclusions .= ')'; } if ( ! empty( $parsed_args['category_name'] ) ) { $parsed_args['category'] = get_term_by( 'name', $parsed_args['category_name'], 'link_category' ); if ( $parsed_args['category'] ) { $parsed_args['category'] = $parsed_args['category']->term_id; } else { $cache[ $key ] = array(); wp_cache_set( 'get_bookmarks', $cache, 'bookmark' ); /** This filter is documented in wp-includes/bookmark.php */ return apply_filters( 'get_bookmarks', array(), $parsed_args ); } } $search = ''; if ( ! empty( $parsed_args['search'] ) ) { $like = '%' . $wpdb->esc_like( $parsed_args['search'] ) . '%'; $search = $wpdb->prepare( ' AND ( (link_url LIKE %s) OR (link_name LIKE %s) OR (link_description LIKE %s) ) ', $like, $like, $like ); } $category_query = ''; $join = ''; if ( ! empty( $parsed_args['category'] ) ) { $incategories = wp_parse_id_list( $parsed_args['category'] ); if ( count( $incategories ) ) { foreach ( $incategories as $incat ) { if ( empty( $category_query ) ) { $category_query = ' AND ( tt.term_id = ' . $incat . ' '; } else { $category_query .= ' OR tt.term_id = ' . $incat . ' '; } } } } if ( ! empty( $category_query ) ) { $category_query .= ") AND taxonomy = 'link_category'"; $join = " INNER JOIN $wpdb->term_relationships AS tr ON ($wpdb->links.link_id = tr.object_id) INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_taxonomy_id = tr.term_taxonomy_id"; } if ( $parsed_args['show_updated'] ) { $recently_updated_test = ', IF (DATE_ADD(link_updated, INTERVAL 120 MINUTE) >= NOW(), 1,0) as recently_updated '; } else { $recently_updated_test = ''; } $get_updated = ( $parsed_args['show_updated'] ) ? ', UNIX_TIMESTAMP(link_updated) AS link_updated_f ' : ''; $orderby = strtolower( $parsed_args['orderby'] ); $length = ''; switch ( $orderby ) { case 'length': $length = ', CHAR_LENGTH(link_name) AS length'; break; case 'rand': $orderby = 'rand()'; break; case 'link_id': $orderby = "$wpdb->links.link_id"; break; default: $orderparams = array(); $keys = array( 'link_id', 'link_name', 'link_url', 'link_visible', 'link_rating', 'link_owner', 'link_updated', 'link_notes', 'link_description' ); foreach ( explode( ',', $orderby ) as $ordparam ) { $ordparam = trim( $ordparam ); if ( in_array( 'link_' . $ordparam, $keys, true ) ) { $orderparams[] = 'link_' . $ordparam; } elseif ( in_array( $ordparam, $keys, true ) ) { $orderparams[] = $ordparam; } } $orderby = implode( ',', $orderparams ); } if ( empty( $orderby ) ) { $orderby = 'link_name'; } $order = strtoupper( $parsed_args['order'] ); if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ), true ) ) { $order = 'ASC'; } $visible = ''; if ( $parsed_args['hide_invisible'] ) { $visible = "AND link_visible = 'Y'"; } $query = "SELECT * $length $recently_updated_test $get_updated FROM $wpdb->links $join WHERE 1=1 $visible $category_query"; $query .= " $exclusions $inclusions $search"; $query .= " ORDER BY $orderby $order"; if ( -1 != $parsed_args['limit'] ) { $query .= ' LIMIT ' . absint( $parsed_args['limit'] ); } $results = $wpdb->get_results( $query ); if ( 'rand()' !== $orderby ) { $cache[ $key ] = $results; wp_cache_set( 'get_bookmarks', $cache, 'bookmark' ); } /** This filter is documented in wp-includes/bookmark.php */ return apply_filters( 'get_bookmarks', $results, $parsed_args ); } /** * Sanitizes all bookmark fields. * * @since 2.3.0 * * @param stdClass|array $bookmark Bookmark row. * @param string $context Optional. How to filter the fields. Default 'display'. * @return stdClass|array Same type as $bookmark but with fields sanitized. */ function sanitize_bookmark( $bookmark, $context = 'display' ) { $fields = array( 'link_id', 'link_url', 'link_name', 'link_image', 'link_target', 'link_category', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_updated', 'link_rel', 'link_notes', 'link_rss', ); if ( is_object( $bookmark ) ) { $do_object = true; $link_id = $bookmark->link_id; } else { $do_object = false; $link_id = $bookmark['link_id']; } foreach ( $fields as $field ) { if ( $do_object ) { if ( isset( $bookmark->$field ) ) { $bookmark->$field = sanitize_bookmark_field( $field, $bookmark->$field, $link_id, $context ); } } else { if ( isset( $bookmark[ $field ] ) ) { $bookmark[ $field ] = sanitize_bookmark_field( $field, $bookmark[ $field ], $link_id, $context ); } } } return $bookmark; } /** * Sanitizes a bookmark field. * * Sanitizes the bookmark fields based on what the field name is. If the field * has a strict value set, then it will be tested for that, else a more generic * filtering is applied. After the more strict filter is applied, if the `$context` * is 'raw' then the value is immediately return. * * Hooks exist for the more generic cases. With the 'edit' context, the {@see 'edit_$field'} * filter will be called and passed the `$value` and `$bookmark_id` respectively. * * With the 'db' context, the {@see 'pre_$field'} filter is called and passed the value. * The 'display' context is the final context and has the `$field` has the filter name * and is passed the `$value`, `$bookmark_id`, and `$context`, respectively. * * @since 2.3.0 * * @param string $field The bookmark field. * @param mixed $value The bookmark field value. * @param int $bookmark_id Bookmark ID. * @param string $context How to filter the field value. Accepts 'raw', 'edit', 'attribute', * 'js', 'db', or 'display' * @return mixed The filtered value. */ function sanitize_bookmark_field( $field, $value, $bookmark_id, $context ) { switch ( $field ) { case 'link_id': // ints case 'link_rating': $value = (int) $value; break; case 'link_category': // array( ints ) $value = array_map( 'absint', (array) $value ); // We return here so that the categories aren't filtered. // The 'link_category' filter is for the name of a link category, not an array of a link's link categories. return $value; case 'link_visible': // bool stored as Y|N $value = preg_replace( '/[^YNyn]/', '', $value ); break; case 'link_target': // "enum" $targets = array( '_top', '_blank' ); if ( ! in_array( $value, $targets, true ) ) { $value = ''; } break; } if ( 'raw' === $context ) { return $value; } if ( 'edit' === $context ) { /** This filter is documented in wp-includes/post.php */ $value = apply_filters( "edit_{$field}", $value, $bookmark_id ); if ( 'link_notes' === $field ) { $value = esc_html( $value ); // textarea_escaped } else { $value = esc_attr( $value ); } } elseif ( 'db' === $context ) { /** This filter is documented in wp-includes/post.php */ $value = apply_filters( "pre_{$field}", $value ); } else { /** This filter is documented in wp-includes/post.php */ $value = apply_filters( "{$field}", $value, $bookmark_id, $context ); if ( 'attribute' === $context ) { $value = esc_attr( $value ); } elseif ( 'js' === $context ) { $value = esc_js( $value ); } } return $value; } /** * Deletes the bookmark cache. * * @since 2.7.0 * * @param int $bookmark_id Bookmark ID. */ function clean_bookmark_cache( $bookmark_id ) { wp_cache_delete( $bookmark_id, 'bookmark' ); wp_cache_delete( 'get_bookmarks', 'bookmark' ); clean_object_term_cache( $bookmark_id, 'link' ); } class-wp-http-encoding.php000064400000014636150320557470011571 0ustar00 0 ) { if ( $flg & 4 ) { list($xlen) = unpack( 'v', substr( $gzData, $i, 2 ) ); $i = $i + 2 + $xlen; } if ( $flg & 8 ) { $i = strpos( $gzData, "\0", $i ) + 1; } if ( $flg & 16 ) { $i = strpos( $gzData, "\0", $i ) + 1; } if ( $flg & 2 ) { $i = $i + 2; } } $decompressed = @gzinflate( substr( $gzData, $i, -8 ) ); if ( false !== $decompressed ) { return $decompressed; } } // Compressed data from java.util.zip.Deflater amongst others. $decompressed = @gzinflate( substr( $gzData, 2 ) ); if ( false !== $decompressed ) { return $decompressed; } return false; } /** * What encoding types to accept and their priority values. * * @since 2.8.0 * * @param string $url * @param array $args * @return string Types of encoding to accept. */ public static function accept_encoding( $url, $args ) { $type = array(); $compression_enabled = self::is_available(); if ( ! $args['decompress'] ) { // Decompression specifically disabled. $compression_enabled = false; } elseif ( $args['stream'] ) { // Disable when streaming to file. $compression_enabled = false; } elseif ( isset( $args['limit_response_size'] ) ) { // If only partial content is being requested, we won't be able to decompress it. $compression_enabled = false; } if ( $compression_enabled ) { if ( function_exists( 'gzinflate' ) ) { $type[] = 'deflate;q=1.0'; } if ( function_exists( 'gzuncompress' ) ) { $type[] = 'compress;q=0.5'; } if ( function_exists( 'gzdecode' ) ) { $type[] = 'gzip;q=0.5'; } } /** * Filters the allowed encoding types. * * @since 3.6.0 * * @param string[] $type Array of what encoding types to accept and their priority values. * @param string $url URL of the HTTP request. * @param array $args HTTP request arguments. */ $type = apply_filters( 'wp_http_accept_encoding', $type, $url, $args ); return implode( ', ', $type ); } /** * What encoding the content used when it was compressed to send in the headers. * * @since 2.8.0 * * @return string Content-Encoding string to send in the header. */ public static function content_encoding() { return 'deflate'; } /** * Whether the content be decoded based on the headers. * * @since 2.8.0 * * @param array|string $headers All of the available headers. * @return bool */ public static function should_decode( $headers ) { if ( is_array( $headers ) ) { if ( array_key_exists( 'content-encoding', $headers ) && ! empty( $headers['content-encoding'] ) ) { return true; } } elseif ( is_string( $headers ) ) { return ( stripos( $headers, 'content-encoding:' ) !== false ); } return false; } /** * Whether decompression and compression are supported by the PHP version. * * Each function is tested instead of checking for the zlib extension, to * ensure that the functions all exist in the PHP version and aren't * disabled. * * @since 2.8.0 * * @return bool */ public static function is_available() { return ( function_exists( 'gzuncompress' ) || function_exists( 'gzdeflate' ) || function_exists( 'gzinflate' ) ); } } class-wp-block-type-registry.php000064400000012033150320557470012732 0ustar00 $instance` pairs. * * @since 5.0.0 * @var WP_Block_Type[] */ private $registered_block_types = array(); /** * Container for the main instance of the class. * * @since 5.0.0 * @var WP_Block_Type_Registry|null */ private static $instance = null; /** * Registers a block type. * * @since 5.0.0 * * @param string|WP_Block_Type $name Block type name including namespace, or alternatively * a complete WP_Block_Type instance. In case a WP_Block_Type * is provided, the $args parameter will be ignored. * @param array $args { * Optional. Array of block type arguments. Accepts any public property of `WP_Block_Type`. * Any arguments may be defined, however the ones described below are supported by default. * Default empty array. * * @type callable $render_callback Callback used to render blocks of this block type. * @type array $attributes Block attributes mapping, property name to schema. * } * @return WP_Block_Type|false The registered block type on success, or false on failure. */ public function register( $name, $args = array() ) { $block_type = null; if ( $name instanceof WP_Block_Type ) { $block_type = $name; $name = $block_type->name; } if ( ! is_string( $name ) ) { $message = __( 'Block type names must be strings.' ); _doing_it_wrong( __METHOD__, $message, '5.0.0' ); return false; } if ( preg_match( '/[A-Z]+/', $name ) ) { $message = __( 'Block type names must not contain uppercase characters.' ); _doing_it_wrong( __METHOD__, $message, '5.0.0' ); return false; } $name_matcher = '/^[a-z0-9-]+\/[a-z0-9-]+$/'; if ( ! preg_match( $name_matcher, $name ) ) { $message = __( 'Block type names must contain a namespace prefix. Example: my-plugin/my-custom-block-type' ); _doing_it_wrong( __METHOD__, $message, '5.0.0' ); return false; } if ( $this->is_registered( $name ) ) { /* translators: %s: Block name. */ $message = sprintf( __( 'Block type "%s" is already registered.' ), $name ); _doing_it_wrong( __METHOD__, $message, '5.0.0' ); return false; } if ( ! $block_type ) { $block_type = new WP_Block_Type( $name, $args ); } $this->registered_block_types[ $name ] = $block_type; return $block_type; } /** * Unregisters a block type. * * @since 5.0.0 * * @param string|WP_Block_Type $name Block type name including namespace, or alternatively * a complete WP_Block_Type instance. * @return WP_Block_Type|false The unregistered block type on success, or false on failure. */ public function unregister( $name ) { if ( $name instanceof WP_Block_Type ) { $name = $name->name; } if ( ! $this->is_registered( $name ) ) { /* translators: %s: Block name. */ $message = sprintf( __( 'Block type "%s" is not registered.' ), $name ); _doing_it_wrong( __METHOD__, $message, '5.0.0' ); return false; } $unregistered_block_type = $this->registered_block_types[ $name ]; unset( $this->registered_block_types[ $name ] ); return $unregistered_block_type; } /** * Retrieves a registered block type. * * @since 5.0.0 * * @param string $name Block type name including namespace. * @return WP_Block_Type|null The registered block type, or null if it is not registered. */ public function get_registered( $name ) { if ( ! $this->is_registered( $name ) ) { return null; } return $this->registered_block_types[ $name ]; } /** * Retrieves all registered block types. * * @since 5.0.0 * * @return WP_Block_Type[] Associative array of `$block_type_name => $block_type` pairs. */ public function get_all_registered() { return $this->registered_block_types; } /** * Checks if a block type is registered. * * @since 5.0.0 * * @param string $name Block type name including namespace. * @return bool True if the block type is registered, false otherwise. */ public function is_registered( $name ) { return isset( $this->registered_block_types[ $name ] ); } public function __wakeup() { if ( ! $this->registered_block_types ) { return; } if ( ! is_array( $this->registered_block_types ) ) { throw new UnexpectedValueException(); } foreach ( $this->registered_block_types as $value ) { if ( ! $value instanceof WP_Block_Type ) { throw new UnexpectedValueException(); } } } /** * Utility method to retrieve the main instance of the class. * * The instance will be created if it does not exist yet. * * @since 5.0.0 * * @return WP_Block_Type_Registry The main instance. */ public static function get_instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } } cache-compat.php000064400000002026150320557470007611 0ustar00ID : false; } /** * Display or retrieve the current post title with optional markup. * * @since 0.71 * * @param string $before Optional. Markup to prepend to the title. Default empty. * @param string $after Optional. Markup to append to the title. Default empty. * @param bool $echo Optional. Whether to echo or return the title. Default true for echo. * @return void|string Void if `$echo` argument is true, current post title if `$echo` is false. */ function the_title( $before = '', $after = '', $echo = true ) { $title = get_the_title(); if ( strlen( $title ) == 0 ) { return; } $title = $before . $title . $after; if ( $echo ) { echo $title; } else { return $title; } } /** * Sanitize the current title when retrieving or displaying. * * Works like the_title(), except the parameters can be in a string or * an array. See the function for what can be override in the $args parameter. * * The title before it is displayed will have the tags stripped and esc_attr() * before it is passed to the user or displayed. The default as with the_title(), * is to display the title. * * @since 2.3.0 * * @param string|array $args { * Title attribute arguments. Optional. * * @type string $before Markup to prepend to the title. Default empty. * @type string $after Markup to append to the title. Default empty. * @type bool $echo Whether to echo or return the title. Default true for echo. * @type WP_Post $post Current post object to retrieve the title for. * } * @return void|string Void if 'echo' argument is true, the title attribute if 'echo' is false. */ function the_title_attribute( $args = '' ) { $defaults = array( 'before' => '', 'after' => '', 'echo' => true, 'post' => get_post(), ); $parsed_args = wp_parse_args( $args, $defaults ); $title = get_the_title( $parsed_args['post'] ); if ( strlen( $title ) == 0 ) { return; } $title = $parsed_args['before'] . $title . $parsed_args['after']; $title = esc_attr( strip_tags( $title ) ); if ( $parsed_args['echo'] ) { echo $title; } else { return $title; } } /** * Retrieve post title. * * If the post is protected and the visitor is not an admin, then "Protected" * will be displayed before the post title. If the post is private, then * "Private" will be located before the post title. * * @since 0.71 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @return string */ function get_the_title( $post = 0 ) { $post = get_post( $post ); $title = isset( $post->post_title ) ? $post->post_title : ''; $id = isset( $post->ID ) ? $post->ID : 0; if ( ! is_admin() ) { if ( ! empty( $post->post_password ) ) { /* translators: %s: Protected post title. */ $prepend = __( 'Protected: %s' ); /** * Filters the text prepended to the post title for protected posts. * * The filter is only applied on the front end. * * @since 2.8.0 * * @param string $prepend Text displayed before the post title. * Default 'Protected: %s'. * @param WP_Post $post Current post object. */ $protected_title_format = apply_filters( 'protected_title_format', $prepend, $post ); $title = sprintf( $protected_title_format, $title ); } elseif ( isset( $post->post_status ) && 'private' === $post->post_status ) { /* translators: %s: Private post title. */ $prepend = __( 'Private: %s' ); /** * Filters the text prepended to the post title of private posts. * * The filter is only applied on the front end. * * @since 2.8.0 * * @param string $prepend Text displayed before the post title. * Default 'Private: %s'. * @param WP_Post $post Current post object. */ $private_title_format = apply_filters( 'private_title_format', $prepend, $post ); $title = sprintf( $private_title_format, $title ); } } /** * Filters the post title. * * @since 0.71 * * @param string $title The post title. * @param int $id The post ID. */ return apply_filters( 'the_title', $title, $id ); } /** * Display the Post Global Unique Identifier (guid). * * The guid will appear to be a link, but should not be used as a link to the * post. The reason you should not use it as a link, is because of moving the * blog across domains. * * URL is escaped to make it XML-safe. * * @since 1.5.0 * * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post. */ function the_guid( $post = 0 ) { $post = get_post( $post ); $guid = isset( $post->guid ) ? get_the_guid( $post ) : ''; $id = isset( $post->ID ) ? $post->ID : 0; /** * Filters the escaped Global Unique Identifier (guid) of the post. * * @since 4.2.0 * * @see get_the_guid() * * @param string $guid Escaped Global Unique Identifier (guid) of the post. * @param int $id The post ID. */ echo apply_filters( 'the_guid', $guid, $id ); } /** * Retrieve the Post Global Unique Identifier (guid). * * The guid will appear to be a link, but should not be used as an link to the * post. The reason you should not use it as a link, is because of moving the * blog across domains. * * @since 1.5.0 * * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post. * @return string */ function get_the_guid( $post = 0 ) { $post = get_post( $post ); $guid = isset( $post->guid ) ? $post->guid : ''; $id = isset( $post->ID ) ? $post->ID : 0; /** * Filters the Global Unique Identifier (guid) of the post. * * @since 1.5.0 * * @param string $guid Global Unique Identifier (guid) of the post. * @param int $id The post ID. */ return apply_filters( 'get_the_guid', $guid, $id ); } /** * Display the post content. * * @since 0.71 * * @param string $more_link_text Optional. Content for when there is more text. * @param bool $strip_teaser Optional. Strip teaser content before the more text. Default false. */ function the_content( $more_link_text = null, $strip_teaser = false ) { $content = get_the_content( $more_link_text, $strip_teaser ); /** * Filters the post content. * * @since 0.71 * * @param string $content Content of the current post. */ $content = apply_filters( 'the_content', $content ); $content = str_replace( ']]>', ']]>', $content ); echo $content; } /** * Retrieve the post content. * * @since 0.71 * @since 5.2.0 Added the `$post` parameter. * * @global int $page Page number of a single post/page. * @global int $more Boolean indicator for whether single post/page is being viewed. * @global bool $preview Whether post/page is in preview mode. * @global array $pages Array of all pages in post/page. Each array element contains * part of the content separated by the `` tag. * @global int $multipage Boolean indicator for whether multiple pages are in play. * * @param string $more_link_text Optional. Content for when there is more text. * @param bool $strip_teaser Optional. Strip teaser content before the more text. Default false. * @param WP_Post|object|int $post Optional. WP_Post instance or Post ID/object. Default null. * @return string */ function get_the_content( $more_link_text = null, $strip_teaser = false, $post = null ) { global $page, $more, $preview, $pages, $multipage; $_post = get_post( $post ); if ( ! ( $_post instanceof WP_Post ) ) { return ''; } // Use the globals if the $post parameter was not specified, // but only after they have been set up in setup_postdata(). if ( null === $post && did_action( 'the_post' ) ) { $elements = compact( 'page', 'more', 'preview', 'pages', 'multipage' ); } else { $elements = generate_postdata( $_post ); } if ( null === $more_link_text ) { $more_link_text = sprintf( '%2$s', sprintf( /* translators: %s: Post title. */ __( 'Continue reading %s' ), the_title_attribute( array( 'echo' => false, 'post' => $_post, ) ) ), __( '(more…)' ) ); } $output = ''; $has_teaser = false; // If post password required and it doesn't match the cookie. if ( post_password_required( $_post ) ) { return get_the_password_form( $_post ); } // If the requested page doesn't exist. if ( $elements['page'] > count( $elements['pages'] ) ) { // Give them the highest numbered page that DOES exist. $elements['page'] = count( $elements['pages'] ); } $page_no = $elements['page']; $content = $elements['pages'][ $page_no - 1 ]; if ( preg_match( '//', $content, $matches ) ) { if ( has_block( 'more', $content ) ) { // Remove the core/more block delimiters. They will be left over after $content is split up. $content = preg_replace( '//', '', $content ); } $content = explode( $matches[0], $content, 2 ); if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) ) { $more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) ); } $has_teaser = true; } else { $content = array( $content ); } if ( false !== strpos( $_post->post_content, '' ) && ( ! $elements['multipage'] || 1 == $elements['page'] ) ) { $strip_teaser = true; } $teaser = $content[0]; if ( $elements['more'] && $strip_teaser && $has_teaser ) { $teaser = ''; } $output .= $teaser; if ( count( $content ) > 1 ) { if ( $elements['more'] ) { $output .= '' . $content[1]; } else { if ( ! empty( $more_link_text ) ) { /** * Filters the Read More link text. * * @since 2.8.0 * * @param string $more_link_element Read More link element. * @param string $more_link_text Read More text. */ $output .= apply_filters( 'the_content_more_link', ' ID}\" class=\"more-link\">$more_link_text", $more_link_text ); } $output = force_balance_tags( $output ); } } return $output; } /** * Display the post excerpt. * * @since 0.71 */ function the_excerpt() { /** * Filters the displayed post excerpt. * * @since 0.71 * * @see get_the_excerpt() * * @param string $post_excerpt The post excerpt. */ echo apply_filters( 'the_excerpt', get_the_excerpt() ); } /** * Retrieves the post excerpt. * * @since 0.71 * @since 4.5.0 Introduced the `$post` parameter. * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @return string Post excerpt. */ function get_the_excerpt( $post = null ) { if ( is_bool( $post ) ) { _deprecated_argument( __FUNCTION__, '2.3.0' ); } $post = get_post( $post ); if ( empty( $post ) ) { return ''; } if ( post_password_required( $post ) ) { return __( 'There is no excerpt because this is a protected post.' ); } /** * Filters the retrieved post excerpt. * * @since 1.2.0 * @since 4.5.0 Introduced the `$post` parameter. * * @param string $post_excerpt The post excerpt. * @param WP_Post $post Post object. */ return apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ); } /** * Determines whether the post has a custom excerpt. * * 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.3.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @return bool True if the post has a custom excerpt, false otherwise. */ function has_excerpt( $post = 0 ) { $post = get_post( $post ); return ( ! empty( $post->post_excerpt ) ); } /** * Displays the classes for the post container element. * * @since 2.7.0 * * @param string|array $class One or more classes to add to the class list. * @param int|WP_Post $post_id Optional. Post ID or post object. Defaults to the global `$post`. */ function post_class( $class = '', $post_id = null ) { // Separates classes with a single space, collates classes for post DIV. echo 'class="' . esc_attr( join( ' ', get_post_class( $class, $post_id ) ) ) . '"'; } /** * Retrieves an array of the class names for the post container element. * * The class names are many. If the post is a sticky, then the 'sticky' * class name. The class 'hentry' is always added to each post. If the post has a * post thumbnail, 'has-post-thumbnail' is added as a class. For each taxonomy that * the post belongs to, a class will be added of the format '{$taxonomy}-{$slug}' - * eg 'category-foo' or 'my_custom_taxonomy-bar'. * * The 'post_tag' taxonomy is a special * case; the class has the 'tag-' prefix instead of 'post_tag-'. All class names are * passed through the filter, {@see 'post_class'}, with the list of class names, followed by * $class parameter value, with the post ID as the last parameter. * * @since 2.7.0 * @since 4.2.0 Custom taxonomy class names were added. * * @param string|string[] $class Space-separated string or array of class names to add to the class list. * @param int|WP_Post $post_id Optional. Post ID or post object. * @return string[] Array of class names. */ function get_post_class( $class = '', $post_id = null ) { $post = get_post( $post_id ); $classes = array(); if ( $class ) { if ( ! is_array( $class ) ) { $class = preg_split( '#\s+#', $class ); } $classes = array_map( 'esc_attr', $class ); } else { // Ensure that we always coerce class to being an array. $class = array(); } if ( ! $post ) { return $classes; } $classes[] = 'post-' . $post->ID; if ( ! is_admin() ) { $classes[] = $post->post_type; } $classes[] = 'type-' . $post->post_type; $classes[] = 'status-' . $post->post_status; // Post Format. if ( post_type_supports( $post->post_type, 'post-formats' ) ) { $post_format = get_post_format( $post->ID ); if ( $post_format && ! is_wp_error( $post_format ) ) { $classes[] = 'format-' . sanitize_html_class( $post_format ); } else { $classes[] = 'format-standard'; } } $post_password_required = post_password_required( $post->ID ); // Post requires password. if ( $post_password_required ) { $classes[] = 'post-password-required'; } elseif ( ! empty( $post->post_password ) ) { $classes[] = 'post-password-protected'; } // Post thumbnails. if ( current_theme_supports( 'post-thumbnails' ) && has_post_thumbnail( $post->ID ) && ! is_attachment( $post ) && ! $post_password_required ) { $classes[] = 'has-post-thumbnail'; } // Sticky for Sticky Posts. if ( is_sticky( $post->ID ) ) { if ( is_home() && ! is_paged() ) { $classes[] = 'sticky'; } elseif ( is_admin() ) { $classes[] = 'status-sticky'; } } // hentry for hAtom compliance. $classes[] = 'hentry'; // All public taxonomies. $taxonomies = get_taxonomies( array( 'public' => true ) ); foreach ( (array) $taxonomies as $taxonomy ) { if ( is_object_in_taxonomy( $post->post_type, $taxonomy ) ) { foreach ( (array) get_the_terms( $post->ID, $taxonomy ) as $term ) { if ( empty( $term->slug ) ) { continue; } $term_class = sanitize_html_class( $term->slug, $term->term_id ); if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) { $term_class = $term->term_id; } // 'post_tag' uses the 'tag' prefix for backward compatibility. if ( 'post_tag' === $taxonomy ) { $classes[] = 'tag-' . $term_class; } else { $classes[] = sanitize_html_class( $taxonomy . '-' . $term_class, $taxonomy . '-' . $term->term_id ); } } } } $classes = array_map( 'esc_attr', $classes ); /** * Filters the list of CSS class names for the current post. * * @since 2.7.0 * * @param string[] $classes An array of post class names. * @param string[] $class An array of additional class names added to the post. * @param int $post_id The post ID. */ $classes = apply_filters( 'post_class', $classes, $class, $post->ID ); return array_unique( $classes ); } /** * Displays the class names for the body element. * * @since 2.8.0 * * @param string|string[] $class Space-separated string or array of class names to add to the class list. */ function body_class( $class = '' ) { // Separates class names with a single space, collates class names for body element. echo 'class="' . esc_attr( join( ' ', get_body_class( $class ) ) ) . '"'; } /** * Retrieves an array of the class names for the body element. * * @since 2.8.0 * * @global WP_Query $wp_query WordPress Query object. * * @param string|string[] $class Space-separated string or array of class names to add to the class list. * @return string[] Array of class names. */ function get_body_class( $class = '' ) { global $wp_query; $classes = array(); if ( is_rtl() ) { $classes[] = 'rtl'; } if ( is_front_page() ) { $classes[] = 'home'; } if ( is_home() ) { $classes[] = 'blog'; } if ( is_privacy_policy() ) { $classes[] = 'privacy-policy'; } if ( is_archive() ) { $classes[] = 'archive'; } if ( is_date() ) { $classes[] = 'date'; } if ( is_search() ) { $classes[] = 'search'; $classes[] = $wp_query->posts ? 'search-results' : 'search-no-results'; } if ( is_paged() ) { $classes[] = 'paged'; } if ( is_attachment() ) { $classes[] = 'attachment'; } if ( is_404() ) { $classes[] = 'error404'; } if ( is_singular() ) { $post_id = $wp_query->get_queried_object_id(); $post = $wp_query->get_queried_object(); $post_type = $post->post_type; if ( is_page_template() ) { $classes[] = "{$post_type}-template"; $template_slug = get_page_template_slug( $post_id ); $template_parts = explode( '/', $template_slug ); foreach ( $template_parts as $part ) { $classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) ); } $classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( '.', '-', $template_slug ) ); } else { $classes[] = "{$post_type}-template-default"; } if ( is_single() ) { $classes[] = 'single'; if ( isset( $post->post_type ) ) { $classes[] = 'single-' . sanitize_html_class( $post->post_type, $post_id ); $classes[] = 'postid-' . $post_id; // Post Format. if ( post_type_supports( $post->post_type, 'post-formats' ) ) { $post_format = get_post_format( $post->ID ); if ( $post_format && ! is_wp_error( $post_format ) ) { $classes[] = 'single-format-' . sanitize_html_class( $post_format ); } else { $classes[] = 'single-format-standard'; } } } } if ( is_attachment() ) { $mime_type = get_post_mime_type( $post_id ); $mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' ); $classes[] = 'attachmentid-' . $post_id; $classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type ); } elseif ( is_page() ) { $classes[] = 'page'; $page_id = $wp_query->get_queried_object_id(); $post = get_post( $page_id ); $classes[] = 'page-id-' . $page_id; if ( get_pages( array( 'parent' => $page_id, 'number' => 1, ) ) ) { $classes[] = 'page-parent'; } if ( $post->post_parent ) { $classes[] = 'page-child'; $classes[] = 'parent-pageid-' . $post->post_parent; } } } elseif ( is_archive() ) { if ( is_post_type_archive() ) { $classes[] = 'post-type-archive'; $post_type = get_query_var( 'post_type' ); if ( is_array( $post_type ) ) { $post_type = reset( $post_type ); } $classes[] = 'post-type-archive-' . sanitize_html_class( $post_type ); } elseif ( is_author() ) { $author = $wp_query->get_queried_object(); $classes[] = 'author'; if ( isset( $author->user_nicename ) ) { $classes[] = 'author-' . sanitize_html_class( $author->user_nicename, $author->ID ); $classes[] = 'author-' . $author->ID; } } elseif ( is_category() ) { $cat = $wp_query->get_queried_object(); $classes[] = 'category'; if ( isset( $cat->term_id ) ) { $cat_class = sanitize_html_class( $cat->slug, $cat->term_id ); if ( is_numeric( $cat_class ) || ! trim( $cat_class, '-' ) ) { $cat_class = $cat->term_id; } $classes[] = 'category-' . $cat_class; $classes[] = 'category-' . $cat->term_id; } } elseif ( is_tag() ) { $tag = $wp_query->get_queried_object(); $classes[] = 'tag'; if ( isset( $tag->term_id ) ) { $tag_class = sanitize_html_class( $tag->slug, $tag->term_id ); if ( is_numeric( $tag_class ) || ! trim( $tag_class, '-' ) ) { $tag_class = $tag->term_id; } $classes[] = 'tag-' . $tag_class; $classes[] = 'tag-' . $tag->term_id; } } elseif ( is_tax() ) { $term = $wp_query->get_queried_object(); if ( isset( $term->term_id ) ) { $term_class = sanitize_html_class( $term->slug, $term->term_id ); if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) { $term_class = $term->term_id; } $classes[] = 'tax-' . sanitize_html_class( $term->taxonomy ); $classes[] = 'term-' . $term_class; $classes[] = 'term-' . $term->term_id; } } } if ( is_user_logged_in() ) { $classes[] = 'logged-in'; } if ( is_admin_bar_showing() ) { $classes[] = 'admin-bar'; $classes[] = 'no-customize-support'; } if ( current_theme_supports( 'custom-background' ) && ( get_background_color() !== get_theme_support( 'custom-background', 'default-color' ) || get_background_image() ) ) { $classes[] = 'custom-background'; } if ( has_custom_logo() ) { $classes[] = 'wp-custom-logo'; } if ( current_theme_supports( 'responsive-embeds' ) ) { $classes[] = 'wp-embed-responsive'; } $page = $wp_query->get( 'page' ); if ( ! $page || $page < 2 ) { $page = $wp_query->get( 'paged' ); } if ( $page && $page > 1 && ! is_404() ) { $classes[] = 'paged-' . $page; if ( is_single() ) { $classes[] = 'single-paged-' . $page; } elseif ( is_page() ) { $classes[] = 'page-paged-' . $page; } elseif ( is_category() ) { $classes[] = 'category-paged-' . $page; } elseif ( is_tag() ) { $classes[] = 'tag-paged-' . $page; } elseif ( is_date() ) { $classes[] = 'date-paged-' . $page; } elseif ( is_author() ) { $classes[] = 'author-paged-' . $page; } elseif ( is_search() ) { $classes[] = 'search-paged-' . $page; } elseif ( is_post_type_archive() ) { $classes[] = 'post-type-paged-' . $page; } } if ( ! empty( $class ) ) { if ( ! is_array( $class ) ) { $class = preg_split( '#\s+#', $class ); } $classes = array_merge( $classes, $class ); } else { // Ensure that we always coerce class to being an array. $class = array(); } $classes = array_map( 'esc_attr', $classes ); /** * Filters the list of CSS body class names for the current post or page. * * @since 2.8.0 * * @param string[] $classes An array of body class names. * @param string[] $class An array of additional class names added to the body. */ $classes = apply_filters( 'body_class', $classes, $class ); return array_unique( $classes ); } /** * Whether post requires password and correct password has been provided. * * @since 2.7.0 * * @param int|WP_Post|null $post An optional post. Global $post used if not provided. * @return bool false if a password is not required or the correct password cookie is present, true otherwise. */ function post_password_required( $post = null ) { $post = get_post( $post ); if ( empty( $post->post_password ) ) { /** This filter is documented in wp-includes/post-template.php */ return apply_filters( 'post_password_required', false, $post ); } if ( ! isset( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ) ) { /** This filter is documented in wp-includes/post-template.php */ return apply_filters( 'post_password_required', true, $post ); } require_once ABSPATH . WPINC . '/class-phpass.php'; $hasher = new PasswordHash( 8, true ); $hash = wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ); if ( 0 !== strpos( $hash, '$P$B' ) ) { $required = true; } else { $required = ! $hasher->CheckPassword( $post->post_password, $hash ); } /** * Filters whether a post requires the user to supply a password. * * @since 4.7.0 * * @param bool $required Whether the user needs to supply a password. True if password has not been * provided or is incorrect, false if password has been supplied or is not required. * @param WP_Post $post Post data. */ return apply_filters( 'post_password_required', $required, $post ); } // // Page Template Functions for usage in Themes. // /** * The formatted output of a list of pages. * * Displays page links for paginated posts (i.e. including the `` * Quicktag one or more times). This tag must be within The Loop. * * @since 1.2.0 * @since 5.1.0 Added the `aria_current` argument. * * @global int $page * @global int $numpages * @global int $multipage * @global int $more * * @param string|array $args { * Optional. Array or string of default arguments. * * @type string $before HTML or text to prepend to each link. Default is `

    Pages:`. * @type string $after HTML or text to append to each link. Default is `

    `. * @type string $link_before HTML or text to prepend to each link, inside the `` tag. * Also prepended to the current item, which is not linked. Default empty. * @type string $link_after HTML or text to append to each Pages link inside the `` tag. * Also appended to the current item, which is not linked. Default empty. * @type string $aria_current The value for the aria-current attribute. Possible values are 'page', * 'step', 'location', 'date', 'time', 'true', 'false'. Default is 'page'. * @type string $next_or_number Indicates whether page numbers should be used. Valid values are number * and next. Default is 'number'. * @type string $separator Text between pagination links. Default is ' '. * @type string $nextpagelink Link text for the next page link, if available. Default is 'Next Page'. * @type string $previouspagelink Link text for the previous page link, if available. Default is 'Previous Page'. * @type string $pagelink Format string for page numbers. The % in the parameter string will be * replaced with the page number, so 'Page %' generates "Page 1", "Page 2", etc. * Defaults to '%', just the page number. * @type int|bool $echo Whether to echo or not. Accepts 1|true or 0|false. Default 1|true. * } * @return string Formatted output in HTML. */ function wp_link_pages( $args = '' ) { global $page, $numpages, $multipage, $more; $defaults = array( 'before' => '

    ' . __( 'Pages:' ), 'after' => '

    ', 'link_before' => '', 'link_after' => '', 'aria_current' => 'page', 'next_or_number' => 'number', 'separator' => ' ', 'nextpagelink' => __( 'Next page' ), 'previouspagelink' => __( 'Previous page' ), 'pagelink' => '%', 'echo' => 1, ); $parsed_args = wp_parse_args( $args, $defaults ); /** * Filters the arguments used in retrieving page links for paginated posts. * * @since 3.0.0 * * @param array $parsed_args An array of arguments for page links for paginated posts. */ $parsed_args = apply_filters( 'wp_link_pages_args', $parsed_args ); $output = ''; if ( $multipage ) { if ( 'number' === $parsed_args['next_or_number'] ) { $output .= $parsed_args['before']; for ( $i = 1; $i <= $numpages; $i++ ) { $link = $parsed_args['link_before'] . str_replace( '%', $i, $parsed_args['pagelink'] ) . $parsed_args['link_after']; if ( $i != $page || ! $more && 1 == $page ) { $link = _wp_link_page( $i ) . $link . '
    '; } elseif ( $i === $page ) { $link = '' . $link . ''; } /** * Filters the HTML output of individual page number links. * * @since 3.6.0 * * @param string $link The page number HTML output. * @param int $i Page number for paginated posts' page links. */ $link = apply_filters( 'wp_link_pages_link', $link, $i ); // Use the custom links separator beginning with the second link. $output .= ( 1 === $i ) ? ' ' : $parsed_args['separator']; $output .= $link; } $output .= $parsed_args['after']; } elseif ( $more ) { $output .= $parsed_args['before']; $prev = $page - 1; if ( $prev > 0 ) { $link = _wp_link_page( $prev ) . $parsed_args['link_before'] . $parsed_args['previouspagelink'] . $parsed_args['link_after'] . ''; /** This filter is documented in wp-includes/post-template.php */ $output .= apply_filters( 'wp_link_pages_link', $link, $prev ); } $next = $page + 1; if ( $next <= $numpages ) { if ( $prev ) { $output .= $parsed_args['separator']; } $link = _wp_link_page( $next ) . $parsed_args['link_before'] . $parsed_args['nextpagelink'] . $parsed_args['link_after'] . ''; /** This filter is documented in wp-includes/post-template.php */ $output .= apply_filters( 'wp_link_pages_link', $link, $next ); } $output .= $parsed_args['after']; } } /** * Filters the HTML output of page links for paginated posts. * * @since 3.6.0 * * @param string $output HTML output of paginated posts' page links. * @param array $args An array of arguments. */ $html = apply_filters( 'wp_link_pages', $output, $args ); if ( $parsed_args['echo'] ) { echo $html; } return $html; } /** * Helper function for wp_link_pages(). * * @since 3.1.0 * @access private * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. * * @param int $i Page number. * @return string Link. */ function _wp_link_page( $i ) { global $wp_rewrite; $post = get_post(); $query_args = array(); if ( 1 == $i ) { $url = get_permalink(); } else { if ( ! get_option( 'permalink_structure' ) || in_array( $post->post_status, array( 'draft', 'pending' ), true ) ) { $url = add_query_arg( 'page', $i, get_permalink() ); } elseif ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) == $post->ID ) { $url = trailingslashit( get_permalink() ) . user_trailingslashit( "$wp_rewrite->pagination_base/" . $i, 'single_paged' ); } else { $url = trailingslashit( get_permalink() ) . user_trailingslashit( $i, 'single_paged' ); } } if ( is_preview() ) { if ( ( 'draft' !== $post->post_status ) && isset( $_GET['preview_id'], $_GET['preview_nonce'] ) ) { $query_args['preview_id'] = wp_unslash( $_GET['preview_id'] ); $query_args['preview_nonce'] = wp_unslash( $_GET['preview_nonce'] ); } $url = get_preview_post_link( $post, $query_args, $url ); } return ''; } // // Post-meta: Custom per-post fields. // /** * Retrieve post custom meta data field. * * @since 1.5.0 * * @param string $key Meta data key name. * @return array|string|false Array of values, or single value if only one element exists. * False if the key does not exist. */ function post_custom( $key = '' ) { $custom = get_post_custom(); if ( ! isset( $custom[ $key ] ) ) { return false; } elseif ( 1 === count( $custom[ $key ] ) ) { return $custom[ $key ][0]; } else { return $custom[ $key ]; } } /** * Display a list of post custom fields. * * @since 1.2.0 * * @deprecated 6.0.2 Use get_post_meta() to retrieve post meta and render manually. */ function the_meta() { _deprecated_function( __FUNCTION__, '6.0.2', 'get_post_meta()' ); $keys = get_post_custom_keys(); if ( $keys ) { $li_html = ''; foreach ( (array) $keys as $key ) { $keyt = trim( $key ); if ( is_protected_meta( $keyt, 'post' ) ) { continue; } $values = array_map( 'trim', get_post_custom_values( $key ) ); $value = implode( ', ', $values ); $html = sprintf( "
  • %s
  • \n", /* translators: %s: Post custom field name. */ esc_html( sprintf( _x( '%s:', 'Post custom field name' ), $key ) ), esc_html( $value ) ); /** * Filters the HTML output of the li element in the post custom fields list. * * @since 2.2.0 * * @param string $html The HTML output for the li element. * @param string $key Meta key. * @param string $value Meta value. */ $li_html .= apply_filters( 'the_meta_key', $html, $key, $value ); } if ( $li_html ) { echo "\n"; } } } // // Pages. // /** * Retrieve or display a list of pages as a dropdown (select list). * * @since 2.1.0 * @since 4.2.0 The `$value_field` argument was added. * @since 4.3.0 The `$class` argument was added. * * @see get_pages() * * @param array|string $args { * Optional. Array or string of arguments to generate a page dropdown. See `get_pages()` for additional arguments. * * @type int $depth Maximum depth. Default 0. * @type int $child_of Page ID to retrieve child pages of. Default 0. * @type int|string $selected Value of the option that should be selected. Default 0. * @type bool|int $echo Whether to echo or return the generated markup. Accepts 0, 1, * or their bool equivalents. Default 1. * @type string $name Value for the 'name' attribute of the select element. * Default 'page_id'. * @type string $id Value for the 'id' attribute of the select element. * @type string $class Value for the 'class' attribute of the select element. Default: none. * Defaults to the value of `$name`. * @type string $show_option_none Text to display for showing no pages. Default empty (does not display). * @type string $show_option_no_change Text to display for "no change" option. Default empty (does not display). * @type string $option_none_value Value to use when no page is selected. Default empty. * @type string $value_field Post field used to populate the 'value' attribute of the option * elements. Accepts any valid post field. Default 'ID'. * } * @return string HTML dropdown list of pages. */ function wp_dropdown_pages( $args = '' ) { $defaults = array( 'depth' => 0, 'child_of' => 0, 'selected' => 0, 'echo' => 1, 'name' => 'page_id', 'id' => '', 'class' => '', 'show_option_none' => '', 'show_option_no_change' => '', 'option_none_value' => '', 'value_field' => 'ID', ); $parsed_args = wp_parse_args( $args, $defaults ); $pages = get_pages( $parsed_args ); $output = ''; // Back-compat with old system where both id and name were based on $name argument. if ( empty( $parsed_args['id'] ) ) { $parsed_args['id'] = $parsed_args['name']; } if ( ! empty( $pages ) ) { $class = ''; if ( ! empty( $parsed_args['class'] ) ) { $class = " class='" . esc_attr( $parsed_args['class'] ) . "'"; } $output = "\n"; } /** * Filters the HTML output of a list of pages as a drop down. * * @since 2.1.0 * @since 4.4.0 `$parsed_args` and `$pages` added as arguments. * * @param string $output HTML output for drop down list of pages. * @param array $parsed_args The parsed arguments array. * @param WP_Post[] $pages Array of the page objects. */ $html = apply_filters( 'wp_dropdown_pages', $output, $parsed_args, $pages ); if ( $parsed_args['echo'] ) { echo $html; } return $html; } /** * Retrieve or display a list of pages (or hierarchical post type items) in list (li) format. * * @since 1.5.0 * @since 4.7.0 Added the `item_spacing` argument. * * @see get_pages() * * @global WP_Query $wp_query WordPress Query object. * * @param array|string $args { * Optional. Array or string of arguments to generate a list of pages. See `get_pages()` for additional arguments. * * @type int $child_of Display only the sub-pages of a single page by ID. Default 0 (all pages). * @type string $authors Comma-separated list of author IDs. Default empty (all authors). * @type string $date_format PHP date format to use for the listed pages. Relies on the 'show_date' parameter. * Default is the value of 'date_format' option. * @type int $depth Number of levels in the hierarchy of pages to include in the generated list. * Accepts -1 (any depth), 0 (all pages), 1 (top-level pages only), and n (pages to * the given n depth). Default 0. * @type bool $echo Whether or not to echo the list of pages. Default true. * @type string $exclude Comma-separated list of page IDs to exclude. Default empty. * @type array $include Comma-separated list of page IDs to include. Default empty. * @type string $link_after Text or HTML to follow the page link label. Default null. * @type string $link_before Text or HTML to precede the page link label. Default null. * @type string $post_type Post type to query for. Default 'page'. * @type string|array $post_status Comma-separated list or array of post statuses to include. Default 'publish'. * @type string $show_date Whether to display the page publish or modified date for each page. Accepts * 'modified' or any other value. An empty value hides the date. Default empty. * @type string $sort_column Comma-separated list of column names to sort the pages by. Accepts 'post_author', * 'post_date', 'post_title', 'post_name', 'post_modified', 'post_modified_gmt', * 'menu_order', 'post_parent', 'ID', 'rand', or 'comment_count'. Default 'post_title'. * @type string $title_li List heading. Passing a null or empty value will result in no heading, and the list * will not be wrapped with unordered list `