diff --git a/app/models/content_instance.rb b/app/models/content_instance.rb index a14f620e..d4104d4c 100644 --- a/app/models/content_instance.rb +++ b/app/models/content_instance.rb @@ -5,6 +5,7 @@ class ContentInstance ## extensions ## include CustomFields::ProxyClassEnabler + include Extensions::Shared::Seo ## fields (dynamic fields) ## field :_slug @@ -29,6 +30,8 @@ class ContentInstance ## methods ## + delegate :site, :to => :content_type + alias :visible? :_visible? alias :_permalink :_slug diff --git a/app/models/extensions/shared/seo.rb b/app/models/extensions/shared/seo.rb new file mode 100644 index 00000000..06d190bc --- /dev/null +++ b/app/models/extensions/shared/seo.rb @@ -0,0 +1,13 @@ +module Extensions + module Shared + module Seo + extend ActiveSupport::Concern + + included do + field :meta_keywords, :type => String + field :meta_description, :type => String + end + + end # Seo + end # Shared +end # Extensions diff --git a/app/models/page.rb b/app/models/page.rb index a64b45db..2a6a4125 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -10,6 +10,7 @@ class Page include Extensions::Page::Templatized include Extensions::Page::Redirect include Extensions::Page::Listed + include Extensions::Shared::Seo ## fields ## field :title diff --git a/app/views/admin/contents/_form.html.haml b/app/views/admin/contents/_form.html.haml index d79bacaf..745b8129 100644 --- a/app/views/admin/contents/_form.html.haml +++ b/app/views/admin/contents/_form.html.haml @@ -2,4 +2,9 @@ = include_javascripts :edit_custom_fields, :contents = include_stylesheets :fancybox += f.foldable_inputs :name => :meta do + + = f.input :meta_keywords + = f.input :meta_description + = render 'admin/custom_fields/custom_form', :form => f, :title => :attributes, :parent => @content_type \ No newline at end of file diff --git a/app/views/admin/pages/_form.html.haml b/app/views/admin/pages/_form.html.haml index 6db15972..34ed29bd 100644 --- a/app/views/admin/pages/_form.html.haml +++ b/app/views/admin/pages/_form.html.haml @@ -11,6 +11,10 @@ = f.input :slug, :required => false, :hint => @page.slug.blank? ? ' ' : page_url(@page), :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}; height: 50px" } += f.foldable_inputs :name => :meta do + + = f.input :meta_keywords + = f.input :meta_description = f.foldable_inputs :name => :advanced_options do diff --git a/config/locales/formtastic.en.yml b/config/locales/formtastic.en.yml index c8baf61d..0e11199f 100644 --- a/config/locales/formtastic.en.yml +++ b/config/locales/formtastic.en.yml @@ -50,10 +50,12 @@ en: templatized: "Use the page as a template for a model you defined." listed: "Control whether to show the page from generated menus." content_type_id: "The type of content this page will be a template for." + meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma." + meta_description: "Overrides the site's meta description used within the head tag of the page." snippet: slug: "You need to know it in order to insert the snippet inside a page" site: - meta_keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO." + meta_keywords: "Meta keywords used within the head tag of the page. They are separated by a comma. Required for SEO." meta_description: "Meta description used within the head tag of the page. Required for SEO." domain_name: "ex: locomotiveapp.org" theme_asset: diff --git a/lib/locomotive/liquid/drops/content.rb b/lib/locomotive/liquid/drops/content.rb index 19715b41..5aafcf75 100644 --- a/lib/locomotive/liquid/drops/content.rb +++ b/lib/locomotive/liquid/drops/content.rb @@ -2,6 +2,7 @@ module Locomotive module Liquid module Drops class Content < Base + delegate :meta_keywords, :meta_description, :to => "@source" def before_method(meth) return '' if @source.nil? diff --git a/lib/locomotive/liquid/drops/page.rb b/lib/locomotive/liquid/drops/page.rb index ea7e0e2c..a6b092a8 100644 --- a/lib/locomotive/liquid/drops/page.rb +++ b/lib/locomotive/liquid/drops/page.rb @@ -2,6 +2,7 @@ module Locomotive module Liquid module Drops class Page < Base + delegate :meta_keywords, :meta_description, :to => "@source" def title @source.templatized? ? @context['content_instance'].highlighted_field_value : @source.title diff --git a/lib/locomotive/liquid/tags/seo_metadata.rb b/lib/locomotive/liquid/tags/seo_metadata.rb index c170729b..5958b47d 100644 --- a/lib/locomotive/liquid/tags/seo_metadata.rb +++ b/lib/locomotive/liquid/tags/seo_metadata.rb @@ -5,8 +5,8 @@ module Locomotive def render(context) %{ - - + + } end @@ -15,6 +15,19 @@ module Locomotive string.strip.gsub(/"/, '') end + def meta_description(context) + object = metadata_object(context) + object.try(:meta_description).blank? ? context.registers[:site].meta_description : object.meta_description + end + + def meta_keywords(context) + object = metadata_object(context) + object.try(:meta_keywords).blank? ? context.registers[:site].meta_keywords : object.meta_keywords + end + + def metadata_object(context) + context['content_instance'] || context['page'] + end end ::Liquid::Template.register_tag('seo_metadata', SEOMetadata) diff --git a/spec/lib/locomotive/liquid/drops/content_spec.rb b/spec/lib/locomotive/liquid/drops/content_spec.rb new file mode 100644 index 00000000..624cff4c --- /dev/null +++ b/spec/lib/locomotive/liquid/drops/content_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Locomotive::Liquid::Drops::Content do + + before(:each) do + @site = Factory.build(:site) + content_type = Factory.build(:content_type) + content_type.content_custom_fields.build :label => 'anything', :kind => 'String' + @content = content_type.contents.build(:meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") + end + + describe 'meta_keywords' do + subject { render_template('{{ content.meta_keywords }}') } + it { should == @content.meta_keywords } + end + + describe 'meta_description' do + subject { render_template('{{ content.meta_description }}') } + it { should == @content.meta_description } + end + + def render_template(template = '', assigns = {}) + assigns = { 'content' => @content }.merge(assigns) + Liquid::Template.parse(template).render(::Liquid::Context.new({}, assigns, { :site => @site })) + end + +end diff --git a/spec/lib/locomotive/liquid/drops/page_spec.rb b/spec/lib/locomotive/liquid/drops/page_spec.rb index ec53c262..b80328cd 100644 --- a/spec/lib/locomotive/liquid/drops/page_spec.rb +++ b/spec/lib/locomotive/liquid/drops/page_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' describe Locomotive::Liquid::Drops::Page do before(:each) do - @home = Factory.build(:page) + site = Factory.build(:site) + @home = Factory.build(:page, :site => site, :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") end context '#rendering tree' do @@ -56,6 +57,16 @@ describe Locomotive::Liquid::Drops::Page do end + describe 'meta_keywords' do + subject { render_template('{{ home.meta_keywords }}') } + it { should == @home.meta_keywords } + end + + describe 'meta_description' do + subject { render_template('{{ home.meta_description }}') } + it { should == @home.meta_description } + end + def render_template(template = '', assigns = {}) assigns = { 'home' => @home diff --git a/spec/lib/locomotive/liquid/tags/seo_metadata_spec.rb b/spec/lib/locomotive/liquid/tags/seo_metadata_spec.rb index fe7200c5..5a5eeea3 100644 --- a/spec/lib/locomotive/liquid/tags/seo_metadata_spec.rb +++ b/spec/lib/locomotive/liquid/tags/seo_metadata_spec.rb @@ -1,19 +1,17 @@ require 'spec_helper' describe Locomotive::Liquid::Tags::SEOMetadata do - - before :each do - @site = Factory.build(:site, :meta_description => 'A short site description', :meta_keywords => 'test only cat dog') + let(:site) do + Factory.build(:site, :meta_description => 'A short site description', :meta_keywords => 'test only cat dog') end - context '#rendering' do - + describe 'rendering' do it 'renders a a meta description tag' do render_seo_metadata.should include '' end it 'strips and removes quote characters from the description' do - @site.meta_description = ' String with " " quotes ' + site.meta_description = ' String with " " quotes ' render_seo_metadata.should include '' end @@ -22,16 +20,53 @@ describe Locomotive::Liquid::Tags::SEOMetadata do end it 'strips and removes quote characters from the keywords' do - @site.meta_keywords = ' one " two " three ' + site.meta_keywords = ' one " two " three ' render_seo_metadata.should include '' end + + context "when page" do + context "has metadata" do + let(:page) { site.pages.build(:meta_keywords => 'hulk,gamma', :meta_description => "Bruce Banner") } + subject { render_seo_metadata('page' => page) } + it { should include(%Q[]) } + it { should include(%Q[]) } + end + context "does not have metadata" do + let(:page) { site.pages.build } + subject { render_seo_metadata('page' => page) } + it { should include(%Q[]) } + it { should include(%Q[]) } + end + end + + context "when content instance" do + let(:content_type) do + Factory.build(:content_type, :site => site).tap do |ct| + ct.content_custom_fields.build :label => 'anything', :kind => 'String' + end + end + + context "has metadata" do + let(:content) { content_type.contents.build(:meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") } + subject { render_seo_metadata('content_instance' => content) } + it { should include(%Q[]) } + it { should include(%Q[]) } + end + + context "does not have metadata" do + let(:content) { content_type.contents.build } + subject { render_seo_metadata('content_instance' => content) } + it { should include(%Q[]) } + it { should include(%Q[]) } + end + end end + - def render_seo_metadata - registers = { :site => @site } - liquid_context = ::Liquid::Context.new({}, {}, registers) + def render_seo_metadata(assigns={}) + registers = { :site => site } + liquid_context = ::Liquid::Context.new({}, assigns, registers) output = Liquid::Template.parse("{% seo_metadata %}").render(liquid_context) end - end \ No newline at end of file diff --git a/spec/models/content_instance_spec.rb b/spec/models/content_instance_spec.rb index 1585ac24..987281f4 100644 --- a/spec/models/content_instance_spec.rb +++ b/spec/models/content_instance_spec.rb @@ -93,6 +93,13 @@ describe ContentInstance do end end + + describe '#site' do + it 'delegates to the content type' do + @content_type.expects(:site) + build_content.site + end + end def build_content(options = {}) @content_type.contents.build({ :title => 'Locomotive', :description => 'Lorem ipsum....' }.merge(options)) @@ -101,5 +108,4 @@ describe ContentInstance do def fake_bson_id(id) BSON::ObjectId(id.to_s.rjust(24, '0')) end - -end +end \ No newline at end of file diff --git a/spec/models/page_spec.rb b/spec/models/page_spec.rb index 11ecf9d6..9d896aa8 100644 --- a/spec/models/page_spec.rb +++ b/spec/models/page_spec.rb @@ -229,8 +229,6 @@ describe Page do @page.redirect_url = "invalid url with spaces" @page.should_not be_valid @page.errors[:redirect_url].should == ["is invalid"] - end - end end