← All Scripts

#106 - Liking & Saving CMS Items v0.2

Allow your members to save CMS items to their profile.

Need help with this MemberScript?

All Memberstack customers can ask for assistance in the 2.0 Slack. Please note that these are not official features and support cannot be guaranteed.

View demo

<!-- 💙 MEMBERSCRIPT #106 v0.2 💙 SAVING & UNSAVING CMS ITEMS -->
<style>
  [ms-code-save], [ms-code-unsave] {
    display: none;
  }
  [ms-code-save-item] {
    display: none;
  }
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
  const memberstack = window.$memberstackDom;
  let isLoggedIn = false;
  let savedItems = [];

  async function checkMemberLogin() {
    try {
      const member = await memberstack.getCurrentMember();
      return !!member;
    } catch (error) {
      return false;
    }
  }

  function getSavedItems(memberData) {
    return memberData.savedItems || [];
  }

  function updateButtonVisibility() {
    const saveButtons = document.querySelectorAll('[ms-code-save]');
    const unsaveButtons = document.querySelectorAll('[ms-code-unsave]');

    saveButtons.forEach(button => {
      const itemId = button.getAttribute('ms-code-save');
      button.style.display = !savedItems.includes(itemId) ? 'block' : 'none';
    });

    unsaveButtons.forEach(button => {
      const itemId = button.getAttribute('ms-code-unsave');
      button.style.display = savedItems.includes(itemId) ? 'block' : 'none';
    });
  }

  function updateItemVisibility() {
    const saveLists = document.querySelectorAll('[ms-code-save-list]');
    saveLists.forEach(list => {
      const filter = list.getAttribute('ms-code-save-list');
      const items = list.querySelectorAll('[ms-code-save-item]');
      items.forEach(item => {
        const saveButton = item.querySelector('[ms-code-save]');
        if (!saveButton) {
          item.style.display = 'block';
          return;
        }
        const itemId = saveButton.getAttribute('ms-code-save');
        
        if (!isLoggedIn || filter === 'all') {
          item.style.display = 'block';
        } else if (filter === 'saved' & savedItems.includes(itemId)) {
          item.style.display = 'block';
        } else if (filter === 'unsaved' & !savedItems.includes(itemId)) {
          item.style.display = 'block';
        } else {
          item.style.display = 'none';
        }
      });
    });
  }

  async function handleButtonClick(event) {
    if (!isLoggedIn) return;

    const button = event.currentTarget;
    const action = button.getAttribute('ms-code-save') ? 'save' : 'unsave';
    const itemId = button.getAttribute(action === 'save' ? 'ms-code-save' : 'ms-code-unsave');
    
    if (action === 'save' && !savedItems.includes(itemId)) {
      savedItems.push(itemId);
    } else if (action === 'unsave') {
      savedItems = savedItems.filter(id => id !== itemId);
    }

    try {
      await memberstack.updateMemberJSON({ json: { savedItems } });
    } catch (error) {
      // Silently handle the error
    }

    updateButtonVisibility();
    updateItemVisibility();
  }

  function addClickListeners() {
    const saveButtons = document.querySelectorAll('[ms-code-save]');
    const unsaveButtons = document.querySelectorAll('[ms-code-unsave]');
    saveButtons.forEach(button => button.addEventListener('click', handleButtonClick));
    unsaveButtons.forEach(button => button.addEventListener('click', handleButtonClick));
  }

  async function initializeScript() {
    isLoggedIn = await checkMemberLogin();

    if (isLoggedIn) {
      try {
        const result = await memberstack.getMemberJSON();
        const memberData = result.data || {};
        savedItems = getSavedItems(memberData);
      } catch (error) {
        // Silently handle the error
      }
    }

    updateButtonVisibility();
    updateItemVisibility();
    addClickListeners();

    // Set up a MutationObserver to watch for changes in the DOM
    const observer = new MutationObserver((mutations) => {
      let shouldUpdate = false;
      mutations.forEach((mutation) => {
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
          shouldUpdate = true;
        }
      });
      if (shouldUpdate) {
        updateButtonVisibility();
        updateItemVisibility();
        addClickListeners();
      }
    });

    // Start observing the document with the configured parameters
    observer.observe(document.body, { childList: true, subtree: true });
  }

  initializeScript();
});
</script>
Description
Attribute
No items found.

v0.2 - Performance enhancements + Finsweet attributes compatible

With this new release, everything should work faster - not only that, but you can use Finsweet Attributes (specifically CMS Load + CMS Filter) in combination with this script.

Creating the Make.com Scenario

1. Download the JSON blueprint below to get stated.

2. Navigate to Make.com and Create a New Scenario...

3. Click the small box with 3 dots and then Import Blueprint...

4. Upload your file and voila! You're ready to link your own accounts.