├── .gitignore
├── .prettierrc.json
├── OptionsField.php
├── OptionsFieldGenerator
├── BaseFieldGenerator.php
├── CheckboxFieldGenerator.php
├── CheckboxesFieldGenerator.php
├── ColorFieldGenerator.php
├── DateFieldGenerator.php
├── EmailFieldGenerator.php
├── FileFieldGenerator.php
├── HiddenFieldGenerator.php
├── MediaFieldGenerator.php
├── NumberFieldGenerator.php
├── PasswordFieldGenerator.php
├── RadiosFieldGenerator.php
├── RangeFieldGenerator.php
├── SearchFieldGenerator.php
├── SelectFieldGenerator.php
├── TextFieldGenerator.php
├── TextareaFieldGenerator.php
├── TimeFieldGenerator.php
├── UrlFieldGenerator.php
└── resources
│ ├── assets
│ ├── css
│ │ ├── file.css
│ │ ├── file.css.map
│ │ ├── file.scss
│ │ ├── libs
│ │ │ └── selectize.css
│ │ ├── media.css
│ │ ├── media.css.map
│ │ ├── media.scss
│ │ ├── sharedStyle.css
│ │ ├── sharedStyle.css.map
│ │ └── sharedStyle.scss
│ └── js
│ │ ├── FileFieldGenerator.js
│ │ ├── MediaFieldGenerator.js
│ │ ├── libs
│ │ └── selectize.js
│ │ └── selectFieldGenerator.js
│ └── templates
│ ├── FileFieldGenerator.blade.php
│ └── MediaFieldGenerator.blade.php
├── OptionsForm.php
├── OptionsPage.php
├── OptionsRepository.php
├── OptionsSection.php
├── composer.json
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | vendor/
3 | composer.lock
4 | .idea/
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "phpVersion": "7.2",
4 | "printWidth": 120
5 | }
6 |
--------------------------------------------------------------------------------
/OptionsField.php:
--------------------------------------------------------------------------------
1 | convertMapToProperties($configs, $optionalConfigs, $requiredConfigs, function ($option) {
84 | return "The option `$option` must be defined when instantiate the class `" . static::class . "`.";
85 | });
86 |
87 | $this->configs = $configs;
88 | }
89 |
90 | /**
91 | * Register field to a specific page.
92 | *
93 | * @param OptionsPageContract|string $optionsPage menu-slug of a page or a SettingsPage object
94 | * @param OptionsSectionContract|string $optionsSection section-id of a section or a SettingsSection object
95 | * @param string $optionGroup The option-group to be used.
96 | * @param string $optionName The option-name to be used.
97 | * @param bool $hook Determine if call register functions in appropriate hook or not.
98 | *
99 | * @return void
100 | */
101 | final public function register($optionsPage, $optionsSection, $optionGroup, $optionName, $hook = true)
102 | {
103 | // check user capabilities
104 | if ( ! current_user_can($this->capability())) {
105 | return;
106 | }
107 |
108 | $page = $optionsPage instanceof OptionsPageContract ? $optionsPage->menuSlug() : $optionsPage;
109 | $section = $optionsSection instanceof OptionsSectionContract ? $optionsSection->id() : $optionsSection;
110 |
111 | // Copy the original `Field` object and change the `optionGroup` and `optionName` private properties.
112 | // So the state of the original object won't change.
113 | $field = $this->cloneAndChangeState(['optionGroup' => $optionGroup, 'optionName' => $optionName]);
114 |
115 | // create the args that will be passed to render function.
116 | $args = [];
117 | $options = OptionsRepository::getInstance($field->optionName());
118 |
119 | if ($this->renderFunction) {
120 | $form = new OptionsForm($options, $page);
121 | $args = ['field' => $field, 'form' => $form];
122 | $renderFunction = $this->renderFunction;
123 | if ($this->sanitizeFunction) {
124 | $sanitizeFunction = $this->sanitizeFunction;
125 | } else {
126 | $sanitizeFunction = function ($values) {
127 | return $values;
128 | };
129 | }
130 | } else {
131 | // the corresponding OptionsFieldGenerator class name to be used for rendering and sanitize the field.
132 | $optionsFieldGeneratorClassName = '\\Laraish\\Options\\OptionsFieldGenerator\\' . ucfirst(strtolower($this->type())) . 'FieldGenerator';
133 |
134 | if ( ! class_exists($optionsFieldGeneratorClassName)) {
135 | throw new InvalidArgumentException("Invalid field type `{$field->type()}`.");
136 | }
137 |
138 | /** @var \Laraish\Contracts\Options\OptionsFieldGenerator $optionsFieldGenerator */
139 | $optionsFieldGenerator = new $optionsFieldGeneratorClassName($field->id(), $options, $page, $field->configs());
140 |
141 | $renderFunction = function () use ($optionsFieldGenerator) {
142 | echo $optionsFieldGenerator->generate();
143 | };
144 |
145 | $sanitizeFunction = $this->sanitizeFunction ?: [$optionsFieldGenerator, 'sanitize'];
146 | }
147 |
148 | // the register function
149 | $register = function (OptionsFieldContract $field, $page, $section, $optionGroup, $optionName, array $args, $renderFunction) {
150 | register_setting($optionGroup, $optionName);
151 | add_settings_field($field->id(), $field->title(), $renderFunction, $page, $section, $args);
152 | };
153 |
154 | if ($hook) {
155 | add_action('admin_init', function () use ($field, $page, $section, $optionGroup, $optionName, $register, $args, $renderFunction) {
156 | $register($field, $page, $section, $optionGroup, $optionName, $args, $renderFunction);
157 | });
158 | } else {
159 | $register($field, $page, $section, $optionGroup, $optionName, $args, $renderFunction);
160 | }
161 |
162 |
163 | // add the sanitize function later (after `admin_init`)
164 | // to avoid unnecessary sanitize function calls at the creation of FieldGenerator classes
165 | add_action('current_screen', function () use ($optionName, $sanitizeFunction, $field) {
166 | add_filter("pre_update_option_{$optionName}", function ($value, $oldValue) use ($sanitizeFunction, $field, $optionName) {
167 | $fieldId = $field->id();
168 |
169 | if (isset($value[$fieldId])) {
170 | $_value = $value[$fieldId];
171 | $_oldValue = isset($oldValue[$fieldId]) ? $oldValue[$fieldId] : null;
172 |
173 | $value[$fieldId] = call_user_func_array($sanitizeFunction, [$_value, $_oldValue]);
174 | } elseif (isset($_FILES[$optionName]['tmp_name'][$fieldId])) {
175 | $filesInfo = $_FILES[$optionName];
176 |
177 | $value[$fieldId] = call_user_func_array($sanitizeFunction, [$filesInfo]);
178 | }
179 |
180 | return $value;
181 | }, 10, 2);
182 | });
183 | }
184 |
185 | /**
186 | * The configurations of the field.
187 | *
188 | * @param null $name
189 | *
190 | * @return mixed
191 | */
192 | public function configs($name = null)
193 | {
194 | if ($name === null) {
195 | return $this->configs;
196 | }
197 |
198 | return isset($this->configs[$name]) ? $this->configs[$name] : null;
199 | }
200 |
201 | /**
202 | * The option-group that this field is going to register or refer.
203 | * @return string
204 | */
205 | final public function optionGroup()
206 | {
207 | return $this->optionGroup;
208 | }
209 |
210 | /**
211 | * The option-name that this field is going to register or refer.
212 | * @return string
213 | */
214 | final public function optionName()
215 | {
216 | return $this->optionName;
217 | }
218 |
219 | /**
220 | * String for use in the 'id' attribute of tags.
221 | * @return string
222 | */
223 | final public function id()
224 | {
225 | return $this->id;
226 | }
227 |
228 | /**
229 | * Title of the field.
230 | * @return string
231 | */
232 | final public function title()
233 | {
234 | return $this->title;
235 | }
236 |
237 | /**
238 | * The type of the field.
239 | * @return string
240 | */
241 | final public function type()
242 | {
243 | return $this->type;
244 | }
245 |
246 | /**
247 | * The capability required for this field to be displayed to the current user.
248 | * @return string
249 | */
250 | public function capability()
251 | {
252 | return $this->capability;
253 | }
254 | }
--------------------------------------------------------------------------------
/OptionsFieldGenerator/BaseFieldGenerator.php:
--------------------------------------------------------------------------------
1 | [],
50 | ];
51 |
52 | /**
53 | * The instance of `Template`.
54 | * @var Template
55 | */
56 | protected $templateInstance;
57 |
58 | /**
59 | * The style sheets to be enqueued for the field.
60 | * A path relatives to `resources/assets`.
61 | * @var string
62 | */
63 | protected static $styles = [];
64 |
65 | /**
66 | * The scripts to be enqueued for the field.
67 | * A path relatives to `resources/assets`.
68 | * @var string
69 | */
70 | protected static $scripts = [];
71 |
72 | /**
73 | * The template file of the field.
74 | * A path relatives to `resources/templates`.
75 | * If you set this property, you will be able to
76 | * call `static::renderTemplate` to render the template.
77 | * @var string
78 | */
79 | protected static $template;
80 |
81 | /**
82 | * A static method for enqueuing style and script related to this field generator.
83 | *
84 | * @param string $optionsPage menu slug of a OptionsPage.
85 | *
86 | * @return void
87 | */
88 | final private static function enqueueAssetsOnce($optionsPage)
89 | {
90 | static $isEnqueued;
91 |
92 | if ($isEnqueued === true) {
93 | return;
94 | }
95 | $isEnqueued = true;
96 |
97 | // if no script and style need to be enqueued quit immediately.
98 | if (!(static::$scripts or static::$styles)) {
99 | return;
100 | }
101 |
102 | $absolutePath = str_replace('\\', '/', ABSPATH);
103 | $currentDir = str_replace('\\', '/', __DIR__);
104 | $assetsUrl = home_url(str_replace($absolutePath, '', $currentDir)) . '/resources/assets/';
105 |
106 | add_action('admin_enqueue_scripts', function ($hook) use ($optionsPage, $assetsUrl) {
107 | $thisPageHookSuffix = '_page_' . $optionsPage;
108 | if (preg_match("/{$thisPageHookSuffix}$/", $hook)) {
109 | $prefix = $optionsPage . '__' . static::class . '__';
110 |
111 | if (static::$scripts) {
112 | foreach ((array) static::$scripts as $script) {
113 | if (filter_var($script, FILTER_VALIDATE_URL) === false) {
114 | $script = $assetsUrl . trim($script, '/');
115 | }
116 |
117 | OptionsPage::enqueueAsset($script, 'script', $prefix);
118 | }
119 | }
120 | if (static::$styles) {
121 | foreach ((array) static::$styles as $style) {
122 | if (filter_var($style, FILTER_VALIDATE_URL) === false) {
123 | $style = $assetsUrl . trim($style, '/');
124 | }
125 |
126 | OptionsPage::enqueueAsset($style, 'style', $prefix);
127 | }
128 | }
129 | }
130 | });
131 | }
132 |
133 | /**
134 | * Load the template file into template engine just once for this class.
135 | *
136 | * @param static $instance
137 | */
138 | final private static function setInstanceTemplateOnce($instance)
139 | {
140 | static $templateContent;
141 |
142 | if (!isset($templateContent)) {
143 | $templateContent = '';
144 |
145 | if (static::$template) {
146 | $templatePath = __DIR__ . '/resources/templates/' . trim(static::$template, '/');
147 | if (file_exists($templatePath)) {
148 | $templateContent = file_get_contents($templatePath);
149 | }
150 | }
151 | }
152 |
153 | $instance->templateInstance = new Template($templateContent);
154 | }
155 |
156 | /**
157 | * Convert a map to attributes string.
158 | *
159 | * @param array $attributes The attributes map something like ['name'=> 'option_name[url]', 'type'=> 'url']
160 | *
161 | * @return string
162 | */
163 | final protected static function convertToAttributesString(array $attributes)
164 | {
165 | $attributesString = '';
166 | foreach ($attributes as $name => $value) {
167 | if ($value === null) {
168 | continue;
169 | }
170 | $escapedValue = esc_attr($value);
171 | $attributesString .= "$name=\"$escapedValue\" ";
172 | }
173 |
174 | return rtrim($attributesString, ' ');
175 | }
176 |
177 | /**
178 | * Generate a datalist element markup.
179 | *
180 | * @param string $id
181 | * @param array $optionValues
182 | *
183 | * @return string
184 | */
185 | final public static function generateDatalist($id, array $optionValues)
186 | {
187 | $innerHTML = '';
188 |
189 | foreach ($optionValues as $optionValue) {
190 | $innerHTML .= "";
191 | }
192 |
193 | return "{$innerHTML} ";
194 | }
195 |
196 | /**
197 | * Field generator constructor.
198 | *
199 | * @param string $fieldName The name of this field.
200 | * @param OptionsRepositoryContract $options The OptionsRepository object.
201 | * @param string $optionsPage The menu slug of an options page.
202 | * @param array $configs The configurations.
203 | */
204 | public function __construct($fieldName, OptionsRepositoryContract $options, $optionsPage, array $configs = [])
205 | {
206 | // check if the 'defaultValue' is a valid value for the field.
207 | if (array_key_exists('defaultValue', $configs)) {
208 | if (!$this->validateFieldValue($configs['defaultValue'])) {
209 | throw new InvalidArgumentException(
210 | "The value `{$configs['defaultValue']}` is not a valid `defaultValue`."
211 | );
212 | }
213 | }
214 |
215 | $this->options = $options;
216 | $this->configs = array_replace_recursive($this->defaultConfigs, $configs);
217 |
218 | $this->fieldId = $fieldName;
219 | $this->fieldName = $this->normalizeFieldName($fieldName);
220 | $this->fieldValue = $this->normalizeFieldValue($fieldName);
221 |
222 | static::enqueueAssetsOnce($optionsPage);
223 | static::setInstanceTemplateOnce($this);
224 | }
225 |
226 | /**
227 | * Get a particular config in `$this->configs`.
228 | *
229 | * @param string $key
230 | *
231 | * @return mixed
232 | */
233 | final protected function config($key)
234 | {
235 | return isset($this->configs[$key]) ? $this->configs[$key] : null;
236 | }
237 |
238 | /**
239 | * Normalize the name attribute value.
240 | *
241 | * @param string $originalFieldName
242 | *
243 | * @return string|null
244 | */
245 | final private function normalizeFieldName($originalFieldName)
246 | {
247 | return $this->options->optionName() . "[$originalFieldName]";
248 | }
249 |
250 | /**
251 | * Get the filed value.
252 | *
253 | * @param string $originalFieldName
254 | *
255 | * @return null|string
256 | */
257 | final private function normalizeFieldValue($originalFieldName)
258 | {
259 | $defaultValue = $this->config('defaultValue');
260 | $value = $this->options->get($originalFieldName, $defaultValue);
261 |
262 | // if the current option has a value
263 | if ($value !== $defaultValue) {
264 | // and if the current option is not a valid value for the field
265 | if (!$this->validateFieldValue($value)) {
266 | // then set the old value to the default value of the field
267 | $this->options->set($originalFieldName, $defaultValue);
268 | $value = $defaultValue;
269 | }
270 | }
271 |
272 | return $value;
273 | }
274 |
275 | /**
276 | * Get the basic attributes (`name` and `value`) and the user defined attributes.
277 | *
278 | * @return string
279 | */
280 | final protected function allAttributes()
281 | {
282 | $name = $this->fieldName;
283 | $value = $this->fieldValue;
284 |
285 | return static::convertToAttributesString(
286 | array_merge($this->config('attributes'), ['name' => $name, 'value' => $value])
287 | );
288 | }
289 |
290 | /**
291 | * A callback function that sanitizes the option's value.
292 | *
293 | * @param mixed $value
294 | *
295 | * @return mixed
296 | */
297 | public function sanitize($value)
298 | {
299 | return $this->validateWithErrorMessage($value, "`{$this->config('title')}` is not a valid value.");
300 | }
301 |
302 | /**
303 | * A helper method could be useful to work together with `sanitize` method.
304 | *
305 | * @param mixed $value The value to be sanitized.
306 | * @param string $message The error message to be shown if the value is invalid.
307 | *
308 | * @return mixed
309 | */
310 | final protected function validateWithErrorMessage($value, $message)
311 | {
312 | //$fieldId = $this->config('id');
313 |
314 | if (!$this->validateFieldValue($value)) {
315 | add_settings_error($this->fieldId, 'invalid_type', $message);
316 |
317 | // restore to old value
318 | $value = $this->fieldValue;
319 | }
320 |
321 | return $value;
322 | }
323 |
324 | /**
325 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
326 | * This method will be automatically called with the current value of the field if the field has a value.
327 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
328 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
329 | *
330 | * @param mixed $value
331 | *
332 | * @return bool
333 | */
334 | protected function validateFieldValue($value)
335 | {
336 | return true;
337 | }
338 |
339 | /**
340 | * Generate the description of the field.
341 | * @return string
342 | */
343 | protected function generateDescription()
344 | {
345 | $markUp = '';
346 |
347 | if ($description = $this->config('description')) {
348 | $markUp = "{$description}
";
349 | }
350 |
351 | return $markUp;
352 | }
353 |
354 | /**
355 | * Generate the help link for the field.
356 | * @return string
357 | */
358 | protected function generateHelpLink()
359 | {
360 | $markUp = '';
361 |
362 | if ($helpLink = $this->config('helpLink')) {
363 | $markUp = " ";
364 | }
365 |
366 | return $markUp;
367 | }
368 |
369 | protected function generateInput($type, $allAttributes = null)
370 | {
371 | $allAttributes = $allAttributes ?: $this->allAttributes();
372 |
373 | // Add `list` attribute if possible
374 | if ($datalist = $this->config('datalist')) {
375 | $datalistHtml = static::generateDatalist($datalist['id'], $datalist['data']);
376 | $allAttributes .= " list=\"{$datalist['id']}\"";
377 | }
378 |
379 | // Create the `input` html
380 | $html = " ";
381 |
382 | // Add `datalist` element if possible
383 | if (isset($datalistHtml)) {
384 | $html .= $datalistHtml;
385 | }
386 |
387 | // Add prefix and suffix if possible
388 | $suffix = $this->config('suffix');
389 | $prefix = $this->config('prefix');
390 | if ($suffix or $prefix) {
391 | $suffix = $suffix ? "{$suffix} " : '';
392 | $prefix = $prefix ? "{$prefix} " : '';
393 | $html = "{$prefix}" . $html . "{$suffix}
";
394 | }
395 |
396 | // Add help link if possible
397 | if ($helpLink = $this->generateHelpLink()) {
398 | $html = '' . $html . "{$helpLink}
";
399 | }
400 |
401 | // Add the description
402 | $html .= $this->generateDescription();
403 |
404 | return $html;
405 | }
406 |
407 | /**
408 | * Render the template instance.
409 | *
410 | * @param array $data
411 | *
412 | * @return string
413 | */
414 | final protected function renderTemplate(array $data)
415 | {
416 | return $this->templateInstance->render($data);
417 | }
418 |
419 | /**
420 | * Generate the field markup.
421 | *
422 | * @return string
423 | */
424 | abstract public function generate();
425 | }
426 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/CheckboxFieldGenerator.php:
--------------------------------------------------------------------------------
1 | '',
13 | 'text' => '',
14 | 'attributes' => [],
15 | 'defaultValue' => '',
16 | ];
17 |
18 | /**
19 | * Generate the field markup.
20 | *
21 | * @return string
22 | */
23 | final public function generate()
24 | {
25 | $optionValue = $this->fieldValue;
26 | $text = $this->config('text');
27 | $value = $this->config('value');
28 | $checked = (string) $value === $optionValue ? 'checked' : null;
29 |
30 | $attributes = static::convertToAttributesString([
31 | 'type' => 'checkbox',
32 | 'name' => $this->fieldName,
33 | 'value' => $value,
34 | 'checked' => $checked,
35 | ]);
36 |
37 | $innerHTML = " ";
38 |
39 | return "{$innerHTML}{$text} " . $this->generateDescription();
40 | }
41 |
42 | /**
43 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
44 | * This method will be automatically called with the current value of the field if the field has a value.
45 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
46 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
47 | *
48 | * @param mixed $value
49 | *
50 | * @return bool
51 | */
52 | protected function validateFieldValue($value)
53 | {
54 | return is_string($value);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/CheckboxesFieldGenerator.php:
--------------------------------------------------------------------------------
1 | true,
13 | 'options' => [],
14 | 'attributes' => [],
15 | 'defaultValue' => [],
16 | ];
17 |
18 | /**
19 | * Generate the field markup.
20 | *
21 | * @return string
22 | */
23 | final public function generate()
24 | {
25 | $checkedOptions = $this->fieldValue;
26 | $normalizedFieldName = $this->fieldName . '[]';
27 | $markUp = '';
28 |
29 | foreach ($this->config('options') as $optionText => $optionValue) {
30 | $escapedOptionText = esc_html($optionText);
31 | $checked = in_array((string) $optionValue, (array) $checkedOptions) ? 'checked' : null;
32 |
33 | $allAttributes = static::convertToAttributesString(
34 | array_merge($this->config('attributes'), [
35 | 'type' => 'checkbox',
36 | 'name' => $normalizedFieldName,
37 | 'value' => $optionValue,
38 | 'checked' => $checked,
39 | ])
40 | );
41 |
42 | $checkboxHtml = " ";
43 |
44 | $markUp .= "{$checkboxHtml}{$escapedOptionText} \n";
45 |
46 | if (!$this->config('horizontal')) {
47 | $markUp .= " \n";
48 | }
49 | }
50 |
51 | return $markUp . $this->generateDescription();
52 | }
53 |
54 | /**
55 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
56 | * This method will be automatically called with the current value of the field if the field has a value.
57 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
58 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
59 | *
60 | * @param mixed $value
61 | *
62 | * @return bool
63 | */
64 | protected function validateFieldValue($value)
65 | {
66 | return is_array($value);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/ColorFieldGenerator.php:
--------------------------------------------------------------------------------
1 | [],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('color');
24 | }
25 |
26 | /**
27 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
28 | * This method will be automatically called with the current value of the field if the field has a value.
29 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
30 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
31 | *
32 | * @param mixed $value
33 | *
34 | * @return bool
35 | */
36 | protected function validateFieldValue($value)
37 | {
38 | return preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/', $value);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/DateFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('date');
24 | }
25 |
26 | /**
27 | * A callback function that sanitizes the option's value.
28 | *
29 | * @param mixed $value
30 | *
31 | * @return mixed
32 | */
33 | public function sanitize($value)
34 | {
35 | return $value;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/EmailFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('email');
24 | }
25 |
26 | /**
27 | * A callback function that sanitizes the option's value.
28 | *
29 | * @param mixed $value
30 | *
31 | * @return mixed
32 | */
33 | public function sanitize($value)
34 | {
35 | return $this->validateWithErrorMessage($value, "`{$this->config('title')}` must be an email.");
36 | }
37 |
38 | /**
39 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
40 | * This method will be automatically called with the current value of the field if the field has a value.
41 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
42 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
43 | *
44 | * @param mixed $value
45 | *
46 | * @return bool
47 | */
48 | protected function validateFieldValue($value)
49 | {
50 | return filter_var($value, FILTER_VALIDATE_EMAIL);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/FileFieldGenerator.php:
--------------------------------------------------------------------------------
1 | [],
13 | 'maxFileSize' => null,
14 | 'isJson' => false,
15 | 'assoc' => false,
16 | 'defaultValue' => [],
17 | ];
18 |
19 | protected static $scripts = ['js/FileFieldGenerator.js'];
20 |
21 | protected static $styles = ['css/sharedStyle.css', 'css/media.css'];
22 |
23 | protected static $template = 'FileFieldGenerator.blade.php';
24 |
25 | /**
26 | * Generate the file field.
27 | * Note that the file field will only accepts a text base file,
28 | * and will save the uploaded file's content as the value of the field.
29 | *
30 | * @return string
31 | */
32 | final public function generate()
33 | {
34 | $data = [
35 | 'field_name' => $this->fieldName,
36 | 'has_value_class' => $this->fieldValue ? 'laraish-has-value' : '',
37 | 'media_img_url' => home_url('/wp-includes/images/media/document.png'),
38 | 'filename' => $this->fieldValue ? $this->fieldValue['filename'] : '',
39 | 'description' => $this->generateDescription(),
40 | ];
41 |
42 | return $this->renderTemplate($data);
43 | }
44 |
45 | /**
46 | * A callback function that sanitizes the option's value.
47 | *
48 | * @param mixed $filesInfo
49 | *
50 | * @return mixed
51 | */
52 | public function sanitize($filesInfo)
53 | {
54 | $defaultValue = $this->defaultConfigs['defaultValue'];
55 | if ($filesInfo === 'laraish::removeFileField' or $filesInfo == []) {
56 | return $defaultValue;
57 | }
58 |
59 | // If the $filesInfo has been sanitized, return it.
60 | if (array_key_exists('content', $filesInfo)) {
61 | return $filesInfo;
62 | }
63 |
64 | $fieldId = $this->fieldId;
65 | $maxFileSize = $this->config('maxFileSize');
66 | $oldValue = $this->fieldValue;
67 |
68 | $error = $filesInfo['error'][$fieldId];
69 | $size = $filesInfo['size'][$fieldId];
70 | $tempFile = $filesInfo['tmp_name'][$fieldId];
71 | $filename = $filesInfo['name'][$fieldId];
72 | $mime = $filesInfo['type'][$fieldId];
73 |
74 | /*------------------------------------*\
75 | # check if has error
76 | \*------------------------------------*/
77 |
78 | $hasError = $error !== 0;
79 | if ($hasError) {
80 | // if no file was uploaded restore the old value and return.
81 | if ($error === UPLOAD_ERR_NO_FILE) {
82 | // restore to old value
83 | return $oldValue;
84 | }
85 |
86 | switch ($error) {
87 | case UPLOAD_ERR_INI_SIZE:
88 | $errorMessage = "The uploaded file `{$this->config(
89 | 'title'
90 | )}` exceeds the upload_max_filesize directive in php.ini.";
91 | break;
92 | case UPLOAD_ERR_FORM_SIZE:
93 | $errorMessage = "The uploaded file `{$this->config(
94 | 'title'
95 | )}` exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.";
96 | break;
97 | case UPLOAD_ERR_PARTIAL:
98 | $errorMessage = "The uploaded file `{$this->config('title')}` was only partially uploaded.";
99 | break;
100 | case UPLOAD_ERR_NO_TMP_DIR:
101 | $errorMessage = "Failed to upload the file `{$this->config(
102 | 'title'
103 | )}`. Missing a upload temporary folder.";
104 | break;
105 | case UPLOAD_ERR_CANT_WRITE:
106 | $errorMessage = "Failed to write the file `{$this->config('title')}` to disk.";
107 | break;
108 | case UPLOAD_ERR_EXTENSION:
109 | $errorMessage = "Failed to upload the file `{$this->config(
110 | 'title'
111 | )}`. A PHP extension stopped the file upload.";
112 | break;
113 | default:
114 | $errorMessage = 'Failed to upload file';
115 | }
116 |
117 | // add error message
118 | add_settings_error($fieldId, 'file_upload_failed', $errorMessage);
119 |
120 | // restore to old value
121 | return $oldValue;
122 | }
123 |
124 | /*-----------------------------------------*\
125 | # check if has exceeded max file size
126 | \*-----------------------------------------*/
127 |
128 | $exceedsMaxFileSize = $maxFileSize ? $size > $maxFileSize : false;
129 | if ($exceedsMaxFileSize) {
130 | $errorMessage = "The uploaded file `{$this->config(
131 | 'title'
132 | )}` exceeds the maximum file size ({$maxFileSize} bytes)";
133 | add_settings_error($fieldId, 'file_upload_failed', $errorMessage);
134 |
135 | // restore to old value
136 | return $oldValue;
137 | }
138 |
139 | /*-------------------------------------------*\
140 | # check if the file is a text base file.
141 | \*-------------------------------------------*/
142 |
143 | $finfo = new \finfo(FILEINFO_MIME);
144 | $type = $finfo->file($tempFile);
145 | $isNotTextFile = !preg_match('@text|json@', $type);
146 | if ($isNotTextFile) {
147 | $errorMessage = "The format of uploaded file `{$this->config('title')}` is not acceptable.";
148 | add_settings_error($fieldId, 'file_upload_failed', $errorMessage);
149 |
150 | // restore to old value
151 | return $oldValue;
152 | }
153 |
154 | /*------------------------------------*\
155 | # finally we can save our data.
156 | \*------------------------------------*/
157 |
158 | $data = [
159 | 'filename' => $filename,
160 | 'mime' => $mime,
161 | 'size' => $size,
162 | ];
163 |
164 | $content = $data['content'] = file_get_contents($tempFile);
165 | if ($this->config('isJson')) {
166 | $json = json_decode($content, $this->config('assoc') === true ? true : false);
167 | if (!$json) {
168 | $errorMessage = "The uploaded file `{$this->config('title')}` should be a valid json file.";
169 | add_settings_error($fieldId, 'file_upload_failed', $errorMessage);
170 |
171 | // restore to old value
172 | return $oldValue;
173 | }
174 |
175 | $data['content'] = $json;
176 | }
177 |
178 | return $data;
179 | }
180 |
181 | /**
182 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
183 | * This method will be automatically called with the current value of the field if the field has a value.
184 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
185 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
186 | *
187 | * @param mixed $value
188 | *
189 | * @return bool
190 | */
191 | protected function validateFieldValue($value)
192 | {
193 | return isset($value['content']);
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/HiddenFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | $allAttributes = $this->allAttributes();
24 | $allAttributes .= " value=\"{$this->config('value')}\"";
25 |
26 | return " ";
27 | }
28 |
29 | /**
30 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
31 | * This method will be automatically called with the current value of the field if the field has a value.
32 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
33 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
34 | *
35 | * @param mixed $value
36 | *
37 | * @return bool
38 | */
39 | protected function validateFieldValue($value)
40 | {
41 | return is_string($value);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/MediaFieldGenerator.php:
--------------------------------------------------------------------------------
1 | null,
13 | 'media_uploader_title' => null,
14 | 'defaultValue' => [],
15 | ];
16 |
17 | protected static $scripts = ['js/MediaFieldGenerator.js'];
18 |
19 | protected static $styles = ['css/sharedStyle.css', 'css/media.css'];
20 |
21 | protected static $template = 'MediaFieldGenerator.blade.php';
22 |
23 | /**
24 | * Generate the field markup.
25 | *
26 | * @return string
27 | */
28 | final public function generate()
29 | {
30 | $mediaInfo = $this->fieldValue;
31 | $fieldName = $this->fieldName;
32 |
33 | $data = [
34 | 'has_value_class' => '',
35 | 'media_img_url' => '',
36 | 'media_type' => '',
37 | 'filename' => '',
38 | 'attachment_id' => 0,
39 | 'description' => $this->generateDescription(),
40 | 'button_text' => $this->config('button_text') ?: __('Add Media'),
41 | 'field_name' => $fieldName,
42 | 'media_uploader_options' => esc_attr(
43 | json_encode([
44 | 'multiple' => false,
45 | 'title' => $this->config('media_uploader_title'),
46 | ])
47 | ),
48 | ];
49 |
50 | if ($mediaInfo) {
51 | $data['has_value_class'] = 'laraish-has-value';
52 | $data['media_img_url'] = $mediaInfo['type'] == 'image' ? $mediaInfo['url'] : $mediaInfo['icon'];
53 | $data['attachment_id'] = $mediaInfo['id'];
54 | $data['media_type'] = $mediaInfo['type'];
55 | $data['filename'] = $mediaInfo['filename'];
56 | }
57 |
58 | return $this->renderTemplate($data);
59 | }
60 |
61 | protected function validateFieldValue($value)
62 | {
63 | return isset($value['url']);
64 | }
65 |
66 | /**
67 | * A callback function that sanitizes the option's value.
68 | *
69 | * @param array|int|null $attachmentId
70 | *
71 | * @return mixed
72 | */
73 | public function sanitize($attachmentId)
74 | {
75 | if (is_string($attachmentId)) {
76 | $mediaMetaData = wp_prepare_attachment_for_js($attachmentId);
77 |
78 | return $mediaMetaData;
79 | }
80 |
81 | return $attachmentId;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/NumberFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => null,
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('number');
24 | }
25 |
26 | /**
27 | * A callback function that sanitizes the option's value.
28 | *
29 | * @param mixed $value
30 | *
31 | * @return mixed
32 | */
33 | public function sanitize($value)
34 | {
35 | return $this->validateWithErrorMessage($value, "`{$this->config('title')}` must be a number.");
36 | }
37 |
38 | /**
39 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
40 | * This method will be automatically called with the current value of the field if the field has a value.
41 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
42 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
43 | *
44 | * @param mixed $value
45 | *
46 | * @return bool
47 | */
48 | protected function validateFieldValue($value)
49 | {
50 | return is_numeric($value);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/PasswordFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | $allAttributes = static::convertToAttributesString(
24 | array_merge($this->config('attributes'), ['name' => $this->fieldName])
25 | );
26 |
27 | return $this->generateInput('password', $allAttributes);
28 | }
29 |
30 | /**
31 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
32 | * This method will be automatically called with the current value of the field if the field has a value.
33 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
34 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
35 | *
36 | * @param mixed $value
37 | *
38 | * @return bool
39 | */
40 | protected function validateFieldValue($value)
41 | {
42 | return is_string($value);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/RadiosFieldGenerator.php:
--------------------------------------------------------------------------------
1 | true,
13 | 'options' => [],
14 | 'attributes' => [],
15 | 'defaultValue' => '',
16 | ];
17 |
18 | /**
19 | * Generate the field markup.
20 | *
21 | * @return string
22 | */
23 | final public function generate()
24 | {
25 | $savedValue = $this->fieldValue;
26 | $markUp = '';
27 |
28 | foreach ($this->config('options') as $optionText => $optionValue) {
29 | $escapedOptionText = esc_html($optionText);
30 | $checked = $optionValue == $savedValue ? 'checked' : null;
31 |
32 | $attributes = static::convertToAttributesString(
33 | array_merge($this->config('attributes'), [
34 | 'name' => $this->fieldName,
35 | 'type' => 'radio',
36 | 'value' => $optionValue,
37 | 'checked' => $checked,
38 | ])
39 | );
40 | $inputHtml = " ";
41 |
42 | $markUp .= "{$inputHtml}{$escapedOptionText} \n";
43 | if (!$this->config('horizontal')) {
44 | $markUp .= " \n";
45 | }
46 | }
47 |
48 | return $markUp . $this->generateDescription();
49 | }
50 |
51 | /**
52 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
53 | * This method will be automatically called with the current value of the field if the field has a value.
54 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
55 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
56 | *
57 | * @param mixed $value
58 | *
59 | * @return bool
60 | */
61 | protected function validateFieldValue($value)
62 | {
63 | return is_string($value);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/RangeFieldGenerator.php:
--------------------------------------------------------------------------------
1 | [
13 | 'min' => 0,
14 | 'max' => 100,
15 | ],
16 | 'defaultValue' => null,
17 | ];
18 |
19 | /**
20 | * Generate the field markup.
21 | *
22 | * @return string
23 | */
24 | final public function generate()
25 | {
26 | return $this->generateInput('range');
27 | }
28 |
29 | /**
30 | * A callback function that sanitizes the option's value.
31 | *
32 | * @param mixed $value
33 | *
34 | * @return mixed
35 | */
36 | public function sanitize($value)
37 | {
38 | $attributes = $this->config('attributes');
39 | $max = $attributes['max'];
40 | $min = $attributes['min'];
41 |
42 | return $this->validateWithErrorMessage(
43 | $value,
44 | "`{$this->config('title')}` must be a number between {$min} and {$max}."
45 | );
46 | }
47 |
48 | /**
49 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
50 | * This method will be automatically called with the current value of the field if the field has a value.
51 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
52 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
53 | *
54 | * @param mixed $value
55 | *
56 | * @return bool
57 | */
58 | protected function validateFieldValue($value)
59 | {
60 | $attributes = $this->config('attributes');
61 | $max = $attributes['max'];
62 | $min = $attributes['min'];
63 |
64 | return $value >= $min and $value <= $max;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/SearchFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('search');
24 | }
25 |
26 | /**
27 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
28 | * This method will be automatically called with the current value of the field if the field has a value.
29 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
30 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
31 | *
32 | * @param mixed $value
33 | *
34 | * @return bool
35 | */
36 | protected function validateFieldValue($value)
37 | {
38 | return is_string($value);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/SelectFieldGenerator.php:
--------------------------------------------------------------------------------
1 | false,
15 | 'options' => [],
16 | 'multiple' => false,
17 | 'attributes' => ['class' => 'regular-text'],
18 | 'defaultValue' => '',
19 | ];
20 |
21 | protected static $scripts = ['js/libs/selectize.js', 'js/selectFieldGenerator.js'];
22 |
23 | protected static $styles = ['css/libs/selectize.css'];
24 |
25 | /**
26 | * Generate the field markup.
27 | *
28 | * @return string
29 | */
30 | final public function generate()
31 | {
32 | $innerHTML = '';
33 | $selectedValue = Arr::cast($this->fieldValue);
34 |
35 | if ($this->config('richMode') === true) {
36 | $this->configs['attributes']['class'] .= ' laraish-select';
37 | }
38 |
39 | $options = Arr::cast($this->config('options'));
40 |
41 | if (Arr::isSequential($options)) {
42 | $options = array_combine($options, $options);
43 | }
44 |
45 | foreach ($options as $optionText => $optionValue) {
46 | // if it's not an option group
47 | if (!is_array($optionValue)) {
48 | $escapedOptionText = esc_html($optionText);
49 | $isSelected = in_array((string) $optionValue, $selectedValue);
50 | $OptionAttributes = static::convertToAttributesString([
51 | 'value' => $optionValue,
52 | 'selected' => $isSelected ? 'selected' : null,
53 | ]);
54 | $innerHTML .= " {$escapedOptionText} ";
55 | } else {
56 | $innerHTML .= "";
57 | if (Arr::isSequential($optionValue)) {
58 | $optionValue = array_combine($optionValue, $optionValue);
59 | }
60 | foreach ($optionValue as $optionTextInGroup => $optionValueInGroup) {
61 | $escapedOptionText = esc_html($optionTextInGroup);
62 | $isSelected = in_array((string) $optionValueInGroup, $selectedValue);
63 | $OptionAttributes = static::convertToAttributesString([
64 | 'value' => $optionValueInGroup,
65 | 'selected' => $isSelected ? 'selected' : null,
66 | ]);
67 | $innerHTML .= "{$escapedOptionText} ";
68 | }
69 | $innerHTML .= ' ';
70 | }
71 | }
72 |
73 | // Add placeholder if possible
74 | $placeholder = $this->config('placeholder');
75 | if (!empty($innerHTML) and $placeholder and $selectedValue === null) {
76 | $placeHolderOption = "{$placeholder} ";
77 | $innerHTML = $placeHolderOption . $innerHTML;
78 | }
79 |
80 | // If `multiple` is allowed append `[]` to the end of `name` attribute,
81 | // so we can receive the data as array instead of string.
82 | $isMultiple = $this->config('multiple');
83 | $attributes = ['name' => $this->fieldName . ($isMultiple ? '[]' : '')];
84 | if ($isMultiple) {
85 | $attributes['multiple'] = 'multiple';
86 | }
87 |
88 | $allAttributes = array_merge($this->config('attributes'), $attributes);
89 | $allAttributes = static::convertToAttributesString($allAttributes);
90 |
91 | $html = "{$innerHTML} ";
92 |
93 | // Add help link if possible
94 | if ($helpLink = $this->generateHelpLink()) {
95 | $html = '
' . $html . "{$helpLink}
";
96 | }
97 |
98 | $html .= $this->generateDescription();
99 |
100 | return $html;
101 | }
102 |
103 | /**
104 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
105 | * This method will be automatically called with the current value of the field if the field has a value.
106 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
107 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
108 | *
109 | * @param mixed $value
110 | *
111 | * @return bool
112 | */
113 | protected function validateFieldValue($value)
114 | {
115 | return is_string($value) or is_array($value);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/TextFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('text');
24 | }
25 |
26 | /**
27 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
28 | * This method will be automatically called with the current value of the field if the field has a value.
29 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
30 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
31 | *
32 | * @param mixed $value
33 | *
34 | * @return bool
35 | */
36 | protected function validateFieldValue($value)
37 | {
38 | return is_string($value);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/TextareaFieldGenerator.php:
--------------------------------------------------------------------------------
1 | [
13 | 'cols' => 60,
14 | 'rows' => 5,
15 | ],
16 | 'defaultValue' => '',
17 | ];
18 |
19 | /**
20 | * Generate the field markup.
21 | *
22 | * @return string
23 | */
24 | final public function generate()
25 | {
26 | $allAttributes = static::convertToAttributesString(
27 | array_merge($this->config('attributes'), ['name' => $this->fieldName])
28 | );
29 | $innerHTML = $this->fieldValue;
30 |
31 | return "" . $this->generateDescription();
32 | }
33 |
34 | /**
35 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
36 | * This method will be automatically called with the current value of the field if the field has a value.
37 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
38 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
39 | *
40 | * @param mixed $value
41 | *
42 | * @return bool
43 | */
44 | protected function validateFieldValue($value)
45 | {
46 | return is_string($value);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/TimeFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('time');
24 | }
25 |
26 | /**
27 | * A callback function that sanitizes the option's value.
28 | *
29 | * @param mixed $value
30 | *
31 | * @return mixed
32 | */
33 | public function sanitize($value)
34 | {
35 | return $value;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/UrlFieldGenerator.php:
--------------------------------------------------------------------------------
1 | ['class' => 'regular-text'],
13 | 'defaultValue' => '',
14 | ];
15 |
16 | /**
17 | * Generate the field markup.
18 | *
19 | * @return string
20 | */
21 | final public function generate()
22 | {
23 | return $this->generateInput('url');
24 | }
25 |
26 | /**
27 | * A callback function that sanitizes the option's value.
28 | *
29 | * @param mixed $value
30 | *
31 | * @return mixed
32 | */
33 | public function sanitize($value)
34 | {
35 | return $this->validateWithErrorMessage($value, "`{$this->config('title')}` must be a URL.");
36 | }
37 |
38 | /**
39 | * An option could be potentially set to a value before the field saving its value to the database for the first time.
40 | * This method will be automatically called with the current value of the field if the field has a value.
41 | * If the value of the current option is a valid value for the field, return `true`, if it's not, return `false`.
42 | * `$this->validateWithErrorMessage` also use this method to validate the field value.
43 | *
44 | * @param mixed $value
45 | *
46 | * @return bool
47 | */
48 | protected function validateFieldValue($value)
49 | {
50 | return filter_var($value, FILTER_VALIDATE_URL);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/file.css:
--------------------------------------------------------------------------------
1 | .laraish-file-field__media {
2 | position: relative;
3 | text-align: center; }
4 | .laraish-file-field__media:hover .laraish-file-field__controller {
5 | opacity: 1;
6 | transform: translateY(-2em); }
7 | .laraish-file-field__media.image .laraish-file-field__filename {
8 | display: none; }
9 | .laraish-file-field__media.application {
10 | max-width: 15em;
11 | background-color: #fdfdfd;
12 | padding: 1em;
13 | border: 1px solid #e0e0e0; }
14 |
15 | .laraish-file-field__controller {
16 | position: absolute;
17 | left: 1em;
18 | top: 1em;
19 | margin: 0;
20 | border-radius: 5px;
21 | box-shadow: 0 25px 53px rgba(0, 0, 0, 0.45);
22 | background-color: #fff;
23 | padding: 0.5em;
24 | opacity: 0;
25 | transition: 0.4s ease-in-out; }
26 | .laraish-file-field__controller li:last-child {
27 | margin-bottom: 0; }
28 |
29 | .laraish-file-field__img {
30 | display: inline-block;
31 | vertical-align: bottom; }
32 |
33 | .laraish-file-field__filename {
34 | line-height: 1;
35 | margin-top: 1em;
36 | padding-top: 0.8em;
37 | border-top: 1px solid #e4e4e4;
38 | font-size: 12px;
39 | text-align: center;
40 | font-weight: 600;
41 | word-wrap: break-word; }
42 |
43 | /*# sourceMappingURL=file.css.map */
44 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/file.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAAA,0BAA2B;EACvB,QAAQ,EAAE,QAAQ;EAClB,UAAU,EAAE,MAAM;EAClB,gEAAwC;IACpC,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,gBAAgB;EAE/B,8DAAsC;IAClC,OAAO,EAAE,IAAI;EAEjB,sCAAc;IACV,SAAS,EAAE,IAAI;IACf,gBAAgB,EAAE,OAAO;IACzB,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,iBAAiB;;AAIjC,+BAAgC;EAC5B,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,GAAG;EACT,GAAG,EAAE,GAAG;EACR,MAAM,EAAE,CAAC;EACT,aAAa,EAAE,GAAG;EAClB,UAAU,EAAE,+BAA+B;EAC3C,gBAAgB,EAAE,IAAI;EACtB,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,gBAAgB;EAC5B,6CAAc;IACV,aAAa,EAAE,CAAC;;AAIxB,wBAAyB;EACrB,OAAO,EAAE,YAAY;EACrB,cAAc,EAAE,MAAM;;AAG1B,6BAA8B;EAC1B,WAAW,EAAE,CAAC;EACd,UAAU,EAAE,GAAG;EACf,WAAW,EAAE,KAAK;EAClB,UAAU,EAAE,iBAAiB;EAC7B,SAAS,EAAE,IAAI;EACf,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,SAAS,EAAE,UAAU",
4 | "sources": ["file.scss"],
5 | "names": [],
6 | "file": "file.css"
7 | }
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/file.scss:
--------------------------------------------------------------------------------
1 | .laraish-file-field__media {
2 | position: relative;
3 | text-align: center;
4 | &:hover .laraish-file-field__controller {
5 | opacity: 1;
6 | transform: translateY(-2em);
7 | }
8 | &.image .laraish-file-field__filename {
9 | display: none;
10 | }
11 | &.application {
12 | max-width: 15em;
13 | background-color: #fdfdfd;
14 | padding: 1em;
15 | border: 1px solid #e0e0e0;
16 | }
17 | }
18 |
19 | .laraish-file-field__controller {
20 | position: absolute;
21 | left: 1em;
22 | top: 1em;
23 | margin: 0;
24 | border-radius: 5px;
25 | box-shadow: 0 25px 53px rgba(0, 0, 0, 0.45);
26 | background-color: #fff;
27 | padding: 0.5em;
28 | opacity: 0;
29 | transition: 0.4s ease-in-out;
30 | li:last-child {
31 | margin-bottom: 0;
32 | }
33 | }
34 |
35 | .laraish-file-field__img {
36 | display: inline-block;
37 | vertical-align: bottom;
38 | }
39 |
40 | .laraish-file-field__filename {
41 | line-height: 1;
42 | margin-top: 1em;
43 | padding-top: 0.8em;
44 | border-top: 1px solid #e4e4e4;
45 | font-size: 12px;
46 | text-align: center;
47 | font-weight: 600;
48 | word-wrap: break-word;
49 | }
50 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/libs/selectize.css:
--------------------------------------------------------------------------------
1 | /**
2 | * selectize.default.css (v0.12.4) - Default Theme
3 | * Copyright (c) 2013–2015 Brian Reavis & contributors
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
6 | * file except in compliance with the License. You may obtain a copy of the License at:
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under
10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11 | * ANY KIND, either express or implied. See the License for the specific language
12 | * governing permissions and limitations under the License.
13 | *
14 | * @author Brian Reavis
15 | */
16 | .selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder {
17 | visibility: visible !important;
18 | background: #f2f2f2 !important;
19 | background: rgba(0, 0, 0, 0.06) !important;
20 | border: 0 none !important;
21 | -webkit-box-shadow: inset 0 0 12px 4px #ffffff;
22 | box-shadow: inset 0 0 12px 4px #ffffff;
23 | }
24 | .selectize-control.plugin-drag_drop .ui-sortable-placeholder::after {
25 | content: '!';
26 | visibility: hidden;
27 | }
28 | .selectize-control.plugin-drag_drop .ui-sortable-helper {
29 | -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
30 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
31 | }
32 | .selectize-dropdown-header {
33 | position: relative;
34 | padding: 5px 8px;
35 | border-bottom: 1px solid #d0d0d0;
36 | background: #f8f8f8;
37 | -webkit-border-radius: 3px 3px 0 0;
38 | -moz-border-radius: 3px 3px 0 0;
39 | border-radius: 3px 3px 0 0;
40 | }
41 | .selectize-dropdown-header-close {
42 | position: absolute;
43 | right: 8px;
44 | top: 50%;
45 | color: #303030;
46 | opacity: 0.4;
47 | margin-top: -12px;
48 | line-height: 20px;
49 | font-size: 20px !important;
50 | }
51 | .selectize-dropdown-header-close:hover {
52 | color: #000000;
53 | }
54 | .selectize-dropdown.plugin-optgroup_columns .optgroup {
55 | border-right: 1px solid #f2f2f2;
56 | border-top: 0 none;
57 | float: left;
58 | -webkit-box-sizing: border-box;
59 | -moz-box-sizing: border-box;
60 | box-sizing: border-box;
61 | }
62 | .selectize-dropdown.plugin-optgroup_columns .optgroup:last-child {
63 | border-right: 0 none;
64 | }
65 | .selectize-dropdown.plugin-optgroup_columns .optgroup:before {
66 | display: none;
67 | }
68 | .selectize-dropdown.plugin-optgroup_columns .optgroup-header {
69 | border-top: 0 none;
70 | }
71 | .selectize-control.plugin-remove_button [data-value] {
72 | position: relative;
73 | padding-right: 24px !important;
74 | }
75 | .selectize-control.plugin-remove_button [data-value] .remove {
76 | z-index: 1;
77 | /* fixes ie bug (see #392) */
78 | position: absolute;
79 | top: 0;
80 | right: 0;
81 | bottom: 0;
82 | width: 17px;
83 | text-align: center;
84 | font-weight: bold;
85 | font-size: 12px;
86 | color: inherit;
87 | text-decoration: none;
88 | vertical-align: middle;
89 | display: inline-block;
90 | padding: 2px 0 0 0;
91 | border-left: 1px solid #0073bb;
92 | -webkit-border-radius: 0 2px 2px 0;
93 | -moz-border-radius: 0 2px 2px 0;
94 | border-radius: 0 2px 2px 0;
95 | -webkit-box-sizing: border-box;
96 | -moz-box-sizing: border-box;
97 | box-sizing: border-box;
98 | }
99 | .selectize-control.plugin-remove_button [data-value] .remove:hover {
100 | background: rgba(0, 0, 0, 0.05);
101 | }
102 | .selectize-control.plugin-remove_button [data-value].active .remove {
103 | border-left-color: #00578d;
104 | }
105 | .selectize-control.plugin-remove_button .disabled [data-value] .remove:hover {
106 | background: none;
107 | }
108 | .selectize-control.plugin-remove_button .disabled [data-value] .remove {
109 | border-left-color: #aaaaaa;
110 | }
111 | .selectize-control.plugin-remove_button .remove-single {
112 | position: absolute;
113 | right: 28px;
114 | top: 6px;
115 | font-size: 23px;
116 | }
117 | .selectize-control {
118 | position: relative;
119 | }
120 | .selectize-dropdown,
121 | .selectize-input,
122 | .selectize-input input {
123 | color: #303030;
124 | font-family: inherit;
125 | font-size: 13px;
126 | line-height: 18px;
127 | -webkit-font-smoothing: inherit;
128 | }
129 | .selectize-input,
130 | .selectize-control.single .selectize-input.input-active {
131 | background: #ffffff;
132 | cursor: text;
133 | display: inline-block;
134 | }
135 | .selectize-input {
136 | border: 1px solid #d0d0d0;
137 | padding: 8px 8px;
138 | display: inline-block;
139 | width: 100%;
140 | overflow: hidden;
141 | position: relative;
142 | z-index: 1;
143 | -webkit-box-sizing: border-box;
144 | -moz-box-sizing: border-box;
145 | box-sizing: border-box;
146 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
147 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
148 | -webkit-border-radius: 3px;
149 | -moz-border-radius: 3px;
150 | border-radius: 3px;
151 | }
152 | .selectize-control.multi .selectize-input.has-items {
153 | padding: 5px 8px 2px;
154 | }
155 | .selectize-input.full {
156 | background-color: #ffffff;
157 | }
158 | .selectize-input.disabled,
159 | .selectize-input.disabled * {
160 | cursor: default !important;
161 | }
162 | .selectize-input.focus {
163 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
164 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
165 | }
166 | .selectize-input.dropdown-active {
167 | -webkit-border-radius: 3px 3px 0 0;
168 | -moz-border-radius: 3px 3px 0 0;
169 | border-radius: 3px 3px 0 0;
170 | }
171 | .selectize-input > * {
172 | vertical-align: baseline;
173 | display: -moz-inline-stack;
174 | display: inline-block;
175 | zoom: 1;
176 | *display: inline;
177 | }
178 | .selectize-control.multi .selectize-input > div {
179 | cursor: pointer;
180 | margin: 0 3px 3px 0;
181 | padding: 2px 6px;
182 | background: #1da7ee;
183 | color: #ffffff;
184 | border: 1px solid #0073bb;
185 | }
186 | .selectize-control.multi .selectize-input > div.active {
187 | background: #92c836;
188 | color: #ffffff;
189 | border: 1px solid #00578d;
190 | }
191 | .selectize-control.multi .selectize-input.disabled > div,
192 | .selectize-control.multi .selectize-input.disabled > div.active {
193 | color: #ffffff;
194 | background: #d2d2d2;
195 | border: 1px solid #aaaaaa;
196 | }
197 | .selectize-input > input {
198 | display: inline-block !important;
199 | padding: 0 !important;
200 | min-height: 0 !important;
201 | max-height: none !important;
202 | max-width: 100% !important;
203 | margin: 0 1px !important;
204 | text-indent: 0 !important;
205 | border: 0 none !important;
206 | background: none !important;
207 | line-height: inherit !important;
208 | -webkit-user-select: auto !important;
209 | -webkit-box-shadow: none !important;
210 | box-shadow: none !important;
211 | }
212 | .selectize-input > input::-ms-clear {
213 | display: none;
214 | }
215 | .selectize-input > input:focus {
216 | outline: none !important;
217 | }
218 | .selectize-input::after {
219 | content: ' ';
220 | display: block;
221 | clear: left;
222 | }
223 | .selectize-input.dropdown-active::before {
224 | content: ' ';
225 | display: block;
226 | position: absolute;
227 | background: #f0f0f0;
228 | height: 1px;
229 | bottom: 0;
230 | left: 0;
231 | right: 0;
232 | }
233 | .selectize-dropdown {
234 | position: absolute;
235 | z-index: 10;
236 | border: 1px solid #d0d0d0;
237 | background: #ffffff;
238 | margin: -1px 0 0 0;
239 | border-top: 0 none;
240 | -webkit-box-sizing: border-box;
241 | -moz-box-sizing: border-box;
242 | box-sizing: border-box;
243 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
244 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
245 | -webkit-border-radius: 0 0 3px 3px;
246 | -moz-border-radius: 0 0 3px 3px;
247 | border-radius: 0 0 3px 3px;
248 | }
249 | .selectize-dropdown [data-selectable] {
250 | cursor: pointer;
251 | overflow: hidden;
252 | }
253 | .selectize-dropdown [data-selectable] .highlight {
254 | background: rgba(125, 168, 208, 0.2);
255 | -webkit-border-radius: 1px;
256 | -moz-border-radius: 1px;
257 | border-radius: 1px;
258 | }
259 | .selectize-dropdown [data-selectable],
260 | .selectize-dropdown .optgroup-header {
261 | padding: 5px 8px;
262 | }
263 | .selectize-dropdown .optgroup:first-child .optgroup-header {
264 | border-top: 0 none;
265 | }
266 | .selectize-dropdown .optgroup-header {
267 | color: #303030;
268 | background: #ffffff;
269 | cursor: default;
270 | }
271 | .selectize-dropdown .active {
272 | background-color: #00a0d2;
273 | color: white;
274 | }
275 | .selectize-dropdown .active.create {
276 | color: #fff;
277 | }
278 | .selectize-dropdown .create {
279 | color: rgba(48, 48, 48, 0.5);
280 | }
281 | .selectize-dropdown-content {
282 | overflow-y: auto;
283 | overflow-x: hidden;
284 | max-height: 200px;
285 | -webkit-overflow-scrolling: touch;
286 | }
287 | .selectize-control.single .selectize-input,
288 | .selectize-control.single .selectize-input input {
289 | cursor: pointer;
290 | }
291 | .selectize-control.single .selectize-input.input-active,
292 | .selectize-control.single .selectize-input.input-active input {
293 | cursor: text;
294 | }
295 | .selectize-control.single .selectize-input:after {
296 | content: ' ';
297 | display: block;
298 | position: absolute;
299 | top: 50%;
300 | right: 15px;
301 | margin-top: -3px;
302 | width: 0;
303 | height: 0;
304 | border-style: solid;
305 | border-width: 5px 5px 0 5px;
306 | border-color: #808080 transparent transparent transparent;
307 | }
308 | .selectize-control.single .selectize-input.dropdown-active:after {
309 | margin-top: -4px;
310 | border-width: 0 5px 5px 5px;
311 | border-color: transparent transparent #808080 transparent;
312 | }
313 | .selectize-control.rtl.single .selectize-input:after {
314 | left: 15px;
315 | right: auto;
316 | }
317 | .selectize-control.rtl .selectize-input > input {
318 | margin: 0 4px 0 -2px !important;
319 | }
320 | .selectize-control .selectize-input.disabled {
321 | opacity: 0.5;
322 | background-color: #fafafa;
323 | }
324 | .selectize-control.multi .selectize-input.has-items {
325 | padding-left: 5px;
326 | padding-right: 5px;
327 | }
328 | .selectize-control.multi .selectize-input.disabled [data-value] {
329 | color: #999;
330 | text-shadow: none;
331 | background: none;
332 | -webkit-box-shadow: none;
333 | box-shadow: none;
334 | }
335 | .selectize-control.multi .selectize-input.disabled [data-value],
336 | .selectize-control.multi .selectize-input.disabled [data-value] .remove {
337 | border-color: #e6e6e6;
338 | }
339 | .selectize-control.multi .selectize-input.disabled [data-value] .remove {
340 | background: none;
341 | }
342 | .selectize-control.multi .selectize-input [data-value] {
343 | text-shadow: 0 1px 0 rgba(0, 51, 83, 0.3);
344 | -webkit-border-radius: 3px;
345 | -moz-border-radius: 3px;
346 | border-radius: 3px;
347 | background-color: #008ec2;
348 | }
349 | .selectize-control.multi .selectize-input [data-value].active {
350 | background-color: #0080b3;
351 | }
352 | .selectize-control.single .selectize-input {
353 | -webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
354 | box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
355 | background-color: #f9f9f9;
356 | background-image: -moz-linear-gradient(top, #fefefe, #f2f2f2);
357 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fefefe), to(#f2f2f2));
358 | background-image: -webkit-linear-gradient(top, #fefefe, #f2f2f2);
359 | background-image: -o-linear-gradient(top, #fefefe, #f2f2f2);
360 | background-image: linear-gradient(to bottom, #fefefe, #f2f2f2);
361 | background-repeat: repeat-x;
362 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffefefe', endColorstr='#fff2f2f2', GradientType=0);
363 | }
364 | .selectize-control.single .selectize-input,
365 | .selectize-dropdown.single {
366 | border-color: #b8b8b8;
367 | }
368 | .selectize-dropdown .optgroup-header {
369 | padding-top: 7px;
370 | font-weight: bold;
371 | font-size: 0.85em;
372 | }
373 | .selectize-dropdown .optgroup {
374 | border-top: 1px solid #f0f0f0;
375 | }
376 | .selectize-dropdown .optgroup:first-child {
377 | border-top: 0 none;
378 | }
379 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/media.css:
--------------------------------------------------------------------------------
1 | .laraish-media-field__media {
2 | position: relative;
3 | text-align: center; }
4 | .laraish-media-field__media:hover .laraish-media-field__controller {
5 | opacity: 1;
6 | transform: translateY(-2em); }
7 | .laraish-media-field__media.image .laraish-media-field__filename {
8 | display: none; }
9 | .laraish-media-field__media.application {
10 | max-width: 15em;
11 | background-color: #fdfdfd;
12 | padding: 1em;
13 | border: 1px solid #e0e0e0; }
14 |
15 | .laraish-media-field__controller {
16 | position: absolute;
17 | left: 1em;
18 | top: 1em;
19 | margin: 0;
20 | border-radius: 5px;
21 | box-shadow: 0 25px 53px rgba(0, 0, 0, 0.45);
22 | background-color: #fff;
23 | padding: 0.5em;
24 | opacity: 0;
25 | transition: 0.4s ease-in-out; }
26 | .laraish-media-field__controller li:last-child {
27 | margin-bottom: 0; }
28 |
29 | .laraish-media-field__img {
30 | display: inline-block;
31 | vertical-align: bottom; }
32 |
33 | .laraish-media-field__filename {
34 | line-height: 1;
35 | margin-top: 1em;
36 | padding-top: 0.8em;
37 | border-top: 1px solid #e4e4e4;
38 | font-size: 12px;
39 | text-align: center;
40 | font-weight: 600;
41 | word-wrap: break-word; }
42 |
43 | /*# sourceMappingURL=media.css.map */
44 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/media.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAAA,2BAA4B;EACxB,QAAQ,EAAE,QAAQ;EAClB,UAAU,EAAE,MAAM;EAElB,kEAAyC;IACrC,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,gBAAgB;EAI3B,gEAA+B;IAC3B,OAAO,EAAE,IAAI;EAIrB,uCAAc;IACV,SAAS,EAAE,IAAI;IACf,gBAAgB,EAAE,OAAO;IACzB,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,iBAAiB;;AAIjC,gCAAiC;EAC7B,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,GAAG;EACT,GAAG,EAAE,GAAG;EACR,MAAM,EAAE,CAAC;EACT,aAAa,EAAE,GAAG;EAClB,UAAU,EAAE,+BAA+B;EAC3C,gBAAgB,EAAE,IAAI;EACtB,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,gBAAgB;EAC5B,8CAAc;IACV,aAAa,EAAE,CAAC;;AAIxB,yBAA0B;EACtB,OAAO,EAAE,YAAY;EACrB,cAAc,EAAE,MAAM;;AAG1B,8BAA+B;EAC3B,WAAW,EAAE,CAAC;EACd,UAAU,EAAE,GAAG;EACf,WAAW,EAAE,KAAK;EAClB,UAAU,EAAE,iBAAiB;EAC7B,SAAS,EAAE,IAAI;EACf,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,SAAS,EAAE,UAAU",
4 | "sources": ["media.scss"],
5 | "names": [],
6 | "file": "media.css"
7 | }
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/media.scss:
--------------------------------------------------------------------------------
1 | .laraish-media-field__media {
2 | position: relative;
3 | text-align: center;
4 |
5 | &:hover .laraish-media-field__controller {
6 | opacity: 1;
7 | transform: translateY(-2em);
8 | }
9 |
10 | &.image {
11 | .laraish-media-field__filename {
12 | display: none;
13 | }
14 | }
15 |
16 | &.application {
17 | max-width: 15em;
18 | background-color: #fdfdfd;
19 | padding: 1em;
20 | border: 1px solid #e0e0e0;
21 | }
22 | }
23 |
24 | .laraish-media-field__controller {
25 | position: absolute;
26 | left: 1em;
27 | top: 1em;
28 | margin: 0;
29 | border-radius: 5px;
30 | box-shadow: 0 25px 53px rgba(0, 0, 0, 0.45);
31 | background-color: #fff;
32 | padding: 0.5em;
33 | opacity: 0;
34 | transition: 0.4s ease-in-out;
35 | li:last-child {
36 | margin-bottom: 0;
37 | }
38 | }
39 |
40 | .laraish-media-field__img {
41 | display: inline-block;
42 | vertical-align: bottom;
43 | }
44 |
45 | .laraish-media-field__filename {
46 | line-height: 1;
47 | margin-top: 1em;
48 | padding-top: 0.8em;
49 | border-top: 1px solid #e4e4e4;
50 | font-size: 12px;
51 | text-align: center;
52 | font-weight: 600;
53 | word-wrap: break-word;
54 | }
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/sharedStyle.css:
--------------------------------------------------------------------------------
1 | .laraish-show-if-value, .laraish-show-if-value--inline-block {
2 | display: none; }
3 |
4 | .laraish-hide-if-value {
5 | display: block; }
6 |
7 | .laraish-has-value .laraish-show-if-value {
8 | display: block; }
9 | .laraish-has-value .laraish-show-if-value--inline-block {
10 | display: inline-block; }
11 | .laraish-has-value .laraish-hide-if-value {
12 | display: none; }
13 |
14 | .laraish-flex-line {
15 | display: inline-flex;
16 | width: 100%; }
17 |
18 | .laraish-input-group {
19 | display: flex; }
20 |
21 | .laraish-input-group-addon {
22 | display: flex;
23 | align-items: center;
24 | margin: 0;
25 | text-align: center;
26 | white-space: nowrap;
27 | vertical-align: middle; }
28 | .laraish-input-group-addon:first-child {
29 | padding-right: 0.5rem; }
30 | .laraish-input-group-addon:last-child {
31 | padding-left: 0.5rem; }
32 |
33 | .laraish-help-link {
34 | display: flex;
35 | align-items: center;
36 | padding: 0 0.5rem;
37 | color: currentColor;
38 | opacity: 0.5; }
39 | .laraish-help-link:hover {
40 | opacity: 1; }
41 |
42 | /*# sourceMappingURL=sharedStyle.css.map */
43 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/sharedStyle.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAAA,4DAA6D;EACzD,OAAO,EAAE,IAAI;;AAGjB,sBAAuB;EACnB,OAAO,EAAE,KAAK;;AAId,yCAAuB;EACnB,OAAO,EAAE,KAAK;AAElB,uDAAqC;EACjC,OAAO,EAAE,YAAY;AAEzB,yCAAuB;EACnB,OAAO,EAAE,IAAI;;AAIrB,kBAAmB;EACf,OAAO,EAAE,WAAW;EACpB,KAAK,EAAE,IAAI;;AAGf,oBAAqB;EACjB,OAAO,EAAE,IAAI;;AAGjB,0BAA2B;EACvB,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,MAAM;EACnB,MAAM,EAAE,CAAC;EACT,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,MAAM;EACnB,cAAc,EAAE,MAAM;EACtB,sCAAc;IACV,aAAa,EAAE,MAAM;EAEzB,qCAAa;IACT,YAAY,EAAE,MAAM;;AAI5B,kBAAmB;EACf,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,MAAM;EACnB,OAAO,EAAE,QAAQ;EACjB,KAAK,EAAE,YAAY;EACnB,OAAO,EAAE,GAAG;EACZ,wBAAQ;IACJ,OAAO,EAAE,CAAC",
4 | "sources": ["sharedStyle.scss"],
5 | "names": [],
6 | "file": "sharedStyle.css"
7 | }
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/css/sharedStyle.scss:
--------------------------------------------------------------------------------
1 | .laraish-show-if-value, .laraish-show-if-value--inline-block {
2 | display: none;
3 | }
4 |
5 | .laraish-hide-if-value {
6 | display: block;
7 | }
8 |
9 | .laraish-has-value {
10 | .laraish-show-if-value {
11 | display: block;
12 | }
13 | .laraish-show-if-value--inline-block {
14 | display: inline-block;
15 | }
16 | .laraish-hide-if-value {
17 | display: none;
18 | }
19 | }
20 |
21 | .laraish-flex-line {
22 | display: inline-flex;
23 | width: 100%;
24 | }
25 |
26 | .laraish-input-group {
27 | display: flex;
28 | }
29 |
30 | .laraish-input-group-addon {
31 | display: flex;
32 | align-items: center;
33 | margin: 0;
34 | text-align: center;
35 | white-space: nowrap;
36 | vertical-align: middle;
37 | &:first-child {
38 | padding-right: 0.5rem;
39 | }
40 | &:last-child {
41 | padding-left: 0.5rem;
42 | }
43 | }
44 |
45 | .laraish-help-link {
46 | display: flex;
47 | align-items: center;
48 | padding: 0 0.5rem;
49 | color: currentColor;
50 | opacity: 0.5;
51 | &:hover {
52 | opacity: 1;
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/js/FileFieldGenerator.js:
--------------------------------------------------------------------------------
1 | jQuery(function ($) {
2 |
3 | function get_substitution_input(name) {
4 | return $(' ').attr('name', name);
5 | }
6 |
7 |
8 | $('.js-laraish-file-field').each(function () {
9 | var $field = $(this),
10 | $input = $field.find('.laraish-file-field__input'),
11 | $filename = $field.find('.laraish-media-field__filename'),
12 | $substitution_input = $();
13 |
14 | $field.find('.laraish-media-field__remove').on('click', function () {
15 | $field.removeClass('laraish-has-value');
16 | $input.after($substitution_input = get_substitution_input($input.attr('name')));
17 | });
18 |
19 | $input.on('change', function () {
20 | $substitution_input.remove();
21 | $filename.text(this.files[0]['name']);
22 | $field.addClass('laraish-has-value');
23 | });
24 |
25 | });
26 | });
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/js/MediaFieldGenerator.js:
--------------------------------------------------------------------------------
1 | jQuery(function ($) {
2 |
3 | var MediaFieldModel = Backbone.Model.extend({
4 |
5 | defaults: {
6 | media: {
7 | id: 0,
8 | url: ''
9 | },
10 | media_frame: null
11 | },
12 |
13 | select_media: function () {
14 | var media = this.get('media'),
15 | media_frame = this.get('media_frame');
16 |
17 | if (media.id == 0) {
18 | return this;
19 | }
20 |
21 | // make the media file selected
22 | var selection = media_frame.state().get('selection'),
23 | attachment = wp.media.attachment(media.id);
24 |
25 | attachment.fetch();
26 | selection.add(attachment);
27 | },
28 |
29 | set_media: function (media) {
30 | this.set({media: media});
31 | this.trigger('set_media');
32 | },
33 |
34 | remove_media: function () {
35 | this.set({media: this.defaults.media});
36 | this.trigger('remove_media');
37 | }
38 | });
39 |
40 | function MediaFieldView(element) {
41 |
42 | var $field = $(element),
43 | $input = $field.find('.laraish-media-field__input'),
44 | $img = $field.find('.laraish-media-field__img'),
45 | $media = $field.find('.laraish-media-field__media'),
46 | $filename = $field.find('.laraish-media-field__filename'),
47 | media_frame = wp.media(JSON.parse($field.find('.laraish-media-uploader-options').val())),
48 | model = new MediaFieldModel({
49 | media: {
50 | id: $input.val(),
51 | url: $img.attr('src')
52 | },
53 | media_frame: media_frame
54 | });
55 |
56 |
57 | /*------------------------------------*\
58 | # bind media frame events
59 | \*------------------------------------*/
60 |
61 | media_frame.on('select', function () {
62 | // Get media attachment details from the frame state
63 | var media = media_frame.state().get('selection').first().toJSON();
64 |
65 | model.set_media(media);
66 | // console.log(media);
67 | });
68 |
69 | media_frame.on('open', function () {
70 | model.select_media();
71 | });
72 |
73 |
74 | /*------------------------------------*\
75 | # bind view events
76 | \*------------------------------------*/
77 |
78 | // add or edit media
79 | $field.find('.laraish-add-media-button, .laraish-media-field__edit').on('click', function () {
80 | media_frame.open();
81 | });
82 |
83 | // remove media
84 | $field.find('.laraish-media-field__remove').on('click', function () {
85 | model.remove_media();
86 | });
87 |
88 | /*------------------------------------*\
89 | # bind model events
90 | \*------------------------------------*/
91 |
92 | model.on('remove_media', function () {
93 | $field.removeClass('laraish-has-value');
94 | });
95 |
96 | model.on('set_media', function () {
97 | $field.addClass('laraish-has-value');
98 | });
99 |
100 | model.on('change', function () {
101 | var media = model.get('media');
102 |
103 | $img.attr('src', media.type == 'image' ? media.url : media.icon);
104 | $media.attr('class', 'laraish-media-field__media ' + media.type);
105 | $filename.text(media.filename);
106 | $input.val(media['id']);
107 | });
108 | }
109 |
110 |
111 | // create views
112 | $('.js-laraish-media-field').each(function () {
113 | MediaFieldView(this);
114 | });
115 |
116 | });
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/assets/js/libs/selectize.js:
--------------------------------------------------------------------------------
1 | /*! selectize.js - v0.12.4 | https://github.com/selectize/selectize.js | Apache License (v2) */
2 | !function(a,b){"function"==typeof define&&define.amd?define("sifter",b):"object"==typeof exports?module.exports=b():a.Sifter=b()}(this,function(){var a=function(a,b){this.items=a,this.settings=b||{diacritics:!0}};a.prototype.tokenize=function(a){if(a=e(String(a||"").toLowerCase()),!a||!a.length)return[];var b,c,d,g,i=[],j=a.split(/ +/);for(b=0,c=j.length;b0)&&d.items.push({score:c,id:e})}):g.iterator(g.items,function(a,b){d.items.push({score:1,id:b})}),e=g.getSortFunction(d,b),e&&d.items.sort(e),d.total=d.items.length,"number"==typeof b.limit&&(d.items=d.items.slice(0,b.limit)),d};var b=function(a,b){return"number"==typeof a&&"number"==typeof b?a>b?1:ab?1:b>a?-1:0)},c=function(a,b){var c,d,e,f;for(c=1,d=arguments.length;c=0&&a.data.length>0){var f=a.data.match(c),g=document.createElement("span");g.className="highlight";var h=a.splitText(e),i=(h.splitText(f[0].length),h.cloneNode(!0));g.appendChild(i),h.parentNode.replaceChild(g,h),b=1}}else if(1===a.nodeType&&a.childNodes&&!/(script|style)/i.test(a.tagName))for(var j=0;j /g,">").replace(/"/g,""")},B={};B.before=function(a,b,c){var d=a[b];a[b]=function(){return c.apply(a,arguments),d.apply(a,arguments)}},B.after=function(a,b,c){var d=a[b];a[b]=function(){var b=d.apply(a,arguments);return c.apply(a,arguments),b}};var C=function(a){var b=!1;return function(){b||(b=!0,a.apply(this,arguments))}},D=function(a,b){var c;return function(){var d=this,e=arguments;window.clearTimeout(c),c=window.setTimeout(function(){a.apply(d,e)},b)}},E=function(a,b,c){var d,e=a.trigger,f={};a.trigger=function(){var c=arguments[0];return b.indexOf(c)===-1?e.apply(a,arguments):void(f[c]=arguments)},c.apply(a,[]),a.trigger=e;for(d in f)f.hasOwnProperty(d)&&e.apply(a,f[d])},F=function(a,b,c,d){a.on(b,c,function(b){for(var c=b.target;c&&c.parentNode!==a[0];)c=c.parentNode;return b.currentTarget=c,d.apply(this,[b])})},G=function(a){var b={};if("selectionStart"in a)b.start=a.selectionStart,b.length=a.selectionEnd-b.start;else if(document.selection){a.focus();var c=document.selection.createRange(),d=document.selection.createRange().text.length;c.moveStart("character",-a.value.length),b.start=c.text.length-d,b.length=d}return b},H=function(a,b,c){var d,e,f={};if(c)for(d=0,e=c.length;d").css({position:"absolute",top:-99999,left:-99999,width:"auto",padding:0,whiteSpace:"pre"}).text(b).appendTo("body");H(c,d,["letterSpacing","fontSize","fontFamily","fontWeight","textTransform"]);var e=d.width();return d.remove(),e},J=function(a){var b=null,c=function(c,d){var e,f,g,h,i,j,k,l;c=c||window.event||{},d=d||{},c.metaKey||c.altKey||(d.force||a.data("grow")!==!1)&&(e=a.val(),c.type&&"keydown"===c.type.toLowerCase()&&(f=c.keyCode,g=f>=97&&f<=122||f>=65&&f<=90||f>=48&&f<=57||32===f,f===q||f===p?(l=G(a[0]),l.length?e=e.substring(0,l.start)+e.substring(l.start+l.length):f===p&&l.start?e=e.substring(0,l.start-1)+e.substring(l.start+1):f===q&&"undefined"!=typeof l.start&&(e=e.substring(0,l.start)+e.substring(l.start+1))):g&&(j=c.shiftKey,k=String.fromCharCode(c.keyCode),k=j?k.toUpperCase():k.toLowerCase(),e+=k)),h=a.attr("placeholder"),!e&&h&&(e=h),i=I(e,a)+4,i!==b&&(b=i,a.width(i),a.triggerHandler("resize")))};a.on("keydown keyup update blur",c),c()},K=function(a){var b=document.createElement("div");return b.appendChild(a.cloneNode(!0)),b.innerHTML},L=function(a,b){b||(b={});var c="Selectize";console.error(c+": "+a),b.explanation&&(console.group&&console.group(),console.error(b.explanation),console.group&&console.groupEnd())},M=function(c,d){var e,f,g,h,i=this;h=c[0],h.selectize=i;var j=window.getComputedStyle&&window.getComputedStyle(h,null);if(g=j?j.getPropertyValue("direction"):h.currentStyle&&h.currentStyle.direction,g=g||c.parents("[dir]:first").attr("dir")||"",a.extend(i,{order:0,settings:d,$input:c,tabIndex:c.attr("tabindex")||"",tagType:"select"===h.tagName.toLowerCase()?v:w,rtl:/rtl/i.test(g),eventNS:".selectize"+ ++M.count,highlightedValue:null,isOpen:!1,isDisabled:!1,isRequired:c.is("[required]"),isInvalid:!1,isLocked:!1,isFocused:!1,isInputHidden:!1,isSetup:!1,isShiftDown:!1,isCmdDown:!1,isCtrlDown:!1,ignoreFocus:!1,ignoreBlur:!1,ignoreHover:!1,hasOptions:!1,currentResults:null,lastValue:"",caretPos:0,loading:0,loadedSearches:{},$activeOption:null,$activeItems:[],optgroups:{},options:{},userOptions:{},items:[],renderCache:{},onSearchChange:null===d.loadThrottle?i.onSearchChange:D(i.onSearchChange,d.loadThrottle)}),i.sifter=new b(this.options,{diacritics:d.diacritics}),i.settings.options){for(e=0,f=i.settings.options.length;e").addClass(n.wrapperClass).addClass(j).addClass(i),c=a("").addClass(n.inputClass).addClass("items").appendTo(b),d=a('
').appendTo(c).attr("tabindex",u.is(":disabled")?"-1":m.tabIndex),h=a(n.dropdownParent||b),e=a("
").addClass(n.dropdownClass).addClass(i).hide().appendTo(h),g=a("
").addClass(n.dropdownContentClass).appendTo(e),(l=u.attr("id"))&&(d.attr("id",l+"-selectized"),a("label[for='"+l+"']").attr("for",l+"-selectized")),m.settings.copyClassesToDropdown&&e.addClass(j),b.css({width:u[0].style.width}),m.plugins.names.length&&(k="plugin-"+m.plugins.names.join(" plugin-"),b.addClass(k),e.addClass(k)),(null===n.maxItems||n.maxItems>1)&&m.tagType===v&&u.attr("multiple","multiple"),m.settings.placeholder&&d.attr("placeholder",n.placeholder),!m.settings.splitOn&&m.settings.delimiter){var w=m.settings.delimiter.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&");m.settings.splitOn=new RegExp("\\s*"+w+"+\\s*")}u.attr("autocorrect")&&d.attr("autocorrect",u.attr("autocorrect")),u.attr("autocapitalize")&&d.attr("autocapitalize",u.attr("autocapitalize")),m.$wrapper=b,m.$control=c,m.$control_input=d,m.$dropdown=e,m.$dropdown_content=g,e.on("mouseenter","[data-selectable]",function(){return m.onOptionHover.apply(m,arguments)}),e.on("mousedown click","[data-selectable]",function(){return m.onOptionSelect.apply(m,arguments)}),F(c,"mousedown","*:not(input)",function(){return m.onItemSelect.apply(m,arguments)}),J(d),c.on({mousedown:function(){return m.onMouseDown.apply(m,arguments)},click:function(){return m.onClick.apply(m,arguments)}}),d.on({mousedown:function(a){a.stopPropagation()},keydown:function(){return m.onKeyDown.apply(m,arguments)},keyup:function(){return m.onKeyUp.apply(m,arguments)},keypress:function(){return m.onKeyPress.apply(m,arguments)},resize:function(){m.positionDropdown.apply(m,[])},blur:function(){return m.onBlur.apply(m,arguments)},focus:function(){return m.ignoreBlur=!1,m.onFocus.apply(m,arguments)},paste:function(){return m.onPaste.apply(m,arguments)}}),q.on("keydown"+o,function(a){m.isCmdDown=a[f?"metaKey":"ctrlKey"],m.isCtrlDown=a[f?"altKey":"ctrlKey"],m.isShiftDown=a.shiftKey}),q.on("keyup"+o,function(a){a.keyCode===t&&(m.isCtrlDown=!1),a.keyCode===r&&(m.isShiftDown=!1),a.keyCode===s&&(m.isCmdDown=!1)}),q.on("mousedown"+o,function(a){if(m.isFocused){if(a.target===m.$dropdown[0]||a.target.parentNode===m.$dropdown[0])return!1;m.$control.has(a.target).length||a.target===m.$control[0]||m.blur(a.target)}}),p.on(["scroll"+o,"resize"+o].join(" "),function(){m.isOpen&&m.positionDropdown.apply(m,arguments)}),p.on("mousemove"+o,function(){m.ignoreHover=!1}),this.revertSettings={$children:u.children().detach(),tabindex:u.attr("tabindex")},u.attr("tabindex",-1).hide().after(m.$wrapper),a.isArray(n.items)&&(m.setValue(n.items),delete n.items),x&&u.on("invalid"+o,function(a){a.preventDefault(),m.isInvalid=!0,m.refreshState()}),m.updateOriginalInput(),m.refreshItems(),m.refreshState(),m.updatePlaceholder(),m.isSetup=!0,u.is(":disabled")&&m.disable(),m.on("change",this.onChange),u.data("selectize",m),u.addClass("selectized"),m.trigger("initialize"),n.preload===!0&&m.onSearchChange("")},setupTemplates:function(){var b=this,c=b.settings.labelField,d=b.settings.optgroupLabelField,e={optgroup:function(a){return'
'+a.html+"
"},optgroup_header:function(a,b){return'"},option:function(a,b){return'
'+b(a[c])+"
"},item:function(a,b){return'
'+b(a[c])+"
"},option_create:function(a,b){return'
Add '+b(a.input)+" …
"}};b.settings.render=a.extend({},e,b.settings.render)},setupCallbacks:function(){var a,b,c={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(a in c)c.hasOwnProperty(a)&&(b=this.settings[c[a]],b&&this.on(a,b))},onClick:function(a){var b=this;b.isFocused||(b.focus(),a.preventDefault())},onMouseDown:function(b){var c=this,d=b.isDefaultPrevented();a(b.target);if(c.isFocused){if(b.target!==c.$control_input[0])return"single"===c.settings.mode?c.isOpen?c.close():c.open():d||c.setActiveItem(null),!1}else d||window.setTimeout(function(){c.focus()},0)},onChange:function(){this.$input.trigger("change")},onPaste:function(b){var c=this;return c.isFull()||c.isInputHidden||c.isLocked?void b.preventDefault():void(c.settings.splitOn&&setTimeout(function(){var b=c.$control_input.val();if(b.match(c.settings.splitOn))for(var d=a.trim(b).split(c.settings.splitOn),e=0,f=d.length;e
h&&(j=g,g=h,h=j),e=g;e<=h;e++)i=l.$control[0].childNodes[e],l.$activeItems.indexOf(i)===-1&&(a(i).addClass("active"),l.$activeItems.push(i));c.preventDefault()}else"mousedown"===d&&l.isCtrlDown||"keydown"===d&&this.isShiftDown?b.hasClass("active")?(f=l.$activeItems.indexOf(b[0]),l.$activeItems.splice(f,1),b.removeClass("active")):l.$activeItems.push(b.addClass("active")[0]):(a(l.$activeItems).removeClass("active"),l.$activeItems=[b.addClass("active")[0]]);l.hideInput(),this.isFocused||l.focus()}},setActiveOption:function(b,c,d){var e,f,g,h,i,j=this;j.$activeOption&&j.$activeOption.removeClass("active"),j.$activeOption=null,b=a(b),b.length&&(j.$activeOption=b.addClass("active"),!c&&y(c)||(e=j.$dropdown_content.height(),f=j.$activeOption.outerHeight(!0),c=j.$dropdown_content.scrollTop()||0,g=j.$activeOption.offset().top-j.$dropdown_content.offset().top+c,h=g,i=g-e+f,g+f>e+c?j.$dropdown_content.stop().animate({scrollTop:i},d?j.settings.scrollDuration:0):g=0;c--)f.items.indexOf(z(d.items[c].id))!==-1&&d.items.splice(c,1);return d},refreshOptions:function(b){var c,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s;"undefined"==typeof b&&(b=!0);var t=this,u=a.trim(t.$control_input.val()),v=t.search(u),w=t.$dropdown_content,x=t.$activeOption&&z(t.$activeOption.attr("data-value"));for(g=v.items.length,"number"==typeof t.settings.maxOptions&&(g=Math.min(g,t.settings.maxOptions)),h={},i=[],c=0;c0||p,t.hasOptions?(v.items.length>0?(r=x&&t.getOption(x),r&&r.length?q=r:"single"===t.settings.mode&&t.items.length&&(q=t.getOption(t.items[0])),q&&q.length||(q=s&&!t.settings.addPrecedence?t.getAdjacentOption(s,1):w.find("[data-selectable]:first"))):q=s,t.setActiveOption(q),b&&!t.isOpen&&t.open()):(t.setActiveOption(null),b&&t.isOpen&&t.close())},addOption:function(b){var c,d,e,f=this;if(a.isArray(b))for(c=0,d=b.length;c=0&&e0),b.$control_input.data("grow",!c&&!d)},isFull:function(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems},updateOriginalInput:function(a){var b,c,d,e,f=this;if(a=a||{},f.tagType===v){for(d=[],b=0,c=f.items.length;b'+A(e)+"");d.length||this.$input.attr("multiple")||d.push(' '),
3 | f.$input.html(d.join(""))}else f.$input.val(f.getValue()),f.$input.attr("value",f.$input.val());f.isSetup&&(a.silent||f.trigger("change",f.$input.val()))},updatePlaceholder:function(){if(this.settings.placeholder){var a=this.$control_input;this.items.length?a.removeAttr("placeholder"):a.attr("placeholder",this.settings.placeholder),a.triggerHandler("update",{force:!0})}},open:function(){var a=this;a.isLocked||a.isOpen||"multi"===a.settings.mode&&a.isFull()||(a.focus(),a.isOpen=!0,a.refreshState(),a.$dropdown.css({visibility:"hidden",display:"block"}),a.positionDropdown(),a.$dropdown.css({visibility:"visible"}),a.trigger("dropdown_open",a.$dropdown))},close:function(){var a=this,b=a.isOpen;"single"===a.settings.mode&&a.items.length&&(a.hideInput(),a.$control_input.blur()),a.isOpen=!1,a.$dropdown.hide(),a.setActiveOption(null),a.refreshState(),b&&a.trigger("dropdown_close",a.$dropdown)},positionDropdown:function(){var a=this.$control,b="body"===this.settings.dropdownParent?a.offset():a.position();b.top+=a.outerHeight(!0),this.$dropdown.css({width:a.outerWidth(),top:b.top,left:b.left})},clear:function(a){var b=this;b.items.length&&(b.$control.children(":not(input)").remove(),b.items=[],b.lastQuery=null,b.setCaret(0),b.setActiveItem(null),b.updatePlaceholder(),b.updateOriginalInput({silent:a}),b.refreshState(),b.showInput(),b.trigger("clear"))},insertAtCaret:function(b){var c=Math.min(this.caretPos,this.items.length);0===c?this.$control.prepend(b):a(this.$control[0].childNodes[c]).before(b),this.setCaret(c+1)},deleteSelection:function(b){var c,d,e,f,g,h,i,j,k,l=this;if(e=b&&b.keyCode===p?-1:1,f=G(l.$control_input[0]),l.$activeOption&&!l.settings.hideSelected&&(i=l.getAdjacentOption(l.$activeOption,-1).attr("data-value")),g=[],l.$activeItems.length){for(k=l.$control.children(".active:"+(e>0?"last":"first")),h=l.$control.children(":not(input)").index(k),e>0&&h++,c=0,d=l.$activeItems.length;c0&&f.start===l.$control_input.val().length&&g.push(l.items[l.caretPos]));if(!g.length||"function"==typeof l.settings.onDelete&&l.settings.onDelete.apply(l,[g])===!1)return!1;for("undefined"!=typeof h&&l.setCaret(h);g.length;)l.removeItem(g.pop());return l.showInput(),l.positionDropdown(),l.refreshOptions(!0),i&&(j=l.getOption(i),j.length&&l.setActiveOption(j)),!0},advanceSelection:function(a,b){var c,d,e,f,g,h,i=this;0!==a&&(i.rtl&&(a*=-1),c=a>0?"last":"first",d=G(i.$control_input[0]),i.isFocused&&!i.isInputHidden?(f=i.$control_input.val().length,g=a<0?0===d.start&&0===d.length:d.start===f,g&&!f&&i.advanceCaret(a,b)):(h=i.$control.children(".active:"+c),h.length&&(e=i.$control.children(":not(input)").index(h),i.setActiveItem(null),i.setCaret(a>0?e+1:e))))},advanceCaret:function(a,b){var c,d,e=this;0!==a&&(c=a>0?"next":"prev",e.isShiftDown?(d=e.$control_input[c](),d.length&&(e.hideInput(),e.setActiveItem(d),b&&b.preventDefault())):e.setCaret(e.caretPos+a))},setCaret:function(b){var c=this;if(b="single"===c.settings.mode?c.items.length:Math.max(0,Math.min(c.items.length,b)),!c.isPending){var d,e,f,g;for(f=c.$control.children(":not(input)"),d=0,e=f.length;d '}},b),c.setup=function(){var d=c.setup;return function(){d.apply(c,arguments),c.$dropdown_header=a(b.html(b)),c.$dropdown.prepend(c.$dropdown_header)}}()}),M.define("optgroup_columns",function(b){var c=this;b=a.extend({equalizeWidth:!0,equalizeHeight:!0},b),this.getAdjacentOption=function(b,c){var d=b.closest("[data-group]").find("[data-selectable]"),e=d.index(b)+c;return e>=0&&e
',a=a.firstChild,c.body.appendChild(a),b=d.width=a.offsetWidth-a.clientWidth,c.body.removeChild(a)),b},e=function(){var e,f,g,h,i,j,k;if(k=a("[data-group]",c.$dropdown_content),f=k.length,f&&c.$dropdown_content.width()){if(b.equalizeHeight){for(g=0,e=0;e
1&&(i=j-h*(f-1),k.eq(f-1).css({width:i})))}};(b.equalizeHeight||b.equalizeWidth)&&(B.after(this,"positionDropdown",e),B.after(this,"refreshOptions",e))}),M.define("remove_button",function(b){b=a.extend({label:"×",title:"Remove",className:"remove",append:!0},b);var c=function(b,c){c.className="remove-single";var d=b,e=''+c.label+" ",f=function(a,b){return a+b};b.setup=function(){var g=d.setup;return function(){if(c.append){var h=a(d.$input.context).attr("id"),i=(a("#"+h),d.settings.render.item);d.settings.render.item=function(a){return f(i.apply(b,arguments),e)}}g.apply(b,arguments),b.$control.on("click","."+c.className,function(a){a.preventDefault(),d.isLocked||d.clear()})}}()},d=function(b,c){var d=b,e=''+c.label+" ",f=function(a,b){var c=a.search(/(<\/[^>]+>\s*)$/);return a.substring(0,c)+b+a.substring(c)};b.setup=function(){var g=d.setup;return function(){if(c.append){var h=d.settings.render.item;d.settings.render.item=function(a){return f(h.apply(b,arguments),e)}}g.apply(b,arguments),b.$control.on("click","."+c.className,function(b){if(b.preventDefault(),!d.isLocked){var c=a(b.currentTarget).parent();d.setActiveItem(c),d.deleteSelection()&&d.setCaret(d.items.length)}})}}()};return"single"===this.settings.mode?void c(this,b):void d(this,b)}),M.define("restore_on_backspace",function(a){var b=this;a.text=a.text||function(a){return a[this.settings.labelField]},this.onKeyDown=function(){var c=b.onKeyDown;return function(b){var d,e;return b.keyCode===p&&""===this.$control_input.val()&&!this.$activeItems.length&&(d=this.caretPos-1,d>=0&&d
2 |
11 |
12 |
13 |
14 |
15 |
16 | {{ $description }}
17 |
--------------------------------------------------------------------------------
/OptionsFieldGenerator/resources/templates/MediaFieldGenerator.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OptionsForm.php:
--------------------------------------------------------------------------------
1 | options = $options;
31 | $this->optionsPage = $optionsPage;
32 | }
33 |
34 | final private function generate($type, $name, array $configs)
35 | {
36 | /** @var \Laraish\Contracts\Options\OptionsFieldGenerator $generator */
37 |
38 | $generatorClassName = '\\Laraish\\Options\\OptionsFieldGenerator\\' . ucfirst($type) . 'FieldGenerator';
39 | $generator = new $generatorClassName($name, $this->options, $this->optionsPage, $configs);
40 |
41 | return $generator->generate();
42 | }
43 |
44 | final public function text($name, array $configs = [])
45 | {
46 | return $this->generate('text', $name, $configs);
47 | }
48 |
49 |
50 | final public function hidden($name, array $configs = [])
51 | {
52 | return $this->generate('hidden', $name, $configs);
53 | }
54 |
55 |
56 | final public function number($name, array $configs = [])
57 | {
58 | return $this->generate('number', $name, $configs);
59 | }
60 |
61 |
62 | final public function url($name, array $configs = [])
63 | {
64 | return $this->generate('url', $name, $configs);
65 | }
66 |
67 |
68 | final public function email($name, array $configs = [])
69 | {
70 | return $this->generate('email', $name, $configs);
71 | }
72 |
73 |
74 | final public function color($name, array $configs = [])
75 | {
76 | return $this->generate('color', $name, $configs);
77 | }
78 |
79 |
80 | final public function search($name, array $configs = [])
81 | {
82 | return $this->generate('search', $name, $configs);
83 | }
84 |
85 |
86 | final public function date($name, array $configs = [])
87 | {
88 | return $this->generate('date', $name, $configs);
89 | }
90 |
91 |
92 | final public function time($name, array $configs = [])
93 | {
94 | return $this->generate('time', $name, $configs);
95 | }
96 |
97 |
98 | final public function range($name, array $configs = [])
99 | {
100 | return $this->generate('range', $name, $configs);
101 | }
102 |
103 |
104 | final public function checkbox($name, array $configs = [])
105 | {
106 | return $this->generate('checkbox', $name, $configs);
107 | }
108 |
109 |
110 | final public function checkboxes($name, array $configs = [])
111 | {
112 | return $this->generate('checkboxes', $name, $configs);
113 | }
114 |
115 |
116 | final public function radios($name, array $configs = [])
117 | {
118 | return $this->generate('radios', $name, $configs);
119 | }
120 |
121 |
122 | final public function file($name, array $configs = [])
123 | {
124 | return $this->generate('file', $name, $configs);
125 | }
126 |
127 | final public function media($name, array $configs = [])
128 | {
129 | return $this->generate('media', $name, $configs);
130 | }
131 |
132 | final public function password($name, array $configs = [])
133 | {
134 | return $this->generate('password', $name, $configs);
135 | }
136 |
137 |
138 | final public function textarea($name, array $configs = [])
139 | {
140 | return $this->generate('textarea', $name, $configs);
141 | }
142 |
143 |
144 | final public function select($name, array $configs = [])
145 | {
146 | return $this->generate('select', $name, $configs);
147 | }
148 | }
--------------------------------------------------------------------------------
/OptionsPage.php:
--------------------------------------------------------------------------------
1 | convertMapToProperties($configs, $acceptableOptions, $requiredOptions, function ($option) {
112 | return "The option `$option` must be defined when instantiate the class `" . static::class . "`.";
113 | });
114 | }
115 |
116 | /**
117 | * Register settings page.
118 | * @return void
119 | */
120 | final public function register()
121 | {
122 | // check user capabilities
123 | if ( ! current_user_can($this->capability())) {
124 | return;
125 | }
126 |
127 | // By default, the options groups for all registered settings require the manage_options capability.
128 | // This filter is required to change the capability required for a certain options page.
129 | $option_page = $this->optionGroup();
130 | add_filter("option_page_capability_{$option_page}", function ($capability) {
131 | return $this->capability();
132 | });
133 |
134 | // enqueue script and style
135 | $this->enqueueAssets();
136 |
137 | // if this is a sub-page, register this page as a sub-page to it's parent page
138 | if ($this->parent()) {
139 | $registerFunction = function () {
140 | $hookSuffix = add_submenu_page(
141 | ($this->parent() instanceof OptionsPageContract ? $this->parent()->menuSlug() : $this->parent()),
142 | $this->pageTitle(),
143 | $this->menuTitle(),
144 | $this->capability(),
145 | $this->menuSlug(),
146 | [$this, 'render']
147 | );
148 |
149 | $this->addHelpTabs($hookSuffix);
150 | };
151 | } else {
152 | $registerFunction = function () {
153 | $hookSuffix = add_menu_page(
154 | $this->pageTitle(),
155 | $this->menuTitle(),
156 | $this->capability(),
157 | $this->menuSlug(),
158 | [$this, 'render'],
159 | $this->iconUrl(),
160 | $this->position()
161 | );
162 |
163 | $this->addHelpTabs($hookSuffix);
164 | };
165 | }
166 |
167 | // register options page.
168 | add_action('admin_menu', $registerFunction);
169 |
170 | // register setting for this options page.
171 | add_action('admin_init', function () {
172 | register_setting($this->optionGroup(), $this->optionName());
173 | });
174 |
175 | // if there are any sections append them into this page.
176 | if ($this->sections) {
177 | foreach ($this->sections as &$section) {
178 | if ( ! $section instanceof OptionsSectionContract) {
179 | $section = new OptionsSection($section);
180 | }
181 |
182 | $section->register($this, $this->optionGroup(), $this->optionName());
183 | }
184 | }
185 | }
186 |
187 | private function addHelpTabs($hookSuffix)
188 | {
189 | if (empty($this->helpTabs)) {
190 | return;
191 | }
192 |
193 | add_action("load-{$hookSuffix}", function () {
194 | $screen = get_current_screen();
195 | foreach ($this->helpTabs as $index => $helpTab) {
196 | if (empty($helpTab['id'])) {
197 | $helpTab['id'] = uniqid('laraish__');
198 | }
199 | $screen->add_help_tab($helpTab);
200 | }
201 | });
202 | }
203 |
204 | /**
205 | * The function to be called to output the content for this page.
206 | * @return void
207 | */
208 | public function render()
209 | {
210 | // Display settings errors registered by `add_settings_error()`.
211 | // It's not necessary to call `settings_errors()` when the page is a sub-page of `Settings` page.
212 | // Because WordPress will call it automatically (see `wp-admin/options-head.php`)
213 | if ($GLOBALS['parent_file'] !== 'options-general.php') {
214 | settings_errors();
215 | }
216 |
217 | if (isset($this->renderFunction)) {
218 | $form = new OptionsForm(OptionsRepository::getInstance($this->optionName()), $this->menuSlug());
219 | call_user_func_array($this->renderFunction, [$this, $form]);
220 | } else {
221 | ?>
222 |
223 |
224 |
238 |
239 | scripts() OR $this->styles())) {
252 | return;
253 | }
254 |
255 | $thisPageHookSuffix = '_page_' . $this->menuSlug();
256 | if (preg_match("/{$thisPageHookSuffix}$/", $hook)) {
257 | $prefix = $this->menuSlug() . '__' . static::class . '__';
258 |
259 | if ($this->scripts()) {
260 | foreach ((array)$this->scripts() as $script) {
261 | static::enqueueAsset($script, 'script', $prefix);
262 | }
263 | }
264 | if ($this->styles()) {
265 | foreach ((array)$this->styles() as $style) {
266 | static::enqueueAsset($style, 'style', $prefix);
267 | }
268 | }
269 | }
270 | });
271 | }
272 |
273 | /**
274 | * Enqueue an style or script
275 | *
276 | * @param string|array $asset : The asset url or 'handle'. : The arguments passed to `wp_enqueue_style()` or `wp_enqueue_script()`.
277 | * @param string $type The type of the asset. Must be 'script' or 'style'.
278 | * @param string $prefix The prefix of the asset name. Ignored if the $asset is an array.
279 | */
280 | static public function enqueueAsset($asset, $type, $prefix = 'laraish__')
281 | {
282 | if ( ! in_array($type, ['script', 'style'])) {
283 | throw new InvalidArgumentException("The '\$type' argument should be either 'script' or 'style'. The given argument is '$type'.");
284 | }
285 |
286 | $scriptDependencies = ['jquery', 'underscore', 'backbone'];
287 |
288 | if (is_array($asset)) {
289 | if (Arr::isSequential($asset)) {
290 | call_user_func_array("wp_enqueue_$type", $asset);
291 | } else {
292 | if ( ! isset($asset['name'])) {
293 | throw new InvalidArgumentException('The `name` key is required.');
294 | }
295 |
296 | $defaults = [
297 | 'src' => '',
298 | 'dependencies' => [],
299 | 'version' => false,
300 | 'media' => 'all',
301 | 'in_footer' => false
302 | ];
303 |
304 | $args = array_merge($defaults, $asset);
305 |
306 | if ($type === 'style') {
307 | wp_enqueue_style($args['name'], $args['src'], $args['dependencies'], $args['version'], $args['media']);
308 | } else {
309 | if ( ! isset($asset['dependencies'])) {
310 | $args['dependencies'] = $scriptDependencies;
311 | }
312 | wp_enqueue_script($args['name'], $args['src'], $args['dependencies'], $args['version'], $args['in_footer']);
313 | }
314 | }
315 | } else {
316 | $assetName = $asset;
317 |
318 | // If asset is a URL
319 | if (filter_var($asset, FILTER_VALIDATE_URL)) {
320 | $assetName = $prefix . pathinfo($asset)['basename'];
321 | }
322 |
323 | if ($type === 'style') {
324 | wp_enqueue_style($assetName, $asset);
325 | } else {
326 | wp_enqueue_script($assetName, $asset, $scriptDependencies);
327 | }
328 | }
329 | }
330 |
331 | /**
332 | * The slug name to refer to this menu by (should be unique for this menu).
333 | * @return string
334 | */
335 | final public function menuSlug()
336 | {
337 | return $this->menuSlug;
338 | }
339 |
340 | /**
341 | * The text to be used for the menu.
342 | * @return string
343 | */
344 | final public function menuTitle()
345 | {
346 | return $this->menuTitle;
347 | }
348 |
349 | /**
350 | * The text to be displayed in the title tags of the page when the menu is selected.
351 | * @return string
352 | */
353 | final public function pageTitle()
354 | {
355 | return $this->pageTitle;
356 | }
357 |
358 | /**
359 | * The option-group to be used in the page.
360 | * @return string
361 | */
362 | final public function optionGroup()
363 | {
364 | return $this->optionGroup;
365 | }
366 |
367 | /**
368 | * The option-name to be used in the page.
369 | * @return string
370 | */
371 | final public function optionName()
372 | {
373 | return $this->optionName;
374 | }
375 |
376 | /**
377 | * The capability required for this menu to be displayed to the user.
378 | * @return string
379 | */
380 | final public function capability()
381 | {
382 | return $this->capability;
383 | }
384 |
385 | /**
386 | * The URL to the icon to be used for this menu.
387 | * @return string
388 | */
389 | final public function iconUrl()
390 | {
391 | return $this->iconUrl;
392 | }
393 |
394 | /**
395 | * The position in the menu order this one should appear.
396 | * @return int
397 | */
398 | final public function position()
399 | {
400 | return $this->position;
401 | }
402 |
403 | /**
404 | * The parent page of this page if any.
405 | * @return null|string|OptionsPage
406 | */
407 | final public function parent()
408 | {
409 | return $this->parent;
410 | }
411 |
412 | /**
413 | * Script to be enqueued.
414 | * @return string
415 | */
416 | final public function scripts()
417 | {
418 | return $this->scripts;
419 | }
420 |
421 | /**
422 | * Style to be enqueued.
423 | * @return string
424 | */
425 | final public function styles()
426 | {
427 | return $this->styles;
428 | }
429 | }
--------------------------------------------------------------------------------
/OptionsRepository.php:
--------------------------------------------------------------------------------
1 | optionName = $optionName;
61 | $this->options = (array)$options;
62 |
63 | add_action("update_option_{$optionName}", [$this, 'syncOption'], 10, 2);
64 | }
65 |
66 |
67 | /**
68 | * Synchronize with the latest value of the option.
69 | *
70 | * @param $old_value
71 | * @param $value
72 | */
73 | final public function syncOption($old_value, $value)
74 | {
75 | $this->options = (array)$value;
76 | }
77 |
78 | /**
79 | * Get a particular value of an option in an options array.
80 | *
81 | * @param $key
82 | * @param mixed $default
83 | *
84 | * @return mixed
85 | */
86 | public function get($key, $default = null)
87 | {
88 | if (array_key_exists($key, $this->options)) {
89 | return $this->options[$key];
90 | }
91 |
92 | $this->set($key, $default);
93 |
94 | return $default;
95 | }
96 |
97 | /**
98 | * Update the option.
99 | *
100 | * @param string $key
101 | * @param mixed $value
102 | *
103 | * @return boolean
104 | */
105 | public function set($key, $value)
106 | {
107 | $this->options[$key] = $value;
108 |
109 | return update_option($this->optionName(), $this->options);
110 | }
111 |
112 | /**
113 | * Delete the option from database.
114 | *
115 | * @return boolean
116 | */
117 | public function delete()
118 | {
119 | return delete_option($this->optionName());
120 | }
121 |
122 | /**
123 | * Get the option-name
124 | * @return string
125 | */
126 | final public function optionName()
127 | {
128 | return $this->optionName;
129 | }
130 | }
--------------------------------------------------------------------------------
/OptionsSection.php:
--------------------------------------------------------------------------------
1 | convertMapToProperties($configs, $acceptableOptions, $requiredOptions, function ($option) {
61 | return "The option `$option` must be defined when instantiate the class `" . static::class . "`.";
62 | });
63 | }
64 |
65 | /**
66 | * Register the section to a specific page.
67 | *
68 | * @param OptionsPageContract|string $optionsPage menu-slug of a page or a OptionsPage object
69 | * @param string $optionGroup The option-group to be used.
70 | * @param string $optionName The option-group to be used.
71 | * @param bool $hook Determine if call register functions in appropriate hook or not.
72 | *
73 | * @return void
74 | */
75 | final public function register($optionsPage, $optionGroup, $optionName, $hook = true)
76 | {
77 | // check user capabilities
78 | if ( ! current_user_can($this->capability())) {
79 | return;
80 | }
81 |
82 | $page = $optionsPage instanceof OptionsPageContract ? $optionsPage->menuSlug() : $optionsPage;
83 |
84 | $register = function ($page, OptionsSectionContract $section, $optionGroup, $optionName) {
85 | add_settings_section($section->id(), $section->title(), [$section, 'render'], $page);
86 | if (isset($this->fields)) {
87 | foreach ($this->fields as &$field) {
88 | if ( ! $field instanceof OptionsFieldContract) {
89 | $field = new OptionsField($field);
90 | }
91 | $field->register($page, $section->id(), $optionGroup, $optionName, false);
92 | }
93 | }
94 | };
95 |
96 | if ($hook) {
97 | add_action('admin_init', function () use ($page, $register, $optionGroup, $optionName) {
98 | $register($page, $this, $optionGroup, $optionName);
99 | });
100 | } else {
101 | $register($page, $this, $optionGroup, $optionName);
102 | }
103 | }
104 |
105 | /**
106 | * The id of the section.
107 | * @return string
108 | */
109 | final public function id()
110 | {
111 | return $this->id;
112 | }
113 |
114 | /**
115 | * Title of the section.
116 | * @return string
117 | */
118 | final public function title()
119 | {
120 | return $this->title;
121 | }
122 |
123 | /**
124 | * The capability required for this field to be displayed to the current user.
125 | * @return string
126 | */
127 | public function capability()
128 | {
129 | return $this->capability;
130 | }
131 |
132 | /**
133 | * The description of the section.
134 | * @return string
135 | */
136 | final public function description()
137 | {
138 | return $this->description;
139 | }
140 |
141 | /**
142 | * Function that fills the section with the desired content. The function should echo its output.
143 | * @return void
144 | */
145 | public function render()
146 | {
147 | if (isset($this->renderFunction)) {
148 | call_user_func_array($this->renderFunction, [$this]);
149 | } elseif ($this->description()) {
150 | echo '' . $this->description() . '
';
151 | }
152 | }
153 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laraish/options",
3 | "description": "Package for creating options page in WordPress.",
4 | "keywords": [
5 | "framework",
6 | "laravel",
7 | "wordpress"
8 | ],
9 | "license": "MIT",
10 | "homepage": "https://github.com/laraish/options",
11 | "support": {
12 | "issues": "https://github.com/laraish/options/issues",
13 | "source": "https://github.com/laraish/options"
14 | },
15 | "authors": [
16 | {
17 | "name": "yaquawa",
18 | "email": "yaquawa@gmail.com"
19 | }
20 | ],
21 | "require": {
22 | "php": "^8.1",
23 | "laraish/contracts": "^3.0",
24 | "laraish/support": "^3.0"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Laraish\\Options\\": "./"
29 | }
30 | },
31 | "scripts": {
32 | "fix-cs": ["prettier **/*.php --write"]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | A simple framework for creating WordPress options page.
2 |
3 | #Basic Usage
4 |
5 | Here is an example for creating an options page.
6 |
7 | ```php
8 | use Laraish\Options\OptionsPage;
9 |
10 | $optionsPage = new OptionsPage([
11 | 'menuSlug' => 'my_options_page',
12 | 'menuTitle' => 'My Options Page',
13 | 'pageTitle' => 'My Options Page',
14 | 'iconUrl' => 'dashicons-welcome-learn-more',
15 | 'optionGroup' => 'my_options_page',
16 | 'optionName' => 'my_options',
17 | 'capability' => 'manage_categories',
18 | 'sections' => [
19 | [
20 | 'id' => 'section-id',
21 | 'title' => 'Section title',
22 | 'description' => 'Section Description',
23 | 'fields' => [
24 | [
25 | 'id' => 'my-avatar',
26 | 'type' => 'media',
27 | 'title' => 'Avatar',
28 | 'description' => 'Choose an image for your avatar.'
29 | ],
30 | [
31 | 'id' => 'my-email',
32 | 'type' => 'email',
33 | 'title' => 'E-mail',
34 | ],
35 | [
36 | 'id' => 'my-nice-name',
37 | 'type' => 'text',
38 | 'title' => 'Nice name',
39 | 'attributes' => [
40 | 'placeholder' => 'your nice name',
41 | 'maxlength' => 10,
42 | 'class' => 'regular-text'
43 | ],
44 | ],
45 | [
46 | 'id' => 'my-description',
47 | 'type' => 'textarea',
48 | 'title' => 'About Me',
49 | ],
50 | ]
51 | ]
52 | ],
53 | 'helpTabs' => [
54 | [
55 | 'title' => 'tab-1',
56 | 'content' => 'description here
',
57 | ],
58 | [
59 | 'title' => 'tab-2',
60 | 'content' => 'description here
',
61 | ]
62 | ],
63 | 'scripts' => ['https://unpkg.com/vue/dist/vue.js'],
64 | 'styles' => ['/my-css.css'],
65 | ]);
66 |
67 | $optionsPage->register();
68 |
69 | ```
70 |
71 | The example code above is going to create an options page looks like this
72 |
73 |
74 |
75 | ## Usage of `OptionsSection` and `OptionsField`
76 | You can also replace the value of `'sections'` with an array of `OptionsSection` objects and replace the value of `'fields'` with an array of `OptionsField` objects.
77 |
78 | ```php
79 | use Laraish\Options\OptionsPage;
80 |
81 | /*------------------------------------*\
82 | # Field objects
83 | \*------------------------------------*/
84 |
85 | $avatarField = new OptionsField([
86 | 'id' => 'my-avatar',
87 | 'type' => 'media',
88 | 'title' => 'Avatar',
89 | 'description' => 'Choose an image for your avatar.'
90 | ]);
91 |
92 | $emailField = new OptionsField([
93 | 'id' => 'my-email',
94 | 'type' => 'email',
95 | 'title' => 'E-mail',
96 | ]);
97 |
98 | $niceNameField = new OptionsField([
99 | 'id' => 'my-nice-name',
100 | 'type' => 'text',
101 | 'title' => 'Nice name',
102 | 'attributes' => [
103 | 'placeholder' => 'your nice name',
104 | 'maxlength' => 10,
105 | 'class' => 'regular-text'
106 | ]
107 | ]);
108 |
109 | $descriptionField = new OptionsField([
110 | 'id' => 'my-description',
111 | 'type' => 'textarea',
112 | 'title' => 'About Me',
113 | ]);
114 |
115 | $demoField = new OptionsField([
116 | 'id' => 'my-demo',
117 | 'type' => 'text',
118 | 'title' => 'Demo text field',
119 | ]);
120 |
121 |
122 |
123 | /*------------------------------------*\
124 | # Section object
125 | \*------------------------------------*/
126 |
127 | $demoSection = new OptionsSection([
128 | 'id' => 'section-id',
129 | 'title' => 'Section title',
130 | 'description' => 'Section Description',
131 | 'fields' => [
132 | $demoField,
133 | ]
134 | ]);
135 |
136 |
137 |
138 | /*------------------------------------*\
139 | # Page object
140 | \*------------------------------------*/
141 |
142 | $optionsPage = new OptionsPage([
143 | 'menuSlug' => 'my_options_page',
144 | 'menuTitle' => 'My Options Page',
145 | 'pageTitle' => 'My Options Page',
146 | 'iconUrl' => 'dashicons-welcome-learn-more',
147 | 'optionGroup' => 'my_options_page',
148 | 'optionName' => 'my_options',
149 | 'capability' => 'manage_categories',
150 | 'sections' => [
151 | [
152 | 'id' => 'section-id',
153 | 'title' => 'Section title',
154 | 'description' => 'Section Description',
155 | 'fields' => [
156 | $avatarField,
157 | $emailField,
158 | $niceNameField,
159 | $descriptionField,
160 | ]
161 | ],
162 |
163 | $demoSection,
164 | ],
165 | 'helpTabs' => [
166 | [
167 | 'title' => 'tab-1',
168 | 'content' => 'description here
',
169 | ],
170 | [
171 | 'title' => 'tab-2',
172 | 'content' => 'description here
',
173 | ]
174 | ],
175 | 'scripts' => ['https://unpkg.com/vue/dist/vue.js'],
176 | 'styles' => ['/my-css.css'],
177 | ]);
178 |
179 |
180 | /*------------------------------------*\
181 | # register page/section/field
182 | \*------------------------------------*/
183 |
184 | // register page
185 | $optionsPage->register();
186 |
187 | // register a section to a page(Settings -> General)
188 | $demoSection->register('general', 'demo-section-group', 'demo-section-options');
189 |
190 | // register a field to a section of page(Settings -> General -> `default` section)
191 | $demoField->register('general', 'default', 'demo-section-group', 'demo-section-options');
192 | ```
193 |
194 | ## Get the value of an option
195 | You can use the `OptionsRepository` to get the value of an option.
196 |
197 | ```php
198 | use Laraish\Options\OptionsRepository;
199 |
200 | // Get the value of 'my-nice-name' in 'my_options'.
201 | // 'my_options' is the option name.
202 | $myOptions = new OptionsRepository('my_options');
203 | echo $myOptions->get('my-nice-name');
204 |
205 | // also you can set the value by calling the set() method.
206 | $myOptions->set('my_options','new value');
207 | ```
208 |
209 |
210 |
211 |
212 | # `OptionsPage`
213 |
214 | ## Options
215 |
216 | ### `menuSlug`
217 | | Type | required |
218 | |--------|----------|
219 | | string | yes |
220 |
221 | The slug name to refer to the menu by (should be unique for this menu).
222 |
223 | ### `menuTitle`
224 | | Type | required |
225 | |--------|----------|
226 | | string | yes |
227 |
228 | The text to be used for the menu.
229 |
230 | ### `pageTitle`
231 | | Type | required |
232 | |--------|----------|
233 | | string | yes |
234 |
235 | The text to be displayed in the title tags of the page when the menu is selected.
236 |
237 | ### `optionGroup`
238 | | Type | required |
239 | |--------|----------|
240 | | string | yes |
241 |
242 | The option group you wish to use in the page.
243 |
244 | ### `optionName`
245 | | Type | required |
246 | |--------|----------|
247 | | string | yes |
248 |
249 | The option name you wish to use in the page.
250 |
251 | ### `capability`
252 | | Type | Default |
253 | |--------|------------------|
254 | | string | 'manage_options' |
255 |
256 | The [capability](https://codex.wordpress.org/Roles_and_Capabilities) required for this menu to be displayed to the user.
257 |
258 | ### `position`
259 | | Type | Default |
260 | |--------|---------|
261 | | int | null |
262 |
263 | The position in the menu order this one should appear.
264 |
265 | ### `iconUrl`
266 | | Type | Default |
267 | |--------|-------- |
268 | | string | '' |
269 |
270 | The URL (or [icon name](https://developer.wordpress.org/resource/dashicons/)) to the icon to be used for the menu.
271 |
272 | ### `parent`
273 |
274 | | Type | Default |
275 | |-------------------------------------|---------|
276 | | null / string / OptionsPageContract | null |
277 |
278 | If you wish to make the page as a sub-page of a top-level page, set the top top-level page here.
279 |
280 | ### `sections`
281 | | Type | Default |
282 | |-------|-------- |
283 | | array | [] |
284 |
285 | Settings-Sections to be inserted into the page. Every element of this array represents a Settings-Section.
286 | See [Options for OptionsSection](#options-1) for more details.
287 |
288 | ### `renderFunction`
289 | | Type | Default |
290 | |----------|-------- |
291 | | callable | null |
292 |
293 | The function to be called to output the content for the page.
294 | This function retrieves two arguments; the first one is an instance of `OptionsPage`, the second one is an instance of `OptionsForm`. By using the `OptionsForm` object you can create form input elements much easier than by hard coding.
295 |
296 | Below is an example of customizing the output of an options page.
297 |
298 | ```php
299 | use Laraish\Options\OptionsPage;
300 |
301 | $optionsPage = new OptionsPage([
302 | 'menuSlug' => 'my_options_page',
303 | 'menuTitle' => 'My Options Page',
304 | 'pageTitle' => 'My Options Page',
305 | 'optionGroup' => 'my_options_page',
306 | 'optionName' => 'my_options',
307 | 'renderFunction' => function (OptionsPage $page, OptionsForm $form) {
308 | ?>
309 |
310 |
pageTitle(); ?>
311 |
328 |
329 |
461 | attributes (array)
462 | The attributes of the field element.
463 | For example ['placeholder'=> 'Type your name', 'class'=> 'foo bar baz']
.
464 |
465 | defaultValue (mixed)
466 | The default value of the field.
467 |
468 |
469 | ## Color
470 | Same as [Common Options](#common-options).
471 |
472 | ## Date
473 | Same as [Common Options](#common-options).
474 |
475 | ## Email
476 | Same as [Common Options](#common-options).
477 |
478 | ## Hidden
479 | Same as [Common Options](#common-options).
480 |
481 | ## Number
482 | Same as [Common Options](#common-options).
483 |
484 | ## Password
485 | Same as [Common Options](#common-options).
486 |
487 | ## Range
488 | Same as [Common Options](#common-options).
489 |
490 | ## Search
491 | Same as [Common Options](#common-options).
492 |
493 | ## Textarea
494 | Same as [Common Options](#common-options).
495 |
496 | ## Text
497 | Same as [Common Options](#common-options).
498 |
499 | ## Time
500 | Same as [Common Options](#common-options).
501 |
502 | ## Url
503 | Same as [Common Options](#common-options).
504 |
505 | ## Checkboxes
506 |
507 | horizontal (true)
508 | The layout of the checkboxes. Set to false
if you want to put the checkboxes vertically.
509 | options ([])
510 | An array of options. For example ['Red'=> '#f00', 'Green'=> '#0f0', 'Blue'=> '#00f']
.
511 |
512 |
513 | ## Checkbox
514 |
515 | text (string)
516 | The text of the checkbox.
517 | value (string)
518 | The value of the checkbox.
519 |
520 |
521 | ## Radios
522 | Same as [Checkboxes](#checkboxes).
523 |
524 | ## Select
525 | Same as [Checkboxes](#checkboxes).
526 |
527 | ## File
528 |
529 | maxFileSize (string)
530 | The maximum file size (byte) of the file.
531 | isJson (bool)
532 | Set to true
if you are going to upload a json file. Default value is false
.
533 |
534 |
535 | ## Media
536 |
537 | button_text (string)
538 | The text of the media uploader button.
539 | media_uploader_title (string)
540 | The title of media uploader.
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
--------------------------------------------------------------------------------