Solved

Custom page for dynamic products

lourding19
Tourist
4 0 1

Hello,


I am working on a motorcycle parts store.

I created a custom page page.motorcycle.liquid that takes the motorId from the URL and sends a request to my own backend in order to find the products that are compatible with that motorId. Then I use the fetch API to get the shopify products based on the handles of the products and I want to render them using the already existent card-product.liquid snippet.

 

<script>
document.addEventListener('DOMContentLoaded', function() {
    const urlParams = new URLSearchParams(window.location.search);
    const motorId = urlParams.get('motorId');
    
    // Fetch products from backend
    fetch(`https://myapi/parts/${motorId}`)
    .then(response => response.json())
    .then(productHandles => {
        displayProducts(productHandles);
    })
});
</script>

 

I tried to display the products using the Section Rendering API, but i failed:

 

function displayProducts(productHandles) {
    const productPromises = productHandles.map(productHandle => {
        return fetch(`/products/${productHandle}.json`)
            .then(response => response.json())
            .then(data => data.product)
    });      
    
    Promise.all(productPromises)
    .then(products => {
        products.map(product=>{
            const sectionUrl = `/sections/custom-product-section?product_id=${product.id}`;
            const response = fetch(sectionUrl);
            if (!response.ok) {
                throw new Error('Failed to fetch section');
            }
            const html = response.text();
            document.getElementById('motor-parts').innerHTML += html; 
        })
    })
    .catch(error => {
        console.error(error);
    });
}

 

The custom section I created is custom-product-section.liquid:

 

{% assign product_id = section.settings.product_id %}
<div id="product-section">
    {% assign product = all_products[product_id] %}
    {% if product %}
        {% render 'card-product', card_product: product %}
    {% endif %}
</div>

{% schema %}
    {
        "name": "Custom Product",
        "settings": [
            {
                "type": "text",
                "id": "product_id",
                "label": "Product ID",
                "default": ""
            }
        ]
    }
    {% endschema %}

 

The error I get is 404 when I try to fetch the section html.
I would appreciate some help regarding what I am doing wrong about that section. Or if I should approach rendering the products in another way?

Accepted Solution (1)

tim
Shopify Expert
3554 298 1317

This is an accepted solution.

You're using section rendering API in a wrong way.

First, you can't pass any data/parameters into section.

Second, the url should be an url of a page on your site and section id comes as parameter. Like https://store.name/?sections=main_product_page.

 

If you're getting a list of handles  from your API there is no need to fetch product data since liquid does not really use product id.

 

What you can do is to create an alternate product page template with {% layout none %} which will actually render the product card HTML:

templates/product.card.liquid

{% layout none %}
<li class=product-card-wrapper>
 {% render 'card-product', card_product: product %}
</li>

and then have something like this in your JS

function displayProducts(productHandles) {
    const productPromises = productHandles.map(productHandle => {
        return fetch(`/products/${productHandle}?view=card`)
            .then(response => response.text())
    });

    Promise.all(productPromises)
    .then( productItems => productsItems.join(' ') )
    .then( productGridInnerHTML => {
        document.getElementById('motor-parts').innerHTML = `<ul class=product-grid> ${ productGridInnerHTML } </ul>`
    });
}

 

If my post is helpful, consider liking it -- it will help others with similar problem to find a solution.
I can be reached via e-mail tairli@yahoo.com

View solution in original post

Replies 5 (5)

tim
Shopify Expert
3554 298 1317

This is an accepted solution.

You're using section rendering API in a wrong way.

First, you can't pass any data/parameters into section.

Second, the url should be an url of a page on your site and section id comes as parameter. Like https://store.name/?sections=main_product_page.

 

If you're getting a list of handles  from your API there is no need to fetch product data since liquid does not really use product id.

 

What you can do is to create an alternate product page template with {% layout none %} which will actually render the product card HTML:

templates/product.card.liquid

{% layout none %}
<li class=product-card-wrapper>
 {% render 'card-product', card_product: product %}
</li>

and then have something like this in your JS

function displayProducts(productHandles) {
    const productPromises = productHandles.map(productHandle => {
        return fetch(`/products/${productHandle}?view=card`)
            .then(response => response.text())
    });

    Promise.all(productPromises)
    .then( productItems => productsItems.join(' ') )
    .then( productGridInnerHTML => {
        document.getElementById('motor-parts').innerHTML = `<ul class=product-grid> ${ productGridInnerHTML } </ul>`
    });
}

 

If my post is helpful, consider liking it -- it will help others with similar problem to find a solution.
I can be reached via e-mail tairli@yahoo.com
lourding19
Tourist
4 0 1

Thank you so much, Tim.


Seems to be working. Can you also help me how to figure how to get the ?view=card parameter to work?
Now it just returns the whole product page with header, footer and other sections. The ?view=card does not seem to make a difference. I tried to edit the product.json file from templates, but no luck. I want the /product/handle URL to work normally, but when the parameter ?view=card is added it should render a minimal product template (card-product.liquid).

tim
Shopify Expert
3554 298 1317

You're getting the whole product page because your alternate template is not recognised.
In this case Shopify falls back to the default one.

 

I can't really say what's wrong in your setup, but to make ?view=card work you need to have an alternate product page template with suffix card, as I've suggested above. Here it's just much simpler to have it as a .liquid template rather then create a json template, then create a section, etc...
And the layout tag should take care of headers, footers and other stuff we do not need here.

 

 

If my post is helpful, consider liking it -- it will help others with similar problem to find a solution.
I can be reached via e-mail tairli@yahoo.com
lourding19
Tourist
4 0 1

Thank you again for the response.
I had a typo in the template file name: I wrote product-card.liquid instead of product.card.liquid. I did not realize it actually parses the file name in order to get the card suffix.

tim
Shopify Expert
3554 298 1317

Cool! Message with the URL when it's live -- would be interesting to have a look.

If my post is helpful, consider liking it -- it will help others with similar problem to find a solution.
I can be reached via e-mail tairli@yahoo.com