From ab4397c05a5b712526615c6b3e69fd72b8036abf Mon Sep 17 00:00:00 2001 From: Erick Hitter <ehitter@gmail.com> Date: Sun, 3 Jun 2012 18:58:25 -0400 Subject: [PATCH] Initial plugin commit. --- date-based-taxonomy-archives.php | 294 +++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 date-based-taxonomy-archives.php diff --git a/date-based-taxonomy-archives.php b/date-based-taxonomy-archives.php new file mode 100644 index 0000000..e292af7 --- /dev/null +++ b/date-based-taxonomy-archives.php @@ -0,0 +1,294 @@ +<?php +/* +Plugin Name: Date-based Taxonomy Archives +Plugin URI: +Description: Renders an unordered list of years with months, linked to corresponding date-based taxonomy archive, nested therein. +Author: Erick Hitter +Version: 0.1 +Author URI: http://www.ethitter.com/ +*/ + +class Date_Based_Taxonomy_Archives { + /** + * Class variables + */ + var $defaults = array( + 'taxonomies' => false, + 'show_post_count' => false, + 'limit' => '', + 'before' => '', + 'after' => '', + 'echo' => true + ); + + var $cache_key_incrementor = 'incrementor'; + var $cache_group = 'date_based_taxonomy_archives'; + + var $filter_archive_links = false; + + /** + * Register actions and filters + * + * @uses add_action, add_filter + * @return null + */ + function __construct() { + add_action( 'transition_post_status', array( $this, 'action_transition_post_status' ), 50, 2 ); + + add_filter( 'date_based_taxonomy_archives_where', array( $this, 'filter_date_based_taxonomy_archives_where' ), 10, 2 ); + add_filter( 'date_based_taxonomy_archives_join', array( $this, 'filter_date_based_taxonomy_archives_join' ), 10, 2 ); + add_filter( 'get_archives_link', array( $this, 'filter_get_archives_link' ) ); + + add_action( 'generate_rewrite_rules', array( $this, 'action_generate_rewrite_rules' ) ); + } + + /** + * Render unordered lists of monthly archive links grouped by year + * + * @param array $args + * @uses $wpdb, $wp_locale, apply_filters, wp_parse_args, absint, this::get_incrementor, wp_cache_get, wp_cache_set, get_month_link, get_archives_link + * @return string or false + */ + function get_archives( $args = array() ) { + global $wpdb, $wp_locale; + + $args = apply_filters( 'date_based_taxonomy_archives_args', $args ); + $args = wp_parse_args( $args, $this->defaults ); + extract( $args ); + + //Build query + $where = apply_filters( 'date_based_taxonomy_archives_where', "WHERE post_type = 'post' AND post_status = 'publish'", $args ); + $join = apply_filters( 'date_based_taxonomy_archives_join', '', $args ); + + if( is_numeric( $limit ) ) + $limit = ' LIMIT ' . absint( $limit ); + + $query = $wpdb->prepare( "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 DESC $limit" ); + + //Generate cache key, check cache, query DB if necessary and cache results + $cache_key = $this->get_incrementor() . md5( $query ); + + if( !$results = wp_cache_get( $cache_key, $this->cache_group ) ) { + $results = $wpdb->get_results( $query ); + + wp_cache_set( $cache_key, $results, $this->cache_group ); + } + + //Bail out if necessary data isn't available + if( !is_array( $results ) || empty( $results ) ) + return false; + + //Render archive + $output = '<ul>'; + $cy = false; + + //Alias $after for use inside of foreach + $_after = $after; + + foreach( $results as $result ) { + if( $cy !== false && $cy != $result->year ) + $output .= '</ul></li>'; + + if( $cy === false || $cy != $result->year ) { + $cy = $result->year; + + $output .= '<li><span>' . absint( $result->year ) . '</span>'; + $output .= '<ul>'; + } + + $url = get_month_link( $result->year, $result->month ); + + $text = $wp_locale->get_month( $result->month ); + + $after = $show_post_count ? ' (' . absint( $result->posts ) . ')' . $_after : $_after; + + $output .= get_archives_link( $url, $text, 'html', $before, $after ); + } + + if( $cy == $result->year ) + $output .= '</ul></li>'; + + $output .= '</ul>'; + + //Reset archive links filter indicator + $this->filter_archive_links = false; + + if( $echo ) + echo $output; + else + return $output; + } + + /** + * Filter where clause used in this::get_archives + * + * @param string $where + * @param array $args + * @uses $wpdb, apply_filters, wp_parse_args, is_category, is_tag, is_tax, get_queried_object + * @filter date_based_taxonomy_archives_where + * @return string + */ + function filter_date_based_taxonomy_archives_where( $where, $args ) { + global $wpdb; + + $args = apply_filters( 'date_based_taxonomy_archives_args', $args ); + $args = wp_parse_args( $args, $this->defaults ); + extract( $args ); + + if( + ( $taxonomies == 'all' && ( is_category() || is_tag() || is_tax() ) ) || + ( $taxonomies == 'custom' && !is_category() && !is_tag() && is_tax() ) + ) { + $queried_object = get_queried_object(); + + if( is_object( $queried_object ) && property_exists( $queried_object, 'term_taxonomy_id' ) ) + $where .= $wpdb->prepare( ' AND dbtrtr.term_taxonomy_id = %d', $queried_object->term_taxonomy_id ); + } + elseif( is_array( $taxonomies ) ) { + $queried_object = get_queried_object(); + + if( is_object( $queried_object ) && property_exists( $queried_object, 'term_taxonomy_id' ) && property_exists( $queried_object, 'taxonomy' ) && in_array( $queried_object->taxonomy, $taxonomies ) ) + $where .= $wpdb->prepare( ' AND dbtrtr.term_taxonomy_id = %d', $queried_object->term_taxonomy_id ); + } + + return $where; + } + + /** + * Filter join clause used in this::get_archives + * + * @param string $join + * @param array $args + * @uses $wpdb, apply_filters, wp_parse_args, is_category, is_tag, is_tax + * @filter date_based_taxonomy_archives_join + * @return string + */ + function filter_date_based_taxonomy_archives_join( $join, $args ) { + global $wpdb; + + $args = apply_filters( 'date_based_taxonomy_archives_args', $args ); + $args = wp_parse_args( $args, $this->defaults ); + extract( $args ); + + if( + ( $taxonomies == 'all' && ( is_category() || is_tag() || is_tax() ) ) || + ( $taxonomies == 'custom' && !is_category() && !is_tag() && is_tax() ) || + is_array( $taxonomies ) + ) { + $join .= $wpdb->prepare( " INNER JOIN {$wpdb->term_relationships} AS dbtrtr on dbtrtr.object_id = {$wpdb->posts}.ID" ); + + $this->filter_archive_links = true; + } + + return $join; + } + + /** + * Filter get_archives_link output to inject taxonomy and term slugs + * + * @param string $link_html + * @uses $wp_rewrite, get_queried_object, is_wp_error, path_join, trailingslashit, home_url, get_taxonomy, add_query_arg + * @filter get_archives_link + * @return string + */ + function filter_get_archives_link( $link_html ) { + if( $this->filter_archive_links ) { + global $wp_rewrite; + + $queried_object = get_queried_object(); + + if( is_object( $queried_object ) && !is_wp_error( $queried_object ) ) { + $exploded = explode( "'", $link_html ); + + if( $wp_rewrite->using_permalinks() && array_key_exists( $queried_object->taxonomy, $wp_rewrite->extra_permastructs ) ) { + $term_rewrite = preg_replace( '#%[^%]+%#i', $queried_object->slug, $wp_rewrite->extra_permastructs[ $queried_object->taxonomy ][ 0 ] ); + $term_rewrite = substr( $term_rewrite, 1 ); //Drop leading slash, otherwise path_join misinterprets request + $term_rewrite = path_join( $term_rewrite, 'date' ); + + $exploded[ 1 ] = str_replace( trailingslashit( home_url() ), trailingslashit( path_join( home_url(), $term_rewrite ) ), $exploded[ 1 ] ); + } + else { + $taxonomy = get_taxonomy( $queried_object->taxonomy ); + + if( is_object( $taxonomy ) && !is_wp_error( $taxonomy ) ) + $exploded[ 1 ] = add_query_arg( $taxonomy->query_var, $queried_object->slug, $exploded[ 1 ] ); + } + + $link_html = implode( "'", $exploded ); + } + } + + return $link_html; + } + + /** + * Add rewrite rules to support [taxonomy]/[term]/date/[year]/[month]/page/[number] + * + * @param object $wp_rewrite + * @uses get_taxonomies + * @action generate_rewrite_rules + * @return null + */ + function action_generate_rewrite_rules( $wp_rewrite ) { + $taxonomies = get_taxonomies( null, 'objects' ); + + if( is_array( $taxonomies ) && !empty( $taxonomies ) ) { + $rules = array(); + + foreach( $taxonomies as $taxonomy ) + $rules[ $taxonomy->rewrite[ 'slug' ] . '/(.+?)/date/([0-9]{4})/([0-9]{1,2})/?(page/?([0-9]{1,})/?)?$' ] = 'index.php?' . $taxonomy->query_var . '=$matches[1]&year=$matches[2]&monthnum=$matches[3]&paged=$matches[5]'; + + $wp_rewrite->rules = $rules + $wp_rewrite->rules; + } + } + + /** + * Return cache incrementor. To invalidate caches, incrementor is deleted via this::action_transition_post_status. + * + * @uses wp_cache_get, wp_cache_set + * @return int + */ + function get_incrementor() { + $incrementor = wp_cache_get( $this->cache_key_incrementor, $this->cache_group ); + + if( !is_numeric( $incrementor ) ) { + $incrementor = time(); + wp_cache_set( $this->cache_key_incrementor, $incrementor, $this->cache_group ); + } + + return (int)$incrementor; + } + + /** + * Invalidate caches when posts are published or published posts are updated + * + * @param string $new_status + * @param string $old_status + * @uses wp_cache_delete + * @action transition_post_status + * @return null + */ + function action_transition_post_status( $new_status, $old_status ) { + if( $new_status == 'publish' || $old_status == 'publish' ) + wp_cache_delete( $this->cache_key_incrementor, $this->cache_group ); + } +} +global $date_based_taxonomy_archives; +if( !is_a( $date_based_taxonomy_archives, 'Date_Based_Taxonomy_Archives' ) ) + $date_based_taxonomy_archives = new Date_Based_Taxonomy_Archives; + +/** + * Render unordered lists of monthly archive links grouped by year + * + * @param array $args + * @uses $date_based_taxonomy_archives + * @return string or false + */ +function date_based_taxonomy_archives( $args = array() ) { + global $date_based_taxonomy_archives; + if( !is_a( $date_based_taxonomy_archives, 'Date_Based_Taxonomy_Archives' ) ) + $date_based_taxonomy_archives = new Date_Based_Taxonomy_Archives; + + return $date_based_taxonomy_archives->get_archives( $args ); +} +?> \ No newline at end of file -- GitLab