source/_plugins/generate_archives.rb (101 lines of code) (raw):

# Jekyll archive page generator with pagination. # # Based on the category generator from # http://recursive-design.com/projects/jekyll-plugins/, # which is copyright (c) 2010 Dave Perrett, # http://recursive-design.com/ and is licensed under the MIT # license (http://www.opensource.org/licenses/mit-license.php), and # on the pagination code from Jekyll itself. # # This code is copyright (c) 2011 Benjamin Curtis, and is licensed # under the MIT license. # # A generator that creates archive pages for jekyll sites. # # To use it, simply drop this script into the _plugins directory of your Jekyll site. You should # also create a file called 'archive_index.html' in the _layouts directory of your jekyll site # with the following contents (note: you should remove the leading '# ' characters): # # ================================== COPY BELOW THIS LINE ================================== # --- # layout: default # --- # # {% for post in paginator.posts %} # {% include post.html %} # {% endfor %} # # <p class="navigation"> # {% if paginator.next_page %} # <span class="alignleft"><a href="/archives/{{ page.year}}/{{ page.month }}/page/{{ paginator.next_page }}/">« Previous Entries</a></span> # {% endif %} # # {% if paginator.previous_page %} # {% if paginator.previous_page > 1 %} # <span class="alignright"><a href="/archives/{{ page.year}}/{{ page.month }}/page/{{ paginator.previous_page }}/">Next Entries »</a></span> # {% else %} # <span class="alignright"><a href="/archives/{{ page.year}}/{{ page.month }}/">Next Entries »</a></span> # {% endif %} # {% endif %} # </p> # ================================== COPY ABOVE THIS LINE ================================== # # You can alter the _layout_ setting if you wish to use an alternate layout, and obviously you # can change the HTML above as you see fit. # # When you compile your jekyll site, this plugin will loop through the list of archives in your # site, and use the layout above to generate a page for each one with a list of links to the # individual posts. # # Included filters : # - archive_links: Outputs the list of archives as <link> tags for use in the <head> # - archive_selects: Outputs the list of archives as <option> tags for use in a navigation drop-down box # # Available _config.yml settings : # - archive_dir: The subfolder to build archive pages in (default is 'archives'). # - archive_title_prefix: The string used before the archive name in the page title (default is # 'Archive: '). # require 'jekyll-paginate' module Jekyll # The ArchiveIndex class creates a single archive page for the specified archive. class ArchiveIndex < Page # Initializes a new ArchiveIndex. # # +base+ is the String path to the <source>. # +archive_dir+ is the String path between <source> and the archive folder. def initialize(site, base, archive_dir, year, month) @site = site @base = base @dir = archive_dir @name = 'index.html' self.process(@name) # Read the YAML data from the layout page. self.read_yaml(File.join(base, '_layouts'), 'archive_index.html') # Set the year and month for this page self.data['year'] = year self.data['month'] = month # Set the title for this page. title_prefix = site.config['archive_title_prefix'] || 'Archive: ' self.data['title'] = "#{title_prefix}#{year} &raquo; #{Jekyll::ArchiveFilter::Months[month.to_i]}" # Set the meta-description for this page. meta_description_prefix = site.config['archive_meta_description_prefix'] || 'Archive: ' self.data['description'] = "#{meta_description_prefix}#{year} #{month}" end end # The Site class is a built-in Jekyll class with access to global site config information. class Site # Creates an instance of ArchiveIndex for each archive page, renders it, and # writes the output to a file. # # +archive_dir+ is the String path to the archive folder. # +archive+ is the archive currently being processed. def write_archive_index(archive_dir, posts, year, month) index = ArchiveIndex.new(self, self.source, archive_dir, year, month) pages = Jekyll::Paginate::Pager.calculate_pages(posts, self.config['paginate']) (1..pages).each do |num_page| pager = Jekyll::Paginate::Pager.new(self, num_page, posts, pages) if num_page > 1 newpage = ArchiveIndex.new(self, self.source, archive_dir, year, month) newpage.pager = pager newpage.dir = File.join(archive_dir, "page/#{num_page}") self.pages << newpage else index.pager = pager end end index.render(self.layouts, site_payload) index.write(self.dest) # Record the fact that this page has been added, otherwise Site::cleanup will remove it. self.pages << index end # Loops through the list of archive pages and processes each one. def write_archive_indexes if self.layouts.key? 'archive_index' dir = self.config['archive_dir'] || 'archives' posts_by_year_month = self.posts.docs.inject({}) do |h, post| ((h[post.date.year] ||= {})[sprintf('%02i', post.date.month)] ||= []) << post h end.each do |year, months| months.each do |month, posts| self.write_archive_index(File.join(dir, year.to_s, month.to_s), posts.reverse, year, month) end end # Throw an exception if the layout couldn't be found. else throw "No 'archive_index' layout found." end end alias_method :original_site_payload, :site_payload def site_payload pl = original_site_payload pl['site']['archives'] = self.posts.docs.inject(Hash.new(0)) do |h, post| h["#{post.date.year}/#{sprintf('%02i', post.date.month)}"] += 1 h end pl end end # Jekyll hook - the generate method is called by jekyll, and generates all of the archive pages. class GenerateArchives < Generator safe true priority :low def generate(site) site.write_archive_indexes end end class Post def year @year ||= date.strftime("%Y") end def month @month ||= date.strftime("%m") end end # Adds some extra filters used during the archive creation process. module ArchiveFilter Months = %w(None January February March April May June July August September October November December) # Outputs a list of archives for archive links in the head # # +archives+ is the list of archives to format. # # Returns string def archive_links(archives) archives.keys.sort.reverse.collect do |path| year, month = path.split('/').map(&:to_i) %Q{<link rel="archives" title="#{Months[month]} #{year}" href="/archives/#{path}/" />} end end # Added by Tomaz def archives_sidebar_links(archives) archives.sort.reverse.collect do |path, count| year, month = path.split('/').map(&:to_i) %Q{<li> <a href="/blog/archives/#{path}/"> #{Months[month]} #{year}</a> &nbsp;(#{count})</li>} end end # Outputs a list of archives for archive select options in the sidebar # # +archives+ is the list of archives to format. # # Returns string def archive_selects(archives) archives.sort.reverse.collect do |path, count| year, month = path.split('/').map(&:to_i) %Q{<option value="/archives/#{path}/"> #{Months[month]} #{year} &nbsp;(#{count})</option>} end end end end Liquid::Template.register_filter(Jekyll::ArchiveFilter)