Sharing content around multi-sites in Drupal 7 using JavaScript

May 18, 2019


Problem: We have 150+ multi-sites and would like to share certain lists of content (Views) between them. In this specific case, there is a need to show a list of programs on a department site. Each department has their own multi-site, and there is 1 programs site that all the data will come from as the "single source of truth." This will also help departments not have to worry about keeping program content up-to-date because it's always being pulled from the source.

A basic diagram of how this functionality will work. The Programs site contains the single source of truth for programs. Within that site there are Views of programs for each department. A simple custom module can be used to pull those in.

Custom module time

First, I made a module that will be able to be activated on department sites that will pull a view of programs tagged by department. Here are the important files:

paragraphs-item--programs-importer.tpl.php

<?php $tag = trim(render($content\['field\_program\_tag'\])); ?>
<div class="<?php print $classes; ?>"<?php print $attributes; ?>>
<?php print render($content\['field\_title'\]); ?>
<div class="bootstrap-fix">
<div class="row">
<div class="programs-feed" data-tag="<?php print $tag; ?>">
<!-- you can also put a loading animation here -->
<p>Your browser has JavaScript disabled. As a result, some features may not function properly. <a href="/programs/by\_dept/page/<?php print $tag; ?>">View <?php print $tag; ?> programs</a></p></div>
</div>
</div>
</div>

Ideally, the "Your browser has JavaScript disabled ... " should be set if the AJAX call ends in an error, but that's not what I ended up implementing.

I'm using the Paragraphs module and allowing users to enter in a title and the 'tag' that will be used to insert into the View URL as a contextual filter.

programs_feed.js

Drupal.behaviors.programsFeedParagraph = {
attach: function (context, settings) {
if (jQuery(".programs-feed").length) {
jQuery(".programs-feed").each(function () {
jQuery(this).load(
"/programs/by_dept/page/" +
jQuery(this).attr("data-tag") +
" .view-content"
);
});
}
},
};

The JavaScript is super simple, it checks to make sure there is a ".programs-feed" element on the page, then loops through each of them and uses jQuery.load to call the View that was created on the programs site. There's more about this View in the next step.

Setting up the programs view

Now, all we need to do is set up a view on the programs multi-site that has the content that we want to import. I make sure that Google cannot index this page because I don't want to impact SEO by having a bunch of duplicate content on the programs site and department sites.

An added layer of complexity is ordering. Alphabetical is not always ideal and departments want to be able to list certain programs above others. For this I ended up creating a vocabulary for "Departments" so each program can be tagged with what department they belong to. Then using the Nodequeue module I created a nodequeue for each department taxonomy term.

Now in the view, I can use the nodequeue reference (which is the same as the taxonomy term the department belongs to) as a contextual filter to get lists of programs based on departments.

The final result is the ability for each department site to pull in a list of programs from the "Programs" multisite. Now it is no longer necessary for department sites to duplicate content that already exists on the program site!