Closed AtmoFX closed 4 weeks ago
Thanks for this.
As far as I can tell, the confusing part that you've tried to address is that the fieldtype page itself doesn't really go into detail about setting up your JS+build process. Is that right?
Well... there certainly was confusion on my end but I am not sure this is going to be useful now that you updated the article. However, I would like to discuss about documentation for beginners from a more general perspective.
I am sure this will come as pedantic (despite my effort) so feel free to ignore it.
From the type of tutorial it is, I would say this page is typically directed at beginners. Actually, this is for first-timers as anyone, even if still beginners, who already created their own field and confirmed it works have no use for copy-our-example-to-see-how-it-works instructions anymore. I think it misses its mark though (even now).
As someone whose job used to include the redaction of documentation, I classify information into what is useful, distracting or undetermined (for lack of a better word). The "undetermined " appears as neither useful nor distracting or rather, in the grand signal-to-noise scheme of things, different people classify it as signal or as noise. I generally consider beginners have fewer memory items, a bigger need for an exhaustive checklist and will see more of these undetermined points as signal, so they should not be excluded. In fact, only the blattantly off-topic (and hardly anything else) should be put in the "disctracting" category and excluded from the beginners' help.
One telling example: between my suggestion and your version, I see you removed a link in the "Prerequisites" section, supposedly to decrease the noise (let me know if I am wrong assuming that).
I (and I think everyone trying to create their first fieldtype) was prepared to invest time to read detailed, very technical documentation but I sure would have traded the hours of browsing through entire webpages for the exhaustive list of relevant sections, linked directly from the procedure.
That was the goal of my "Prerequisites" section suggestion: include it but let people know it may be skipped unless "this is the first fieldtype [they] are creating".
BTW, the same can be said about editing package.json
in the same section. Maybe you are like: "of course you have to edit it, duh!" but:
-> I leave that to your evaluation.
PS: In case you wonder how it could possibly have taken me hours, I can explain easily:
Hey @jasonvarga
Just one tiny additional comment since I am actually using what I learned starting today: php please make:fieldtype ABC
shows this message:
⇂ Don't forget to import and register your fieldtype's Vue component in resources/js/addon.js
⇂ For more information, see the documentation: https://statamic.dev/fieldtypes#vue-components
Just wanted to highlight addon.js
is not consistent with the cp.js
from the documentation.
Hello,
I have recently tried my hand on https://statamic.dev/extending/fieldtypes, to see if I was able to extend statamic.
To people like me who are having their very first web development on Statamic, some of the obvious things to you guys are not obvious at all. I felt being a little bit more verbose for the password introductory example could have saved me from hours of cargo cult programming.
Below is my humble suggestion to improve the help page, with:
php please make:fieldtype TogglePassword
, with no comments in the current help page, left me wonder what I was supposed to do with it more time than I want to publicly admit.... hopefully nothing too crazy.
Let me know if you think that is useful.
Registering
Any fieldtype classes inside the
App\Fieldtypes
namespace will be automatically registered.To store them elsewhere, manually register an action in a service provider by calling the static
register
method on your action class.Creating
Fieldtypes have two pieces:
For this example we will create a password field with a "show" toggle control:
Prerequisites
If this is the first fieldtype you are creating, you will need to:
devDependencies
inpackage.json
.resources/js/cp.js
andresources/css/cp.css
.app/Providers/AppServiceProvider.php
, add the path to both files in thepublic function boot(): void
(see the "Using vite" help section). In most situations, you may only need to uncomment the function's body.vite.config.js
uncomment the lines as highlighted in the "Adding assets to your build process" help section.Creating the field
Create a fieldtype PHP class and Vue component by running the following command:
This creates the following:
app/FieldTypes/<class name>.php
file with a pre-filled class inside it.resources/js/components/fieldtypes/<class name>.vue
file.Your component has two requirements:
value
prop.input
event whenever the value updates.Statamic provides you with a
Fieldtype
mixin that does this automatically to reduce boilerplate code.At this point, coding will take place in the following 4 files, the first 2 of which are shared across all the fieldtypes you create:
resources/js/cp.js
resources/css.cp.css
app/FieldTypes/<class name>.php
resources/js/components/fieldtypes/<class name>.vue
Refer to the language written in each of the code snippets below to find out what file to edit.
Example Vue component
As the first example, the
TogglePassword
class will not require editing all 4 of the above files.Create it using the command below:
Register your Vue component as
[handle]-fieldtype
:The component in this example is defined by the code:
Finally, build the component:
Example walk-through:
Fieldtype
mixin is providing anvalue
prop containing the initial value of the field.text-input
component emits aninput
event whenever you type into it. Our component is listening for that event and calls theupdate
method.Fieldtype
mixin is providing anupdateDebounced
method which emits the requiredinput
event. This is how the parent component is detecting changes in your fieldtype.:::warning Do not modify the
value
prop directly. Instead, callthis.update(value)
(orthis.updateDebounced(value)
) and let the Vuex store handle the update appropriately. :::Fieldtype Icon
You can use an existing SVG icon from Statamic's
resources/svg
directory by passing it's name into an$icon
class variable, by returning a full SVG as a string, or returning it as a string from theicon()
method.Fieldtype Categories
When using the blueprint builder inside the control panel, your fieldtype will be listed under the
special
category by default. To move your fieldtype into a different category, define the$categories
property on your class:You can select from any of the keys available in the
FieldtypeSelector
:text
controls
media
number
relationship
structured
special
Configuration Fields
You can make your fieldtype configurable with configuration fields. These fields are defined by adding a
configFieldItems()
method on your PHP class that returns an array of fields.The configuration values can be accessed in the Vue component using the
config
property.Options
:::tip A little code diving will reveal all the possible config options for each field type. Look for the
configFieldItems()
method in each class here: https://github.com/statamic/cms/tree/3.3/src/Fieldtypes :::Adding configuration fields to existing fieldtypes
Sometimes you may want to add a config field to another fieldtype rather than creating a completely new one.
You can do this using the
appendConfigField
orappendConfigFields
methods on the respective fieldtype.Meta Data
Fieldtypes can preload additional "meta" data from PHP into JavaScript. This can be anything you want, from settings to eager loaded data.
This can be accessed in the Vue component using the
meta
property.If you have a need to update this meta data on the JavaScript side, use the
updateMeta
method. This will persist the value back to Vuex store and communicate the update to the appropriate places.Example use cases -
Here are some reasons why you might want to use this feature:
Replicator Preview
When Replicator (or Bard) sets are collapsed, Statamic will display a preview of the values within it.
By default, Statamic will do its best to display your fields value. However, if you have a value more complex than a simple string or array, you may want to customize it.
You may customize the preview text by adding a
replicatorPreview
computed value to your Vue component. For example::::tip This does support returning an HTML string so you could display image tags for a thumbnail, etc. Just be aware of the limited space. :::
Index Fieldtypes
In listings (collection indexes in the Control Panel, for example), string values will be displayed as a truncated string and arrays will be displayed as JSON.
You can adjust the value before it gets sent to the listing with the
preProcessIndex
method:If you need extra control or functionality, fieldtypes may have an additional "index" Vue component.
The
IndexFieldtype
mixin will provide you with avalue
prop so you can display it however you'd like. Continuing our example above, we will replace the value with bullets.Augmentation
By default, a fieldtype will not perform any augmentation. It will just return the value as-is.
You can customize how it gets augmented with an augment method:
Read more about augmentation
Accessing Other Fields
If you find yourself needing to access other form field values, configs, etc., you can reach into the publish form store from within your Vue component:
Updating from v2
In Statamic v2 we pass a
data
prop that can be directly modified. You might be see something like this:In v3 you need to pass the value down in a prop (call it
value
), and likewise pass the modified value up by emitting aninput
event. This change is the result of architectural changes in Vue.js 2.An alternate solution could be to add a
data
property, initialize it from the newvalue
prop, then emit the event whenever thedata
changes. By doing this, you won't need to modify your template or the rest of your JavaScript logic. You can just continue to modifydata
.If you had a
replicatorPreviewText
method, it should be renamed toreplicatorPreview
and moved to a computed.The PHP file should require no changes.