Passed
Push — master ( a8b33d...121632 )
by Dominik
04:21 queued 12s
created

Options::createOptionSubPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 36
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 25
c 1
b 0
f 0
dl 0
loc 36
rs 9.52
cc 2
nc 2
nop 2
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 $optionCategory Category of option page. One of these three values: component, feature, customPostType.
157
     * @param string $subPageName Name of the sub page.
158
     * @param string $fieldName (optional) Name of the field to get.
159
     * @return mixed The value of the option or array of options. False if subpage doesn't exist or no option was found.
160
     **/
161
    public static function get($optionType, $scope, $fieldName = null)
162
    {
163
        if (!static::checkRequiredHooks($optionType, $scope, $fieldName)) {
164
            return false;
165
        }
166
167
        // convert parameters
168
        $optionType = lcfirst($optionType);
169
        $scope = ucfirst($scope);
170
171
        if (!isset(static::OPTION_TYPES[$optionType])) {
172
            return false;
173
        }
174
175
        $prefix = implode('_', [$optionType, $scope, '']);
176
        $isTranslatable = static::OPTION_TYPES[$optionType]['translatable'];
177
        if (empty($fieldName)) {
178
            $optionNames = ((static::$registeredOptions[$optionType] ?? [])[$scope] ?? []);
179
            return array_combine(
180
                $optionNames,
181
                array_map(function ($optionName) use ($prefix, $isTranslatable) {
182
                    $fieldKey = $prefix . $optionName;
183
                    return static::getOptionField($fieldKey, $isTranslatable);
184
                }, $optionNames)
185
            );
186
        } else {
187
            $fieldKey = $prefix . $fieldName;
188
            return static::getOptionField($fieldKey, $isTranslatable);
189
        }
190
    }
191
192
    public static function addTranslatable($scope, $fields, $category = 'Default')
193
    {
194
        static::addOptions($scope, $fields, 'translatable', $category);
195
    }
196
197
    public static function addGlobal($scope, $fields, $category = 'Default')
198
    {
199
        static::addOptions($scope, $fields, 'global', $category);
200
    }
201
202
    public static function addOptions($scope, $fields, $type, $category = 'Default')
203
    {
204
        static::createOptionSubPage($type, $category);
205
        $fieldGroupTitle = StringHelpers::splitCamelCase($scope);
206
        $optionsPageSlug = self::$optionPages[$type]['sub_pages'][$category]['menu_slug'];
207
        $fieldGroupName = implode('_', [$type, $scope]);
208
        static::addOptionsFieldGroup(
209
            $fieldGroupName,
210
            $fieldGroupTitle,
211
            $optionsPageSlug,
212
            $fields
213
        );
214
        static::registerOptionNames($type, $scope, $fields);
215
    }
216
217
    protected static function registerOptionNames($type, $scope, $fields)
218
    {
219
        static::$registeredOptions[$type] = static::$registeredOptions[$type] ?? [];
220
        static::$registeredOptions[$type] = static::$registeredOptions[$type] ?? [];
221
        static::$registeredOptions[$type][$scope] = array_column($fields, 'name');
222
        return static::$registeredOptions;
223
    }
224
225
    protected static function addOptionsFieldGroup($name, $title, $optionsPageSlug, $fields)
226
    {
227
        $fieldGroup = ACFComposer\ResolveConfig::forFieldGroup(
228
            [
229
                'name' => $name,
230
                'title' => $title,
231
                'fields' => array_merge([
232
                    [
233
                        'label' => $title,
234
                        'name' => '',
235
                        'type' => 'accordion',
236
                        'placement' => 'left',
237
                        'endpoint' => false,
238
                    ]
239
                ], $fields),
240
                'style' => 'seamless',
241
                'location' => [
242
                    [
243
                        [
244
                            'param' => 'options_page',
245
                            'operator' => '==',
246
                            'value' => $optionsPageSlug
247
                        ]
248
                    ]
249
                ]
250
            ]
251
        );
252
        $fieldGroup['fields'] = static::prefixFields($fieldGroup['fields'], $name);
253
        foreach ($fieldGroup['fields'] as $field) {
254
            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

254
            /** @scrutinizer ignore-call */ 
255
            acf_add_local_field(array_merge($field, [
Loading history...
255
                'parent' => 'group_' . $optionsPageSlug,
256
            ]));
257
        }
258
    }
259
260
    protected static function prefixFields($fields, $prefix)
261
    {
262
        return array_map(function ($field) use ($prefix) {
263
            $field['name'] = $prefix . '_' . $field['name'];
264
            return $field;
265
        }, $fields);
266
    }
267
268
    protected static function checkRequiredHooks($optionType, $scope, $fieldName)
269
    {
270
        if (did_action('acf/init') < 1) {
271
            $parameters = "${optionType}, ${scope}, ";
272
            $parameters .= isset($fieldName) ? $fieldName : 'NULL';
273
            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);
274
            return false;
275
        }
276
        return true;
277
    }
278
279
    protected static function getOptionField($key, $translatable)
280
    {
281
        if ($translatable) {
282
            $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

282
            $option = /** @scrutinizer ignore-call */ get_field('field_' . $key, 'option');
Loading history...
283
        } else {
284
            // switch to default language to get global options
285
            add_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100);
286
287
            $option = get_field('field_' . $key, 'option');
288
289
            remove_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100);
290
        }
291
292
        return $option;
293
    }
294
295
    public static function getDefaultAcfLanguage()
296
    {
297
        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

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