Passed
Push — master ( 6d02eb...4a4aa8 )
by Daniel
02:05 queued 11s
created

Algolia_Woo_Indexer   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 489
Duplicated Lines 0 %

Importance

Changes 33
Bugs 0 Features 1
Metric Value
eloc 176
c 33
b 0
f 1
dl 0
loc 489
rs 8.64
wmc 47

18 Methods

Rating   Name   Duplication   Size   Complexity  
A algolia_woo_indexer_index_name_output() 0 7 2
A get_instance() 0 6 2
A send_new_product_to_algolia() 0 6 3
A algolia_woo_indexer_section_text() 0 3 1
B init() 0 56 6
A maybe_send_products() 0 4 2
A setup_settings_sections() 0 57 2
A deactivate_plugin() 0 3 1
A algolia_woo_indexer_application_id_output() 0 7 2
A admin_menu() 0 9 1
A load_textdomain() 0 3 1
A algolia_woo_indexer_settings() 0 21 2
A settings_fields_validate_options() 0 9 1
A __construct() 0 3 1
A algolia_woo_indexer_automatically_send_new_products_output() 0 10 2
B update_settings_options() 0 66 11
A activate_plugin() 0 39 5
A algolia_woo_indexer_admin_api_key_output() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like Algolia_Woo_Indexer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Algolia_Woo_Indexer, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Main Algolia Woo Indexer class
4
 * Called from main plugin file algolia-woo-indexer.php
5
 *
6
 * @package algolia-woo-indexer
7
 */
8
9
namespace Algowoo;
10
11
use \Algowoo\Algolia_Check_Requirements as Algolia_Check_Requirements;
12
use \Algowoo\Algolia_Verify_Nonces as Algolia_Verify_Nonces;
13
use \Algowoo\Algolia_Send_Products as Algolia_Send_Products;
14
15
/**
16
 * Abort if this file is called directly
17
 */
18
if ( ! defined( 'ABSPATH' ) ) {
19
	exit;
20
}
21
22
/**
23
 * Include plugin file if function is_plugin_active does not exist
24
 */
25
if (! function_exists('is_plugin_active')) {
26
    require_once(ABSPATH . '/wp-admin/includes/plugin.php');
27
}
28
29
if (! class_exists('Algolia_Woo_Indexer')) {
30
    /**
31
     * Algolia WooIndexer main class
32
     */
33
    class Algolia_Woo_Indexer
34
    {
35
        const PLUGIN_NAME      = 'Algolia Woo Indexer';
36
        const PLUGIN_TRANSIENT = 'algowoo-plugin-notice';
37
38
        /**
39
         * Class instance
40
         *
41
         * @var object
42
         */
43
        private static $instance;
44
45
        /**
46
         * The plugin URL
47
         *
48
         * @var string
49
         */
50
        private static $plugin_url = '';
51
52
        /**
53
         * The Algolia instance
54
         *
55
         * @var \Algolia\AlgoliaSearch\SearchClient
56
         */
57
        private static $algolia = null;
0 ignored issues
show
introduced by
The private property $algolia is not used, and could be removed.
Loading history...
58
59
        /**
60
         * Class constructor
61
         *
62
         * @return void
63
         */
64
        public function __construct()
65
        {
66
            $this->init();
67
        }
68
69
        /**
70
         * Setup sections and fields to store and retrieve values from Settings API
71
         *
72
         * @return void
73
         */
74
        public static function setup_settings_sections()
75
        {
76
            /**
77
            * Setup arguments for settings sections and fields
78
            *
79
            * @see https://developer.wordpress.org/reference/functions/register_setting/
80
            */
81
            if (is_admin()) {
82
                $arguments = array(
83
                    'type'              => 'string',
84
                    'sanitize_callback' => 'settings_fields_validate_options',
85
                    'default'           => null,
86
                );
87
                register_setting('algolia_woo_options', 'algolia_woo_options', $arguments);
88
89
                /**
90
                 * Make sure we reference the instance of the current class by using self::get_instance()
91
                 * This way we can setup the correct callback function for add_settings_section and add_settings_field
92
                 */
93
                $algowooindexer = self::get_instance();
94
95
                /**
96
                 * Add our necessary settings sections and fields
97
                 */
98
                add_settings_section(
99
                    'algolia_woo_indexer_main',
100
                    esc_html__('Algolia Woo Plugin Settings', 'algolia-woo-indexer'),
101
                    array( $algowooindexer, 'algolia_woo_indexer_section_text' ),
102
                    'algolia_woo_indexer'
103
                );
104
                add_settings_field(
105
                    'algolia_woo_indexer_application_id',
106
                    esc_html__('Application ID', 'algolia-woo-indexer'),
107
                    array( $algowooindexer, 'algolia_woo_indexer_application_id_output' ),
108
                    'algolia_woo_indexer',
109
                    'algolia_woo_indexer_main'
110
                );
111
                add_settings_field(
112
                    'algolia_woo_indexer_admin_api_key',
113
                    esc_html__('Admin API Key', 'algolia-woo-indexer'),
114
                    array( $algowooindexer, 'algolia_woo_indexer_admin_api_key_output' ),
115
                    'algolia_woo_indexer',
116
                    'algolia_woo_indexer_main'
117
                );
118
                add_settings_field(
119
                    'algolia_woo_indexer_index_name',
120
                    esc_html__('Index name (will be created if not existing)', 'algolia-woo-indexer'),
121
                    array( $algowooindexer, 'algolia_woo_indexer_index_name_output' ),
122
                    'algolia_woo_indexer',
123
                    'algolia_woo_indexer_main'
124
                );
125
                add_settings_field(
126
                    'algolia_woo_indexer_automatically_send_new_products',
127
                    esc_html__('Automatically index new products', 'algolia-woo-indexer'),
128
                    array( $algowooindexer, 'algolia_woo_indexer_automatically_send_new_products_output' ),
129
                    'algolia_woo_indexer',
130
                    'algolia_woo_indexer_main'
131
                );
132
            }
133
        }
134
135
        /**
136
         * Output for admin API key field
137
         *
138
         * @see https://developer.wordpress.org/reference/functions/wp_nonce_field/
139
         *
140
         * @return void
141
         */
142
        public static function algolia_woo_indexer_admin_api_key_output()
143
        {
144
            $api_key = get_option(ALGOWOO_DB_OPTION . ALGOLIA_API_KEY);
145
            $api_key = is_string($api_key) ? $api_key : CHANGE_ME;
146
147
            wp_nonce_field('algolia_woo_indexer_admin_api_nonce_action', 'algolia_woo_indexer_admin_api_nonce_name');
148
149
            echo "<input id='algolia_woo_indexer_admin_api_key' name='algolia_woo_indexer_admin_api_key[key]'
150
				type='text' value='" . esc_attr($api_key) . "' />";
151
        }
152
153
        /**
154
         * Output for application ID field
155
         *
156
         * @return void
157
         */
158
        public static function algolia_woo_indexer_application_id_output()
159
        {
160
            $application_id = get_option(ALGOWOO_DB_OPTION . ALGOLIA_APPLICATION_ID);
161
            $application_id = is_string($application_id) ? $application_id : CHANGE_ME;
162
163
            echo "<input id='algolia_woo_indexer_application_id' name='algolia_woo_indexer_application_id[id]'
164
				type='text' value='" . esc_attr($application_id) . "' />";
165
        }
166
167
        /**
168
         * Output for index name field
169
         *
170
         * @return void
171
         */
172
        public static function algolia_woo_indexer_index_name_output()
173
        {
174
            $index_name = get_option(ALGOWOO_DB_OPTION . INDEX_NAME);
175
            $index_name = is_string($index_name) ? $index_name : CHANGE_ME;
176
177
            echo "<input id='algolia_woo_indexer_index_name' name='algolia_woo_indexer_index_name[name]'
178
				type='text' value='" . esc_attr($index_name) . "' />";
179
        }
180
        
181
        /**
182
         * Output for checkbox to check if we automatically send new products to Algolia
183
         *
184
         * @return void
185
         */
186
        public static function algolia_woo_indexer_automatically_send_new_products_output()
187
        {
188
            /**
189
             * Sanitization is not really needed as the variable is not directly echoed
190
             * But I have still done it to be 100% safe
191
             */
192
            $automatically_send_new_products = get_option(ALGOWOO_DB_OPTION . AUTOMATICALLY_SEND_NEW_PRODUCTS);
193
            $automatically_send_new_products = (! empty($automatically_send_new_products)) ? 1 : 0; ?>
194
			<input id="algolia_woo_indexer_automatically_send_new_products" name="algolia_woo_indexer_automatically_send_new_products[checked]"
195
			type="checkbox" <?php checked(1, $automatically_send_new_products); ?> />
196
			<?php
197
        }
198
199
        /**
200
         * Section text for plugin settings section text
201
         *
202
         * @return void
203
         */
204
        public static function algolia_woo_indexer_section_text()
205
        {
206
            echo esc_html__('Enter your settings here', 'algolia-woo-indexer');
207
        }
208
209
        /**
210
         * Check if we are going to send products by verifying send products nonce
211
         *
212
         * @return void
213
         */
214
        public static function maybe_send_products()
215
        {
216
            if (true === Algolia_Verify_Nonces::verify_send_products_nonce()) {
217
                Algolia_Send_Products::send_products_to_algolia();
218
            }
219
        }
220
221
        /**
222
         * Initialize class, setup settings sections and fields
223
         *
224
         * @return void
225
         */
226
        public static function init()
227
        {
228
229
            /**
230
             * Fetch the option to see if we are going to automatically send new products
231
             */
232
            $automatically_send_new_products = get_option(ALGOWOO_DB_OPTION . AUTOMATICALLY_SEND_NEW_PRODUCTS);
233
234
            /**
235
             * Check that we have the minimum versions required and all of the required PHP extensions
236
             */
237
            Algolia_Check_Requirements::check_unmet_requirements();
238
239
            if (! Algolia_Check_Requirements::algolia_wp_version_check() || ! Algolia_Check_Requirements::algolia_php_version_check()) {
240
                add_action(
241
                    'admin_notices',
242
                    function () {
243
                        echo '<div class="error notice">
244
                                  <p>' . esc_html__('Please check the server requirements for Algolia Woo Indexer. <br/> It requires minimum PHP version 7.2 and WordPress version 5.0', 'algolia-woo-indexer') . '</p>
245
                                </div>';
246
                    }
247
                );
248
            }
249
250
            $ob_class = get_called_class();
251
252
            /**
253
             * Setup translations
254
             */
255
            add_action('plugins_loaded', array( $ob_class, 'load_textdomain' ));
256
257
            /**
258
             * Add actions to setup admin menu
259
             */
260
            if (is_admin()) {
261
                add_action('admin_menu', array( $ob_class, 'admin_menu' ));
262
                add_action('admin_init', array( $ob_class, 'setup_settings_sections' ));
263
                add_action('admin_init', array( $ob_class, 'update_settings_options' ));
264
                add_action('admin_init', array( $ob_class, 'maybe_send_products' ));
265
266
                /**
267
                 * Register hook to automatically send new products if the option is set
268
                 */
269
270
                if ('1' === $automatically_send_new_products) {
271
                    add_action('save_post', array( $ob_class, 'send_new_product_to_algolia' ), 10, 3);
272
                }
273
274
                self::$plugin_url = admin_url('options-general.php?page=algolia-woo-indexer-settings');
275
276
                if (! is_plugin_active('woocommerce/woocommerce.php')) {
277
                    add_action(
278
                        'admin_notices',
279
                        function () {
280
                            echo '<div class="error notice">
281
								  <p>' . esc_html__('WooCommerce plugin must be enabled for Algolia Woo Indexer to work.', 'algolia-woo-indexer') . '</p>
282
								</div>';
283
                        }
284
                    );
285
                }
286
            }
287
        }
288
289
        /**
290
         * Send a single product to Algolia once a new product has been published
291
         *
292
         * @param int   $post_id ID of the product.
293
         * @param array $post Post array.
294
         *
295
         * @return void
296
         */
297
        public static function send_new_product_to_algolia($post_id, $post)
298
        {
299
            if ('publish' !== $post->post_status || 'product' !== $post->post_type) {
300
                return;
301
            }
302
            self::send_products_to_algolia($post_id);
0 ignored issues
show
Bug introduced by
The method send_products_to_algolia() does not exist on Algowoo\Algolia_Woo_Indexer. ( Ignorable by Annotation )

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

302
            self::/** @scrutinizer ignore-call */ 
303
                  send_products_to_algolia($post_id);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
303
        }
304
305
        /**
306
         * Verify nonces before we update options and settings
307
         * Also retrieve the value from the send_products_to_algolia hidden field to check if we are sending products to Algolia
308
         *
309
         * @return void
310
         */
311
        public static function update_settings_options()
312
        {
313
            Algolia_Verify_Nonces::verify_settings_nonce();
314
315
            /**
316
             * Do not proceed if we are going to send products
317
             */
318
            if (true === Algolia_Verify_Nonces::verify_send_products_nonce()) {
319
                return;
320
            }
321
322
            /**
323
             * Filter the application id, api key, index name and verify that the input is an array
324
             *
325
             * @see https://www.php.net/manual/en/function.filter-input.php
326
             */
327
            $post_application_id             = filter_input(INPUT_POST, 'algolia_woo_indexer_application_id', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
328
            $post_api_key                    = filter_input(INPUT_POST, 'algolia_woo_indexer_admin_api_key', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
329
            $post_index_name                 = filter_input(INPUT_POST, 'algolia_woo_indexer_index_name', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
330
            $automatically_send_new_products = filter_input(INPUT_POST, 'algolia_woo_indexer_automatically_send_new_products', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
331
332
            /**
333
             * Properly sanitize text fields before updating data
334
             *
335
             * @see https://developer.wordpress.org/reference/functions/sanitize_text_field/
336
             */
337
            $filtered_application_id = sanitize_text_field($post_application_id['id']);
338
            $filtered_api_key        = sanitize_text_field($post_api_key['key']);
339
            $filtered_index_name     = sanitize_text_field($post_index_name['name']);
340
341
            /**
342
             * Sanitizing by setting the value to either 1 or 0
343
             */
344
            $filtered_automatically_send_new_products = (! empty($automatically_send_new_products)) ? 1 : 0;
345
346
            /**
347
             * Values have been filtered and sanitized
348
             * Check if set and not empty and update the database
349
             *
350
             * @see https://developer.wordpress.org/reference/functions/update_option/
351
             */
352
            if (isset($filtered_application_id) && (! empty($filtered_application_id))) {
353
                update_option(
354
                    ALGOWOO_DB_OPTION . ALGOLIA_APPLICATION_ID,
355
                    $filtered_application_id
356
                );
357
            }
358
359
            if (isset($filtered_api_key) && (! empty($filtered_api_key))) {
360
                update_option(
361
                    ALGOWOO_DB_OPTION . ALGOLIA_API_KEY,
362
                    $filtered_api_key
363
                );
364
            }
365
366
            if (isset($filtered_index_name) && (! empty($filtered_index_name))) {
367
                update_option(
368
                    ALGOWOO_DB_OPTION . INDEX_NAME,
369
                    $filtered_index_name
370
                );
371
            }
372
373
            if (isset($filtered_automatically_send_new_products) && (! empty($filtered_automatically_send_new_products))) {
374
                update_option(
375
                    ALGOWOO_DB_OPTION . AUTOMATICALLY_SEND_NEW_PRODUCTS,
376
                    $filtered_automatically_send_new_products
377
                );
378
            }
379
        }
380
381
        /**
382
         * Sanitize input in settings fields and filter through regex to accept only a-z and A-Z
383
         *
384
         * @param string $input Settings text data
385
         * @return array
386
         */
387
        public static function settings_fields_validate_options($input)
388
        {
389
            $valid         = array();
390
            $valid['name'] = preg_replace(
391
                '/[^a-zA-Z\s]/',
392
                '',
393
                $input['name']
394
            );
395
            return $valid;
396
        }
397
398
        /**
399
         * Load text domain for translations
400
         *
401
         * @return void
402
         */
403
        public static function load_textdomain()
404
        {
405
            load_plugin_textdomain('algolia-woo-indexer', false, basename(dirname(__FILE__)) . '/languages/');
406
        }
407
408
        /**
409
         * Add the new menu to settings section so that we can configure the plugin
410
         *
411
         * @return void
412
         */
413
        public static function admin_menu()
414
        {
415
            add_submenu_page(
416
                'options-general.php',
417
                esc_html__('Algolia Woo Indexer Settings', 'algolia-woo-indexer'),
418
                esc_html__('Algolia Woo Indexer Settings', 'algolia-woo-indexer'),
419
                'manage_options',
420
                'algolia-woo-indexer-settings',
421
                array( get_called_class(), 'algolia_woo_indexer_settings' )
422
            );
423
        }
424
425
        /**
426
         * Display settings and allow user to modify them
427
         *
428
         * @return void
429
         */
430
        public static function algolia_woo_indexer_settings()
431
        {
432
            /**
433
            * Verify that the user can access the settings page
434
            */
435
            if (! current_user_can('manage_options')) {
436
                wp_die(esc_html__('Action not allowed.', 'algolia_woo_indexer_settings'));
437
            } ?>
438
			<div class="wrap">
439
				<h1><?php esc_html__('Algolia Woo Indexer Settings', 'algolia-woo-indexer'); ?></h1>
440
				<form action="<?php echo esc_url(self::$plugin_url); ?>" method="POST">
441
			<?php
442
            settings_fields('algolia_woo_options');
443
            do_settings_sections('algolia_woo_indexer');
444
            submit_button('', 'primary wide'); ?>
445
				</form>
446
				<form action="<?php echo esc_url(self::$plugin_url); ?>" method="POST">
447
					<?php wp_nonce_field('send_products_to_algolia_nonce_action', 'send_products_to_algolia_nonce_name'); ?>
448
					<input type="hidden" name="send_products_to_algolia" id="send_products_to_algolia" value="true" />
449
					<?php submit_button(esc_html__('Send products to Algolia', 'algolia_woo_indexer_settings'), 'primary wide', '', false); ?>
450
				</form>
451
			</div>
452
			<?php
453
        }
454
455
        /**
456
         * Get active object instance
457
         *
458
         * @return object
459
         */
460
        public static function get_instance()
461
        {
462
            if (! self::$instance) {
463
                self::$instance = new Algolia_Woo_Indexer();
464
            }
465
            return self::$instance;
466
        }
467
468
        /**
469
         * The actions to execute when the plugin is activated.
470
         *
471
         * @return void
472
         */
473
        public static function activate_plugin()
474
        {
475
476
            /**
477
             * Set default values for options if not already set
478
             */
479
            $automatically_send_new_products = get_option(ALGOWOO_DB_OPTION . AUTOMATICALLY_SEND_NEW_PRODUCTS);
480
            $algolia_application_id          = get_option(ALGOWOO_DB_OPTION . ALGOLIA_APPLICATION_ID);
481
            $algolia_api_key                 = get_option(ALGOWOO_DB_OPTION . ALGOLIA_API_KEY);
482
            $algolia_index_name              = get_option(ALGOWOO_DB_OPTION . INDEX_NAME);
483
            
484
            if (empty($automatically_send_new_products)) {
485
                add_option(
486
                    ALGOWOO_DB_OPTION . AUTOMATICALLY_SEND_NEW_PRODUCTS,
487
                    '0'
488
                );
489
            }
490
491
            if (empty($algolia_application_id)) {
492
                add_option(
493
                    ALGOWOO_DB_OPTION . ALGOLIA_APPLICATION_ID,
494
                    'Change me'
495
                );
496
            }
497
498
            if (empty($algolia_api_key)) {
499
                add_option(
500
                    ALGOWOO_DB_OPTION . ALGOLIA_API_KEY,
501
                    'Change me'
502
                );
503
            }
504
505
            if (empty($algolia_index_name)) {
506
                add_option(
507
                    ALGOWOO_DB_OPTION . INDEX_NAME,
508
                    'Change me'
509
                );
510
            }
511
            set_transient(self::PLUGIN_TRANSIENT, true);
512
        }
513
514
        /**
515
         * The actions to execute when the plugin is deactivated.
516
         *
517
         * @return void
518
         */
519
        public static function deactivate_plugin()
520
        {
521
            delete_transient(self::PLUGIN_TRANSIENT);
522
        }
523
    }
524
}