eleventy: generating each category in a permalink for sitemap - static-site

i use Skeleventy to generate my static site.
Njk template there uses collections.all to generate sitemap for all possible pages, like so
---
permalink: sitemap.xml
hidden: true
---
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{%- for page in collections.all %}
{%- if not page.data.hidden %}
<url>
<loc>{{ site.url }}{{ page.url | url }}</loc>
<lastmod>{{ page.date | htmlDateDisplay }}</lastmod>
</url>
{%- endif %}
{%- endfor %}
One of the outputs in a resulting sitemap is
https://skeleventy.netlify.app/category/all/
which is a collection of all possible pages - a bit of a mess.
Instead of "category all", it would be better that google indexes each category, for example
<url>
<loc>https://skeleventy.netlify.app/category/software/</loc>
<lastmod>2020-7-20</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/category/writing/</loc>
<lastmod>2020-7-20</lastmod>
</url>
But how can i edit that njk template so that it
-captures and outputs different categories in the sitemap?
-excludes category/all
-leaves other important pages like homepage, each blog post etc.

I think I have it working. I've got this running on my machine and if you want a copy, just reach out. I don't use Nunjucks normally so forgive any dumb mistake. The first mod I did to sitemap.njk was to hide collections.all:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{%- for page in collections.all %}
{%- if not page.data.hidden %}
{%- if page.url !== "/category/all/" %}
<url>
<loc>{{ site.url }}{{ page.url | url }}</loc>
<lastmod>{{ page.date | htmlDateDisplay }}</lastmod>
</url>
{% endif %}
{%- endif %}
{%- endfor %}
Kinda hacky but worked. Next, I needed a way to get the blog category pages. I looked at tags.njk. Based on what I saw there, I wrote a filter for .eleventy.js named categories. I do not think this is a great name:
eleventyConfig.addFilter("categories", function(collections) {
let categories = Object.keys(collections).filter(c => c !== 'all');
return categories;
});
Back in the sitemap, I then did this:
{%- set cats = collections | categories %}
{%- for cat in cats %}
{% set newestDate = collections[cat] | getLatestDate %}
<url>
<loc>{{ site.url }}/category/{{ cat }}/</loc>
<lastmod>{{ newestDate | htmlDateDisplay }}</lastmod>
</url>
{%- endfor %}
</urlset>
Note the getLatestDate filter, this is defined as such:
eleventyConfig.addFilter("getLatestDate", function(collection) {
console.log('running getLatestDate');
return collection[0].date;
});
It seemed to work well. Here is my output:
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://skeleventy.netlify.app/blog/post-1/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/blog/post-2/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/blog/post-3/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/about/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/blog/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/contact/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/category/blog/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/category/business/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/category/digital/</loc>
<lastmod>2020-8-26</lastmod>
</url>
<url>
<loc>https://skeleventy.netlify.app/category/health/</loc>
<lastmod>2020-8-26</lastmod>
</url>
</urlset>
If you want a complete copy, just reach out to me.

Related

How can I dynamically set SEO titles and descriptions for my Shopify products

I want to set all my products titles to be like {Product_titles | Store Name}. How can I set that?
The issue I'm seeing is that the products already have some manually put SEO titles, as we have added lots of products recently we want a single formula for all products SEO titles and meta descriptions.
The template already has this dynamic code for titles
<title>
{{ page_title }}{% if current_tags %}{% assign meta_tags = current_tags | join: ', ' %} – {{ 'general.meta.tags' | t: tags: meta_tags }}{% endif %}{% if current_page != 1 %} – {{ 'general.meta.page' | t: page: current_page }}{% endif %}{% unless page_title contains shop.name %} – {{ shop.name }}{% endunless %}
</title>
and for meta description
{%- if page_description -%}
<meta name="description" content="{{ page_description | escape }}">
I want to keep different types of titles and meta descriptions for products, collections, pages and blog posts.
Can I edit them in shopify theme.liquid or is there any app that can help us in this?
To dynamically change title's on the Product page only.
Find your <title></title> tags in your theme.
Add an {% if %} statement in there. Like so:
<title>{% if template == "product" %}Hey I'm a product page{% endif %}</title>
You can have quite a few if statements within the title tag.
In your case:
<title>{% if template == "product" %}{{ product.title }} | {{ shop.name }}{% endif %}</title>

How to display Shopify blogs in their own categories?

I'm new to Shopify. I have 5 blog categories (using multiple blogs) and I need to find a way to show each post in its own blog category. My code is currently populating the news articles and displaying the same ones in every category. How can I rewrite my for loop to loop through each category and display the articles only related to that category.
{% for article in blogs.news.articles %}
{% assign content = article.content | split: '[/email]' %}
<li class="widget-article">
<div class="widget-image">
<a href="{{ article.url }}">
<img src="{{ article.image | article_img_url: 'original' }}" alt="">
</a>
</div><!-- /.widget-image -->
<div class="widget-content">
<h3 class="widget-title">{{ article.title }}</h3><!-- /.widget-title -->
<p>
{% if content[1] %}
{{ content[1] | strip_html | truncatewords:15 }}
{% else %}
{{ content[0] | strip_html | truncatewords:15 }}
{% endif %}
</p>
</div><!-- /.widget-content -->
</li><!-- /.widget -->
{% endfor %}
Thanks
When you write "category" do you mean collection? Are you trying to associate a blog with a collection? If that's what you are trying to do then one way is to give the blog and collection the same handle.
then you could add your code to your collection template (I'd suggest as a snippet) and the snippet would start like:
{% assign blog = blogs[collection.handle] %}
{% if blog %}
<div class='blog-wrap'>...
{% for article in blog.articles %}

Display name of colour variant selected on Shopify

On this page I have some swatches that when selected they don't display the variant name.
Basically, I need to add a paragraph text under the variant swatches that indicate the name of the variant selected...
I'm not good on javascript and online I didn't found any complete guide about that
Thanks a lot for your help!
That looks like a theme I've seen before. If I recall correctly, that theme uses a file called swatch.liquid to make those colour circles. I'm writing this answer using a version of a swatch file that I happen to have on hand, so the specific code may not be exactly what your theme has, but hopefully I'll be able to help you find what you need.
Here is the code from my swatch.liquid file that prints out the swatches. (This is roughly the bottom half of the swatch.liquid file, found in the snippets folder)
<div class="product-options">
<div class="swatch clearfix" data-option-index="{{ option_index }}">
<div class="header">
{% assign values = '' %}
{% for variant in product.variants %}
{% assign value = variant.options[option_index] %}
{% unless values contains value %}
{% assign values = values | join: ',' %}
{% assign values = values | append: ',' | append: value %}
{% assign values = values | split: ',' %}
<div data-value="{{ value | escape }}" class="swatch-element {% if is_color %}color {% else %}size {% endif %}{{ value | handle }} {% if variant.available %}available{% else %}soldout{% endif %}">
<input id="swatch-{{ option_index }}-{{ value | handle }}" type="radio" name="option-{{ option_index }}" value="{{ value | escape }}"{% if forloop.first %} checked{% endif %} {% unless variant.available %}disabled{% endunless %} />
{% if is_color %}
<label for="swatch-{{ option_index }}-{{ value | handle }}" style="background-color: {{ value | split: ' ' | last | handle }};">
<img class="crossed-out" src="{{ 'soldout.png' | asset_url }}" />
</label>
{% else %}
<label for="swatch-{{ option_index }}-{{ value | handle }}">
{{ value }}
<img class="crossed-out" src="{{ 'soldout.png' | asset_url }}" />
</label>
{% endif %}
</div>
{% endunless %}
{% if variant.available %}
<script>
jQuery('.swatch[data-option-index="{{ option_index }}"] .{{ value | handle }}').removeClass('soldout').addClass('available').find(':radio').removeAttr('disabled');
</script>
{% endif %}
{% endfor %}
</div>
</div>
</div>
That looks a bit messy, I know - so let's try and find the part that you'll want to modify.
Here's the part from the above example that prints the swatch element when the swatch is a colour:
{% if is_color %}
<label for="swatch-{{ option_index }}-{{ value | handle }}" style="background-color: {{ value | split: ' ' | last | handle }};">
<img class="crossed-out" src="{{ 'soldout.png' | asset_url }}" />
</label>
{% else %}
In between those <label> tags you should be able to add any text that you need - such as a <span class="swatch-color-name">{{ value }}</span>
Adding extra HTML in here may throw off the current styles of your page, so you may need to add some extra CSS rules to apply to any elements you add to get things to line up nicely again.
Hope this helps!
NB: If you're using Chrome, there's a useful extension called "Search All" that lets you search your entire Shopify theme if you're having trouble finding the file that needs to be edited. Searching for keywords like 'color' or 'variant.options' should help point you in the right direction.

Current Shopify page URL for Blog page tagged view

I have replaced the Shopify signup form by a GetResponse form and I want the page to stay in the same place after the form is submitted. For that I am trying to dynamically generate the current URL so that I can pass it as the return URL. Here’s what my code snippet looks like:
{% assign current_url = '' %}
{% case template %}
{% when 'page' %}
{% assign current_url = page.url %}
{% when 'blog' %}
{% assign current_url = blog.url %}
{% when 'article' %}
{% assign current_url = article.url %}
{% when 'collection' %}
{% assign current_url = collection.url %}
{% when 'product' %}
{% assign current_url = product.url %}
{% endcase %}
<form action="https://app.getresponse.com/add_subscriber.html" accept-charset="utf-8" method="post">
<!-- Show the name field (required) -->
<input type="hidden" name="name"/>
<!-- Email field (required) -->
<input type="text" name="email"/>
<!-- Campaign token -->
<!-- Get the token at: https://app.getresponse.com/campaign_list.html -->
<input type="hidden" name="campaign_token" value="xxxxx"/>
<!-- Subscriber button -->
<input type="submit" value="Sign Me Up" onclick="javascript:window.alert('Thanks for entering your email address!');"/>
<!-- Add any optional code here (explained below) -->
<input type="hidden" name="thankyou_url" value="https://example.com{{ current_url }}"/>
As you can see in the case statements I have taken care of all the page types separately. When the user is in the main blog page (https://example.com/blogs/news), blog.url correctly returns /blogs/news. However when I click on any of the tags, I go to the URL line https://example.com/blogs/news/tagged/diy or https://example.com/blogs/news/tagged/bizarre. So I am trying to get my code to handle this case as well so that current_url gets the value /blogs/news/tagged/diy or /blogs/news/tagged/bizarre etc.
If there’s no single variable that returns it that’s OK too. I just need a way to return the tag value (like diy or bizarre). Then I can concatenate blog.url + /tagged/ +
Is this possible?
You can do this using current_tags. Refer https://help.shopify.com/themes/liquid/objects/current-tags#inside-collection-liquid
A simple change in your code will be like this
{% capture current_url %}
{% case template %}
{% when 'page' %}{{page.url}}
{% when 'blog' %}{% if current_tags %}/{{ current_tags.first | handleize }}{% endif %}
{% when 'article' %}{{article.url}}
{% when 'collection' %}{{collection.url}}{% if current_tags %}/{{ current_tags.first | handleize }}{% endif %}
{% when 'product' %}{{product.url}}
{% endcase %}
{% endcapture %}
<input type="hidden" name="thankyou_url" value="https://example.com{{ current_url | strip_newlines }}" />

How can I pass variables between DRY templates and ncludes in Jekyll

I have a simple Blog site where the front page index is a list of posts, non truncated and rendered exactly like the individual pages.
I have the index page setup and working:
---
layout: default
---
<div>
{% for post in site.posts %}
{% include post/post.html %}
{% endfor %}
</div>
Where post/post.html contains the post layout using the post variable like so:
<article>
<header>
{% include post/title.html %}
{% include post/metadata.html %}
</header>
<div class="entry-content" itemprop="text">
{{ post.content }}
</div>
</article>
Now, on a specific post page, I want to reuse this include layout so that I can keep my code DRY, so I have the posts use the post.html layout (different from posts/post.html above):
---
layout: default
comments: true
---
{% include post/post.html %}
but the problem is that the include file expects a post variable to exist such post.content is how you access the content.
I have tried:
{% assign post = page %}
and that seems to be the right to pass a variable in, but page is not the right one as it renders as a markdown string instead of the html on the page.
So, how can I pass self -- or whatever is needed -- so that the include file does not need to be altered for the index page or the post page, thus sharing the same code?
While #David Jacquel's answer work, I found it to be unclean and a little verbose, though it did get me on the right track.
_includes/post/post.html swaps the {{ post.content }} for {{ body }}
<article>
<header>
{% include post/title.html %}
{% include post/metadata.html %}
</header>
<div class="entry-content" itemprop="text">
{{ body }}
</div>
</article>
_layouts/index.html now uses
{% assign body = post.content %}
{% include post/post.html %}
_layouts/post.html uses:
{% assign post = page %}
{% assign body = content %}
{% include post/post.html %}
Simple.
We can do it ! With some layout and variable passing.
Regular post use post layout :
---
layout: post
....
---
post content ...
A custom post use the custom_post layout (_layouts/custom_post.hmtl)
---
layout: custom_post
...
---
post content ...
The _layouts/custom_post.hmtl layout just calls our post include, passing the page variable :
---
layout: default
---
{% include post/post.html page=page %}
And finally the _includes/post/post.html conditionally assign the post variable if the page variable is set :
{% if include.page %}
{% comment %}
This only append in the custom_post view context
{% endcomment %}
{% assign post = include.page %}
{% endif %}
<article>
<header>
{% include post/title.html %}
{% include post/metadata.html %}
</header>
<div class="entry-content" itemprop="text">
{{ post.content }}
</div>
</article>