inc/WPWD/Components/Field.php
<?php
/**
* WPWD\Components\Field class
*
* @package WPWD
* @subpackage Components
* @author Felix Arntz <felix-arntz@leaves-and-love.net>
* @since 0.5.0
*/
namespace WPWD\Components;
use WPWD\Utility as Utility;
use WPDLib\Components\Manager as ComponentManager;
use WPDLib\Components\Base as Base;
use WPDLib\FieldTypes\Manager as FieldManager;
use WPDLib\Util\Error as UtilError;
use WP_Error as WPError;
if ( ! defined( 'ABSPATH' ) ) {
die();
}
if ( ! class_exists( 'WPWD\Components\Field' ) ) {
/**
* Class for a field component.
*
* A field denotes a field in a widget form, i.e. both the widget option and the visual input in the WordPress admin.
* The field slugs are used as array keys in the widget's `$data` array.
*
* @internal
* @since 0.5.0
*/
class Field extends Base {
/**
* @since 0.5.0
* @var WPDLib\FieldTypes\Base Holds the field type object from WPDLib.
*/
protected $_field = null;
/**
* Class constructor.
*
* @since 0.5.0
* @param string $slug the field slug
* @param array $args array of field properties
*/
public function __construct( $slug, $args ) {
parent::__construct( $slug, $args );
$this->validate_filter = 'wpwd_field_validated';
}
/**
* Magic get method.
*
* This function exists to allow direct access to properties that are stored on the internal WPDLib\FieldTypes\Base object of the field.
*
* @since 0.5.0
* @param string $property name of the property to find
* @return mixed value of the property or null if it does not exist
*/
public function __get( $property ) {
$value = parent::__get( $property );
if ( null === $value ) {
$value = $this->_field->$property;
}
return $value;
}
/**
* Renders the field.
*
* This function will show the input field(s) in the WordPress admin.
*
* @since 0.5.0
* @param mixed $widget_option the field's current value
* @param WPWD\Components\Widget $parent_widget the parent widget component of this field
* @param WPWD\Components\Section $parent_section the parent section component of this field
*/
public function render( $widget_option, $parent_widget = null, $parent_section = null ) {
if ( null === $parent_section ) {
$parent_section = $this->get_parent();
}
if ( null === $parent_widget ) {
$parent_widget = $parent_section->get_parent();
}
/**
* This action can be used to display additional content on top of this field.
*
* @since 0.5.0
* @param string the slug of the current field
* @param array the arguments array for the current field
* @param string the slug of the current section
* @param string the slug of the current widget
*/
do_action( 'wpwd_field_before', $this->slug, $this->args, $parent_section->slug, $parent_widget->slug );
echo '<p>';
echo '<label for="' . $this->_field->id . '">' . sprintf( __( '%s:', 'widgets-definitely' ), $this->args['title'] ) . '</label> ';
$this->_field->display( $widget_option );
if ( ! empty( $this->args['description'] ) ) {
echo '<br/><span class="description">' . $this->args['description'] . '</span>';
}
echo '</p>';
/**
* This action can be used to display additional content at the bottom of this field.
*
* @since 0.5.0
* @param string the slug of the current field
* @param array the arguments array for the current field
* @param string the slug of the current section
* @param string the slug of the current widget
*/
do_action( 'wpwd_field_after', $this->slug, $this->args, $parent_section->slug, $parent_widget->slug );
}
/**
* Validates the option for this field.
*
* @see WPWD\Components\Widget::validate_widget_options()
* @since 0.5.0
* @param mixed $widget_option the new widget option value to validate
* @return mixed either the validated widget option or a WP_Error object
*/
public function validate_widget_option( $widget_option = null, $skip_required = false ) {
if ( $this->args['required'] && ! $skip_required ) {
if ( $widget_option === null || $this->_field->is_empty( $widget_option ) ) {
return new WPError( 'invalid_empty_value', __( 'No value was provided for the required field.', 'widgets-definitely' ) );
}
}
return $this->_field->validate( $widget_option );
}
/**
* Validates the arguments array.
*
* @since 0.5.0
* @param WPWD\Components\Section $parent the parent component
* @return bool|WPDLib\Util\Error an error object if an error occurred during validation, true if it was validated, false if it did not need to be validated
*/
public function validate( $parent = null ) {
$status = parent::validate( $parent );
if ( $status === true ) {
if ( is_array( $this->args['class'] ) ) {
$this->args['class'] = implode( ' ', $this->args['class'] );
}
if ( ! empty( $this->args['class'] ) ) {
$this->args['class'] .= ' ';
}
$this->args['class'] .= 'widefat';
if ( isset( $this->args['options'] ) && ! is_array( $this->args['options'] ) ) {
$this->args['options'] = array();
}
$this->_field = FieldManager::get_instance( $this->args );
if ( $this->_field === null ) {
return new UtilError( 'no_valid_field_type', sprintf( __( 'The field type %1$s assigned to the field component %2$s is not a valid field type.', 'widgets-definitely' ), $this->args['type'], $this->slug ), '', ComponentManager::get_scope() );
}
if ( null === $this->args['default'] ) {
$this->args['default'] = $this->_field->validate();
}
$this->args = Utility::validate_position_args( $this->args );
}
return $status;
}
/**
* Returns the keys of the arguments array and their default values.
*
* Read the plugin guide for more information about the field arguments.
*
* @since 0.5.0
* @return array
*/
protected function get_defaults() {
$defaults = array(
'title' => __( 'Field title', 'widgets-definitely' ),
'description' => '',
'type' => 'text',
'class' => '',
'default' => null,
'required' => false,
'position' => null,
);
/**
* This filter can be used by the developer to modify the default values for each field component.
*
* @since 0.5.0
* @param array the associative array of default values
*/
return apply_filters( 'wpwd_field_defaults', $defaults );
}
/**
* Returns whether this component supports multiple parents.
*
* @since 0.5.0
* @return bool
*/
protected function supports_multiparents() {
return false;
}
/**
* Returns whether this component supports global slugs.
*
* If it does not support global slugs, the function either returns false for the slug to be globally unique
* or the class name of a parent component to ensure the slug is unique within that parent's scope.
*
* @since 0.5.0
* @return bool|string
*/
protected function supports_globalslug() {
return 'WPWD\Components\Widget';
}
}
}