Passed
Pull Request — master (#173)
by
unknown
02:11
created

Algolia_Attributes::update_attribute_options()   B

Complexity

Conditions 8
Paths 72

Size

Total Lines 71
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 8
eloc 30
c 3
b 0
f 0
nc 72
nop 0
dl 0
loc 71
rs 8.1954

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Main Algolia Woo Indexer class
5
 * Called from main plugin file algolia-woo-indexer.php
6
 *
7
 * @package algolia-woo-indexer
8
 */
9
10
namespace Algowoo;
11
12
/**
13
 * Definitions for attributes
14
 */
15
define('ATTRIBUTES_ENABLED', '_attributes_enabled');
16
define('ATTRIBUTES_VISIBILITY', '_attributes_visibility');
17
define('ATTRIBUTES_VISIBILITY_STATES', array('all', 'visible', 'hidden'));
18
define('ATTRIBUTES_LIST', '_attributes_list');
19
define('ATTRIBUTES_INTERP', '_attributes_interp');
20
define('ATTRIBUTES_TAX_FIELDS', '_attributes_tax_fields');
21
define('ALLOWED_TAXONOMIES', array(
22
    'term_id',
23
    'name',
24
    'slug',
25
    'term_group',
26
    'description',
27
    'count',
28
    'filter'
29
));
30
31
/**
32
 * definitions of available settings
33
 */
34
define('ATTRIBUTES_SETTINGS', array(
35
    'enabled' => 'Enable indexing of attributes',
36
    'visibility' => 'Visibility',
37
    'list' => 'Valid Attributes',
38
    'interp' => 'Numeric Interpolation',
39
    'tax_fields' => 'Content of each attribute term'
40
));
41
42
/**
43
 * Abort if this file is called directly
44
 */
45
if (!defined('ABSPATH')) {
46
    exit;
47
}
48
49
50
if (!class_exists('Algolia_Attributes')) {
51
    /**
52
     * Algolia WooIndexer Attributes
53
     */
54
    class Algolia_Attributes
55
    {
56
57
58
        /**
59
         * Class instance
60
         *
61
         * @var object
62
         */
63
        private static $instance;
64
65
66
        /**
67
         * Setup sections and fields to store and retrieve values from Settings API
68
         *
69
         * @return void
70
         */
71
        public static function setup_attributes_settings()
72
        {
73
            /**"
74
             * Make sure we reference the instance of the current class by using self::get_instance()
75
             * This way we can setup the correct callback function for add_settings_section and add_settings_field
76
             */
77
            $algowoo_attributes = self::get_instance();
78
79
            /**
80
             * Add sections and fields for the attributes
81
             */
82
            add_settings_section(
83
                'algolia_woo_indexer_attributes',
84
                esc_html__('Attributes indexing settings', 'algolia-woo-indexer'),
85
                array($algowoo_attributes, 'algolia_woo_indexer_attributes_section_text'),
86
                'algolia_woo_indexer'
87
            );
88
89
            /**
90
             * Add fields based on ATTRIBUTES_SETTINGS
91
             */
92
            foreach (ATTRIBUTES_SETTINGS as $key => $description) {
93
                add_settings_field(
94
                    'algolia_woo_indexer_attributes_' . $key,
95
                    esc_html__($description, 'algolia-woo-indexer'),
96
                    array($algowoo_attributes, 'algolia_woo_indexer_attributes_' . $key . '_output'),
97
                    'algolia_woo_indexer',
98
                    'algolia_woo_indexer_attributes'
99
                );
100
            }
101
        }
102
103
        /**
104
         * Output for attributes if functionality is enabled
105
         *
106
         * @return void
107
         */
108
        public static function algolia_woo_indexer_attributes_enabled_output()
109
        {
110
            $value = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_ENABLED);
111
            $isChecked = (!empty($value)) ? 1 : 0;
112
?>
113
            <input id="algolia_woo_indexer_attributes_enabled" name="algolia_woo_indexer_attributes_enabled[checked]" type="checkbox" <?php checked(1, $isChecked); ?> />
114
            <?php
115
        }
116
117
        /**
118
         * Output for attributes how to handle visibility setting
119
         *
120
         * @return void
121
         */
122
        public static function algolia_woo_indexer_attributes_visibility_output()
123
        {
124
            $value = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_VISIBILITY);
125
            foreach (ATTRIBUTES_VISIBILITY_STATES as $state) {
126
                $id = 'algolia_woo_indexer_attributes_visibility_' . $state;
127
            ?>
128
                <p><input id="<?php echo $id; ?>" name="algolia_woo_indexer_attributes_visibility[value]" type="radio" value="<?php echo $state; ?>" <?php checked($state, $value); ?> /><label for="<?php echo $id; ?>"><?php echo esc_html__($state, 'algolia-woo-indexer'); ?></label></p>
129
            <?php
130
            }
131
        }
132
133
        /**
134
         * Output for attributes list which attributes are whitelisted
135
         *
136
         * @return void
137
         */
138
        public static function algolia_woo_indexer_attributes_list_output()
139
        {
140
            $value = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_LIST);
141
            $selectedIds = explode(",", $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
            $selectedIds = explode(",", /** @scrutinizer ignore-type */ $value);
Loading history...
142
            $name = "algolia_woo_indexer_attributes_list[list]";
143
            $description = __('Here you can whitelist all the attributes. Use the <b>shift</b> or <b>control</b> buttons to select multiple attributes.', 'algolia-woo-indexer');
144
            self::generic_attributes_select_output($name, $selectedIds, $description);
145
        }
146
147
        /**
148
         * Output for attributes list which are using a numeric interpolation
149
         *
150
         * @return void
151
         */
152
        public static function algolia_woo_indexer_attributes_interp_output()
153
        {
154
            $value = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_INTERP);
155
            $selectedIds = explode(",", $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
            $selectedIds = explode(",", /** @scrutinizer ignore-type */ $value);
Loading history...
156
            $name = "algolia_woo_indexer_attributes_interp[list]";
157
            $description = __('If you have some attributes based on number which shall be interpd between the lowest to the highest number, you can select it here. A common usecase for this is if you want to have a <b>range slider</b> in aloglia which works for a certain range. Example: a plant grows between 20 and 25cm tall. for this you enter 20 and 25 as attribute values to your product and it will automatically extend the data to [20,21,22,23,24,25]', 'algolia-woo-indexer');
158
            self::generic_attributes_select_output($name, $selectedIds, $description);
159
        }
160
161
        /**
162
         * Output for attributes list which are using a numeric interpolation
163
         *
164
         * @return void
165
         */
166
        public static function algolia_woo_indexer_attributes_tax_fields_output()
167
        {
168
            $selected_raw = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_TAX_FIELDS);
169
            $selected_entries = explode(",", $selected_raw);
0 ignored issues
show
Bug introduced by
It seems like $selected_raw can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
            $selected_entries = explode(",", /** @scrutinizer ignore-type */ $selected_raw);
Loading history...
170
            $name = "algolia_woo_indexer_attributes_tax_fields[list]";
171
            $description = __('Select which taxonomy fields for each attribute shall be indexed', 'algolia-woo-indexer');
172
            $values = ALLOWED_TAXONOMIES;
173
            ?>
174
            <p><?php echo $description; ?></p>
175
            <select multiple="multiple" name="<?php echo $name; ?>[]" size="<?php echo count($values); ?>">
176
                <?php
177
                foreach ($values as $tax) {
178
                    $selected = in_array($tax, $selected_entries) ? ' selected="selected" ' : '';
179
                ?>
180
                    <option value="<?php echo $tax; ?>" <?php echo $selected; ?>>
181
                        <?php echo __($tax, 'algolia-woo-indexer'); ?>
182
                    </option>
183
                <?php
184
                }
185
                ?>
186
            </select>
187
        <?php
188
        }
189
190
        /**
191
         * Generic Output for attributes list where attributes are whitelisted using Woocommerce attributes taxonomies
192
         * @param string $name id and name for select
193
         * @param array $selected_entries will be preselected if matching with WC taxonomies
194
         * @param string $description will be displayed on top
195
         * 
196
         */
197
        public static function generic_attributes_select_output($name, $selected_entries, $description)
198
        {
199
200
201
            $values = wc_get_attribute_taxonomies();
0 ignored issues
show
Bug introduced by
The function wc_get_attribute_taxonomies 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

201
            $values = /** @scrutinizer ignore-call */ wc_get_attribute_taxonomies();
Loading history...
202
            if (!$values) {
203
                echo esc_html__('You don\'t have any attributes defined yet. Go to WooCommerce and add some to use this feature.', 'algolia-woo-indexer');
204
                return;
205
            }
206
207
        ?>
208
            <p><?php echo $description; ?></p>
209
            <select multiple="multiple" name="<?php echo $name; ?>[]" size="<?php echo count($values); ?>">
210
                <?php
211
                foreach ($values as $tax) {
212
213
                    $id = $tax->attribute_id;
214
                    $label = $tax->attribute_label;
215
                    $name = $tax->attribute_name;
216
                    $selected = in_array($id, $selected_entries) ? ' selected="selected" ' : '';
217
                ?>
218
                    <option value="<?php echo $id; ?>" <?php echo $selected; ?>>
219
                        <?php echo $label . ' (' . $name . ')'; ?>
220
                    </option>
221
                <?php
222
                }
223
                ?>
224
            </select>
225
<?php
226
227
        }
228
229
        /**
230
         * Section text for attributes settings section text
231
         *
232
         * @return void
233
         */
234
        public static function algolia_woo_indexer_attributes_section_text()
235
        {
236
            
237
        }
238
239
240
        /**
241
         * parse, sanitize and update attribute settings in DB
242
         *
243
         * @return void
244
         */
245
        public static function update_attribute_options()
246
        {
247
248
            /**
249
             * Filter the inputs
250
             *
251
             * @see https://www.php.net/manual/en/function.filter-input.php
252
             */
253
            $attributes_enabled              = filter_input(INPUT_POST, 'algolia_woo_indexer_attributes_enabled', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
254
            $attributes_visibility           = filter_input(INPUT_POST, 'algolia_woo_indexer_attributes_visibility', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
255
            $attributes_list                 = filter_input(INPUT_POST, 'algolia_woo_indexer_attributes_list', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
256
            $attributes_interp               = filter_input(INPUT_POST, 'algolia_woo_indexer_attributes_interp', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
257
            $attributes_tax_fields           = filter_input(INPUT_POST, 'algolia_woo_indexer_attributes_tax_fields', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
258
259
            /**
260
             * Properly sanitize text fields before updating data
261
             *
262
             * @see https://developer.wordpress.org/reference/functions/sanitize_text_field/
263
             */
264
            $sanitized = array();
265
            $sanitized['attributes_visibility']     = sanitize_text_field($attributes_visibility['value']);
266
267
            /**
268
             * sanitize select list of id's by getting integers and them implode seperated with comma
269
             */
270
271
            $attributes_list_integers = [];
272
            foreach ($attributes_list['list'] as $id) {
273
                $sanitizedId = sanitize_text_field($id);
274
                array_push($attributes_list_integers, (int) $sanitizedId);
275
            }
276
            $sanitized['attributes_list'] = implode(',', $attributes_list_integers);
277
278
            $attributes_interp_int = [];
279
            foreach ($attributes_interp['list'] as $id) {
280
                $sanitizedId = sanitize_text_field($id);
281
                array_push($attributes_interp_int, (int) $sanitizedId);
282
            }
283
            $sanitized['attributes_interp'] = implode(',', $attributes_interp_int);
284
285
            /**
286
             * only allow values from the ALLOWED_TAXONOMIES to be saved
287
             */
288
            $sanitized['attributes_tax_fields'] = [];
289
            foreach ($attributes_tax_fields['list'] as $name) {
290
                if (in_array($name, ALLOWED_TAXONOMIES)) {
291
                    array_push($sanitized['attributes_tax_fields'], $name);
292
                }
293
            }
294
            $sanitized['attributes_tax_fields'] = implode(',', $sanitized['attributes_tax_fields']);
295
296
            /**
297
             * Sanitizing by setting the value to either 1 or 0
298
             */
299
            $sanitized['attributes_enabled'] = (!empty($attributes_enabled)) ? 1 : 0;
300
301
302
            /**
303
             * Values have been filtered and sanitized
304
             * Check if set and not empty and update the database
305
             *
306
             * @see https://developer.wordpress.org/reference/functions/update_option/
307
             */
308
309
            foreach (array_keys(ATTRIBUTES_SETTINGS) as $key) {
310
                $value = $sanitized['attributes_' . $key];
311
                if (isset($value)) {
312
                    $extension = constant('ATTRIBUTES_' . strtoupper($key));
313
                    update_option(
314
                        ALGOWOO_DB_OPTION . $extension,
315
                        $value
316
                    );
317
                }
318
            }
319
        }
320
321
322
        /**
323
         * The actions to execute when the plugin is activated.
324
         *
325
         * @return void
326
         */
327
        public static function activate_attributes()
328
        {
329
330
            /**
331
             * Set default values for options if not already set
332
             */
333
            $attributes_enabled              = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_ENABLED);
334
            $attributes_visibility           = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_VISIBILITY);
335
            $attributes_list                 = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_LIST);
336
            $attributes_interp               = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_INTERP);
337
            $attributes_tax_fields           = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_TAX_FIELDS);
338
339
340
            if (empty($attributes_enabled)) {
341
                add_option(
342
                    ALGOWOO_DB_OPTION . ATTRIBUTES_ENABLED,
343
                    1
344
                );
345
            }
346
            if (empty($attributes_visibility)) {
347
                add_option(
348
                    ALGOWOO_DB_OPTION . ATTRIBUTES_VISIBILITY,
349
                    ATTRIBUTES_VISIBILITY_STATES[0]
350
                );
351
            }
352
            if (empty($attributes_list)) {
353
                add_option(
354
                    ALGOWOO_DB_OPTION . ATTRIBUTES_LIST,
355
                    ''
356
                );
357
            }
358
            if (empty($attributes_interp)) {
359
                add_option(
360
                    ALGOWOO_DB_OPTION . ATTRIBUTES_INTERP,
361
                    ''
362
                );
363
            }
364
            if (empty($attributes_tax_fields)) {
365
                add_option(
366
                    ALGOWOO_DB_OPTION . ATTRIBUTES_TAX_FIELDS,
367
                    'name,slug'
368
                );
369
            }
370
        }
371
        /**
372
         * Get active object instance
373
         *
374
         * @return object
375
         */
376
        public static function get_instance()
377
        {
378
            if (!self::$instance) {
379
                self::$instance = new Algolia_Attributes();
380
            }
381
            return self::$instance;
382
        }
383
384
        /**
385
         * format attributes terms according to settings in ATTRIBUTES_TAX_FIELDS
386
         *
387
         * @param  array $terms list of woocommerce attribute taxonomy
388
         * @return array Array with fields set in config as defined in ATTRIBUTEX_TAX_FIELDS.
389
         */
390
        public static function format_product_attribute_terms($terms, $interpolateValues)
391
        {
392
            $allowed_keys_raw = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_TAX_FIELDS);
393
            $allowed_keys = explode(',', $allowed_keys_raw);
0 ignored issues
show
Bug introduced by
It seems like $allowed_keys_raw can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

393
            $allowed_keys = explode(',', /** @scrutinizer ignore-type */ $allowed_keys_raw);
Loading history...
394
            $final_terms = array();
395
396
            switch ($interpolateValues) {
397
                case true:
398
                    $integers = array();
399
                    foreach ($terms as $term) {
400
                        array_push($integers, (int) $term->name);
401
                    }
402
                    if (count($integers) > 0) {
403
                        for ($i = min($integers); $i <= max($integers); $i++) {
404
                            array_push($final_terms, $i);
405
                        }
406
                    }
407
                    break;
408
                    /**
409
                     * normal mixed content case 
410
                     */
411
                default:
412
                    foreach ($terms as $term) {
413
                        $final_term = array();
414
                        foreach ($allowed_keys as $key) {
415
                            array_push($final_term, esc_html($term->{$key}));
416
                        }
417
                        $string_with_Separator = implode("|", $final_term);
418
                        array_push($final_terms, $string_with_Separator);
419
                    }
420
            }
421
            return $final_terms;
422
        }
423
424
        /**
425
         * skip variable related attributes,
426
         * ensure it is a taxonomy,
427
         * ensure that taxonomy is whitelisted and
428
         * ensure that the visibility and variation is respected
429
         * @param mixed $attribute Woocommerce attribute
430
         */
431
        private static function is_attribute_not_allowed($attribute)
432
        {
433
            /**
434
             * gather settings
435
             */
436
            $setting_visibility = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_VISIBILITY);
437
            $setting_ids = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_LIST);
438
            $setting_ids = explode(",", $setting_ids);
0 ignored issues
show
Bug introduced by
It seems like $setting_ids can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

438
            $setting_ids = explode(",", /** @scrutinizer ignore-type */ $setting_ids);
Loading history...
439
            $visibility = $attribute["visible"];
440
            $attribute_id = $attribute->get_id();
441
442
            return ($attribute->get_variation() ||
443
                !$attribute->is_taxonomy() ||
444
                !in_array($attribute_id, $setting_ids) ||
445
                ($setting_visibility ===  "visible" && $visibility === false) ||
446
                ($setting_visibility ===  "hidden" && $visibility === true)
447
            );
448
        }
449
450
        /**
451
         * Get attributes from product
452
         *
453
         * @param  mixed $product Product to check   
454
         * @return array ['pa_name' => ['value1', 'value2']] Array with key set to the product attribute internal name and values as array. returns false if not attributes found.
455
         */
456
        public static function get_product_attributes($product)
457
        {
458
            /**
459
             * ensure that attributes are actually enabled and we having data
460
             */
461
            $attributes_enabled = (int) get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_ENABLED);
462
            $rawAttributes = $product->get_attributes("edit");
463
            if ($attributes_enabled !== 1 || !$rawAttributes) {
464
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
465
            }
466
467
468
            $setting_ids_interp = get_option(ALGOWOO_DB_OPTION . ATTRIBUTES_INTERP);
469
            $setting_ids_interp = explode(",", $setting_ids_interp);
0 ignored issues
show
Bug introduced by
It seems like $setting_ids_interp can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

469
            $setting_ids_interp = explode(",", /** @scrutinizer ignore-type */ $setting_ids_interp);
Loading history...
470
471
472
            $attributes = [];
473
            foreach ($rawAttributes as $attribute) {
474
                if (!self::is_attribute_not_allowed($attribute)) {
475
                    $name = $attribute->get_name();
476
                    $terms = wp_get_post_terms($product->get_id(), $name, 'all');
0 ignored issues
show
Bug introduced by
'all' of type string is incompatible with the type array expected by parameter $args of wp_get_post_terms(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

476
                    $terms = wp_get_post_terms($product->get_id(), $name, /** @scrutinizer ignore-type */ 'all');
Loading history...
477
                    $is_interpolation = in_array($attribute->get_id(), $setting_ids_interp);
478
                    $attributes[$name] = self::format_product_attribute_terms($terms, $is_interpolation);
0 ignored issues
show
Bug introduced by
$terms of type WP_Error is incompatible with the type array expected by parameter $terms of Algowoo\Algolia_Attribut...oduct_attribute_terms(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

478
                    $attributes[$name] = self::format_product_attribute_terms(/** @scrutinizer ignore-type */ $terms, $is_interpolation);
Loading history...
479
                }
480
            }
481
            return $attributes;
482
        }
483
    }
484
}
485