locomotivecms/steam

View on GitHub
lib/locomotive/steam/middlewares/sitemap.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Locomotive::Steam
  module Middlewares

    class Sitemap < ThreadSafe

      include Concerns::Helpers

      def _call
        if env['PATH_INFO'] == '/sitemap.xml' && (page.nil? || page.not_found?)
          render_response(build_xml, 200, 'application/xml')
        end
      end

      private

      def build_xml
        <<-XML
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
#{build_pages_to_xml}
</urlset>
        XML
      end

      def build_pages_to_xml
        # we request the data based on the default locale
        page_repository.locale = site.default_locale

        page_repository.published.map do |page|
          next if skip_page?(page)

          _page = Locomotive::Steam::Decorators::I18nDecorator.new(page)

          if page.templatized?
            build_templatized_page_to_xml(_page)
          else
            build_page_to_xml(_page)
          end
        end.flatten.join.strip
      end

      def build_page_to_xml(page)
        entry = { date: page.updated_at.to_date, links: [] }

        site.locales.each_with_index do |locale, index|
          page.__locale__ = locale

          # if blank, means that the page is not translated, so skip it
          next if page.title.blank?

          if index == 0 # default locale
            entry[:loc] = url_for(page, locale)
          else
            entry[:links] << { locale: locale, href: url_for(page, locale) }
          end
        end

        entry_to_xml(entry)
      end

      def build_templatized_page_to_xml(page)
        content_type = repositories.content_type.find(page.content_type_id)

        repositories.content_entry.with(content_type).all({ _visible: true }).map do |content_entry|
          _content_entry  = Locomotive::Steam::Decorators::I18nDecorator.new(content_entry, locale)
          entry           = { date: content_entry.updated_at.to_date, links: [] }

          site.locales.each_with_index do |locale, index|
            page.__locale__           = locale
            _content_entry.__locale__ = locale

            # if blank, means that the page or the content entry is not translated, so skip it
            next if _content_entry._label.blank? || page.title.blank?

            page.content_entry = _content_entry

            if index == 0 # default locale
              entry[:loc] = url_for(page, locale)
            else
              entry[:links] << { locale: locale, href: url_for(page, locale) }
            end
          end

          entry_to_xml(entry)
        end.flatten.join.strip
      end

      def entry_to_xml(entry)
        <<-XML
  <url>
    <loc>#{base_url}#{entry[:loc]}</loc>
    <lastmod>#{entry[:date].to_fs('%Y-%m-%d')}</lastmod>
    #{entry_links_to_xml(entry[:links])}
  </url>
        XML
      end

      def entry_links_to_xml(links)
        links.map do |link|
          <<-XML
     <xhtml:link rel="alternate" hreflang="#{link[:locale]}" href="#{base_url}#{link[:href]}" />
          XML
        end.flatten.join.strip
      end

      def skip_page?(page)
        page.not_found? ||
        page.layout? ||
        page.redirect? ||
        (!page.templatized? && !page.index? && !page.listed?)
      end

      def repositories
        services.repositories
      end

      def page_repository
        repositories.page
      end

      def url_for(page, locale = nil)
        services.url_builder.url_for(page, locale)
      end

      def base_url
        "#{request.scheme}://#{request.host_with_port}"
      end

    end

  end
end