Q Card Docs
Modules

Partners

Partner carousel, deal description, and partner logo strip modules.

Partners

Description

Partners modules showcase retailer deals and logos. There are three parts: a carousel of partner deals, a description section on each deal page, and a static strip of partner logos.

How to edit

  1. Manage the deal and merchant content first (see Deals and Merchants) — most of what appears on these modules comes from the deal itself.
  2. Go to Elementor → Editor → Templates.
  3. Search for Partner (or a word from the specific template name below).
  4. Open the template and edit the static content, such as headings and captions.
  5. Save, then check a deal page that uses the template.

The deal cards are generated from your deal data, so edit the deal rather than the card.

Variants

Carousel

TemplateWhat it is
Ck – Partners – CarouselCarousel of partner deals with logos and navigation controls
Ck – Partners – CardThe deal card used by the carousel

Description

TemplateWhat it is
CK – Partners – DescriptionThe reasons to shop at a particular merchant
CK – Partners – Description itemA single line item inside a description card
CK – Partner – Description ButtonsThe buttons in the description section
CK – Partner – Hero ButtonsThe buttons in the deal page hero

Logos

TemplateWhat it is
CK – Partners – LogosA static strip of partner logos

The two carousel templates begin with a lowercase Ck, which is just an inconsistency in the naming and does not affect how they work.

A responsive carousel for displaying partner deals with logos and navigation controls. The deal cards are created by a Dynamic Posts widget using the Ck – Partners – Card template, then moved into the carousel by the script below.

Where a deal is available in only one location, the location label has the word "only" added to it automatically. Where there are several locations, they are separated by a small dot.

Partners description

This section shows the reasons to shop at a particular merchant. It includes:

  • A heading
  • A description
  • Four value proposition cards
  • A list of finance offers to choose from

The heading, description, and card labels are static content and can be edited in Elementor. The values inside the cards come from the deal:

CardField on the dealWhat it shows
Shopping methodAvailability (deal_availability)The merchant's shopping methods: in-house, in-store, online, or phone orders only
Minimum spendDeal Minimum spend (deal_minimum_spend)The minimum spend, falling back to See terms when the field is empty
Promotional cardPromotional Card (show_promotional_card)The promotional card belonging to the campaign chosen on the deal
Offer valid untilDeal expire date (deal_expire_date)The expiry date as day, month, and year — for example 31 July 2026
Interest-free payment optionsInterest free term (deal_interest_free_term)The highest interest-free option available for the deal

A few things worth knowing about those values:

  • Promotional Card is a campaign picker rather than a simple on or off switch. Choose the campaign you want and its promotional card appears, or leave it empty for no card. The content of the card is managed on the campaign itself (see Offers & campaigns).
  • Offer valid until only has a date to show when the deal's schedule is set to Specific dates.
  • The interest-free list is filtered so it only shows the terms attached to the deal you are viewing, rather than every term in the system. That filtering is handled in the site's code and does not need to be set up per deal.

Partner logos

A static strip of partner logos on a light gradient background. Logos sit inside rounded white pill containers. Separate desktop and mobile images are used, so if you update the logos, update both.

Classes

Primary classes used by the partners components:

Carousel

ClassWhat it's for
ck-partner-carouselMain wrapper
partners-carousel-content-loaderDynamic Posts loader that fetches the deals
partners-swiperCarousel container
partners-carousel-interactionsNavigation and pagination area
partners-paginationPagination dots
seperator-dotDot between multiple locations

Description

ClassWhat it's for
partners-descriptionMain wrapper
partners-tilesThe value proposition card grid
partners-tiles__min-spend / partners-tiles__interest-freeThe minimum spend and interest-free cards
ck-partner__description-itemA single line item inside a card
partners-description__fieldRich text field content
partners-description__count-offersThe offers count heading
partners-offer-tile / partners-offer-tile__title / partners-offer-tile__bodyFinance offer tiles
ck-partner-description__payment-holidayPayment holiday value used to match an offer
partners-badgeBadge added to a matching offer title

Logos

ClassWhat it's for
partners-logosMain wrapper
logo-wrapperRounded white container around each logo
partner-image-first / partner-image-lastFirst and last logo rows
partner-logos-image-desktop / partner-logos-image-mobileDesktop and mobile logo images

Styling is done through a combination of the built-in page builder options as well as custom CSS where needed.

Scripts

Both scripts below are added using the HTML editor template.

Moves the loaded deal cards into the carousel, starts the carousel, and tidies up the location labels. This script is compiled to JavaScript before it is added.

import Swiper from "swiper";

function movePartnerContent() {
  const cards = document.querySelectorAll(
    ".partners-carousel-content-loader .dce-posts-wrapper .dce-post-item",
  );
  const target = document.querySelector(".partners-swiper .swiper-wrapper");

  if (target) {
    cards.forEach((card) => {
      target.appendChild(card);
      card.classList.add("swiper-slide");
    });
  }
}

function createPartnerPagination() {
  const paginationCount = document.querySelectorAll(
    ".partners-carousel-content-loader .dce-posts-wrapper .dce-post-item",
  ).length;
  let paginationHtml = "";
  for (let i = 0; i < paginationCount; i++) {
    paginationHtml += `<span class="swiper-pagination-bullet"><div class="display-dot"></div></span>`;
  }

  const target = document.querySelector(".partners-carousel-interactions");
  if (target) {
    target.insertAdjacentHTML(
      "beforeend",
      `<div class="partners-pagination">
            ${paginationHtml}    
        </div>`,
    );
  }
}

function initailisePartnerSwiper() {
  const swiper = new Swiper(".partners-swiper", {
    spaceBetween: 12,
    navigation: {
      nextEl: ".partners-swiper .swiper-button-next",
      prevEl: ".partners-swiper .swiper-button-prev",
    },
    pagination: {
      el: ".partners-pagination",
      clickable: true,
      renderBullet: function (index: number, className: string) {
        return (
          '<span class="' + className + '"><div class="display-dot"></div></span>'
        );
      },
    },
    breakpoints: {
      768: {
        slidesPerView: 2,
      },
      1024: {
        slidesPerView: "auto",
      },
    },
  });
}

function modifyCardContent() {
  const cards = document.querySelectorAll(".partners-swiper .swiper-slide");
  cards.forEach((card) => {
    const content = card.querySelector(".location-container");
    if (content && content.children.length == 1) {
      const label = card.querySelector(".location-label .elementor-heading-title");
      if (label) {
        label.textContent = label.textContent + " only";
      }
    } else if (content && content.children.length > 1) {
      const labels = card.querySelectorAll(".location-container >div");
      for (const child of labels) {
        child.insertAdjacentHTML(
          "afterend",
          '<svg class="seperator-dot" xmlns="http://www.w3.org/2000/svg" width="2" height="2" viewBox="0 0 2 2" fill="none"><circle cx="1" cy="1" r="1" fill="currentColor"/></svg>',
        );
      }
    }
  });
}

function waitForSwiper(method: () => void) {
  if (typeof Swiper !== "undefined") {
    method();
  } else {
    const checkInterval = setInterval(() => {
      if (typeof Swiper !== "undefined") {
        clearInterval(checkInterval);
        method();
      }
    }, 100);
  }
}

document.addEventListener("DOMContentLoaded", async () => {
  waitForSwiper(() => {
    createPartnerPagination();
    movePartnerContent();
    initailisePartnerSwiper();
    modifyCardContent();
  });
});

Partners description

Formats the interest-free wording, adds the bullet icons, counts the offers, appends the minimum spend to each offer, and adds the payment holiday badge.

<script>
  (() => {
    document.addEventListener("DOMContentLoaded", () => {
      // display only the last interest free
      document
        .querySelectorAll(
          ".partners-tiles .partners-tiles__interest-free .ck-partner__description-item .elementor-heading-title",
        )
        .forEach((element) => {
          const hasSpan = element.querySelectorAll("span").length;
          if (hasSpan > 0) {
            element.querySelectorAll("span").forEach((span, index) => {
              if (index < hasSpan - 1) {
                span.style.display = "none";
              }
            });

            // wrap the last span in a text
            const defaultText = "Up to [xx] interest-free";
            const lastSpan = element.querySelector("span:last-child");
            const interestFree = lastSpan.textContent.toLowerCase().trim();
            if (interestFree.indexOf("month") !== -1 && /\d/.test(interestFree)) {
              const text = defaultText.replace("[xx]", interestFree);
              lastSpan.textContent = text;
            }
          }
        });

      // Add class to parent and child elements to display the bullet point
      document
        .querySelectorAll(
          ".partners-tiles .ck-partner__description-item .elementor-heading-title",
        )
        .forEach((element) => {
          const hasSpan = element.querySelectorAll("span").length;
          if (hasSpan > 0) {
            element.classList.add("ck-partner__description-item-child-icon");
          } else {
            element.classList.add("ck-partner__description-item-parent-icon");
          }
        });

      // count how many offers are displayed and update the count
      let totalOffers = 0;
      document
        .querySelectorAll(".partners-offer-body .partners-offer-tile")
        .forEach((element) => {
          totalOffers++;
        });
      const countElement = document.querySelectorAll(
        ".partners-description__count-offers .elementor-heading-title",
      );
      if (countElement.length > 0) {
        let countText = countElement[0].textContent.trim();
        countText = countText
          .replace("[X]", totalOffers)
          .replace("[x]", totalOffers);
        if (totalOffers === 1) {
          countText = countText.replace("offers", "offer");
        }
        countElement[0].textContent = countText;
      }

      // add the min spent to the description of each offer
      const minSpent = document.querySelector(
        ".partners-tiles__min-spend .ck-partner__description-item .elementor-heading-title",
      );
      const description = document.querySelectorAll(
        ".partners-offer-body .partners-offer-tile .partners-offer-tile__body",
      );
      if (minSpent) {
        let minSpentText = minSpent.textContent.trim().toLowerCase();
        if (minSpentText.includes("$") || minSpentText.match(/\d+/)) {
          description.forEach((desc) => {
            desc.textContent =
              desc.textContent + " Min spend " + minSpent.textContent + ".";
          });
        }
      }

      // add payment holiday badge
      const isPaymetnHoliday = document.querySelector(
        ".ck-partner-description__payment-holiday",
      );
      if (isPaymetnHoliday) {
        const paymentHolidayText = isPaymetnHoliday.textContent.trim();
        const offersTitle = document.querySelectorAll(
          ".partners-offer-body .partners-offer-tile .partners-offer-tile__title",
        );
        offersTitle.forEach((title) => {
          const offerText = title.textContent.trim();
          if (offerText === paymentHolidayText) {
            const badge = document.createElement("span");
            badge.className = "partners-badge";
            badge.textContent = "Payment Holiday";
            title.appendChild(badge);
          }
        });
      }
    });
  })();
</script>

On this page