├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── jekyll-contentful.gemspec └── lib ├── jekyll-contentful.rb └── jekyll-contentful ├── contentful-monkeypatch.rb ├── language_switcher_tag.rb └── version.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in jekyllcontentful.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Dommmel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jekyll-Contentful 2 | 3 | Generate Pages for Contentful Entries 4 | 5 | ## Installation 6 | 7 | Add this line to your Gemfile: 8 | 9 | ```ruby 10 | group :jekyll_plugins do 11 | gem "jekyll-contentful" 12 | end 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Alternatively install the gem yourself as: 20 | 21 | $ gem install jekyll-contentful 22 | 23 | and put this in your ``_config.yml`` 24 | 25 | ```yaml 26 | gems: [jekyll-contentful] 27 | # This will require each of these gems automatically. 28 | ``` 29 | 30 | ## Configuration 31 | 32 | Configure in your _config.yml file 33 | 34 | 35 | ```yaml 36 | contentful: 37 | preview: No 38 | production_access_token: 'YOUR_PRODUCTION_TOKEN' 39 | preview_access_token: 'YOUR_PREVIEW_TOKEN' 40 | space: 'YOUR_SPACE' 41 | content_types: 42 | - "First Content Type" 43 | - "Second Content Type" 44 | published_locales_field: "published_languages" 45 | localization: 46 | - locale: en-US 47 | url_prefix: "" 48 | lang: "English" 49 | - locale: de-DE 50 | url_prefix: "de/" 51 | lang: "Deutsch" 52 | ``` 53 | 54 | 55 | ### Translations 56 | You can globally specify the languages/locales that you want to generate pages for. 57 | See the ``localization`` array in the ``_config.yml`` example above. You need to set the ``locale``, a string that this locale's urls will be prefixed with (``url_prefix``) and the language name (``lang``). The ``lang`` setting is used by the language switcher. 58 | 59 | #### Language switcher 60 | you can use the tag ``{% language_switcher %}`` in your templates to insert a link to the translations of the current page. 61 | 62 | #### Selective Translations 63 | By default the plugin will – for every entry – generate a page for every locale you specified in your ``_config.yml``. 64 | 65 | You can also **specify** which **locales** should be published **on the entry level**: 66 | 67 | 1. Add a Content Type called "Languages" to your space (you can name it differently). 68 | 2. Add a field called "locale" to that content type (this field has to be called "locale" and nothing else). 69 | 3. Add an entry of that content type for every locale you have enabled in your space. Set those entries' "locale" field accordingly. 70 | 4. Add a reference field (many) to the content type you want to selectively translate. Call it "published_languages" (you can name it differently but it has to match the name in the next step). Set the validations to allow only the content type "Languages" to be referenced. 71 | 5. Add ``published_locales_field: "published_languages"`` in the ``contentful:``section of your ``_config.yml`` 72 | 73 | Now for every entry you can specify the languages you want to generate pages for by adding them to your entries "published_languages" list. 74 | 75 | #### Content Fields: 76 | 77 | All Entry fields can be used inside the layout templates as {{ page.contentful_fields.fieldname }}. 78 | The plugin adds two more fields to pages generated from Contentful entries: ``{ page.contentful_id }}`` and ``{{ page.contentful_locale }}``. 79 | 80 | #### ULRs and Layouts: 81 | 82 | Let's say you have a content type named "Blog Post" with an entry that has its title field set to "Awesome Title". 83 | The plugin will generate a page using the "blog-post.html" layout at the url: /en/blog-post/awesome-title/index.html 84 | 85 | If no layout named "blog-post.html" can be found the plugin will fallback to use the "default.html" layout. 86 | 87 | ## Minimal Layout Example 88 | 89 | the following example assumes a content type with two fields. A long text field named "body" and a short text field named "title". 90 | 91 | ```liquid 92 | 93 | 94 | 95 |
96 |
97 | {% for p in site.pages %} 98 | {% if p.title and page.contentful_locale == p.contentful_locale %} 99 | {% if p.url == page.url %} 100 | {{ p.title }} 101 | {% else %} 102 | {{ p.title }} 103 | {% endif %} 104 | {% endif %} 105 | {% endfor %} 106 |
107 |
108 |
109 |

{{ page.title }}

110 |

{{ page.body | markdownify }}

111 |
112 | {% language_switcher %} 113 | 114 | 115 | ``` 116 | 117 | You can find a more comprehensive example over at [github.com/dommmel/jekyll-contentful-example](https://github.com/dommmel/jekyll-contentful-example). 118 | 119 | ## License 120 | 121 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /jekyll-contentful.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'jekyll-contentful/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "jekyll-contentful" 8 | spec.version = Jekyll::Contentful::VERSION 9 | spec.authors = ["Dommmel"] 10 | spec.email = ["dommmel@gmail.com"] 11 | 12 | spec.summary = %q{jekyll plugin that generates pages from contentful entries} 13 | spec.description = %q{jekyll plugin that generates pages from contentful entries} 14 | spec.homepage = "https://github.com/dommmel/jekyll-contentful" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.require_paths = ["lib"] 19 | 20 | spec.add_dependency 'jekyll' 21 | spec.add_dependency "contentful" 22 | spec.add_development_dependency "bundler", "~> 1.10" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | end 25 | -------------------------------------------------------------------------------- /lib/jekyll-contentful.rb: -------------------------------------------------------------------------------- 1 | require "jekyll" 2 | require "contentful" 3 | require "jekyll-contentful/version" 4 | require "jekyll-contentful/contentful-monkeypatch" 5 | require "jekyll-contentful/language_switcher_tag" 6 | 7 | module Jekyll 8 | class ContentfulEntryPage < Page 9 | def initialize(site, entry, content_type_name, prefix) 10 | 11 | @site = site 12 | @base = site.source 13 | @name = 'index.html' 14 | 15 | content_type_slug = Utils.slugify content_type_name 16 | 17 | layout_filename = site.layouts.key?(content_type_slug) ? "#{content_type_slug}.html" : "default.html" 18 | self.read_yaml(File.join(@base, '_layouts'), layout_filename) 19 | 20 | # stringify hash keys 21 | fields = Jekyll::Utils.stringify_hash_keys(entry.fields) 22 | self.data['contentful_fields'] = fields 23 | 24 | display_field = entry.content_type.resolve.display_field 25 | self.data['title'] = fields[display_field] if display_field 26 | 27 | self.data["contentful_id"] = entry.id 28 | self.data["contentful_locale"] = entry.locale 29 | self.data["contentful_content_type_name"] = content_type_name 30 | 31 | # If there is a title fields make it the url 32 | page_title_slug = Utils.slugify(self.data["title"] || "") 33 | @dir = "/#{prefix}#{content_type_slug}/#{page_title_slug}" 34 | 35 | self.process(@name) 36 | end 37 | end 38 | 39 | class ContentfulEntryPageGenerator < Generator 40 | safe true 41 | 42 | def generate(site) 43 | 44 | if site.config['contentful']['preview'] 45 | api_url = 'preview.contentful.com' 46 | access_token = site.config['contentful']['preview_access_token'] 47 | else 48 | api_url = 'cdn.contentful.com' 49 | access_token = site.config['contentful']['production_access_token'] 50 | end 51 | 52 | client = ::Contentful::Client.new( 53 | access_token: access_token, 54 | space: site.config['contentful']['space'], 55 | api_url: api_url 56 | ) 57 | 58 | # Loop over all content types 59 | site.config['contentful']['content_types'].each do |content_type_id| 60 | # Get name for content type ID 61 | content_type = client.content_types('sys.id' => content_type_id).first 62 | 63 | throw "Content_type \'#{content_type_id}\' does not exist." if content_type.nil? 64 | 65 | localization = site.config['contentful']['localization'] || [{locale: nil, url_prefix: ""}] 66 | 67 | # Get all entries of content type 68 | 69 | localization.each do |loc| 70 | entries = client.entries(content_type: content_type_id, locale: loc["locale"], limit: 1000) 71 | entries.each do |entry| 72 | 73 | next if entry.fields.nil? 74 | 75 | published_locales_field = site.config['contentful']['published_locales_field'] 76 | pub_langs = published_locales_field.nil? ? nil : entry.fields[published_locales_field.to_sym] 77 | 78 | if pub_langs.nil? or pub_langs.map{|x| x.fields[:locale]}.include?(loc["locale"]) 79 | site.pages << ContentfulEntryPage.new(site, entry, content_type.name, "#{loc['url_prefix']}") 80 | end 81 | end 82 | end 83 | 84 | end 85 | end 86 | end 87 | 88 | end 89 | -------------------------------------------------------------------------------- /lib/jekyll-contentful/contentful-monkeypatch.rb: -------------------------------------------------------------------------------- 1 | # Make asset arrays work in liquid templates 2 | # e.g. 3 | # 4 | # {% for pic in page.gallery %} 5 | # {{ pic.title }} 6 | # 7 | # {% endfor %} 8 | # 9 | 10 | module Contentful 11 | class Asset 12 | def to_liquid 13 | Jekyll::Utils.stringify_hash_keys(self.fields) 14 | end 15 | end 16 | class File 17 | def to_liquid 18 | Jekyll::Utils.stringify_hash_keys(self.properties) 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /lib/jekyll-contentful/language_switcher_tag.rb: -------------------------------------------------------------------------------- 1 | module Jekyll 2 | class LanguageSwitcherTag < Liquid::Tag 3 | 4 | def initialize(tag_name, text, tokens) 5 | super 6 | @text = text 7 | end 8 | 9 | def render(context) 10 | @site = context.registers[:site] 11 | this_page = context.registers[:page] 12 | 13 | return "" if @site.config['contentful']['localization'].nil? || this_page["contentful_id"].nil? 14 | 15 | translated_pages = @site.pages.select do |that_page| 16 | that_page["contentful_id"] == this_page["contentful_id"] and that_page["contentful_locale"] != this_page["contentful_locale"] 17 | end 18 | if translated_pages.length > 1 19 | list = translated_pages.dup.map do |tp| 20 | "
  • #{anchor(tp)}
  • " 21 | end.join() 22 | return "" 23 | elsif translated_pages.length == 1 24 | return anchor(translated_pages[0]) 25 | end 26 | end 27 | 28 | def anchor(page) 29 | lang = @site.config['contentful']['localization'].detect{ |loc| loc["locale"] == page['contentful_locale']}["lang"] 30 | "#{ lang }" 31 | end 32 | end 33 | end 34 | 35 | Liquid::Template.register_tag('language_switcher', Jekyll::LanguageSwitcherTag) -------------------------------------------------------------------------------- /lib/jekyll-contentful/version.rb: -------------------------------------------------------------------------------- 1 | module Jekyll 2 | module Contentful 3 | VERSION = "0.1.5" 4 | end 5 | end 6 | --------------------------------------------------------------------------------