Finsweet + Jetboost Wishlist

Hi Luis

i see there’s already a topic for this problem but there’s no follow up from the customer so i’m opening this topic

We have finsweet load (render-all) on our customer website and it’s working well.

We then tried to implement jetboost wishlist and it appears to work (in the staging site it’s working everytime i think i never noticed the problem i’m about to describe)

In production we found that, sometimes, cms items dont show the jetboost wishlist icons, we tried a number of workaround, i contacted the jetboost support and they gave me 2 options, injecting the script once all the finsweet libraries are loaded and an init function (recomended) that should do everything inside it before initializing jetboost.

We tried but none of this approach worked out.

I then put some logs (the finsweet load item count, 280 items at this moment) and everytime i see that number before the log about the finsweet completed everything works, sometimes i see the count after and at that point i have the problem

i am using this file:
https://alporifesta.com/mlk-js/finsweet-loader/finsweet-loader.js

as you can see we have the renderItems that logs
console.log(‘Loading Jetboost after Finsweet initialization and renderitems event’);

this should happen AFTER the load “render-all” completed, right?

But sometimes i see this in the console:

Array(5)
Loading Jetboost after Finsweet initialization and renderitems event
Array(280)

so it renders 5 items before completing the load, and this is why the jetboost integration stops working.

Am i doing something wrong in the initialization process?

This version of the script has been tweaked many times during our tests so it may contain some errors, that said we are experiencing the same behavior as before

here the read-only link:
https://preview.webflow.com/preview/alpori-festa?utm_medium=preview_link&utm_source=designer&utm_content=alpori-festa&preview=c6fc4858d7836a1036dcce7f1f616ae2&workflow=preview

the script is loaded in the custom script in site settings

thank you as always

i’m trying to read the cmscore documentation, i tried using the event “additems” instead of renderitems but nothing changes

the fact that even if i wait for cms load to init the cmsfilter i still see only 5 items rendered for a split seconds it’s confusing me

Hey @gianluca!

If you are using the render-all load more, the correct function to use is this one

async function processRenderingQueue() {
  try {
    // Await the fulfillment of the renderingQueue Promise
    // The result is an array of the items rendered
    const result = await listInstance.renderingQueue;
  } catch (error) {
    // Handle any errors that may occur during the execution
    console.error('Error processing renderingQueue:', error);
  }
}

As the load mode does not fire the normal renderitems event we listen with these lines:

listInstance.on('renderitems', (renderedItems) => {
  console.log(renderedItems);
});

The end result should look something like this

<script>
  window.fsAttributes = window.fsAttributes || [];
  window.fsAttributes.push([
    'cmsload',
    (listInstances) => {
      console.log('cmsload Successfully loaded!');

      async function processRenderingQueue() {
        try {
          // Await the fulfillment of the renderingQueue Promise
          // The result is an array of the items rendered
          const result = await listInstance.renderingQueue;
          console.log(result);

          // You can Initialize Jetboost here
        } catch (error) {
          // Handle any errors that may occur during the execution
          console.error('Error processing renderingQueue:', error);
        }
      }

      processRenderingQueue();
    },
  ]);
</script>

Hi luis, you’re a lifesaver!

this seems to work perfectly, i’d like to know if there’s documentation for the apis, if i search your website i only find something about cms core, add items and render items

That being said i’d like to tell you about a related “bug” (i really dont know if it’s on finsweet side or webflow membership)

We have the logged in state used for showing some element in our cms items, with finsweet load we see those element only on the cms items that are loaded by default (the first 100 i guess) other items have none of those icons as if the membership logged in state is being checked once and never again after finsweet initialization

I already wrote to the webflow support because i feel like this is more on their side.

I am afraid we do not have much public documentation for the API but this will change for V2! :muscle:

Please let me know Webflow’s response on the matter and if needed I will help out with the code!

Hi Luiss,

they told us to contact your support, i think the problem is that the load happens after webflow checks for logged in user state, any workaround?

If they set a cookie or have any kind of “flag” to note that a user is or isn’t signed in we can restart CMS Load.

Do they have any documentation on this?

While we wait for webflow to answer my last email i tested your solution for waiting for the render-all to finish.

i think i may be doing something wrong:

i still see only 5 element from time to time

https://alporifesta.com/mlk-js/finsweet-loader/finsweet-loader.js

this is the code, do you spot anything out of place?

adding my last test, i added a number of logs to try to understand the behaviour.

I’m checking on renderingqueue 5 times and it returns always the same 5 items.

Also, at the top of the logs you can see a webflow-membership log telling that the user “isLoggedIn = false” maybe this can help with the integration of webflow membership

Starting to load Finsweet scripts...
webflow-membership.ts:97 Sa5Core {handlers: Array(1)}
webflow-membership.ts:49 isLoggedIn = false
finsweet-loader.js:13 Script loaded: https://cdn.jsdelivr.net/npm/@finsweet/attributes-cmsload@1/cmsload.js
finsweet-loader.js:13 Script loaded: https://cdn.jsdelivr.net/npm/@finsweet/attributes-cmscombine@1/cmscombine.js
finsweet-loader.js:13 Script loaded: https://cdn.jsdelivr.net/npm/@finsweet/attributes-cmsnest@1/cmsnest.js
finsweet-loader.js:13 Script loaded: https://cdn.jsdelivr.net/npm/@finsweet/attributes-cmssort@1/cmssort.js
finsweet-loader.js:13 Script loaded: https://cdn.jsdelivr.net/npm/@finsweet/attributes-cmsfilter@1/cmsfilter.js
finsweet-loader.js:13 Script loaded: https://cdn.jsdelivr.net/npm/@finsweet/attributes-cmsslider@1/cmsslider.js
finsweet-loader.js:34 All Finsweet scripts loaded successfully
finsweet-loader.js:133 Finished loading Finsweet scripts. Starting initialization...
finsweet-loader.js:44 Initializing cmsload...
finsweet-loader.js:46 cmsLoad Successfully loaded!
finsweet-loader.js:48 Initializing cmscombine...
finsweet-loader.js:50 cmsCombine Successfully loaded!
finsweet-loader.js:52 Initializing cmsnest...
finsweet-loader.js:54 cmsNest Successfully loaded!
finsweet-loader.js:56 Initializing cmsfilter...
finsweet-loader.js:58 cmsFilter Successfully loaded!
finsweet-loader.js:60 Initializing cmsslider...
finsweet-loader.js:62 cmsSlider Successfully loaded!
finsweet-loader.js:64 Initializing cmssort...
finsweet-loader.js:66 cmsSort Successfully loaded!
finsweet-loader.js:135 Finished initializing Finsweet. Pushing cmsload attributes...
finsweet-loader.js:145 cmsload event triggered. Focusing on listInstance[0]
finsweet-loader.js:148 Details of listInstance[0]: v {debug: {…}, wrapper: div.collection-list-wrapper-6.w-dyn-list, index: 0, emptyState: false, paginationActive: true, …}
finsweet-loader.js:81 Waiting for renderingQueue to fulfill for listInstance[0]... (Attempt 1/5)
finsweet-loader.js:83 RenderingQueue fulfilled: (5) [x, x, x, x, x]
finsweet-loader.js:88 Last item in the renderingQueue: x {element: div.collection-item-8.w-dyn-item, list: div.collection-list-5.w-dyn-items, staticIndex: undefined, props: {…}, valid: true, …}
finsweet-loader.js:89 Last item currentIndex: 4
finsweet-loader.js:90 Last item href: https://catalogo.alporifesta.com/vini/326-rose-dosaggio-zero-45949
finsweet-loader.js:98 Not all items are rendered yet. Waiting for the next renderingQueue...
finsweet-loader.js:81 Waiting for renderingQueue to fulfill for listInstance[0]... (Attempt 2/5)
finsweet-loader.js:83 RenderingQueue fulfilled: (5) [x, x, x, x, x]
finsweet-loader.js:88 Last item in the renderingQueue: x {element: div.collection-item-8.w-dyn-item, list: div.collection-list-5.w-dyn-items, staticIndex: undefined, props: {…}, valid: true, …}
finsweet-loader.js:89 Last item currentIndex: 4
finsweet-loader.js:90 Last item href: https://catalogo.alporifesta.com/vini/326-rose-dosaggio-zero-45949
finsweet-loader.js:98 Not all items are rendered yet. Waiting for the next renderingQueue...
finsweet-loader.js:81 Waiting for renderingQueue to fulfill for listInstance[0]... (Attempt 3/5)
finsweet-loader.js:83 RenderingQueue fulfilled: (5) [x, x, x, x, x]
finsweet-loader.js:88 Last item in the renderingQueue: x {element: div.collection-item-8.w-dyn-item, list: div.collection-list-5.w-dyn-items, staticIndex: undefined, props: {…}, valid: true, …}
finsweet-loader.js:89 Last item currentIndex: 4
finsweet-loader.js:90 Last item href: https://catalogo.alporifesta.com/vini/326-rose-dosaggio-zero-45949
finsweet-loader.js:98 Not all items are rendered yet. Waiting for the next renderingQueue...
finsweet-loader.js:81 Waiting for renderingQueue to fulfill for listInstance[0]... (Attempt 4/5)
finsweet-loader.js:83 RenderingQueue fulfilled: (5) [x, x, x, x, x]
finsweet-loader.js:88 Last item in the renderingQueue: x {element: div.collection-item-8.w-dyn-item, list: div.collection-list-5.w-dyn-items, staticIndex: undefined, props: {…}, valid: true, …}
finsweet-loader.js:89 Last item currentIndex: 4
finsweet-loader.js:90 Last item href: https://catalogo.alporifesta.com/vini/326-rose-dosaggio-zero-45949
finsweet-loader.js:98 Not all items are rendered yet. Waiting for the next renderingQueue...
finsweet-loader.js:81 Waiting for renderingQueue to fulfill for listInstance[0]... (Attempt 5/5)
finsweet-loader.js:83 RenderingQueue fulfilled: (5) [x, x, x, x, x]
finsweet-loader.js:88 Last item in the renderingQueue: x {element: div.collection-item-8.w-dyn-item, list: div.collection-list-5.w-dyn-items, staticIndex: undefined, props: {…}, valid: true, …}
finsweet-loader.js:89 Last item currentIndex: 4
finsweet-loader.js:90 Last item href: https://catalogo.alporifesta.com/vini/326-rose-dosaggio-zero-45949
finsweet-loader.js:98 Not all items are rendered yet. Waiting for the next renderingQueue...
finsweet-loader.js:124 Rendering did not complete successfully within the maximum attempts.

Hello @gianluca!

On which page are you testing this? I do not see the processRenderingQueue() on the home page or the link you’ve shared above :thinking:


Hi luis, cache maybe?

Ah I see the issue now, it boils down to the number of instance you are looking at. The order of these instances might be counter-intuitive I am afraid, something that should be addressed for Attributes V2 as we are dropping the -x instance naming.

You are currently looking into the first instance of CMS Load on the page, which would be the the one named list-11. If we console log all the instances, the one you should be looking is the third, or position 2 on the array, meaning that this should be the correct line for the processRenderingQueue function

const result = await listInstances[2].renderingQueue;

So in short, you should use listInstances[2] to target the correct instance for processRenderingQueue. This will wait until the 294 items are rendered to start Jetboost.

Let me know if this makes sense!

this totally makes sense and now i can see the 294 products in my console log

sadly jetboost still cant process those items (even if they are there, rendered on the page) i know that they use an embedded element containing:

<input type="hidden" class="jetboost-list-item" value="THE SLUG FROM CMS" />

to find the element on the page, maybe we can work that around knowing this? (i’m watching at the html and the embedded code is there so i really dont know why their script is not working)

I’m afraid I don’t know why Jetboost is failing. Could you contact their support and ask for guidance?

Hi luis,

thank you for your patience.

At last we decided to do the wishlist ourself with a node app integrating the webflow apis

Hey @gianluca!

Thank you for getting back to me on this. Please let me know if there is anything I can do to help.

For what it’s worth, we are developing a Favorite solution as well for Attributes V2.

hi luis!

good to know

i have a question indeed, now we are consuming our apis to update a live collection (the wishlist collection), i need a way to “reload” the cms collection and/or the finsweet load integration to show updated count on my page.

I can listen for the success of the create-cms-item endpoint and, at that point, i would like to be able to reload my finsweet load instance

Would you just be reloading CMS Load or all of the scripts? I do see you have a function to initialize all the scripts.

You can destroy Attributes by running window.fsAttributes.destroy(); and then run your initializeFinsweet().

Will the API code be added to the loader script? Or where can I see?

below the code we are using in our node.js app

create and delete functions are working as expected, i want a way to reload the wishlist collection and the items in the main collection interested by it.

at this time i need to reload the page after creating the new wishlist item in order to be able to delete it and to see the updated cms count (i’m using the result count feature of the cms filter for this)


// Funzione per generare uno slug randomico
function generateRandomSlug(length = 8) {
  return crypto.randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length);
}

// Create a new CMS record
app.post('/create-cms-record', async (req, res) => {
    try {
      // Extract data from the request body
      const { product_id, user_id_alt } = req.body;
      // Genera uno slug randomico
      const slug = generateRandomSlug(12);
      // Prepare the CMS item data
      const cmsData = {
        cmsLocaleId: WEBFLOW_COLLECTION_ID,
        isArchived: false,
        isDraft: false,
        fieldData: {
          name: slug,
          vino: product_id,
          slug: slug,
          user: user_id_alt
        }
      };
  
      // Send the request to the Webflow API
      const url = `https://api.webflow.com/v2/collections/${WEBFLOW_COLLECTION_ID}/items/live`;
      const headers = {
        Authorization: `Bearer ${WEBFLOW_API_TOKEN}`,
        'Content-Type': 'application/json'
      };
  
      const response = await axios.post(url, cmsData, { headers });
  
      // Return the response from Webflow API
      res.status(response.status).json(response.data);
    } catch (error) {
      console.error(error.response ? error.response.data : error.message);
      res.status(400).json({ error: error.response ? error.response.data : error.message });
    }
  });

// Delete a CMS record
app.post('/delete-cms-record', async (req, res) => {
    try {
      // Extract data from the request body
      const { slug } = req.body;
      
      // Log slug to verify the value
      console.log('Deleting CMS record with slug:', slug);
      
      // Fetch all items in the collection to find the item ID by slug
      let items = [];
      let offset = 0;
      let hasMore = true;
      const headers = {
        Authorization: `Bearer ${WEBFLOW_API_TOKEN}`,
        'Content-Type': 'application/json'
      };

      while (hasMore) {
        const url = `https://api.webflow.com/v2/collections/${WEBFLOW_COLLECTION_ID}/items?offset=${offset}`;
        const response = await axios.get(url, { headers });
        response.data.items.forEach(item => {
          items.push(item);
        });
        offset += response.data.count;
        hasMore = response.data.count > 0;
      }

      // Find the item ID by slug
      const item = items.find(item => item.fieldData && item.fieldData.slug === slug);
      if (!item) {
        console.error('Item not found for slug:', slug);
        return res.status(404).json({ error: 'Item not found' });
      }

      const itemId = item.id;  // Correctly accessing the item's ID
      console.log('Found item ID for deletion:', itemId);
      
      // Send the request to the Webflow API to delete based on item ID
      const deleteUrl = `https://api.webflow.com/v2/collections/${WEBFLOW_COLLECTION_ID}/items/${itemId}/live`;
      const deleteResponse = await axios.delete(deleteUrl, { headers });
  
      // Return the response from Webflow API
      res.status(deleteResponse.status).json(deleteResponse.data);
    } catch (error) {
      console.error(error.response ? error.response.data : error.message);
      res.status(400).json({ error: error.response ? error.response.data : error.message });
    }
  });
  
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

hey @gianluca! If you are using CMS Load on this list, you can use the native addItems and renderItems to reload the list after a user has added a wishlist item instead of having to refresh the page completely.

You can read more here:

and here