We have made the form fields, used by SiteOrigin widgets, extendible so that you can easily create your own custom fields. There are a few steps involved, but each of them is fairly simple. You can see the example code in the so-dev-examples repository here.
The SiteOrigin Widgets Bundle supports PHP 5.2.0 and above, so we avoid the use of the namespaces feature which is only available from PHP 5.3.0 onwards. We "namespace" our classes by prefixing their names with some (hopefully unique) prefix. The full class name then follows the convention $class_prefix . $field_type
. For example, the basic text field in the Widgets Bundle has the type text
and it is prefixed by SiteOrigin_Widget_Field_
, so the resulting class name is SiteOrigin_Widget_Field_Text
.
We encourage you to prefix your custom field class names to avoid conflicts with other class names. If you do this, the Widgets Bundle needs to know what your chosen prefix is, in order to autoload and instantiate your custom field classes. If you need to, you can add more than one prefix, but one is sufficient for the Widgets Bundle.
function my_custom_fields_class_prefixes( $class_prefixes ) {
$class_prefixes[] = 'My_Custom_Field_';
return $class_prefixes;
}
add_filter( 'siteorigin_widgets_field_class_prefixes', 'my_custom_fields_class_prefixes' );
It is necessary for the Widgets Bundle to know which directory you custom field class files are kept in for the purpose of autoloading. You can add your class paths to the autoloader by adding the siteorigin_widgets_field_class_paths
filter.
function my_custom_fields_class_paths( $class_paths ) {
$class_paths[] = plugin_dir_path( __FILE__ ) . 'custom-fields/';
return $class_paths;
}
add_filter( 'siteorigin_widgets_field_class_paths', 'my_custom_fields_class_paths' );
Implementing a custom field is as simple as extending one of the existing field classes and implementing or overriding at least the render_field
and sanitize_input
methods. There is much more that can be done, but this is all that is required to successfully render a custom field and save it's input.
The SiteOrigin_Widget_Field_Base
abstract class handles most of the work required for the widget form fields. It contains various properties and methods which are used to render the field for display in the front end and preparing input from the field for database persistence. When extending this class there are two abstract methods which must be implemented, namely, render_field
and sanitize_input
.
render_field
should output the HTML required for your custom field's display in the front end. The method receives two arguments, $value
and $instance
. $value
is the current value of the field for a specific instance of a widget form and should always be escaped just before output. $instance
is the widget form instance containing all it's current values.
protected function render_field( $value, $instance ) {
?>
<input type="text" id="<?php echo $this->element_id ?>" name="<?php echo $this->element_name ?>"
value="<?php echo esc_attr( $value ); ?>"/>
<?php
}
sanitize_input
should ensure that the input received from the front end is in the desired format and any unwanted characters are removed. It receives one argument, $value
, which is the raw current value of the field input in the front end. Typically this value is sanitized using the built-in WordPress sanitization and escaping functions.
protected function sanitize_field_input( $value ) {
$sanitized_value = sanitize_text_field( $value );
return $sanitized_value;
}
You may wish to have additional configuration properties for your custom fields. Adding one is as simple as declaring the property in your custom class, then to use it, specify a configuration option with the same name as your property and the base field class will make sure it is set.
In your custom class simple declare an instance variable.
class My_Custom_Field_Better_Text extends SiteOrigin_Widget_Field_Base {
/**
* My custom property for doing custom things.
*
* @access protected
* @var mixed
*/
protected $my_property;
}
Then when using the field, you may simply add a configuration option with the same name.
array(
'text' => array(
'type' => 'better-text',
'my_property' => 'This is my custom property value',
'label' => __('A better text field.', 'my-custom-field-test-widget-text-domain'),
'default' => 'Some better text.'
),
),
It is fairly common for fields to have a label, so the SiteOrigin_Widget_Field_Base
class includes a default label rendering function render_field_label
. There are two ways to customise the label rendering. You can override render_field_label
and do your own rendering, or you can override the get_label_classes
function to return CSS classes to affect the styling of the existing label. The second method makes it easier for subclasses to customize the labels. You will need to ensure that your stylesheet containing the custom label CSS class is enqueued elsewhere.
protected function render_field_label() {
?>
<h1>My custom label rendering</h1>
<?php
}
protected function get_label_classes() {
$label_classes = parent::get_label_classes();
$label_classes[] = 'additional-CSS-class';
return $label_classes;
}
Similarly to the field label, the SiteOrigin_Widget_Field_Base
class includes a default description rendering function render_field_description
. It's default rendering may be customized in the same way as labels.
The SiteOrigin_Widget_Field_Base
class has two additional rendering methods, render_before_field
and render_after_field
which are called before and after the main rendering method. These serve to avoid duplication of commonly rendered items, such as a label above the field and a description below the field. You should override these if you wish to prevent rendering of the label before a field, or the description after a field, or if you want to render additional items.
Say you want to render the description after the label, but before the field.
protected function render_before_field( $value, $instance ) {
// This is to keep the default label rendering behaviour.
parent::render_before_field( $value, $instance );
// Add custom rendering here.
$this->render_field_description();
}
protected function render_after_field( $value, $instance ) {
// Leave this blank so that the description is not rendered twice
}
There are case where a field may affect values on the widget instance, other than it's own input. It then becomes necessary to perform additional sanitization on the widget instance. In such a case the sanitize_instance
method may be overridden.
Occasionally it is necessary for a field to set a variable to be used in the front end. For such cases, override the get_javascript_variables
function. This will be called by the containing widget while it is rendering it's form and it will pass all field javascript variables to the front end where they will be accessible as a global object called sow_field_javascript_variables
.
You can use your custom field in a widget, just like any other field.
$form_options = array(
'text' => array(
'type' => 'better-text',
'my_property' => 'This is my custom property value',
'label' => __( 'A better text field.', 'my-custom-field-test-widget-text-domain' ),
'description' => __( 'A description for my custom text field.' ),
'default' => 'Some better text.'
),
);