Fields (Pro)
There are more than 25 types of fields defined by this plugin.
The field CraftField
handles every custom Craft field with the exception of Table, Matrix and Neo fields. Their displayers will display the Craft field associated with them.
Then there are custom fields defined by this plugin that will render a Craft element's native field or attribute :
- AllowedQty : for variants only
- Author : for channels and structures only
- DateCreated
- DateUpdated
- Dimensions : for variants only
- ElementUrl : for entries/categories/assets/products only
- ExpiryDate : for channels, structures and products only
- File : for assets only
- Matrix
- NeoField : introduced in 3.1
- PostDate : for entries and products only
- Price : for variants only
- Sku : for variants only
- Stock : for variants only
- SuperTable : introduced in 3.1
- Table
- TagTitle : for tags only
- Title : for entries/categories/assets/products/variants only
- UserEmail : For users only
- UserFirstName : For users only
- LastLoginDate : For users only
- UserLastName : For users only
- UserPhoto : For users only
- UserUsername : For users only
- Variants : for products only
- Weight : for variants only
A field displayer defines how a field is rendered on the front end,
each field displayer will handle one type of field. This is controlled
by the method getFieldTarget(): string
which will return either the
class of the Craft field this displayer can handle, or the class of the
themes field (like Title
, Author
etc).
Define a new field
PHP
Define a new field model class, example for a field that will handle the dateCreated
of a element :
<?php use Ryssbowh\CraftThemes\interfaces\LayoutInterface; use Ryssbowh\CraftThemes\models\Field; class MyField extends Field { /** * @inheritDoc */ public static function getType(): string { return 'date-created'; } /** * @inheritDoc */ public static function shouldExistOnLayout(LayoutInterface $layout): bool { return true; } /** * @inheritDoc */ public function getHandle(): string { return 'dateCreated'; } /** * @inheritDoc */ public function getName(): string { return \Craft::t('themes', 'Date created'); } }
Register your php field class (implementing FieldInterface
) by responding to the event :
Event::on( FieldsService::class, FieldsService::EVENT_REGISTER_FIELDS, function (RegisterFieldsEvent $event) { $event->register(MyField::class); });
Create field automatically on elements
Custom fields (any field that doesn't extend from CraftField
) can
be created automatically on layouts if you return true to the method
shouldExistOnLayout(LayoutInterface $layout)
. By default this method
returns false.
This method won't have any effect for fields that extends
CraftField
, as they will be created automatically (assuming a Craft
field exists on the category group/entry type).
After creating your field you will need to rebuild the fields using the Themes settings or the command craft themes/install
so that they are created.
Complex fields
If your field is "complex" (has sub fields for example), you may need a bespoke Vue component to render it in CP :
To hook in the backend Vue system, register a javascript file with a bundle :
Event::on( CpDisplayController::class, CpDisplayController::EVENT_REGISTER_ASSET_BUNDLES, function (RegisterBundles $event) { $event->bundles[] = MyBundle::class; });
This bundle should depend on Ryssbowh\CraftThemes\assets\VueAssets
.
Javascript
Your javascript must register an object to window.CraftThemes.fieldComponents
and register an object with two keys, component
(a Vue component) and clone
(the function used to clone the field when creating new view modes)
import Matrix from './components/Matrix.js'; //Regular Vue component import { merge } from 'lodash'; window.CraftThemes.fieldComponents['matrix'] = { component : Matrix, clone: function (field, app) { let newField = merge({}, field); for (let i in field.types) { for (let j in field.types[i].fields) { newField.types[i].fields[j] = app.config.globalProperties.cloneField(field.types[i].fields[j]); } } return newField; } }
More examples here
Modify displayers
You may also need to modify displayers so that they can handle your field :
Event::on( UrlLink::class, FieldDisplayerService::EVENT_REGISTER_FIELD_TARGETS, function (RegisterDisplayerTargetsEvent $event) { $event->targets[] = MyField::class; });
Eager loading (Pro)
When a view mode is rendered the eager load map will be built to eager load every possible field on that view mode. The map will also contain nested view modes fields (displayers that render other layouts/view modes) and assets transforms. This map will be stored in cache.
The cache is enabled when devMode is off and can be cleared with the
following command : ./craft invalidate-tags/themes::eagerLoad
, it will
be automatically cleared for the relevant view modes when anything is
changed in them.
Eager loading will nest until 5 levels, after that it will stop.
Example :
- View mode 'default' :
- field entries pointing to view mode 'small' : level 1
- View mode 'small'
- Field categories pointing to view mode 'featured' : Level 2
- View mode 'featured' :
- Field assets : Level 3
Settings can be controlled by creating the config/themes.php
file :
<?php return [ 'eagerLoad' => false, 'eagerLoadingCache' => false, 'maxEagerLoadLevel' => 10 ];
All the templates defined by this plugin expect fields to be eager loaded, switching off that feature could result in lots of extra n+1 queries (especially if your displayer cache is off).