Passed
Branch options (6cb94b)
by Dominik
06:35
created

Options::getOptionField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 14
rs 10
c 0
b 0
f 0
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
    const OPTION_CATEGORIES = [
23
        'component' => [
24
            'title' => 'Component',
25
            'icon' => 'dashicons-editor-table',
26
            'showType' => true
27
        ],
28
        'customPostType' => [
29
            'title' => 'Custom Post Type',
30
            'icon' => 'dashicons-palmtree',
31
            'showType' => true
32
            // 'label' => [ 'labels', 'menu_item' ], // TODO add this functionality
33
        ],
34
        'feature' => [
35
            'title' => 'Feature',
36
            'icon' => 'dashicons-carrot',
37
            'showType' => true
38
        ]
39
    ];
40
41
    protected static $initialized = false;
42
43
    protected static $optionPages = [];
44
45
    protected static $registeredOptions = [];
46
47
    protected static function createOptionPages()
48
    {
49
        if (static::$initialized) {
50
            return;
51
        } else {
52
            static::$initialized = true;
53
        }
54
        foreach (static::OPTION_TYPES as $optionType => $option) {
55
            $title = _x($option['title'], 'title', 'flynt');
56
            $slug = ucfirst($optionType) . 'Options ';
57
58
            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

58
            /** @scrutinizer ignore-call */ 
59
            acf_add_options_page([
Loading history...
59
                'page_title'  => $title,
60
                'menu_title'  => $title,
61
                'redirect'    => true,
62
                'menu_slug'   => $slug,
63
                'icon_url'    => $option['icon']
64
            ]);
65
66
            static::$optionPages[$optionType] = [
67
                'menu_slug' => $slug,
68
                'menu_title' => $title
69
            ];
70
            $fieldGroup = ACFComposer\ResolveConfig::forFieldGroup(
71
                [
72
                    'name' => $slug,
73
                    'title' => $title,
74
                    'style' => 'seamless',
75
                    'fields' => [],
76
                    'location' => [
77
                        [
78
                            [
79
                                'param' => 'options_page',
80
                                'operator' => '==',
81
                                'value' => $slug
82
                            ]
83
                        ]
84
                    ]
85
                ]
86
            );
87
            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

87
            /** @scrutinizer ignore-call */ 
88
            acf_add_local_field_group($fieldGroup);
Loading history...
88
        }
89
90
        add_action('current_screen', function ($currentScreen) {
91
            foreach (static::OPTION_TYPES as $optionType => $option) {
92
                $isTranslatable = $option['translatable'];
93
                $toplevelPageId = 'toplevel_page_' . $optionType;
94
                $menuTitle = static::$optionPages[$optionType]['menu_title'];
95
                $subPageId = sanitize_title($menuTitle) . '_page_' . $optionType;
96
                $currentScreenId = strtolower($currentScreen->id);
97
                $isCurrentPage = StringHelpers::startsWith(strtolower($toplevelPageId), $currentScreenId)
98
                || StringHelpers::startsWith(strtolower($subPageId), $currentScreenId);
99
100
                if (!$isTranslatable && $isCurrentPage) {
101
                    // set acf field values to default language
102
                    add_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 101);
103
104
                    // hide language selector in admin bar
105
                    add_action('wp_before_admin_bar_render', function () {
106
                        $adminBar = $GLOBALS['wp_admin_bar'];
107
                        $adminBar->remove_menu('WPML_ALS');
108
                    });
109
                }
110
            }
111
        });
112
    }
113
114
115
    // ============
116
    // PUBLIC API
117
    // ============
118
    public static function getTranslatable($optionCategory, $subPageName, $fieldName = null)
119
    {
120
        return self::get('translatable', $optionCategory, $subPageName, $fieldName);
121
    }
122
123
    public static function getGlobal($optionCategory, $subPageName, $fieldName = null)
124
    {
125
        return self::get('global', $optionCategory, $subPageName, $fieldName);
126
    }
127
128
    /**
129
     * Get option(s) from a sub page.
130
     *
131
     * Returns an option of a sub page. If no field name is provided it will get all option of that sub page.
132
     * Parameters are expected to be camelCase.
133
     *
134
     * @since 0.2.0 introduced as a replacement for OptionPages::getOption and OptionPages::getOptions
135
     * @since 0.2.2 added check for required hooks to have run to alert of timing issues when used incorrectly
136
     *
137
     * @param string $optionType Type of option page. Either global or translatable.
138
     * @param string $optionCategory Category of option page. One of these three values: component, feature, customPostType.
139
     * @param string $subPageName Name of the sub page.
140
     * @param string $fieldName (optional) Name of the field to get.
141
     * @return mixed The value of the option or array of options. False if subpage doesn't exist or no option was found.
142
     **/
143
    public static function get($optionType, $optionCategory, $subPageName, $fieldName = null)
144
    {
145
        if (!static::checkRequiredHooks($optionType, $optionCategory, $subPageName, $fieldName)) {
146
            return false;
147
        }
148
149
        // convert parameters
150
        $optionType = lcfirst($optionType);
151
        $optionCategory = ucfirst($optionCategory);
152
        $subPageName = ucfirst($subPageName);
153
154
        if (!isset(static::OPTION_TYPES[$optionType])) {
155
            return false;
156
        }
157
158
        $prefix = implode('_', [$optionType, $optionCategory, $subPageName, '_']);
159
        $isTranslatable = static::OPTION_TYPES[$optionType]['translatable'];
160
        if (empty($fieldName)) {
161
            $optionNames = (((static::$registeredOptions[$optionType] ?? [])[lcfirst($optionCategory)] ?? [])[$subPageName] ?? []);
162
            return array_combine(
163
                $optionNames,
164
                array_map(function ($optionName) use ($prefix, $isTranslatable) {
165
                    $fieldKey = $prefix . $optionName;
166
                    return static::getOptionField($fieldKey, $isTranslatable);
167
                }, $optionNames)
168
            );
169
        } else {
170
            $fieldKey = $prefix . $fieldName;
171
            return static::getOptionField($fieldKey, $isTranslatable);
172
        }
173
    }
174
175
    public static function addTranslatable($scope, $fields, $category = null)
176
    {
177
        static::addOptions($scope, $fields, 'translatable', $category);
178
    }
179
180
    public static function addGlobal($scope, $fields, $category = null)
181
    {
182
        static::addOptions($scope, $fields, 'global', $category);
183
    }
184
185
    public static function addOptions($scope, $fields, $type, $category = null)
186
    {
187
        static::createOptionPages();
188
        if (empty($category)) {
189
            global $flyntCurrentOptionCategory;
190
            $category = $flyntCurrentOptionCategory ?? 'component';
191
        }
192
        $optionCategorySettings = static::OPTION_CATEGORIES[$category];
193
        $iconClasses = 'flynt-submenu-item dashicons-before ' . $optionCategorySettings['icon'];
194
        $prettyScope = StringHelpers::splitCamelCase($scope);
195
        $fieldGroupTitle = "<span class='{$iconClasses}'>{$prettyScope}</span>";
196
        $optionsPageSlug = self::$optionPages[$type]['menu_slug'];
197
        $fieldGroupName = implode('_', [$type, ucfirst($category), $scope]);
198
        static::addOptionsFieldGroup($fieldGroupName, $fieldGroupTitle, $optionsPageSlug, $fields);
199
        static::registerOptionNames($type, $category, $scope, $fields);
200
    }
201
202
    protected static function registerOptionNames($type, $category, $scope, $fields)
203
    {
204
        static::$registeredOptions[$type] = static::$registeredOptions[$type] ?? [];
205
        static::$registeredOptions[$type][$category] = static::$registeredOptions[$type][$category] ?? [];
206
        static::$registeredOptions[$type][$category][$scope] = array_column($fields, 'name');
207
        return static::$registeredOptions;
208
    }
209
210
    protected static function addOptionsFieldGroup($name, $title, $optionsPageSlug, $fields)
211
    {
212
        $fieldGroup = ACFComposer\ResolveConfig::forFieldGroup(
213
            [
214
                'name' => $name,
215
                'title' => $title,
216
                'fields' => array_merge([
217
                    [
218
                        'label' => $title,
219
                        'name' => '',
220
                        'type' => 'accordion',
221
                        'placement' => 'left',
222
                        'endpoint' => false,
223
                    ]
224
                ], $fields),
225
                'style' => 'seamless',
226
                'location' => [
227
                    [
228
                        [
229
                            'param' => 'options_page',
230
                            'operator' => '==',
231
                            'value' => $optionsPageSlug
232
                        ]
233
                    ]
234
                ]
235
            ]
236
        );
237
        $fieldGroup['fields'] = static::prefixFields($fieldGroup['fields'], $name);
238
        foreach ($fieldGroup['fields'] as $field) {
239
            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

239
            /** @scrutinizer ignore-call */ 
240
            acf_add_local_field(array_merge($field, [
Loading history...
240
                'parent' => 'group_' . $optionsPageSlug,
241
            ]));
242
        }
243
    }
244
245
    protected static function prefixFields($fields, $prefix)
246
    {
247
        return array_map(function ($field) use ($prefix) {
248
            $field['name'] = $prefix . '_' . $field['name'];
249
            return $field;
250
        }, $fields);
251
    }
252
253
    protected static function checkRequiredHooks($optionType, $optionCategory, $subPageName, $fieldName)
254
    {
255
        if (did_action('acf/init') < 1) {
256
            $parameters = "${optionType}, ${optionCategory}, ${subPageName}, ";
257
            $parameters .= isset($fieldName) ? $fieldName : 'NULL';
258
            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);
259
            return false;
260
        }
261
        return true;
262
    }
263
264
    protected static function getOptionField($key, $translatable)
265
    {
266
        if ($translatable) {
267
            $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

267
            $option = /** @scrutinizer ignore-call */ get_field('field_' . $key, 'option');
Loading history...
268
        } else {
269
            // switch to default language to get global options
270
            add_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100);
271
272
            $option = get_field('field_' . $key, 'option');
273
274
            remove_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100);
275
        }
276
277
        return $option;
278
    }
279
280
    public static function getDefaultAcfLanguage()
281
    {
282
        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

282
        return /** @scrutinizer ignore-call */ acf_get_setting('default_language');
Loading history...
283
    }
284
}
285