Options::get()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 28
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
eloc 19
c 3
b 0
f 1
dl 0
loc 28
rs 9.6333
cc 4
nc 4
nop 3
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
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 ignore-call  annotation

77
            /** @scrutinizer ignore-call */ 
78
            acf_add_options_page([
Loading history...
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
Bug introduced by
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 ignore-call  annotation

106
            /** @scrutinizer ignore-call */ 
107
            acf_add_options_page($pageConfig);
Loading history...
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
Bug introduced by
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 ignore-call  annotation

128
            /** @scrutinizer ignore-call */ 
129
            acf_add_local_field_group($fieldGroup);
Loading history...
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
Bug introduced by
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 ignore-call  annotation

253
            /** @scrutinizer ignore-call */ 
254
            acf_add_local_field(array_merge($field, [
Loading history...
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
Bug introduced by
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 ignore-call  annotation

281
            $option = /** @scrutinizer ignore-call */ get_field('field_' . $key, 'option');
Loading history...
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
Bug introduced by
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 ignore-call  annotation

296
        return /** @scrutinizer ignore-call */ acf_get_setting('default_language');
Loading history...
297
    }
298
}
299