Custom Field Options via Blueprint

Custom Field Authors!

A recent bug in my Location Field plugin subverted my notions about how options were passed to custom fields, from the Blueprint.

The Problem

When a field is initialized, it seems like the extra params are not available in any easily accessible way.

A Blueprint containing the following field…

fields:
  location:
    label: Location
    type: place
    center:
      lat: 45.5230622
      lng: -122.67648159999999
      zoom: 9
    help: >
      Move the pin wherever you'd like, or search for a location!

…will accept the standard label, type and help keys, but not expose the custom center key to the constructor. To be more specific, when inspecting the Field class, the center property has not been set, and that portion of the decoded YAML is, as far as I can tell, never actually is persisted as a property (or properties) on the class.

The authors of the Selector plugin has a clever way of capturing these additional keys by overriding the low-level “magic method” __set, as seen here.

I’m going to posit that this is the wrong approach (to no one’s fault), in that it could easily compromise other functionality that depends on the __set method (any assignment of properties on PHP object), and that we ought not have to hook into low-level PHP functionality to handle custom options assignment— that should be automatic, but I accept that defaults handling can be done on a plugin-by-plugin basis.

Furthermore, when I used the magic method strategy, it seemed like forms built inside a structure field were not receiving the options at all. I ended that line of inquiry for the reason above.

What We Need

In order to make custom field development safe and accessible, it seems as though we need the complete map of options passed in to the constructor function.

What We Have

  • It would appear as though the Form class provides the behind-the-scenes setting behavior that the Selector plugin takes advantage of.
  • When the Fields collection is created, the entire $params array is passed in, but it isn’t stored. A couple of keys are re-set, and then the Obj constructor is called, which, according to the source, already maps key/value pairs into properties. What gives? I don’t see any of those keys when inspecting my class. Perhaps the chain of inheritance doesn’t go back this far? Maybe I have more flawed notions about the inheritance and sequence of initialization.

Any ideas? I’m fine using a reliable solution that exists, or authoring a Pull Request to the Panel core to make this a reality. I just don’t know (conceptually, technically) where the best place to start would be.

Thanks for your time!

I found something that might help. Posted it on GitHub

Hi, the creator of the Selector field here.

As far as I know, every custom option set in a blueprint is applied to your fields properties without any further ado. All you have to do is to actually create all the custom properties you want to offer in your class and make them public.

Also, a very important thing to know is that the properties will be applied after your fields constructor has been run. So you can’t just use the custom option values in the constructor.

For this plugin, I explicitly defined the properties as protected since I actually want the __set() function to run. This let’s me sanitize the option values and apply defaults, if the user has set anything invalid.

Glad to have @PaulMorel’s suspicion about this confirmed. I’ve updated the plugin with this in mind. I may come around to the __set magic method if the configuration options need more grooming— for now, I think the fallbacks are as sophisticated as they need to be,

Thanks to both of you for taking the time to help. :blush:

1 Like