New links module?


#1

Overview

Linking to things tends to be important in a CMS, and has high reuse value.
This can be observed in the large download numbers for GitHub - sheadawson/silverstripe-linkable: Easily add external or internal links to a dataobject with a dialog form. I’m keen to start a conversation with module authors on how we can take this forward.

Shea’s module is now deprecated. A common replacement is GitHub - gorriecoe/silverstripe-linkfield: Adds a Linkfield for gorriecoe/silverstripe-link
(plus the underlying data model of GitHub - gorriecoe/silverstripe-link: Adds a Link Object that can be link to a URL, Email, Phone number, an internal Page or File.).

The has_one UI is pretty cruddy (it’s using GridField’s defaults)

We’ve also created a similar (more limited) implementation of this as part of GitHub - silverstripe/silverstripe-elemental-bannerblock: A banner block for the dnadesign/silverstripe-elemental module.
It only supports internal links (see Should support external links · Issue #23 · silverstripe/silverstripe-elemental-bannerblock · GitHub), but has a nicer way to manage them (in a modal).
And it is tied to the concept of a “banner”, but should really be useable outside of that (see Should BlockLinkField be pulled out into its own module? · Issue #10 · silverstripe/silverstripe-elemental-bannerblock · GitHub).


image

In my opinion, all of these modules have a shortcoming in terms of UX: They force users
to treat links as an object that’s managed on it’s own screen, rather than something that’s easily inlined.
This becomes particularly apparent in blocks implementations where the inline editing flow becomes more important due to granular content creation (e.g. a “call to action” button)

Proposed Requirements

  • Supports linking to internal pages and external URLs
  • Supports linking to emails
  • Supports grouping links in has_many or many_many relationships (incl. sorting)
  • Can choose to open links in new window
  • Validates formats (e.g. valid email addresses)
  • Optinally supports linking to phone numbers (with good template defaults to make them behave like phone numbers)
  • Can be extended (e.g. to support custom formatted links to VOIP apps based on staff name lookup)
  • Same data model can be managed in different ways (= separate out form field into own module)
  • Supports drafting changes in links before publishing them
  • Can be folded into other form contexts without requiring it’s own detail view to reduce editing friction
  • Only shows options releva
  • Supports more than one link editing UI in the same form

Implementation notes

  • Regarding folding this into other form contexts (e.g. GridField), I see two options:
  • Option A: CompositeField which can be either applied to a “Link” DataObject, or any other DataObject directly. CompositeField would create database columns like “PageID”, “ExternalURL”, “OpenInNewWindow” etc
  • Option B: Create a form field which can manage a has_one relationship inline
  • Techncailly, we also have SilverStripe’s built in “link” modal dialog for HTML content, which only supports writing to HTML embedded shortcodes, not data objects. I don’t think those use cases need to overlap, because it’ll introduce quite a lot of complexity.

#2

This is needed so much. It’s a constant source of pain for me.


#3

It’s a constant source of pain for me too.


#4

There’s further designs available in one of those GitHub issues you mentioned for the link field:

Designs: Design Systems Manager
Issue: Should support external links · Issue #23 · silverstripe/silverstripe-elemental-bannerblock · GitHub

Is the suggestion to ditch both of the existing options and make a new module? Or is it a question of which we should “adopt”? This discussion has come up often at SilverStripe too - quite a few developers already use and are familiar with the gorriecoe library, but the field will need to be “Reactified” at some point. That’s one advantage of the bannerblock implementation - it’s already “Reactified”.


#5

There are lots of options for links, but generally only the URL is critical. Sometimes the link text may be critical too, but this depends on context as a button label etc. may be predefined.

Maybe a compromise could be to have inline editing for the critical component (whatever defines the URL) then have an options button to open a modal for non-critical settings.

Here’s a quick mockup of what I mean:

inline-link


#6

Maybe a compromise could be to have inline editing for the critical component (whatever defines the URL) then have an options button to open a modal for non-critical settings.

Yeah, I think for blocks, the inline editing flow on the most important field(s) is becoming pretty crucial. We’re up against Squarespace and Wordpress Gutenberg in this regard, and those are butter smooth when it comes to quickly inserting content. That being said, we’ve already got designs for a modal, which is much better than a full CMS reload to a GridField detail form.

Is the suggestion to ditch both of the existing options and make a new module?

Assuming we can create editing UIs for anything, it comes down to data model choices:

  • Data Model Option A: Link DataObject. Implemented by sheadawson and gorriecoe. Easiest to extend via DataExtension. Can be shaped to has_one, has_many, many_many. More complex relationship versioning and handling (although we have that solved through cascading publish etc.). More performance impact on query time. Can use lots of built-in editing UIs directly (e.g. GridField). Works with other core features like diff views, reports, etc. But also adds more database tables and schema complexity. Most consistent, SilverStripe devs know how to deal with this.
  • Data Model Option B: DBLink DBField with serialised JSON. Implemented by bannerblock. Harder to extend. Serialised JSON makes it hard to query individual fields (without using something like GitHub - phptek/silverstripe-jsontext: JSON storage and querying and JSON database support). Harder to enforce consistent schema. Creates new dependency if done properly (e.g. through phptek’s module). Less native form handling (e.g. validation errors?)
  • Data Model Option C: DBLink CompositeField with individual database columns. Harder to extend. Easy to query. Strong schema. Can be wrapped in arbitrary DataObject structures or relationships. Can “inline” columns into a DataObject to avoid relationship in cases where only one link is required. Can use lots of built-in editing UIs indirectly (e.g. GridField through DataObject). Less native form handling (e.g. validation errors?)
  • Data Model Option D: Shortcodes. Just mentioning it for completeness here. Technically we could store dedicated links in the same format as links inlined in our HTML.

The easy path is Option A: DataObject. Given that we’re already dealing with deeply nested hierarchies in the CMS (Blocks, Images, etc), I don’t think doing this for links as well will make or break the system. And you get a lot of tooling from the wider SilverStripe ecosystem.

My least favourite is Option B, unless we take this all the way and create some schema validation and deep querying abilities (by adding jsontext). Which would increase our implicit maintenance surface on a supported module. jsontext wouldn’t need to become supported, but we’d be on the hook for any bugs that permeate through our own module surface :slight_smile: I’m sure @theruss has done a great job here, just generally wary of adding more dependencies on a team of eight devs maintaining 90+ modules. I think there’s a case to be made for moving much of the SilverStripe data model into JSON blob columns, but as a one-off I don’t feel like it adds a whole lot of benefit?


#7

Any update on this becoming a thing? The UI of the elemental one is rather pleasant.


#8

Not planned at the moment. One of our two project teams is busy with implementing MFA for the next two months, and the other has a pretty full backlog of GraphQL and a broader “recipe” for SilverStripe incl. more modules and default functionality. Help appreciated :slight_smile:


#9

having an easy UI for managing has_many/many_many links WITH sort order is super, super nice and i wholeheartedly support this.


#10

I’ve been thinking about this a little recently again. The ux team has come up with some good ideas and we’ve made a start on those in the bannerblock module as chillu mentioned above. Given we might implement the designs, as I see it there are these options:

  • A: Do everything ourselves from scratch. This not only includes the field but a lot of extra DB work
  • B: Fork and update Shea’s module which does a lot of the groundwork - we can update the field
  • C: Contribute a redesign to the gorriecoe/linkfield module - this provides a field in a module that relies on a different module (gorricoe/link) to handle all the extra DB stuff.
  • D: Create an alternative to gorriecoe/linkfield that still ties into the gorriecoe/link module. This could be done as a fork or as a brand new module

Option D and C might mean we add the gorriecoe modules to our “supported” list.

I think option D probably makes the most sense. Keeping those concerns separate is nice. Contributions can always be made back to the base module if required too :slight_smile: