Completed
Push — componentlibrary ( cb207c...9747f1 )
by Dominik
03:33 queued 01:37
created

Options::prefixFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Flynt\Utils;
4
5
use ACFComposer;
6
7
class Options
8
{
9
    const OPTION_TYPES = [
10
        'translatableOptions' => [
11
            'title' => 'Translatable Options',
12
            'icon' => 'dashicons-translation',
13
            'translatable' => true
14
        ],
15
        'globalOptions' => [
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-starter-theme');
56
            $slug = ucfirst($optionType);
57
58
            acf_add_options_page([
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);
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
                $isCurrentPage = StringHelpers::startsWith($toplevelPageId, $currentScreen->id)
97
                || StringHelpers::startsWith($subPageId, $currentScreen->id);
98
99
                if (!$isTranslatable && $isCurrentPage) {
100
                    // set acf field values to default language
101
                    add_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 101);
102
103
                    // hide language selector in admin bar
104
                    add_action('wp_before_admin_bar_render', function () {
105
                        $adminBar = $GLOBALS['wp_admin_bar'];
106
                        $adminBar->remove_menu('WPML_ALS');
107
                    });
108
                }
109
            }
110
        });
111
    }
112
113
114
    // ============
115
    // PUBLIC API
116
    // ============
117
118
    /**
119
     * Get option(s) from a sub page.
120
     *
121
     * Returns an option of a sub page. If no field name is provided it will get all option of that sub page.
122
     * Parameters are expected to be camelCase.
123
     *
124
     * @since 0.2.0 introduced as a replacement for OptionPages::getOption and OptionPages::getOptions
125
     * @since 0.2.2 added check for required hooks to have run to alert of timing issues when used incorrectly
126
     *
127
     * @param string $optionType Type of option page. Either globalOptions or translatableOptions.
128
     * @param string $optionCategory Category of option page. One of these three values: component, feature, customPostType.
129
     * @param string $subPageName Name of the sub page.
130
     * @param string $fieldName (optional) Name of the field to get.
131
     * @return mixed The value of the option or array of options. False if subpage doesn't exist or no option was found.
132
     **/
133
    public static function get($optionType, $optionCategory, $subPageName, $fieldName = null)
134
    {
135
        if (!static::checkRequiredHooks($optionType, $optionCategory, $subPageName, $fieldName)) {
136
            return false;
137
        }
138
139
        // convert parameters
140
        $optionType = lcfirst($optionType);
141
        $optionCategory = ucfirst($optionCategory);
142
        $subPageName = ucfirst($subPageName);
143
144
        if (!isset(static::OPTION_TYPES[$optionType])) {
145
            return false;
146
        }
147
148
        $prefix = implode('', [$optionType, $optionCategory, $subPageName, '_']);
149
        $isTranslatable = static::OPTION_TYPES[$optionType]['translatable'];
150
        if (empty($fieldName)) {
151
            $optionNames = (((static::$registeredOptions[$optionType] ?? [])[lcfirst($optionCategory)] ?? [])[$subPageName] ?? []);
152
            return array_combine(
153
                $optionNames,
154
                array_map(function ($optionName) use ($prefix, $isTranslatable) {
155
                    $fieldKey = $prefix . $optionName;
156
                    return static::getOptionField($fieldKey, $isTranslatable);
157
                }, $optionNames)
158
            );
159
        } else {
160
            $fieldKey = $prefix . $fieldName;
161
            return static::getOptionField($fieldKey, $isTranslatable);
162
        }
163
    }
164
165
    public static function addTranslatable($scope, $fields, $category = null)
166
    {
167
        static::addOptions($scope, $fields, 'translatableOptions', $category);
168
    }
169
170
    public static function addGlobal($scope, $fields, $category = null)
171
    {
172
        static::addOptions($scope, $fields, 'globalOptions', $category);
173
    }
174
175
    public static function addOptions($scope, $fields, $type, $category = null)
176
    {
177
        static::createOptionPages();
178
        if (empty($category)) {
179
            global $flyntCurrentOptionCategory;
180
            $category = $flyntCurrentOptionCategory ?? 'component';
181
        }
182
        $optionCategorySettings = static::OPTION_CATEGORIES[$category];
183
        $iconClasses = 'flynt-submenu-item dashicons-before ' . $optionCategorySettings['icon'];
184
        $prettyScope = StringHelpers::splitCamelCase($scope);
185
        $fieldGroupTitle = "<span class='{$iconClasses}'>{$prettyScope}</span>";
186
        $optionsPageSlug = self::$optionPages[$type]['menu_slug'];
187
        $fieldGroupName = $type . ucfirst($category) . $scope;
188
        static::addOptionsFieldGroup($fieldGroupName, $fieldGroupTitle, $optionsPageSlug, $fields);
189
        static::registerOptionNames($type, $category, $scope, $fields);
190
    }
191
192
    protected static function registerOptionNames($type, $category, $scope, $fields)
193
    {
194
        static::$registeredOptions[$type] = static::$registeredOptions[$type] ?? [];
195
        static::$registeredOptions[$type][$category] = static::$registeredOptions[$type][$category] ?? [];
196
        static::$registeredOptions[$type][$category][$scope] = array_column($fields, 'name');
197
        return static::$registeredOptions;
198
    }
199
200
    protected static function addOptionsFieldGroup($name, $title, $optionsPageSlug, $fields)
201
    {
202
        $fieldGroup = ACFComposer\ResolveConfig::forFieldGroup(
203
            [
204
                'name' => $name,
205
                'title' => $title,
206
                'fields' => array_merge([
207
                    [
208
                        'label' => $title,
209
                        'name' => '',
210
                        'type' => 'accordion',
211
                        'placement' => 'left',
212
                        'endpoint' => false,
213
                    ]
214
                ], $fields),
215
                'style' => 'seamless',
216
                'location' => [
217
                    [
218
                        [
219
                            'param' => 'options_page',
220
                            'operator' => '==',
221
                            'value' => $optionsPageSlug
222
                        ]
223
                    ]
224
                ]
225
            ]
226
        );
227
        $fieldGroup['fields'] = static::prefixFields($fieldGroup['fields'], $name);
228
        foreach ($fieldGroup['fields'] as $field) {
229
            acf_add_local_field(array_merge($field, [
230
                'parent' => 'group_' . $optionsPageSlug,
231
            ]));
232
        }
233
        // acf_add_local_field_group($fieldGroup);
234
    }
235
236
    protected static function prefixFields($fields, $prefix)
237
    {
238
        return array_map(function ($field) use ($prefix) {
239
            $field['name'] = $prefix . '_' . $field['name'];
240
            return $field;
241
        }, $fields);
242
    }
243
244
    protected static function checkRequiredHooks($optionType, $optionCategory, $subPageName, $fieldName)
245
    {
246
        if (did_action('acf/init') < 1) {
247
            $parameters = "${optionType}, ${optionCategory}, ${subPageName}, ";
248
            $parameters .= isset($fieldName) ? $fieldName : 'NULL';
249
            trigger_error("Could not get option/s for [${parameters}]. Required hooks have not yet been executed! Please make sure to run `OptionPages::get()` after the `acf/init` action is finished.", E_USER_WARNING);
250
            return false;
251
        }
252
        return true;
253
    }
254
255
    protected static function getOptionField($key, $translatable)
256
    {
257
        global $sitepress;
258
259
        if (!isset($sitepress)) {
260
            $option = get_field('field_' . $key, 'option');
261
        } elseif ($translatable) {
262
            // get options from cache with language namespace
263
            $option = get_field('field_' . $key . '_' . ICL_LANGUAGE_CODE, 'option');
264
        } else {
265
            // switch to default language to get global options
266
            $sitepress->switch_lang(acf_get_setting('default_language'));
267
268
            add_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100);
269
270
            // get optios from cache with global namespace
271
            $option = get_field('field_' . $key . '_global', 'option');
272
273
            remove_filter('acf/settings/current_language', 'Flynt\Utils\Options::getDefaultAcfLanguage', 100);
274
275
            $sitepress->switch_lang(ICL_LANGUAGE_CODE);
276
        }
277
278
        return $option;
279
    }
280
281
    public static function getDefaultAcfLanguage()
282
    {
283
        return acf_get_setting('default_language');
284
    }
285
}
286