Share content between websites


how share content between websites(getKirby) ?

for example:

fetch the news from a other webpage
but only the news content with a specific tag ‘publicNews’.

greetings perry.

Do you want to synchronize the content between two sites?

Since Kirby uses the filesystem for the content, you can copy over the content using rsync or a similar tool.
If you want to limit it to a specific tag, you can write a command line PHP script that loads the Kirby bootstrap.php and then you can read the information from the content files to build a list of pages to copy over using rsync.

But a general question: Why do you want to do this? Duplicating content isn’t that great. Not only for SEO but also for your users.

I think the best way would be to create a JSON endpoint which you can then call from the other website. With Kirby 2.4, you will be able to create a JSON representation of your news template, so you would be able to call this representation via URL (e.g.

If you don’t want to wait until 2.4 comes out, you can achieve the same via a JSON page or use a route.

@texnixe I’ll wait until kirby 2.4
yes duplicate content is not great.

Folgende Situation:
Ein Kulturzentrum das verschiedene Institution beherbergt.
Das Kulturzentrum hat eine eigene Webseite mit einem Newsfeed
dort werden alle Veranstaltungen publiziert.

Innerhalb des Kulturzentrums ist eine Gastronomie die auch eine Webseite
betreibt und eigene Veranstaltungen publiziert.

Meine Idee ist das nur das Kulturzentrum(parent) die News erstellt und die Website
der Gastronomie(child) nur die für sie relevante News fetcht, um die News zu filtern dachte ich eben an tags.

Warum nicht nur eine Website ? Der Wunsch des Kunden(Gastronomie) war ein eigenes Erscheinungsbild zu haben um unabhängig vom Ort zu sein.

thanks for your help.

Sorry to get this topic up again, but as the title is exactly the thing I am searching for, I’ll still go with it. Here’s my situation:

A while ago I developed a client’s multi-lang website with a mid-sized product “database” (as products are kirby pages) with ~500 products and some more or less complex logics around it (bookmarks list, product search, products being linked in visual examples, and so on). Now, one of the client’s distributors from Switzerland wants basically a clone of the website with some content being adopted to the distributors needs (info, contact, e.g.), while the products should be shared between the two pages.

Now, my first idea was the above recommended, so cloning the website, adjusting the content which need to be adjusted and requesting everything else via the JSON representations (or a similar, custom build API – don’t really now yet). Still, somehow this feels like a hack to me.

The second idea which came to my mind was just adding a new “language” – we have German, English and French – and changing the “language” label to “country”. But of course that’s not the best way to do either, as there are definitely people visiting the Swiss/distributors site who need translated content.

The perfect solution for me would be if both sites could live on the same installation (of course multiple licenses when using multiple domains), sharing some defined parts of the site, where everything else is individually manageable. I thought about putting everything which is not shared into separate subfolders for each site, but this feels even more like a hack. Maybe some of you have an idea how to solve this issue?

The problem I see here is that you want to share like parts of folders, for example, a part of the content folder and not the complete content folder, so a multi-site setup wouldn’t work for you. Don’t know if the rsync solution could work or if this would easily mess things up, especially if the distributor site has different (additional) languages, this might get pretty difficult. If the distributor needs additional translations, how would you want to handle that? In that case, even a custom API would be pretty useless unless the translations are stored in the original installation.

If the changes are small and don’t change a lot over time, maybe the distributors content could be stored in a database and passed to the templates via a route (depending on domain), while the rest of the stuff is shared between installations.

I am also working out something similar: a central “newshub” where all news (multilingual) is managed and a few “affiliate newssites” which list the news articles.

I’ve tackled the duplicate content issue by disabling a “public front end” on the newshub website AND by giving each news article a dedicated affiliate site.

The newshub site generates JSON feeds for each affiliated website which are then pulled from each affiliate site. The JSON file is then cached on the affiliate site which uses custom controllers and templates to render the news from the JSON file instead of from “kirby pages”. This works perfectly (and news articles can even be cached), but it also has other issues I haven’t found a solution for yet (e.g. make them findable via site search, or re-create the pagination object). If anyone has ideas and would like to discuss this, I’m all ears :wink:

I also have a proof-of-concept working which “pings” the affiliate site upon each “create/edit” of a news article on the newshub site. That ping then busts the cache on the affiliate site and drags in the updated JSON. I can’t use that not yet though, because of a nasty bug with hooks in the panel.

Thanks for your thoughts guys!

@texnixe exactly, multi-site setup doesn’t work unfortunately. I think rsync might work, but is still not the best solution, as I have to store files, images (HD), and so on of all products twice on the server. Additional languages are not planned, so for the moment that shouldn’t be a big issue. Also, products will be managed only by the original site, so no need for the distributor to access them in the panel (I could just hide it via blueprints, for example).

@bvdputte this approach does sound like something I might work out as well. Completely outsourcing the shared things, maybe inside an own panel installation, and then both sites just getting information via JSON.

If I know more about this and found a solution, I will come back to this.

Are the websites hosted on the same server? If so I’d try using symbolic links (you will need to make sure Apache/Nginx follows them when resolving paths).

I have successfully used symlinks on a project on shared-host where I had two types of contents that required slightly different blueprints but shared controllers and templates:

- blueprints
  - accessories.yml
  - accessory.yml
  - product.yml
  - products.yml
- controllers
  - accessories.php // --> symlink to products.php
  - accessory.php // --> symlink to product.php
  - product.php
  - products.php
- templates
  - accessories.php // --> symlink to products.php
  - accessory.php // --> symlink to product.php
  - product.php
  - products.php

A different use case, but you get the idea.


@pedroborges, Interesting concept but not usable in my case: I have 1 directory with all the news articles, but different “subsets” to affiliate sites.

Sorry for not making it clear @bvdputte, my answer was directed to @jakobploens’s problem.

For your problem I think you’ve got the right solution. Let’s hope that panel bug is fixed soon!

1 Like

Late reply but, in general that is true, but if you mix content, it may work just fine. I use the same facts on these two sites, but the “story” content is different so it’s not duplicate content:

@jakobploens @pedroborges

It looks like many people need the same information across sites. Maybe you are not surpriced, but I built a plugin for that about a year ago. It’s not public because it has some custom stuff that only my site would benefit from.

Anyway, I can share with you what I did. I can mention that all I needed was the content text file and the blueprint file.

Site 1

This first site work as a hub where all the content is created in a special folder. I created the content in a folder called data.

A plugin was created with a route. It basically returned the content of the data file, depending on an a page id (uri), sent to the route. Similar was done with the blueprint. I also have a token to keep it private.

An update/create/move hook is created and each time a page is changed it will call an API on site 2 (see site 2 below). It will trigger site 2 to get content from site 1.

Site 2

Another plugin was created. A route was created here as well. This route calls the API of site 1 and get the content from it that way. Then it saves it in the content data folder on site 2. Now site 2 mirrors some of the content of site 1.

In short it does this:

  1. I save new data on the hub domain.
  2. It will run a hook to trigger the API on site 2.
  3. Site 2 will then get content from site 1.
  4. Save the content on site 2.

Because more than me need to sync part of their content, I might build a more generic plugin out of this. It would be the perfect time because my old plugin for some reason stopped syncing so I need to make it more reliable anyway.


Both of your suggestions seem like very interesting solutions. I’ll dig into them and definitely report about my experiences, thank you for the inspiration :slight_smile:

I’ve spent a few days building a new plugin that I call Kirby Sync.

You setup a hub domain that contains the original conent and some additional node domains that the original content will be copied to.

This is the closest I get to a screenshot:

hub (domain)
├─ node (domain)
└─ node (domain)

When you save the content on the hub, it will be sent to the nodes. To not sync the whole hub domain, you specify a parent folder with the domain config, like this:

c::set('', [
    '' => [
    '' => [

There are many options in the repo, especially for the node. You can prefix the content, blueprint, you can add an additional parent page wrapper, you can choose if you want to send both blueprint and the content, or just the content etc.

The first version includes hooks for create and update, but not for delete and move.

I tag some of you:

@Perry @jakobploens @bvdputte


Does the nodes’ files system need to be on the same server as the hub file system?

Or the plugin allows to sync pages hosted on diffrent physical servers?

The hub calls the nodes api with a http get request on save. Then the node will do a http get request back to get data from the hub and then save it.

So it does not need to be on the same server.

Ok so I imagine the only constraint is to have the same blueprint/template on the hub and the node(s)?

I’ve thought about blueprints as well and there is an option to sync them as well:

You can change this to true.

c::set('plugin.sync.blueprint', false);

To prevent the mistake of overwriting blueprints that already exists, the blueprint and the content is prefixed by default:

c::set('plugin.sync.blueprint.prefix', 'synced-');
c::set('plugin.sync.content.prefix', c::get('plugin.sync.blueprint.prefix'));

It would look like this:


Because both of them are prefixed they will also match up and work in the panel. To remove the prefixes you can do this:

c::set('plugin.sync.blueprint.prefix', '');

but be careful as it will overwrite blueprints with the same names.

By default a wrapper parent page is also created for the content to prevent page collisions:

c::set('plugin.sync.parent', 'synced-data');

If you want to save the blueprints somewhere else than in the blueprint folder you can change it by changing site.php in the node domain root:

$kirby = kirby();
$kirby->roots->sync_blueprints = $kirby->roots()->blueprints();

Did I answer your question? I got a little carried away. :slight_smile:

Yes you answer my question, thank you very much for this detail explanation :slight_smile:

Hey jenstornell,

what a perfect Plugin for my recent project!! I’m playing around with your plugin since yesterday, and it works great, but i do have an important question:

It doesnt sync the state (visible/invisible), right? :confused: Or am i missing something? :slight_smile:

Thanks in advance, Chris

P.S.: What i have to say is, that the synced pages from the hub are sorted by date, so the folder-name on the server isn’t 01-example, 02-example… but 20171001-example and 20171002-example etc. Could this be a problem?