This is a completely blank WordPress page created to test whether O2O coursework catalogue would work on IVMF website, which was built on WordPress as well. This page has some stylesheets and plugins but the goal is to check whether the fundamental workflow would work. Eventually, the process would need to be tested on IVMF website for errors and conflicts.

How does this work?

What’s in the template?

A pre-designed card
<template id="temp-card2">
    <div id="%CERT_CARD_ID%" class="col card-path">
        <div class="card h-100">
            <div class="card-body">
                <h4 class="card-title">%TITLE% </h4>
                <h6 class="card-subtitle mb-2 text-body-secondary">%SUBTITLE%</h6>
                <p style="font-size: 0.9rem;" class="card-text">%CERT_DESC%</p>
                <ul style="font-size: 0.85rem; line-height: 1.1rem;" class="list-inline">
                    <li>
                        <span><strong>Keywords: </strong></span> %CAREER%
                    </li>
                </ul>
                <a role="button" data-bs-toggle="modal" data-bs-target="%CERT_MODAL_ID_HASHTAG%" class="btn btn-sm btn-outline-primary"> View detail </a>
            </div>
        </div>
    </div>
    <div tabindex="-1" id="%CERT_MODAL_ID%" class="modal fade p-0" aria-labelledby="%CERT_MODAL_TITLE_ID%" aria-hidden="true">
        <div class="modal-dialog modal-fullscreen-sm-down modal-dialog-centered modal-dialog-scrollable">
            <div class="modal-content">
                <div class="modal-header">
                    <ul role="tablist" id="myTab" class="nav nav-pills">
                        <li role="presentation" class="nav-item">
                            <button
                                type="button"
                                tabindex="-1"
                                role="tab"
                                id="%CERT_MODAL_NAV_DESC_ID%"
                                data-bs-toggle="tab"
                                data-bs-target="%CERT_MODAL_DESC_ID_HASHTAG%"
                                class="nav-link active"
                                aria-selected="false"
                                aria-controls="%CERT_MODAL_DESC_ID%"
                            >
                                Description
                            </button>
                        </li>
                        <li role="presentation" class="nav-item">
                            <button
                                type="button"
                                tabindex="-1"
                                role="tab"
                                id="%CERT_MODAL_NAV_TOPIC_ID%"
                                data-bs-toggle="tab"
                                data-bs-target="%CERT_MODAL_TOPIC_ID_HASHTAG%"
                                class="nav-link"
                                aria-selected="false"
                                aria-controls="%CERT_MODAL_TOPIC_ID%"
                            >
                                Topic
                            </button>
                        </li>
                    </ul>
                </div>
                <div class="modal-body">
                    <div class="tab-content">
                        <div role="tabpanel" id="%CERT_MODAL_DESC_ID%" class="tab-pane active" aria-labelledby="%CERT_MODAL_NAV_DESC_ID%">%CERT_DESC%</div>
                        <div role="tabpanel" id="%CERT_MODAL_TOPIC_ID%" class="tab-pane" aria-labelledby="%CERT_MODAL_NAV_TOPIC_ID%">%EXAM_TOPIC%</div>
                    </div>
                </div>
                <div class="modal-footer"><button type="button" data-bs-dismiss="modal" class="btn btn-secondary btn-sm">Close</button><button type="button" class="btn btn-primary btn-sm">Select</button></div>
            </div>
        </div>
    </div>
</template>
An accordion (collapsible) filter panel
<div style="font-family: 'Overpass', sans-serif;" id="accordionExample" class="accordion">
    <div class="accordion-item">
        <h2 id="headingOne" class="accordion-header">
            <button type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" class="accordion-button" aria-expanded="true" aria-controls="collapseOne">Narrow down your search</button>
        </h2>

        <div id="collapseOne" data-bs-parent="#accordionExample" class="accordion-collapse collapse show" aria-labelledby="headingOne">
            <div id="filter-panel" class="accordion-body">
                <h6><label for="dropdown-agency">Agency</label></h6>
                <select id="dropdown-agency" class="form-select">
                    <option value=""></option>
                </select>

                <fieldset id="filter-pathways">
                    <legend></legend>

                    <h6>Pathways</h6>
                </fieldset>
            </div>
        </div>
    </div>
</div>
A (hidden) table
<table style="width: 90%; margin: auto;" id="pathTable" class="table table-striped nowrap">
    <thead>
        <tr>
            <th id="pathTable-id" data-visible="false" data-data="id">id</th>
            <th id="pathTable-title" data-priority="1" data-data="title">Title</th>
            <th id="pathTable-certificate-link" data-searchable="false" data-data="certificate-link">Certificate Link</th>
            <th id="pathTable-description" data-priority="2" data-data="description">Description</th>
            <th id="pathTable-agency" data-data="agency">Agency</th>
            <th id="pathTable-agency-link" data-searchable="false" data-data="agency-link">Agency Link</th>
            <th id="pathTable-agency-contact" data-searchable="false" data-data="agency-contact">Agency Contact</th>
            <th id="pathTable-eligibility" data-data="eligibility">Eligibility</th>
            <th id="pathTable-exam" data-data="exam">Exam</th>
            <th id="pathTable-pathways" data-visible="false" data-data="pathways">Pathways</th>
            <th id="pathTable-exam-topic" data-visible="false" data-data="exam-topic">Topics</th>
        </tr>
    </thead>
</table>
Some scripts
var cardPath = '<li class="list-inline-item text-secondary card-path me-0 " style="margin-top: 0.25em;" value="%VAL%">%VAL%</li>';
var pathTable, visibleIds;
  // Pull data and populate table
  jQuery.getJSON(
    "https://gist.githubusercontent.com/yuenhsu/d7da45122fce175f8a758efc4ce95a00/raw/0a8c70f8e1004c612c77a3bda0df2da72a02a1ce/o2o_coursework.json",
    function (response) {
      console.log("jQuery get success. Record count: " + response.length);
      pathTable = jQuery("#pathTable").DataTable({
        data: response,
        info: false,
        ordering: false,
        paging: false,
        autoWidth: true,
        //searching: false,
        responsive: true,
      });

      jQuery("#pathTable_filter").hide();

      console.log("table initiated");

      // Populate card view
      var view = pathTable
        .data()
        .toArray()
        .map((row) =>
          jQuery("#temp-card2")
            .html()
            .replaceAll("%TITLE%", row["title"])
            .replaceAll("%SUBTITLE%", row["agency"])
            .replaceAll("%CERT_DESC%", row["description"])
            .replaceAll("%CERT_CARD_ID%", row["id"])
            .replaceAll("%CERT_MODAL_ID%", "modal_" + row["id"])
            .replaceAll("%CERT_MODAL_ID_HASHTAG%", "#modal_" + row["id"])
            .replaceAll("%CERT_MODAL_TITLE_ID%", "modalheader_" + row["id"])
            .replace("%EXAM_TOPIC%", row["exam-topic"])
            .replaceAll("%CERT_MODAL_DESC_ID%", "modaldesc_" + row["id"])
            .replaceAll(
              "%CERT_MODAL_DESC_ID_HASHTAG%",
              "#modaldesc_" + row["id"],
            )
            .replaceAll("%CERT_MODAL_NAV_DESC_ID%", "modaldesclab_" + row["id"])
            .replaceAll("%CERT_MODAL_TOPIC_ID%", "modaltopic_" + row["id"])
            .replaceAll(
              "%CERT_MODAL_TOPIC_ID_HASHTAG%",
              "#modaltopic_" + row["id"],
            )
            .replaceAll(
              "%CERT_MODAL_NAV_TOPIC_ID%",
              "modaltopiclab_" + row["id"],
            )
            .replace(
              "%CAREER%",
              row["pathways"]
                .filter((value, index, array) => array.indexOf(value) === index)
                .sort()
                .map((c) => cardPath.replaceAll("%VAL%", c))
                .join(", "),
            ),
        )
        .join("");

      jQuery("#pathCard").append(view);

      // Hide table and show cards
      jQuery("#pathTable").attr("hidden", "");
      jQuery("#pathCard").removeAttr("hidden");

      // Move Modal
      jQuery("div.modal").detach().appendTo("body");

      // Make button float
      jQuery("#NextButton").css({
        position: "fixed",
        bottom: "2rem",
        right: "2rem",
        "box-shadow": "2px 2px 3px #999",
      });

      /*jQuery("#pathTable_wrapper").prepend('<button type="button" class="btn btn-outline-primary" id="btn-cardview2" > Card View </button>');
		
		
		jQuery("#btn-cardview2").click(function () {
			let thisTable = jQuery("#pathTable");
			let thisCardDiv = jQuery("#pathCard");

			if ((thisTable.attr("hidden") == null) && (thisCardDiv.attr("hidden"))) {
				thisTable.attr("hidden", "");
				thisCardDiv.removeAttr("hidden");
			} else {
				thisCardDiv.attr("hidden", "");
				thisTable.removeAttr("hidden");
			}
		});*/

      // Get values for filter
      pathTable
        .column("#pathTable-agency")
        .data()
        .unique()
        .sort()
        .each(function (item) {
          jQuery("#dropdown-agency").append(
            jQuery("<option>", {
              value: item,
              text: item,
            }),
          );
        });

      pathTable
        .column("#pathTable-pathways")
        .data()
        .flatten()
        .unique()
        .sort()
        .each(function (item) {
          jQuery("#filter-pathways").append(
            jQuery("<input>").attr({
              type: "checkbox",
              autocomplete: "off",
              class: "btn-check btn-sm",
              id: "btn-" + item.toLowerCase().replace(/[\W_]+/g, "-"),
              value: item,
              onclick:
                "jQuery('#lab' + this.id).toggleClass('btn-outline-secondary').toggleClass('btn-primary'); this.toggleAttribute('checked');",
            }),
            jQuery("<label>")
              .text(item)
              .attr({
                for: "btn-" + item.toLowerCase().replace(/[\W_]+/g, "-"),
                id: "labbtn-" + item.toLowerCase().replace(/[\W_]+/g, "-"),
                class: "btn btn-sm rounded-pill btn-outline-secondary",
              }),
          );
        });

      jQuery("#dropdown-agency").on("change", function () {
        console.log("&#x1f4cd; Filter by agency: " + jQuery(this).val());
        pathTable
          .column("#pathTable-agency")
          .search(jQuery("#dropdown-agency").val())
          .draw();
        visibleIds = getVisibleIds();
        updateCardView(visibleIds);
      });

      jQuery("#filter-pathways>input").on("change", function () {
        if (jQuery(this).is(":checked")) {
          jQuery("li.card-path.text-secondary")
            .filter(function () {
              return jQuery("#filter-pathways>input[checked]")
                .toArray()
                .map((a) => a.value)
                .includes(jQuery(this).attr("value"));
            })
            .toggleClass("text-secondary")
            .toggleClass("text-primary")
            .toggleClass("strong");
        } else {
          jQuery("li.card-path.text-primary")
            .toggleClass("text-secondary")
            .toggleClass("text-primary")
            .toggleClass("strong");
        }

        let searchArray = jQuery("#filter-pathways>input[checked]")
          .toArray()
          .map((a) => a.value);

        console.log("&#x1f4cd; Filter by pathway: " + searchArray.join(", "));

        // Filter table
        pathTable
          .column("#pathTable-pathways")
          .search(searchArray.join("|"), true, false)
          .draw();
        visibleIds = getVisibleIds();
        updateCardView(visibleIds);
      });
    },
  );

  function getVisibleIds() {
    let ids = pathTable
      .rows({ filter: "applied" })
      .data()
      .toArray()
      .map((a) => a.id);
    console.log("Displaying " + ids.length + " rows: " + ids.join(", "));
    return ids;
  }

  function updateCardView(inputIds) {
    jQuery("div.card-path").each(function () {
      if (inputIds.includes(jQuery(this).attr("id"))) {
        jQuery(this).removeClass("d-none");
      } else {
        jQuery(this).addClass("d-none");
      }
    });
  }

Result

Keywords
id Title Certificate Link Description Agency Agency Link Agency Contact Eligibility Exam Pathways Topics