1 | <?php |
||||||
2 | |||||||
3 | namespace Flynt\Utils; |
||||||
4 | |||||||
5 | use ACFComposer; |
||||||
6 | |||||||
7 | class Options |
||||||
8 | { |
||||||
9 | const OPTION_TYPES = [ |
||||||
10 | 'translatable' => [ |
||||||
11 | 'title' => 'Translatable Options', |
||||||
12 | 'icon' => 'dashicons-translation', |
||||||
13 | 'translatable' => true |
||||||
14 | ], |
||||||
15 | 'global' => [ |
||||||
16 | 'title' => 'Global Options', |
||||||
17 | 'icon' => 'dashicons-admin-site', |
||||||
18 | 'translatable' => false |
||||||
19 | ] |
||||||
20 | ]; |
||||||
21 | |||||||
22 | protected static $initialized = false; |
||||||
23 | |||||||
24 | protected static $optionPages = []; |
||||||
25 | |||||||
26 | protected static $registeredOptions = []; |
||||||
27 | |||||||
28 | protected static function init() |
||||||
29 | { |
||||||
30 | if (static::$initialized) { |
||||||
31 | return; |
||||||
32 | } else { |
||||||
33 | static::$initialized = true; |
||||||
34 | } |
||||||
35 | |||||||
36 | add_action('current_screen', function ($currentScreen) { |
||||||
37 | $currentScreenId = strtolower($currentScreen->id); |
||||||
38 | foreach (static::OPTION_TYPES as $optionType => $option) { |
||||||
39 | $isTranslatable = $option['translatable']; |
||||||
40 | // NOTE: because the first subpage starts with toplevel instead (there is no overview page) |
||||||
41 | $toplevelPageId = strtolower('toplevel_page_' . $optionType); |
||||||
42 | $menuTitle = static::$optionPages[$optionType]['menu_title']; |
||||||
43 | // NOTE: all other subpages have the parent menu-title in front instead |
||||||
44 | $subPageId = strtolower( |
||||||
45 | sanitize_title($menuTitle) . '_page_' . $optionType |
||||||
46 | ); |
||||||
47 | $isCurrentPage = |
||||||
48 | StringHelpers::startsWith( |
||||||
49 | $toplevelPageId, |
||||||
50 | $currentScreenId |
||||||
51 | ) || |
||||||
52 | StringHelpers::startsWith($subPageId, $currentScreenId); |
||||||
53 | if (!$isTranslatable && $isCurrentPage) { |
||||||
54 | // set acf field values to default language |
||||||
55 | add_filter( |
||||||
56 | 'acf/settings/current_language', |
||||||
57 | 'Flynt\Utils\Options::getDefaultAcfLanguage', |
||||||
58 | 101 |
||||||
59 | ); |
||||||
60 | // hide language selector in admin bar |
||||||
61 | add_action('wp_before_admin_bar_render', function () { |
||||||
62 | $adminBar = $GLOBALS['wp_admin_bar']; |
||||||
63 | $adminBar->remove_menu('WPML_ALS'); |
||||||
64 | }); |
||||||
65 | } |
||||||
66 | } |
||||||
67 | }); |
||||||
68 | } |
||||||
69 | |||||||
70 | protected static function createOptionPage($optionType) |
||||||
71 | { |
||||||
72 | if (empty(static::$optionPages[$optionType])) { |
||||||
73 | $option = static::OPTION_TYPES[$optionType]; |
||||||
74 | $title = _x($option['title'], 'title', 'flynt'); |
||||||
75 | $slug = ucfirst($optionType) . 'Options'; |
||||||
76 | |||||||
77 | acf_add_options_page([ |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
78 | 'page_title' => $title, |
||||||
79 | 'menu_title' => $title, |
||||||
80 | 'redirect' => true, |
||||||
81 | 'menu_slug' => $slug, |
||||||
82 | 'icon_url' => $option['icon'] |
||||||
83 | ]); |
||||||
84 | |||||||
85 | static::$optionPages[$optionType] = [ |
||||||
86 | 'menu_slug' => $slug, |
||||||
87 | 'menu_title' => $title |
||||||
88 | ]; |
||||||
89 | } |
||||||
90 | return static::$optionPages[$optionType]; |
||||||
91 | } |
||||||
92 | |||||||
93 | protected static function createOptionSubPage($optionType, $optionCategory = "Default") |
||||||
94 | { |
||||||
95 | if (empty(static::$optionPages[$optionType]['sub_pages'][$optionCategory])) { |
||||||
96 | $optionPage = static::createOptionPage($optionType); |
||||||
97 | $categoryTitle = _x($optionCategory, 'title', 'flynt'); |
||||||
98 | $categorySlug = implode('-', [$optionPage['menu_slug'], $optionCategory]); |
||||||
99 | $pageConfig = [ |
||||||
100 | 'page_title' => $optionPage['menu_title'] . ': ' . $categoryTitle, |
||||||
101 | 'menu_title' => $categoryTitle, |
||||||
102 | 'redirect' => true, |
||||||
103 | 'menu_slug' => $categorySlug, |
||||||
104 | 'parent_slug' => $optionPage['menu_slug'] |
||||||
105 | ]; |
||||||
106 | acf_add_options_page($pageConfig); |
||||||
0 ignored issues
–
show
The function
acf_add_options_page was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
107 | static::$optionPages[$optionType]['sub_pages'][ |
||||||
108 | $optionCategory |
||||||
109 | ] = [ |
||||||
110 | 'menu_slug' => $categorySlug, |
||||||
111 | 'menu_title' => $categoryTitle |
||||||
112 | ]; |
||||||
113 | $fieldGroup = ACFComposer\ResolveConfig::forFieldGroup([ |
||||||
114 | 'name' => $categorySlug, |
||||||
115 | 'title' => $categoryTitle, |
||||||
116 | 'style' => 'seamless', |
||||||
117 | 'fields' => [], |
||||||
118 | 'location' => [ |
||||||
119 | [ |
||||||
120 | [ |
||||||
121 | 'param' => 'options_page', |
||||||
122 | 'operator' => '==', |
||||||
123 | 'value' => $categorySlug |
||||||
124 | ] |
||||||
125 | ] |
||||||
126 | ] |
||||||
127 | ]); |
||||||
128 | acf_add_local_field_group($fieldGroup); |
||||||
0 ignored issues
–
show
The function
acf_add_local_field_group was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
129 | } |
||||||
130 | } |
||||||
131 | |||||||
132 | |||||||
133 | // ============ |
||||||
134 | // PUBLIC API |
||||||
135 | // ============ |
||||||
136 | public static function getTranslatable($scope, $fieldName = null) |
||||||
137 | { |
||||||
138 | return self::get('translatable', $scope, $fieldName); |
||||||
139 | } |
||||||
140 | |||||||
141 | public static function getGlobal($scope, $fieldName = null) |
||||||
142 | { |
||||||
143 | return self::get('global', $scope, $fieldName); |
||||||
144 | } |
||||||
145 | |||||||
146 | /** |
||||||
147 | * Get option(s) from a sub page. |
||||||
148 | * |
||||||
149 | * Returns an option of a sub page. If no field name is provided it will get all option of that sub page. |
||||||
150 | * Parameters are expected to be camelCase. |
||||||
151 | * |
||||||
152 | * @since 0.2.0 introduced as a replacement for OptionPages::getOption and OptionPages::getOptions |
||||||
153 | * @since 0.2.2 added check for required hooks to have run to alert of timing issues when used incorrectly |
||||||
154 | * |
||||||
155 | * @param string $optionType Type of option page. Either global or translatable. |
||||||
156 | * @param string $scope Scope of the option. |
||||||
157 | * @param string|null $fieldName (optional) Name of the field to get. |
||||||
158 | * @return mixed The value of the option or array of options. False if subpage doesn't exist or no option was found. |
||||||
159 | **/ |
||||||
160 | public static function get($optionType, $scope, $fieldName = null) |
||||||
161 | { |
||||||
162 | if (!static::checkRequiredHooks($optionType, $scope, $fieldName)) { |
||||||
163 | return false; |
||||||
164 | } |
||||||
165 | |||||||
166 | // convert parameters |
||||||
167 | $optionType = lcfirst($optionType); |
||||||
168 | $scope = ucfirst($scope); |
||||||
169 | |||||||
170 | if (!isset(static::OPTION_TYPES[$optionType])) { |
||||||
171 | return false; |
||||||
172 | } |
||||||
173 | |||||||
174 | $prefix = implode('_', [$optionType, $scope, '']); |
||||||
175 | $isTranslatable = static::OPTION_TYPES[$optionType]['translatable']; |
||||||
176 | if (empty($fieldName)) { |
||||||
177 | $optionNames = ((static::$registeredOptions[$optionType] ?? [])[$scope] ?? []); |
||||||
178 | return array_combine( |
||||||
179 | $optionNames, |
||||||
180 | array_map(function ($optionName) use ($prefix, $isTranslatable) { |
||||||
181 | $fieldKey = $prefix . $optionName; |
||||||
182 | return static::getOptionField($fieldKey, $isTranslatable); |
||||||
183 | }, $optionNames) |
||||||
184 | ); |
||||||
185 | } else { |
||||||
186 | $fieldKey = $prefix . $fieldName; |
||||||
187 | return static::getOptionField($fieldKey, $isTranslatable); |
||||||
188 | } |
||||||
189 | } |
||||||
190 | |||||||
191 | public static function addTranslatable($scope, $fields, $category = 'Default') |
||||||
192 | { |
||||||
193 | static::addOptions($scope, $fields, 'translatable', $category); |
||||||
194 | } |
||||||
195 | |||||||
196 | public static function addGlobal($scope, $fields, $category = 'Default') |
||||||
197 | { |
||||||
198 | static::addOptions($scope, $fields, 'global', $category); |
||||||
199 | } |
||||||
200 | |||||||
201 | public static function addOptions($scope, $fields, $type, $category = 'Default') |
||||||
202 | { |
||||||
203 | static::createOptionSubPage($type, $category); |
||||||
204 | $fieldGroupTitle = StringHelpers::splitCamelCase($scope); |
||||||
205 | $optionsPageSlug = self::$optionPages[$type]['sub_pages'][$category]['menu_slug']; |
||||||
206 | $fieldGroupName = implode('_', [$type, $scope]); |
||||||
207 | static::addOptionsFieldGroup( |
||||||
208 | $fieldGroupName, |
||||||
209 | $fieldGroupTitle, |
||||||
210 | $optionsPageSlug, |
||||||
211 | $fields |
||||||
212 | ); |
||||||
213 | static::registerOptionNames($type, $scope, $fields); |
||||||
214 | } |
||||||
215 | |||||||
216 | protected static function registerOptionNames($type, $scope, $fields) |
||||||
217 | { |
||||||
218 | static::$registeredOptions[$type] = static::$registeredOptions[$type] ?? []; |
||||||
219 | static::$registeredOptions[$type] = static::$registeredOptions[$type] ?? []; |
||||||
220 | static::$registeredOptions[$type][$scope] = array_column($fields, 'name'); |
||||||
221 | return static::$registeredOptions; |
||||||
222 | } |
||||||
223 | |||||||
224 | protected static function addOptionsFieldGroup($name, $title, $optionsPageSlug, $fields) |
||||||
225 | { |
||||||
226 | $fieldGroup = ACFComposer\ResolveConfig::forFieldGroup( |
||||||
227 | [ |
||||||
228 | 'name' => $name, |
||||||
229 | 'title' => $title, |
||||||
230 | 'fields' => array_merge([ |
||||||
231 | [ |
||||||
232 | 'label' => $title, |
||||||
233 | 'name' => '', |
||||||
234 | 'type' => 'accordion', |
||||||
235 | 'placement' => 'left', |
||||||
236 | 'endpoint' => false, |
||||||
237 | ] |
||||||
238 | ], $fields), |
||||||
239 | 'style' => 'seamless', |
||||||
240 | 'location' => [ |
||||||
241 | [ |
||||||
242 | [ |
||||||
243 | 'param' => 'options_page', |
||||||
244 | 'operator' => '==', |
||||||
245 | 'value' => $optionsPageSlug |
||||||
246 | ] |
||||||
247 | ] |
||||||
248 | ] |
||||||
249 | ] |
||||||
250 | ); |
||||||
251 | $fieldGroup['fields'] = static::prefixFields($fieldGroup['fields'], $name); |
||||||
252 | foreach ($fieldGroup['fields'] as $field) { |
||||||
253 | acf_add_local_field(array_merge($field, [ |
||||||
0 ignored issues
–
show
The function
acf_add_local_field was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
254 | 'parent' => 'group_' . $optionsPageSlug, |
||||||
255 | ])); |
||||||
256 | } |
||||||
257 | } |
||||||
258 | |||||||
259 | protected static function prefixFields($fields, $prefix) |
||||||
260 | { |
||||||
261 | return array_map(function ($field) use ($prefix) { |
||||||
262 | $field['name'] = $prefix . '_' . $field['name']; |
||||||
263 | return $field; |
||||||
264 | }, $fields); |
||||||
265 | } |
||||||
266 | |||||||
267 | protected static function checkRequiredHooks($optionType, $scope, $fieldName) |
||||||
268 | { |
||||||
269 | if (did_action('acf/init') < 1) { |
||||||
270 | $parameters = "${optionType}, ${scope}, "; |
||||||
271 | $parameters .= isset($fieldName) ? $fieldName : 'NULL'; |
||||||
272 | trigger_error("Could not get option/s for [${parameters}]. Required hooks have not yet been executed! Please make sure to run `Options::get()` after the `acf/init` action is finished.", E_USER_WARNING); |
||||||
273 | return false; |
||||||
274 | } |
||||||
275 | return true; |
||||||
276 | } |
||||||
277 | |||||||
278 | protected static function getOptionField($key, $translatable) |
||||||
279 | { |
||||||
280 | if ($translatable) { |
||||||
281 | $option = get_field('field_' . $key, 'option'); |
||||||
0 ignored issues
–
show
The function
get_field was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
282 | } else { |
||||||
283 | // switch to default language to get global options |
||||||
284 | add_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100); |
||||||
285 | |||||||
286 | $option = get_field('field_' . $key, 'option'); |
||||||
287 | |||||||
288 | remove_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100); |
||||||
289 | } |
||||||
290 | |||||||
291 | return $option; |
||||||
292 | } |
||||||
293 | |||||||
294 | public static function getDefaultAcfLanguage() |
||||||
295 | { |
||||||
296 | return acf_get_setting('default_language'); |
||||||
0 ignored issues
–
show
The function
acf_get_setting was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
297 | } |
||||||
298 | } |
||||||
299 |