Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.


Module of the Month: One thing at a time

This week's module of the month dives into forming a better CMS user experience when creating relations, by simplifying the overall process.

Read post

To keep the CMS users happy in their day-to-day work, it’s important to have the CMS configured in a way that gives a good user experience. One of the more complicated relations to add, is a one to many relation, for example on a page. This is pretty straight forward with the default dropdown, but is not always the best solution.

Consider you have a one to one relation with has_one and belongs_to back. This means you need a ModelAdmin for handling all the DataObjects that are only used once on the other side of the relation.

Although it works, it’s slightly inconvenient for the CMS users as they have to go through multiple steps to get a single relation set up.

We’ll stick with a Page::has_one ⇔ DataObject::belongs_to relation for the rest of this article.

For example, a CMS user has to go through the following steps:

  • go to the ModelAdmin
  • create the one object
  • go to pages
  • find the right page
  • link the new object

That’s a lot of steps for one object.

One could argue it’s more convenient to just put everything on the page, but in a lot of cases that’s not a proper Object Oriented approach. This causes code mess and possible technical debt in the future.

For any developer, the words “Technical debt” make their hair raise (think bloodshot eyes of pure anger). 

The solution

Still use the proper Object Oriented approach, but with HasOneField to reduce the hassle of linking everything together. This module creates a button on the Page that will easily let a CMS editor add the related object on the page itself. No more clicking around in the CMS until everything is prepared, just do it on the fly.

Sure, an optional ModelAdmin is still useful for cleaning up no-longer used objects, but there’s no need to go through all the steps anymore. 


As per usual, installation is as easy as

composer require silvershop/silverstripe-hasonefield

Inner workings

The field itself is secretly a GridField, but only allows for one record to be in the gridfield, by changing the Add button to an Edit button once a record is added. Pretty clever! 


So, let’s start with a Page type that has a Call to Action. A Call to Action is often just used on a single page and not re-used. I’m talking about landing pages kind of Call to Actions, not a generic multi-used one here.

Adding a call to action

Add a Call to Action

A single button, to handle the single relation directly from the about-us page. A simple click of a button gives us

Created Call to Action page

Now, we can add a single relationship easily, without having to go through the hoops of going through a ModelAdmin.

After hitting Create, the relation is saved back into it’s parent Page, which then looks like this

Editing the Call to Action page

Yes! The relation is properly saved, and my Call to Action is there. Assuming you followed the instructions on GitHub, on how to create the button with the read-only field, you should be able to easily replicate this behaviour.

As you can see, the Add button is now an Edit button, which edits the existing Call to Action and not a new, empty one.

Future improvements

Have a GridFieldAddExisting that respects the has_many relations, with adding an option by default to hook in an existing one (instead of the default dropdown) if it is a one to many relation. It should be possible to do so already with adding a GridFieldAddExisting button, but it should respect the has_one relation back, which AddExisting doesn’t do yet it seems.


If you have a has_one relation that you’d like to edit from the parent, this module is quite handy!

As per usual, give it a try, contribute and enjoy! 

If you want to stay updated about changes in the SilverStripe community, sign up to our SilverStripe community slack channel

Community Slack CTA

About the author
Simon Erkelens

Simon is a developer at SilverStripe. When not at work, he's writing other programs or focusses on one of his modules he wrote or co-wrote. Or writing new things.

As a real backend developer, he's usually staring at a dark screen with code only. Although every now and then, he can be convinced to work on some frontend things or testing.

In real life, he looks nothing like the cow in his avatar, but he does love cows (both alive and medium rare)

Post your comment


No one has commented on this page yet.

RSS feed for comments on this page | RSS feed for all comments