/** * Fetch descendants for located comments. * * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch * the descendant trees for all matched top-level comments. * * @since 4.4.0 * * @param array $comments Array of top-level comments whose descendants should be filled in. * @return array */ protected function fill_descendants($comments) { global $wpdb; $levels = array(0 => wp_list_pluck($comments, 'comment_ID')); /* * The WHERE clause for the descendant query is the same as for the top-level * query, minus the `parent`, `parent__in`, and `parent__not_in` sub-clauses. */ $_where = $this->filtered_where_clause; $exclude_keys = array('parent', 'parent__in', 'parent__not_in'); foreach ($exclude_keys as $exclude_key) { if (isset($this->sql_clauses['where'][$exclude_key])) { $clause = $this->sql_clauses['where'][$exclude_key]; // Strip the clause as well as any adjacent ANDs. $pattern = '|(?:AND)?\\s*' . $clause . '\\s*(?:AND)?|'; $_where_parts = preg_split($pattern, $_where); // Remove empties. $_where_parts = array_filter(array_map('trim', $_where_parts)); // Reassemble with an AND. $_where = implode(' AND ', $_where_parts); } } $key = md5(serialize(wp_array_slice_assoc($this->query_vars, array_keys($this->query_var_defaults)))); $last_changed = wp_cache_get_last_changed('comment'); // Fetch an entire level of the descendant tree at a time. $level = 0; do { // Parent-child relationships may be cached. Only query for those that are not. $child_ids = $uncached_parent_ids = array(); $_parent_ids = $levels[$level]; foreach ($_parent_ids as $parent_id) { $cache_key = "get_comment_child_ids:{$parent_id}:{$key}:{$last_changed}"; $parent_child_ids = wp_cache_get($cache_key, 'comment'); if (false !== $parent_child_ids) { $child_ids = array_merge($child_ids, $parent_child_ids); } else { $uncached_parent_ids[] = $parent_id; } } if ($uncached_parent_ids) { // Fetch this level of comments. $parent_query_args = $this->query_vars; foreach ($exclude_keys as $exclude_key) { $parent_query_args[$exclude_key] = ''; } $parent_query_args['parent__in'] = $uncached_parent_ids; $parent_query_args['no_found_rows'] = true; $parent_query_args['hierarchical'] = false; $parent_query_args['offset'] = 0; $parent_query_args['number'] = 0; $level_comments = get_comments($parent_query_args); // Cache parent-child relationships. $parent_map = array_fill_keys($uncached_parent_ids, array()); foreach ($level_comments as $level_comment) { $parent_map[$level_comment->comment_parent][] = $level_comment->comment_ID; $child_ids[] = $level_comment->comment_ID; } foreach ($parent_map as $parent_id => $children) { $cache_key = "get_comment_child_ids:{$parent_id}:{$key}:{$last_changed}"; wp_cache_set($cache_key, $children, 'comment'); } } $level++; $levels[$level] = $child_ids; } while ($child_ids); // Prime comment caches for non-top-level comments. $descendant_ids = array(); for ($i = 1, $c = count($levels); $i < $c; $i++) { $descendant_ids = array_merge($descendant_ids, $levels[$i]); } _prime_comment_caches($descendant_ids, $this->query_vars['update_comment_meta_cache']); // Assemble a flat array of all comments + descendants. $all_comments = $comments; foreach ($descendant_ids as $descendant_id) { $all_comments[] = get_comment($descendant_id); } // If a threaded representation was requested, build the tree. if ('threaded' === $this->query_vars['hierarchical']) { $threaded_comments = $ref = array(); foreach ($all_comments as $k => $c) { $_c = get_comment($c->comment_ID); // If the comment isn't in the reference array, it goes in the top level of the thread. if (!isset($ref[$c->comment_parent])) { $threaded_comments[$_c->comment_ID] = $_c; $ref[$_c->comment_ID] = $threaded_comments[$_c->comment_ID]; // Otherwise, set it as a child of its parent. } else { $ref[$_c->comment_parent]->add_child($_c); $ref[$_c->comment_ID] = $ref[$_c->comment_parent]->get_child($_c->comment_ID); } } // Set the 'populated_children' flag, to ensure additional database queries aren't run. foreach ($ref as $_ref) { $_ref->populated_children(true); } $comments = $threaded_comments; } else { $comments = $all_comments; } return $comments; }
/** * Gets a list of networks matching the query vars. * * @since 4.6.0 * @access public * * @return int|array The list of networks. */ public function get_networks() { $this->parse_query(); /** * Fires before networks are retrieved. * * @since 4.6.0 * * @param WP_Network_Query &$this Current instance of WP_Network_Query, passed by reference. */ do_action_ref_array('pre_get_networks', array(&$this)); // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. $key = md5(serialize(wp_array_slice_assoc($this->query_vars, array_keys($this->query_var_defaults)))); $last_changed = wp_cache_get_last_changed('networks'); $cache_key = "get_network_ids:{$key}:{$last_changed}"; $cache_value = wp_cache_get($cache_key, 'networks'); if (false === $cache_value) { $network_ids = $this->get_network_ids(); if ($network_ids) { $this->set_found_networks(); } $cache_value = array('network_ids' => $network_ids, 'found_networks' => $this->found_networks); wp_cache_add($cache_key, $cache_value, 'networks'); } else { $network_ids = $cache_value['network_ids']; $this->found_networks = $cache_value['found_networks']; } if ($this->found_networks && $this->query_vars['number']) { $this->max_num_pages = ceil($this->found_networks / $this->query_vars['number']); } // If querying for a count only, there's nothing more to do. if ($this->query_vars['count']) { // $network_ids is actually a count in this case. return intval($network_ids); } $network_ids = array_map('intval', $network_ids); if ('ids' == $this->query_vars['fields']) { $this->networks = $network_ids; return $this->networks; } if ($this->query_vars['update_network_cache']) { _prime_network_caches($network_ids); } // Fetch full network objects from the primed cache. $_networks = array(); foreach ($network_ids as $network_id) { if ($_network = get_network($network_id)) { $_networks[] = $_network; } } /** * Filters the network query results. * * @since 4.6.0 * * @param array $results An array of networks. * @param WP_Network_Query &$this Current instance of WP_Network_Query, passed by reference. */ $_networks = apply_filters_ref_array('the_networks', array($_networks, &$this)); // Convert to WP_Network instances $this->networks = array_map('get_network', $_networks); return $this->networks; }
/** * Get terms, based on query_vars. * * @param 4.6.0 * @access public * * @global wpdb $wpdb WordPress database abstraction object. * * @return array */ public function get_terms() { global $wpdb; $this->parse_query($this->query_vars); $args = $this->query_vars; // Set up meta_query so it's available to 'pre_get_terms'. $this->meta_query = new WP_Meta_Query(); $this->meta_query->parse_query_vars($args); /** * Fires before terms are retrieved. * * @since 4.6.0 * * @param WP_Term_Query $this Current instance of WP_Term_Query. */ do_action('pre_get_terms', $this); $taxonomies = $args['taxonomy']; // Save queries by not crawling the tree in the case of multiple taxes or a flat tax. $has_hierarchical_tax = false; if ($taxonomies) { foreach ($taxonomies as $_tax) { if (is_taxonomy_hierarchical($_tax)) { $has_hierarchical_tax = true; } } } if (!$has_hierarchical_tax) { $args['hierarchical'] = false; $args['pad_counts'] = false; } // 'parent' overrides 'child_of'. if (0 < intval($args['parent'])) { $args['child_of'] = false; } if ('all' == $args['get']) { $args['childless'] = false; $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } /** * Filters the terms query arguments. * * @since 3.1.0 * * @param array $args An array of get_terms() arguments. * @param array $taxonomies An array of taxonomies. */ $args = apply_filters('get_terms_args', $args, $taxonomies); // Avoid the query if the queried parent/child_of term has no descendants. $child_of = $args['child_of']; $parent = $args['parent']; if ($child_of) { $_parent = $child_of; } elseif ($parent) { $_parent = $parent; } else { $_parent = false; } if ($_parent) { $in_hierarchy = false; foreach ($taxonomies as $_tax) { $hierarchy = _get_term_hierarchy($_tax); if (isset($hierarchy[$_parent])) { $in_hierarchy = true; } } if (!$in_hierarchy) { return array(); } } // 'term_order' is a legal sort order only when joining the relationship table. $_orderby = $this->query_vars['orderby']; if ('term_order' === $_orderby && empty($this->query_vars['object_ids'])) { $_orderby = 'term_id'; } $orderby = $this->parse_orderby($_orderby); if ($orderby) { $orderby = "ORDER BY {$orderby}"; } $order = $this->parse_order($this->query_vars['order']); if ($taxonomies) { $this->sql_clauses['where']['taxonomy'] = "tt.taxonomy IN ('" . implode("', '", array_map('esc_sql', $taxonomies)) . "')"; } $exclude = $args['exclude']; $exclude_tree = $args['exclude_tree']; $include = $args['include']; $inclusions = ''; if (!empty($include)) { $exclude = ''; $exclude_tree = ''; $inclusions = implode(',', wp_parse_id_list($include)); } if (!empty($inclusions)) { $this->sql_clauses['where']['inclusions'] = 't.term_id IN ( ' . $inclusions . ' )'; } $exclusions = array(); if (!empty($exclude_tree)) { $exclude_tree = wp_parse_id_list($exclude_tree); $excluded_children = $exclude_tree; foreach ($exclude_tree as $extrunk) { $excluded_children = array_merge($excluded_children, (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0))); } $exclusions = array_merge($excluded_children, $exclusions); } if (!empty($exclude)) { $exclusions = array_merge(wp_parse_id_list($exclude), $exclusions); } // 'childless' terms are those without an entry in the flattened term hierarchy. $childless = (bool) $args['childless']; if ($childless) { foreach ($taxonomies as $_tax) { $term_hierarchy = _get_term_hierarchy($_tax); $exclusions = array_merge(array_keys($term_hierarchy), $exclusions); } } if (!empty($exclusions)) { $exclusions = 't.term_id NOT IN (' . implode(',', array_map('intval', $exclusions)) . ')'; } else { $exclusions = ''; } /** * Filters the terms to exclude from the terms query. * * @since 2.3.0 * * @param string $exclusions `NOT IN` clause of the terms query. * @param array $args An array of terms query arguments. * @param array $taxonomies An array of taxonomies. */ $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args, $taxonomies); if (!empty($exclusions)) { // Must do string manipulation here for backward compatibility with filter. $this->sql_clauses['where']['exclusions'] = preg_replace('/^\\s*AND\\s*/', '', $exclusions); } if (!empty($args['name'])) { $names = (array) $args['name']; foreach ($names as &$_name) { // `sanitize_term_field()` returns slashed data. $_name = stripslashes(sanitize_term_field('name', $_name, 0, reset($taxonomies), 'db')); } $this->sql_clauses['where']['name'] = "t.name IN ('" . implode("', '", array_map('esc_sql', $names)) . "')"; } if (!empty($args['slug'])) { if (is_array($args['slug'])) { $slug = array_map('sanitize_title', $args['slug']); $this->sql_clauses['where']['slug'] = "t.slug IN ('" . implode("', '", $slug) . "')"; } else { $slug = sanitize_title($args['slug']); $this->sql_clauses['where']['slug'] = "t.slug = '{$slug}'"; } } if (!empty($args['term_taxonomy_id'])) { if (is_array($args['term_taxonomy_id'])) { $tt_ids = implode(',', array_map('intval', $args['term_taxonomy_id'])); $this->sql_clauses['where']['term_taxonomy_id'] = "tt.term_taxonomy_id IN ({$tt_ids})"; } else { $this->sql_clauses['where']['term_taxonomy_id'] = $wpdb->prepare("tt.term_taxonomy_id = %d", $args['term_taxonomy_id']); } } if (!empty($args['name__like'])) { $this->sql_clauses['where']['name__like'] = $wpdb->prepare("t.name LIKE %s", '%' . $wpdb->esc_like($args['name__like']) . '%'); } if (!empty($args['description__like'])) { $this->sql_clauses['where']['description__like'] = $wpdb->prepare("tt.description LIKE %s", '%' . $wpdb->esc_like($args['description__like']) . '%'); } if (!empty($args['object_ids'])) { $object_ids = $args['object_ids']; if (!is_array($object_ids)) { $object_ids = array($object_ids); } $object_ids = implode(', ', array_map('intval', $object_ids)); $this->sql_clauses['where']['object_ids'] = "tr.object_id IN ({$object_ids})"; } /* * When querying for object relationships, the 'count > 0' check * added by 'hide_empty' is superfluous. */ if (!empty($args['object_ids'])) { $args['hide_empty'] = false; } if ('' !== $parent) { $parent = (int) $parent; $this->sql_clauses['where']['parent'] = "tt.parent = '{$parent}'"; } $hierarchical = $args['hierarchical']; if ('count' == $args['fields']) { $hierarchical = false; } if ($args['hide_empty'] && !$hierarchical) { $this->sql_clauses['where']['count'] = 'tt.count > 0'; } $number = $args['number']; $offset = $args['offset']; // Don't limit the query results when we have to descend the family tree. if ($number && !$hierarchical && !$child_of && '' === $parent) { if ($offset) { $limits = 'LIMIT ' . $offset . ',' . $number; } else { $limits = 'LIMIT ' . $number; } } else { $limits = ''; } if (!empty($args['search'])) { $this->sql_clauses['where']['search'] = $this->get_search_sql($args['search']); } // Meta query support. $join = ''; $distinct = ''; // Reparse meta_query query_vars, in case they were modified in a 'pre_get_terms' callback. $this->meta_query->parse_query_vars($this->query_vars); $mq_sql = $this->meta_query->get_sql('term', 't', 'term_id'); $meta_clauses = $this->meta_query->get_clauses(); if (!empty($meta_clauses)) { $join .= $mq_sql['join']; $this->sql_clauses['where']['meta_query'] = preg_replace('/^\\s*AND\\s*/', '', $mq_sql['where']); $distinct .= "DISTINCT"; } $selects = array(); switch ($args['fields']) { case 'all': case 'all_with_object_id': case 'tt_ids': case 'slugs': $selects = array('t.*', 'tt.*'); if ('all_with_object_id' === $args['fields'] && !empty($args['object_ids'])) { $selects[] = 'tr.object_id'; } break; case 'ids': case 'id=>parent': $selects = array('t.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy'); break; case 'names': $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy'); break; case 'count': $orderby = ''; $order = ''; $selects = array('COUNT(*)'); break; case 'id=>name': $selects = array('t.term_id', 't.name', 'tt.count', 'tt.taxonomy'); break; case 'id=>slug': $selects = array('t.term_id', 't.slug', 'tt.count', 'tt.taxonomy'); break; } $_fields = $args['fields']; /** * Filters the fields to select in the terms query. * * Field lists modified using this filter will only modify the term fields returned * by the function when the `$fields` parameter set to 'count' or 'all'. In all other * cases, the term fields in the results array will be determined by the `$fields` * parameter alone. * * Use of this filter can result in unpredictable behavior, and is not recommended. * * @since 2.8.0 * * @param array $selects An array of fields to select for the terms query. * @param array $args An array of term query arguments. * @param array $taxonomies An array of taxonomies. */ $fields = implode(', ', apply_filters('get_terms_fields', $selects, $args, $taxonomies)); $join .= " INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id"; if (!empty($this->query_vars['object_ids'])) { $join .= " INNER JOIN {$wpdb->term_relationships} AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id"; } $where = implode(' AND ', $this->sql_clauses['where']); /** * Filters the terms query SQL clauses. * * @since 3.1.0 * * @param array $pieces Terms query SQL clauses. * @param array $taxonomies An array of taxonomies. * @param array $args An array of terms query arguments. */ $clauses = apply_filters('terms_clauses', compact('fields', 'join', 'where', 'distinct', 'orderby', 'order', 'limits'), $taxonomies, $args); $fields = isset($clauses['fields']) ? $clauses['fields'] : ''; $join = isset($clauses['join']) ? $clauses['join'] : ''; $where = isset($clauses['where']) ? $clauses['where'] : ''; $distinct = isset($clauses['distinct']) ? $clauses['distinct'] : ''; $orderby = isset($clauses['orderby']) ? $clauses['orderby'] : ''; $order = isset($clauses['order']) ? $clauses['order'] : ''; $limits = isset($clauses['limits']) ? $clauses['limits'] : ''; if ($where) { $where = "WHERE {$where}"; } $this->sql_clauses['select'] = "SELECT {$distinct} {$fields}"; $this->sql_clauses['from'] = "FROM {$wpdb->terms} AS t {$join}"; $this->sql_clauses['orderby'] = $orderby ? "{$orderby} {$order}" : ''; $this->sql_clauses['limits'] = $limits; $this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}"; // $args can be anything. Only use the args defined in defaults to compute the key. $key = md5(serialize(wp_array_slice_assoc($args, array_keys($this->query_var_defaults))) . serialize($taxonomies) . $this->request); $last_changed = wp_cache_get_last_changed('terms'); $cache_key = "get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 'terms'); if (false !== $cache) { if ('all' === $_fields) { $cache = array_map('get_term', $cache); } $this->terms = $cache; return $this->terms; } if ('count' == $_fields) { $count = $wpdb->get_var($this->request); wp_cache_set($cache_key, $count, 'terms'); return $count; } $terms = $wpdb->get_results($this->request); if ('all' == $_fields || 'all_with_object_id' === $_fields) { update_term_cache($terms); } // Prime termmeta cache. if ($args['update_term_meta_cache']) { $term_ids = wp_list_pluck($terms, 'term_id'); update_termmeta_cache($term_ids); } if (empty($terms)) { wp_cache_add($cache_key, array(), 'terms', DAY_IN_SECONDS); return array(); } if ($child_of) { foreach ($taxonomies as $_tax) { $children = _get_term_hierarchy($_tax); if (!empty($children)) { $terms = _get_term_children($child_of, $terms, $_tax); } } } // Update term counts to include children. if ($args['pad_counts'] && 'all' == $_fields) { foreach ($taxonomies as $_tax) { _pad_term_counts($terms, $_tax); } } // Make sure we show empty categories that have children. if ($hierarchical && $args['hide_empty'] && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = get_term_children($term->term_id, $term->taxonomy); if (is_array($children)) { foreach ($children as $child_id) { $child = get_term($child_id, $term->taxonomy); if ($child->count) { continue 2; } } } // It really is empty. unset($terms[$k]); } } } /* * When querying for terms connected to objects, we may get * duplicate results. The duplicates should be preserved if * `$fields` is 'all_with_object_id', but should otherwise be * removed. */ if (!empty($args['object_ids']) && 'all_with_object_id' != $_fields) { $_tt_ids = $_terms = array(); foreach ($terms as $term) { if (isset($_tt_ids[$term->term_id])) { continue; } $_tt_ids[$term->term_id] = 1; $_terms[] = $term; } $terms = $_terms; } $_terms = array(); if ('id=>parent' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->parent; } } elseif ('ids' == $_fields) { foreach ($terms as $term) { $_terms[] = (int) $term->term_id; } } elseif ('tt_ids' == $_fields) { foreach ($terms as $term) { $_terms[] = (int) $term->term_taxonomy_id; } } elseif ('names' == $_fields) { foreach ($terms as $term) { $_terms[] = $term->name; } } elseif ('slugs' == $_fields) { foreach ($terms as $term) { $_terms[] = $term->slug; } } elseif ('id=>name' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->name; } } elseif ('id=>slug' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->slug; } } if (!empty($_terms)) { $terms = $_terms; } // Hierarchical queries are not limited, so 'offset' and 'number' must be handled now. if ($hierarchical && $number && is_array($terms)) { if ($offset >= count($terms)) { $terms = array(); } else { $terms = array_slice($terms, $offset, $number, true); } } wp_cache_add($cache_key, $terms, 'terms', DAY_IN_SECONDS); if ('all' === $_fields || 'all_with_object_id' === $_fields) { $terms = array_map('get_term', $terms); } $this->terms = $terms; return $this->terms; }
/** * Display archive links based on type and format. * * @since 1.2.0 * @since 4.4.0 $post_type arg was added. * * @see get_archives_link() * * @global wpdb $wpdb * @global WP_Locale $wp_locale * * @param string|array $args { * Default archive links arguments. Optional. * * @type string $type Type of archive to retrieve. Accepts 'daily', 'weekly', 'monthly', * 'yearly', 'postbypost', or 'alpha'. Both 'postbypost' and 'alpha' * display the same archive link list as well as post titles instead * of displaying dates. The difference between the two is that 'alpha' * will order by post title and 'postbypost' will order by post date. * Default 'monthly'. * @type string|int $limit Number of links to limit the query to. Default empty (no limit). * @type string $format Format each link should take using the $before and $after args. * Accepts 'link' (`<link>` tag), 'option' (`<option>` tag), 'html' * (`<li>` tag), or a custom format, which generates a link anchor * with $before preceding and $after succeeding. Default 'html'. * @type string $before Markup to prepend to the beginning of each link. Default empty. * @type string $after Markup to append to the end of each link. Default empty. * @type bool $show_post_count Whether to display the post count alongside the link. Default false. * @type bool|int $echo Whether to echo or return the links list. Default 1|true to echo. * @type string $order Whether to use ascending or descending order. Accepts 'ASC', or 'DESC'. * Default 'DESC'. * @type string $post_type Post type. Default 'post'. * } * @return string|void String when retrieving. */ function wp_get_archives($args = '') { global $wpdb, $wp_locale; $defaults = array('type' => 'monthly', 'limit' => '', 'format' => 'html', 'before' => '', 'after' => '', 'show_post_count' => false, 'echo' => 1, 'order' => 'DESC', 'post_type' => 'post'); $r = wp_parse_args($args, $defaults); $post_type_object = get_post_type_object($r['post_type']); if (!is_post_type_viewable($post_type_object)) { return; } $r['post_type'] = $post_type_object->name; if ('' == $r['type']) { $r['type'] = 'monthly'; } if (!empty($r['limit'])) { $r['limit'] = absint($r['limit']); $r['limit'] = ' LIMIT ' . $r['limit']; } $order = strtoupper($r['order']); if ($order !== 'ASC') { $order = 'DESC'; } // this is what will separate dates on weekly archive links $archive_week_separator = '–'; $sql_where = $wpdb->prepare("WHERE post_type = %s AND post_status = 'publish'", $r['post_type']); /** * Filters the SQL WHERE clause for retrieving archives. * * @since 2.2.0 * * @param string $sql_where Portion of SQL query containing the WHERE clause. * @param array $r An array of default arguments. */ $where = apply_filters('getarchives_where', $sql_where, $r); /** * Filters the SQL JOIN clause for retrieving archives. * * @since 2.2.0 * * @param string $sql_join Portion of SQL query containing JOIN clause. * @param array $r An array of default arguments. */ $join = apply_filters('getarchives_join', '', $r); $output = ''; $last_changed = wp_cache_get_last_changed('posts'); $limit = $r['limit']; if ('monthly' == $r['type']) { $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM {$wpdb->posts} {$join} {$where} GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date {$order} {$limit}"; $key = md5($query); $key = "wp_get_archives:{$key}:{$last_changed}"; if (!($results = wp_cache_get($key, 'posts'))) { $results = $wpdb->get_results($query); wp_cache_set($key, $results, 'posts'); } if ($results) { $after = $r['after']; foreach ((array) $results as $result) { $url = get_month_link($result->year, $result->month); if ('post' !== $r['post_type']) { $url = add_query_arg('post_type', $r['post_type'], $url); } /* translators: 1: month name, 2: 4-digit year */ $text = sprintf(__('%1$s %2$d'), $wp_locale->get_month($result->month), $result->year); if ($r['show_post_count']) { $r['after'] = ' (' . $result->posts . ')' . $after; } $output .= get_archives_link($url, $text, $r['format'], $r['before'], $r['after']); } } } elseif ('yearly' == $r['type']) { $query = "SELECT YEAR(post_date) AS `year`, count(ID) as posts FROM {$wpdb->posts} {$join} {$where} GROUP BY YEAR(post_date) ORDER BY post_date {$order} {$limit}"; $key = md5($query); $key = "wp_get_archives:{$key}:{$last_changed}"; if (!($results = wp_cache_get($key, 'posts'))) { $results = $wpdb->get_results($query); wp_cache_set($key, $results, 'posts'); } if ($results) { $after = $r['after']; foreach ((array) $results as $result) { $url = get_year_link($result->year); if ('post' !== $r['post_type']) { $url = add_query_arg('post_type', $r['post_type'], $url); } $text = sprintf('%d', $result->year); if ($r['show_post_count']) { $r['after'] = ' (' . $result->posts . ')' . $after; } $output .= get_archives_link($url, $text, $r['format'], $r['before'], $r['after']); } } } elseif ('daily' == $r['type']) { $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, DAYOFMONTH(post_date) AS `dayofmonth`, count(ID) as posts FROM {$wpdb->posts} {$join} {$where} GROUP BY YEAR(post_date), MONTH(post_date), DAYOFMONTH(post_date) ORDER BY post_date {$order} {$limit}"; $key = md5($query); $key = "wp_get_archives:{$key}:{$last_changed}"; if (!($results = wp_cache_get($key, 'posts'))) { $results = $wpdb->get_results($query); wp_cache_set($key, $results, 'posts'); } if ($results) { $after = $r['after']; foreach ((array) $results as $result) { $url = get_day_link($result->year, $result->month, $result->dayofmonth); if ('post' !== $r['post_type']) { $url = add_query_arg('post_type', $r['post_type'], $url); } $date = sprintf('%1$d-%2$02d-%3$02d 00:00:00', $result->year, $result->month, $result->dayofmonth); $text = mysql2date(get_option('date_format'), $date); if ($r['show_post_count']) { $r['after'] = ' (' . $result->posts . ')' . $after; } $output .= get_archives_link($url, $text, $r['format'], $r['before'], $r['after']); } } } elseif ('weekly' == $r['type']) { $week = _wp_mysql_week('`post_date`'); $query = "SELECT DISTINCT {$week} AS `week`, YEAR( `post_date` ) AS `yr`, DATE_FORMAT( `post_date`, '%Y-%m-%d' ) AS `yyyymmdd`, count( `ID` ) AS `posts` FROM `{$wpdb->posts}` {$join} {$where} GROUP BY {$week}, YEAR( `post_date` ) ORDER BY `post_date` {$order} {$limit}"; $key = md5($query); $key = "wp_get_archives:{$key}:{$last_changed}"; if (!($results = wp_cache_get($key, 'posts'))) { $results = $wpdb->get_results($query); wp_cache_set($key, $results, 'posts'); } $arc_w_last = ''; if ($results) { $after = $r['after']; foreach ((array) $results as $result) { if ($result->week != $arc_w_last) { $arc_year = $result->yr; $arc_w_last = $result->week; $arc_week = get_weekstartend($result->yyyymmdd, get_option('start_of_week')); $arc_week_start = date_i18n(get_option('date_format'), $arc_week['start']); $arc_week_end = date_i18n(get_option('date_format'), $arc_week['end']); $url = add_query_arg(array('m' => $arc_year, 'w' => $result->week), home_url('/')); if ('post' !== $r['post_type']) { $url = add_query_arg('post_type', $r['post_type'], $url); } $text = $arc_week_start . $archive_week_separator . $arc_week_end; if ($r['show_post_count']) { $r['after'] = ' (' . $result->posts . ')' . $after; } $output .= get_archives_link($url, $text, $r['format'], $r['before'], $r['after']); } } } } elseif ('postbypost' == $r['type'] || 'alpha' == $r['type']) { $orderby = 'alpha' == $r['type'] ? 'post_title ASC ' : 'post_date DESC, ID DESC '; $query = "SELECT * FROM {$wpdb->posts} {$join} {$where} ORDER BY {$orderby} {$limit}"; $key = md5($query); $key = "wp_get_archives:{$key}:{$last_changed}"; if (!($results = wp_cache_get($key, 'posts'))) { $results = $wpdb->get_results($query); wp_cache_set($key, $results, 'posts'); } if ($results) { foreach ((array) $results as $result) { if ($result->post_date != '0000-00-00 00:00:00') { $url = get_permalink($result); if ($result->post_title) { /** This filter is documented in wp-includes/post-template.php */ $text = strip_tags(apply_filters('the_title', $result->post_title, $result->ID)); } else { $text = $result->ID; } $output .= get_archives_link($url, $text, $r['format'], $r['before'], $r['after']); } } } } if ($r['echo']) { echo $output; } else { return $output; } }
/** * Retrieve a list of pages. * * @global wpdb $wpdb WordPress database abstraction object. * * @since 1.5.0 * * @param array|string $args { * Optional. Array or string of arguments to retrieve pages. * * @type int $child_of Page ID to return child and grandchild pages of. Note: The value * of `$hierarchical` has no bearing on whether `$child_of` returns * hierarchical results. Default 0, or no restriction. * @type string $sort_order How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'. * @type string $sort_column What columns to sort pages by, comma-separated. Accepts 'post_author', * 'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order', * 'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'. * 'post_' can be omitted for any values that start with it. * Default 'post_title'. * @type bool $hierarchical Whether to return pages hierarchically. If false in conjunction with * `$child_of` also being false, both arguments will be disregarded. * Default true. * @type array $exclude Array of page IDs to exclude. Default empty array. * @type array $include Array of page IDs to include. Cannot be used with `$child_of`, * `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`. * Default empty array. * @type string $meta_key Only include pages with this meta key. Default empty. * @type string $meta_value Only include pages with this meta value. Requires `$meta_key`. * Default empty. * @type string $authors A comma-separated list of author IDs. Default empty. * @type int $parent Page ID to return direct children of. Default -1, or no restriction. * @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude. * Default empty array. * @type int $number The number of pages to return. Default 0, or all pages. * @type int $offset The number of pages to skip before returning. Requires `$number`. * Default 0. * @type string $post_type The post type to query. Default 'page'. * @type string|array $post_status A comma-separated list or array of post statuses to include. * Default 'publish'. * } * @return array|false List of pages matching defaults or `$args`. */ function get_pages($args = array()) { global $wpdb; $defaults = array('child_of' => 0, 'sort_order' => 'ASC', 'sort_column' => 'post_title', 'hierarchical' => 1, 'exclude' => array(), 'include' => array(), 'meta_key' => '', 'meta_value' => '', 'authors' => '', 'parent' => -1, 'exclude_tree' => array(), 'number' => '', 'offset' => 0, 'post_type' => 'page', 'post_status' => 'publish'); $r = wp_parse_args($args, $defaults); $number = (int) $r['number']; $offset = (int) $r['offset']; $child_of = (int) $r['child_of']; $hierarchical = $r['hierarchical']; $exclude = $r['exclude']; $meta_key = $r['meta_key']; $meta_value = $r['meta_value']; $parent = $r['parent']; $post_status = $r['post_status']; // Make sure the post type is hierarchical. $hierarchical_post_types = get_post_types(array('hierarchical' => true)); if (!in_array($r['post_type'], $hierarchical_post_types)) { return false; } if ($parent > 0 && !$child_of) { $hierarchical = false; } // Make sure we have a valid post status. if (!is_array($post_status)) { $post_status = explode(',', $post_status); } if (array_diff($post_status, get_post_stati())) { return false; } // $args can be whatever, only use the args defined in defaults to compute the key. $key = md5(serialize(wp_array_slice_assoc($r, array_keys($defaults)))); $last_changed = wp_cache_get_last_changed('posts'); $cache_key = "get_pages:{$key}:{$last_changed}"; if ($cache = wp_cache_get($cache_key, 'posts')) { // Convert to WP_Post instances. $pages = array_map('get_post', $cache); /** This filter is documented in wp-includes/post.php */ $pages = apply_filters('get_pages', $pages, $r); return $pages; } $inclusions = ''; if (!empty($r['include'])) { $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include $parent = -1; $exclude = ''; $meta_key = ''; $meta_value = ''; $hierarchical = false; $incpages = wp_parse_id_list($r['include']); if (!empty($incpages)) { $inclusions = ' AND ID IN (' . implode(',', $incpages) . ')'; } } $exclusions = ''; if (!empty($exclude)) { $expages = wp_parse_id_list($exclude); if (!empty($expages)) { $exclusions = ' AND ID NOT IN (' . implode(',', $expages) . ')'; } } $author_query = ''; if (!empty($r['authors'])) { $post_authors = preg_split('/[\\s,]+/', $r['authors']); if (!empty($post_authors)) { foreach ($post_authors as $post_author) { //Do we have an author id or an author login? if (0 == intval($post_author)) { $post_author = get_user_by('login', $post_author); if (empty($post_author)) { continue; } if (empty($post_author->ID)) { continue; } $post_author = $post_author->ID; } if ('' == $author_query) { $author_query = $wpdb->prepare(' post_author = %d ', $post_author); } else { $author_query .= $wpdb->prepare(' OR post_author = %d ', $post_author); } } if ('' != $author_query) { $author_query = " AND ({$author_query})"; } } } $join = ''; $where = "{$exclusions} {$inclusions} "; if ('' !== $meta_key || '' !== $meta_value) { $join = " LEFT JOIN {$wpdb->postmeta} ON ( {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id )"; // meta_key and meta_value might be slashed $meta_key = wp_unslash($meta_key); $meta_value = wp_unslash($meta_value); if ('' !== $meta_key) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_key = %s", $meta_key); } if ('' !== $meta_value) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_value = %s", $meta_value); } } if (is_array($parent)) { $post_parent__in = implode(',', array_map('absint', (array) $parent)); if (!empty($post_parent__in)) { $where .= " AND post_parent IN ({$post_parent__in})"; } } elseif ($parent >= 0) { $where .= $wpdb->prepare(' AND post_parent = %d ', $parent); } if (1 == count($post_status)) { $where_post_type = $wpdb->prepare("post_type = %s AND post_status = %s", $r['post_type'], reset($post_status)); } else { $post_status = implode("', '", $post_status); $where_post_type = $wpdb->prepare("post_type = %s AND post_status IN ('{$post_status}')", $r['post_type']); } $orderby_array = array(); $allowed_keys = array('author', 'post_author', 'date', 'post_date', 'title', 'post_title', 'name', 'post_name', 'modified', 'post_modified', 'modified_gmt', 'post_modified_gmt', 'menu_order', 'parent', 'post_parent', 'ID', 'rand', 'comment_count'); foreach (explode(',', $r['sort_column']) as $orderby) { $orderby = trim($orderby); if (!in_array($orderby, $allowed_keys)) { continue; } switch ($orderby) { case 'menu_order': break; case 'ID': $orderby = "{$wpdb->posts}.ID"; break; case 'rand': $orderby = 'RAND()'; break; case 'comment_count': $orderby = "{$wpdb->posts}.comment_count"; break; default: if (0 === strpos($orderby, 'post_')) { $orderby = "{$wpdb->posts}." . $orderby; } else { $orderby = "{$wpdb->posts}.post_" . $orderby; } } $orderby_array[] = $orderby; } $sort_column = !empty($orderby_array) ? implode(',', $orderby_array) : "{$wpdb->posts}.post_title"; $sort_order = strtoupper($r['sort_order']); if ('' !== $sort_order && !in_array($sort_order, array('ASC', 'DESC'))) { $sort_order = 'ASC'; } $query = "SELECT * FROM {$wpdb->posts} {$join} WHERE ({$where_post_type}) {$where} "; $query .= $author_query; $query .= " ORDER BY " . $sort_column . " " . $sort_order; if (!empty($number)) { $query .= ' LIMIT ' . $offset . ',' . $number; } $pages = $wpdb->get_results($query); if (empty($pages)) { /** This filter is documented in wp-includes/post.php */ $pages = apply_filters('get_pages', array(), $r); return $pages; } // Sanitize before caching so it'll only get done once. $num_pages = count($pages); for ($i = 0; $i < $num_pages; $i++) { $pages[$i] = sanitize_post($pages[$i], 'raw'); } // Update cache. update_post_cache($pages); if ($child_of || $hierarchical) { $pages = get_page_children($child_of, $pages); } if (!empty($r['exclude_tree'])) { $exclude = wp_parse_id_list($r['exclude_tree']); foreach ($exclude as $id) { $children = get_page_children($id, $pages); foreach ($children as $child) { $exclude[] = $child->ID; } } $num_pages = count($pages); for ($i = 0; $i < $num_pages; $i++) { if (in_array($pages[$i]->ID, $exclude)) { unset($pages[$i]); } } } $page_structure = array(); foreach ($pages as $page) { $page_structure[] = $page->ID; } wp_cache_set($cache_key, $page_structure, 'posts'); // Convert to WP_Post instances $pages = array_map('get_post', $pages); /** * Filters the retrieved list of pages. * * @since 2.1.0 * * @param array $pages List of pages to retrieve. * @param array $r Array of get_pages() arguments. */ return apply_filters('get_pages', $pages, $r); }