Is it possible to have a different template for pagination? - bolt-cms

I'm wanting to have my list of entries be formatted differently on the first page. But I can't figure out if there's any way to check which page is being shown.
I'm able to get my posts and have them paginated, but I can't find information on how to do something like this (or if it's even possible or not)
{% if record.number == 1 %}
first page template
{% else %}
other pages
{% endif %}
Or possibly set another twig file as for the other layouts.

You can use app.request to get the GET parameter which contains the page number. Then you can check if you are on the first page or not.

Related

For Loop All Products Regardless of Page Number

I wrote a code for one of our Shopify store and it is not working the way I want. I request your support for this.
This is a check for every item on our collections page. I get the tag that contains the base_sku name of the product and I look for the products with this tag in all products.
Then I pull the tags containing color from the products with the same base_sku and link them under the main product.
I'm using pagination here and I know I can pull up to 1000 items. What I need is to be able to loop the pagination as many times as I want per product, regardless of the page number.
Because in this way, it only checks for the first 1000 products on the first page of the collection, and when I switch to the second page, it checks the number of remaining products.
Here I have to proceed with the tags because although the products seem to be variants here, all the ones I show are separate products.
https://gyazo.com/bc139013bdb7d9ad249ca907bf4b83a1
This is an issue that I have been dealing with for a long time but could not resolve, I would be very happy if you could support me.
Best regards,
Berk
<div id="prod-var" class="prod-variants">
{% for tag in product_card_product.tags %}
{% if tag contains "BASE SKU" %}
{% assign base_url = tag | split: "_" | last %}
{% endif %}
{% if tag contains "COLOUR" %}
{% assign first_colour = tag | split: "_" | last %}
{% endif %}
{% if tag contains "SIZE" %}
{% assign first_size = tag | split: "_" | last %}
{% endif %}
{% endfor %}
<div class="variant-all-div">
{% paginate collections.all.products by 1000 %}
{% for product in collections.all.products %}
{% for tag in product.tags %}
{% if tag contains base_url %}
{% for tag in product.tags %}
{% if tag contains "COLOUR" %}
{% assign colour = tag | split: "_" | last %}
{% endif %}
{% endfor %}
{% for tag in product.tags %}
{% if tag contains "SIZE" %}
{% assign size = tag | split: "_" | last %}
{% endif %}
{% endfor %}
{% if first_colour == colour and first_size == size%}{% continue %}{% endif %}
<div class="variant-div">
<a class="collec-variant" href="{{product.url}}"><img style="width: 30px; height: 30px;" src="{{ product.featured_media | img_url:'30x30' }}"></a>
<span class="tooltiptext">{{ colour }}</span>
</div>
{% endif %}
{% endfor %}
{% endfor %}
{% endpaginate %}
</div>
</div>
Step 1: Don't paginate through a huge number of products in Liquid
The 1000-item limit is a hard limit imposed by Shopify, for what I imagine are completely reasonable server-load reasons. Whatever code you're writing has to be run on Shopify's servers when the page is generated for a user. Remember also that Liquid is a templating language, not a programming language, and so is optimized for templating functions and not for complex object manipulation!
The time required for Shopify to compile and send the page to the client's browser can also be severely affected by huge loops with costly server operations, significantly increasing the lag between when a user requests your page and when Shopify is able to start transmitting the page content. I have seen pages that have tried to do variations of what you're looking to do and have watched as the TTFB (time-to-first-byte) grow to 5 seconds... 10 seconds... even as high as 20+ seconds in extreme cases. Your visitors will quickly decide that their time is better spent elsewhere as the loading time increases!
Step 2: Step back and look for ways to defer grabbing the additional content
'Defer' in this case means breaking up your code & logic in such a way that you can start fetching information without interrupting the initial compilation, transmission and rendering of the page.
Here's a rough overview of how I might approach this. Of course, you know your specific circumstances a lot better than a random stranger on the internet, so this is presented as a guide for inspiration and not as something carved in stone.
Javascript will allow us to fetch data from a different URL in an 'asynchronous' (non-blocking) way and generate HTML that we can insert later, so let's move as much as we can to Javascript.
Remove the entire <div id="prod-var" class="prod-variants"> component from the Liquid code and replace it with a placeholder. We will need to be able to identify the placeholder and which product it belongs to, so let's make it something like <div class="prod-var loading" data-product-id="{{ product.id }}"> (Note: If there is any chance that there can be more than one prod-var element on the page we should be using classes, not IDs. Per HTML spec, an ID is expected to be 100% absolutely unique on any given page)
Optionally, in our CSS file, we can make some styles for .prod-var.loading so that we show a nice loading animation or something while we fetch the data.
Now let's make our JS file. We will want the code to execute after the initial paint of the page so that our customers can see all of our fantastic products as soon as possible, so let's load it with the defer attribute so that it won't run until after all of the HTML content has loaded: <script src="{{ 'script-filename.js' | asset_url }}" defer></script>
In our JS file, we know that we want to perform the following steps:
Fetch a lot of product data
Keep fetching product data until we run out
Loop through all the products on the page
For each product, generate our HTML for the prod-var elements
Append the HTML to the appropriate element and remove the loading class
Sketching out a rough idea for our JS file, we might have something that looks similar to this:
function populateAllProdVars(){
// I set this up using promise-chaining notation, but you can certainly use async/await, traditional callbacks, or anything else you are comfortable with
fetchMyProducts()
.then(generateProdVarHTML)
.catch(/* SOME ERROR HANDLING FUNCTION */)
}
fetchMyProducts(productListSoFar, page){
productListSoFar = productListSoFar || []; // Setting [] as a default
page = page || 1; // Setting page 1 as a default
return fetch('/collections/all/products.json?page=' + page)
.then(function(response){ return response.json() })
.then(function(collectionJSON){
// Recursively keep going until we run out of products
if(collectionJSON.products.length){
productListSoFar = productListSoFar.concat(collectionJSON.products);
return fetchMyProducts(productListSoFar, page+1);
}
else {
// No more products, time to move on to the next step
return productListSoFar;
}
}
}
function generateProdVarHTML(productList){
var prodVarElements = document.querySelectorAll('.prod-var.loading');
for(var i=0; i<prodVarElements.length; i++){
var element = prodVarElements[e];
var productId = element.dataset.productId;
var relatedProducts = productList.filter(/* SOME FILTER FUNCTION */);
var prodVarHTML = /* SOME FUNCTION TO TURN ARRAY OF RELATED PRODUCTS INTO RELEVANT HTML */
element.innerHTML = prodVarHTML;
element.classList.remove('loading');
}
}
populateAllProdVars();
There are plenty of places where this could be improved further, especially if you can find all the related products through a more specific collection. You might also want to consider making a custom collection view that only prints the relevant data rather than fetch the entire prodct.json contents and thus save some bandwidth for your customers and simplify the objects that the user's device needs to hold in memory (which can benefit shoppers on mobile devices). I used the default pagination limit, but you can adjust that by adding a &limit=100 (or whatever value you find works best) to the end of the collections/all/products URL.
Hopefully this gets you closer to what you need while also helping your site's performance overall.

How to use Liquid "sample" filter to generate a random post in Jekyll?

There's a Liquid filter sample that allows you to "pick a random value from an array. Optionally, pick multiple values". (See documentation here)
My use case is to have a photo journal for viewers to click and generate one random post from my existing collection "photodiary", and not repeat the post in the next click.
Here's my code:
{% assign posts = site.photodiary | where_exp:"post", "post.url != page.url" | sample: 8 %}
{% for post in posts limit:1 %}
<a class="prev" href="{{post.url}}">Load a post</a>
{% endfor %}
</div>
<main>
{%- if page.content-type == "photodiary" -%}
<h2>{{page.title}}</h2>
<p> {{content}} </p>
{%- endif -%}
</main>
Currently I only have 8 entries, hence the sample: 8.
While the code works, after 1-2 clicks, the posts will be repeated and my page will only load the same 2 to 3 posts.
Can anyone let me know if there's a flaw in the logic or my code?
Thanks much!
Jekyll is a static site generator. This means that Jekyll generates the site once, so filters are applied only when building the site. The sample filter will randomly choose one or more posts and insert it in your page, but won't change when reloading the page, because the site has already been generated.
The kind of dynamic behavior you want can't be achieved by Jekyll, so you will have to do it other way. Take a look to Generating a random link through Javascript/HTML

Counting items in Django templates

Is it possible to tally items being listed as part of the django template within the html?
For example, I have a django template with the following code snippet in it:
<div>
{% for thing in thing_list %}
{% if thing.status == "n" %}
<a>{{ thing.status.count }}</a>
{% endif %}
{% endfor %}
</div>
This django template displays all of the things in a list, and I can call each attribute of the thing and display it, so I know I have access to all of the fields.
I want to count then number of "things" and display that number as text. My current attempt above isn't working. Does anyone have any suggestions?
As Willem says, you should do this in the view. Rather than passing a list of all Things and then checking their status in the template with if, you should filter your Things when querying them from the database in the first place:
thing_list = Thing.objects.filter(status='n')
Then you can do just {{ thing_list.count }} in the template.

Can a liquid for loop contain a page variable in Jekyll?

Let's say I have a bunch of _data files that I use to create a list for specific pages. All of the pages that have these lists have a custom front matter variable of pageName. The value of pageName just so happens to match the _data file with the list.
Rather than pasting the html blocks of code into each page, I'd like to use an include to pull in a generic block of html. To do that, the include has to be dynamic or contain liquid markup to become dynamic.
That might be more context than you need, but my question boils down to this, is something like this possible:
{% for item in site.data.{{page.pageName}} %}
{{ item.label }}
{% endfor %}
Unless I'm missing something, this doesn't work so I'm wanting to know if there's a way of achieving similar functionality.
I found this similar question, but it doesn't seem to answer whether it can be used to access a page variable to build a file name.
You can use the bracket notation like this :
{% for item in site.data[page.pageName] %}

Is there a way to evaluate string with liquid tags

I need to provide page content reference list (it should contain references on sections on page).
The only way which I can see is to use page.content and parse it, but I stumbled on problem with data evaluation. For example I can pull out this string from page.content: {{site.data.sdk.language}} SDK but there is no way to make jekyll process it, it outputs as is.
Also I want to make it possible to create cross-pages links (on specific section on page, but that link generated by another inclusion and doesn't persist in page.content in HTML form).
Is there any way to make it evaluate values from page.content?
P.S. I'm including piece of code which should build page content and return HTML with list (so there is no recursions).
P.P.S. I can't use submodules, because I need to run this pages on github pages.
Thanks.
Shouldn't {{ site.data.sdk.language | strip_html }} do it? I don't know, most probably I didn't understand the problem. Can you elaborate more? Maybe provide a link to a post you're referring to?
Thinking about the similar
{% assign title = site.data.sdk.language %}
which is a stock Liquid tag and does the job well, so instead of
{% section title={{site.data.sdk.language}} %}
write your code as
{% section title = site.data.sdk.language %}
The key here is that once you enter {%, you're in Liquid. Don't expect Liquid to go "Inception" all over itself. {{ is just a shorthand for "print this to output", but an parameter passing is not output, it's just reading a variable.
You should be able to also go wild and do:
{% section title = site.data.sdk.language | capitalize %}
For more re-read the docs: https://github.com/Shopify/liquid/wiki/Liquid-for-Designers