├── .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 .= ""; 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 .= ""; 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 = ""; 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 = ""; 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'
'+b(a[d])+"
"},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;eh&&(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
'+a.title+'×
'}},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;e1&&(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 |
3 |
4 | 5 |
    6 |
  • 7 |
8 |
{{ $filename }}
9 |
10 |
11 | 12 |
13 | 14 |
15 | 16 | {{ $description }} 17 |
-------------------------------------------------------------------------------- /OptionsFieldGenerator/resources/templates/MediaFieldGenerator.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
    6 |
  • 7 |
  • 8 |
9 |
{{ $filename }}
10 |
11 |
12 | 13 |
14 | 15 |
16 | 17 | {{ $description }} 18 | 19 | 20 | 21 |
-------------------------------------------------------------------------------- /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 |
225 | optionGroup) { 227 | // output security fields for the registered setting "{{ $this->optionGroup }}" 228 | settings_fields($this->optionGroup); 229 | } 230 | 231 | // output setting sections and their fields 232 | do_settings_sections($this->menuSlug()); 233 | 234 | // output save settings button 235 | submit_button(); 236 | ?> 237 |
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 |
312 | optionGroup }}" 314 | settings_fields($page->optionGroup()); 315 | 316 | 317 | // output fields 318 | ?> 319 |

email('email', ['attributes' => ['placeholder' => 'foo@example.com']]); ?>

320 |

textarea('about-us'); ?>

321 | 322 | 323 | 327 |
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 | --------------------------------------------------------------------------------