Completed
Branch BUG-10381-asset-loading (0f96c1)
by
unknown
60:43 queued 48:13
created

LegacyShortcodesManager   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 418
Duplicated Lines 2.15 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 9
loc 418
rs 8.3673
wmc 45
lcom 1
cbo 5

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A registerShortcodes() 0 4 1
B getShortcodes() 0 24 3
B registerShortcode() 9 61 5
B addShortcodes() 0 29 4
C initializeShortcodes() 0 67 12
A parseContentForShortcodes() 0 12 4
B initializeShortcode() 0 38 6
A generateShortcodeTagFromClassName() 0 4 1
B generateShortcodeClassNameFromTag() 0 24 1
A addShortcodeClassPrefix() 0 4 2
A getEspressoShortcodeTags() 0 8 2
A doShortcode() 0 10 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like LegacyShortcodesManager 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 LegacyShortcodesManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace EventEspresso\core\services\shortcodes;
3
4
use EE_Config;
5
use EE_Error;
6
use EE_Front_controller;
7
use EE_Registry;
8
use ReflectionClass;
9
use WP;
10
use WP_Query;
11
12
defined('EVENT_ESPRESSO_VERSION') || exit;
13
14
15
16
/**
17
 * Class LegacyShortcodesManager
18
 * Legacy code extracted from EE_Config, will be deprecated sometime in the future.
19
 * Please use the ShortcodesManager for registering shortcodes
20
 *
21
 * @package       Event Espresso
22
 * @author        Brent Christensen
23
 * @since         $VID:$
24
 */
25
class LegacyShortcodesManager
26
{
27
28
    /**
29
     * @var EE_Registry $registry
30
     */
31
    private $registry;
32
33
34
35
36
    /**
37
     * LegacyShortcodesManager constructor.
38
     *
39
     * @param \EE_Registry $registry
40
     */
41
    public function __construct(EE_Registry $registry)
42
    {
43
        $this->registry = $registry;
44
    }
45
46
47
48
    /**
49
     * registerShortcodes
50
     *
51
     * @return void
52
     */
53
    public function registerShortcodes()
54
    {
55
        $this->registry->shortcodes = $this->getShortcodes();
56
    }
57
58
59
60
    /**
61
     * getShortcodes
62
     *
63
     * @return array
64
     */
65
    public function getShortcodes()
66
    {
67
        // previously this method would glob the shortcodes directory
68
        // then filter that list of shortcodes to register,
69
        // but now we are going to just supply an empty array.
70
        // this allows any shortcodes that have not yet been converted to the new system
71
        // to still get loaded and processed, albeit using the same legacy logic as before
72
        $shortcodes_to_register = apply_filters(
73
            'FHEE__EE_Config__register_shortcodes__shortcodes_to_register',
74
            array()
75
        );
76
        if ( ! empty($shortcodes_to_register)) {
77
            // cycle thru shortcode folders
78
            foreach ($shortcodes_to_register as $shortcode_path) {
79
                // add to list of installed shortcode modules
80
                LegacyShortcodesManager::registerShortcode($shortcode_path);
81
            }
82
        }
83
        // filter list of installed modules
84
        return apply_filters(
85
            'FHEE__EE_Config___register_shortcodes__installed_shortcodes',
86
            $this->registry->shortcodes
87
        );
88
    }
89
90
91
92
    /**
93
     *    register_shortcode - makes core aware of this shortcode
94
     *
95
     * @access    public
96
     * @param    string $shortcode_path - full path up to and including shortcode folder
97
     * @return    bool
98
     */
99
    public function registerShortcode($shortcode_path = null)
100
    {
101
        do_action('AHEE__EE_Config__register_shortcode__begin', $shortcode_path);
102
        $shortcode_ext = '.shortcode.php';
103
        // make all separators match
104
        $shortcode_path = str_replace(array('\\', '/'), DS, $shortcode_path);
105
        // does the file path INCLUDE the actual file name as part of the path ?
106
        if (strpos($shortcode_path, $shortcode_ext) !== false) {
107
            // grab shortcode file name from directory name and break apart at dots
108
            $shortcode_file = explode('.', basename($shortcode_path));
109
            // take first segment from file name pieces and remove class prefix if it exists
110
            $shortcode = strpos($shortcode_file[0], 'EES_') === 0
111
                ? substr($shortcode_file[0], 4)
112
                : $shortcode_file[0];
113
            // sanitize shortcode directory name
114
            $shortcode = sanitize_key($shortcode);
115
            // now we need to rebuild the shortcode path
116
            $shortcode_path = explode(DS, $shortcode_path);
117
            // remove last segment
118
            array_pop($shortcode_path);
119
            // glue it back together
120
            $shortcode_path = implode(DS, $shortcode_path) . DS;
121
        } else {
122
            // we need to generate the filename based off of the folder name
123
            // grab and sanitize shortcode directory name
124
            $shortcode = sanitize_key(basename($shortcode_path));
125
            $shortcode_path = rtrim($shortcode_path, DS) . DS;
126
        }
127
        // create classname from shortcode directory or file name
128
        $shortcode = str_replace(' ', '_', ucwords(str_replace('_', ' ', $shortcode)));
129
        // add class prefix
130
        $shortcode_class = 'EES_' . $shortcode;
131
        // does the shortcode exist ?
132 View Code Duplication
        if ( ! is_readable($shortcode_path . DS . $shortcode_class . $shortcode_ext)) {
133
            $msg = sprintf(
134
                __(
135
                    'The requested %s shortcode file could not be found or is not readable due to file permissions. It should be in %s',
136
                    'event_espresso'
137
                ),
138
                $shortcode_class,
139
                $shortcode_path . DS . $shortcode_class . $shortcode_ext
140
            );
141
            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
142
            return false;
143
        }
144
        // load the shortcode class file
145
        require_once($shortcode_path . $shortcode_class . $shortcode_ext);
146
        // verify that class exists
147
        if ( ! class_exists($shortcode_class)) {
148
            $msg = sprintf(
149
                __('The requested %s shortcode class does not exist.', 'event_espresso'),
150
                $shortcode_class
151
            );
152
            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
153
            return false;
154
        }
155
        $shortcode = strtoupper($shortcode);
156
        // add to array of registered shortcodes
157
        $this->registry->shortcodes->{$shortcode} = $shortcode_path . $shortcode_class . $shortcode_ext;
158
        return true;
159
    }
160
161
162
163
    /**
164
     *    _initialize_shortcodes
165
     *    allow shortcodes to set hooks for the rest of the system
166
     *
167
     * @access private
168
     * @return void
169
     */
170
    public function addShortcodes()
171
    {
172
        // cycle thru shortcode folders
173
        foreach ($this->registry->shortcodes as $shortcode => $shortcode_path) {
174
            // add class prefix
175
            $shortcode_class = 'EES_' . $shortcode;
176
            // fire the shortcode class's set_hooks methods in case it needs to hook into other parts of the system
177
            // which set hooks ?
178
            if (is_admin()) {
179
                // fire immediately
180
                call_user_func(array($shortcode_class, 'set_hooks_admin'));
181
            } else {
182
                // delay until other systems are online
183
                add_action(
184
                    'AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons',
185
                    array($shortcode_class, 'set_hooks')
186
                );
187
                // convert classname to UPPERCASE and create WP shortcode.
188
                $shortcode_tag = strtoupper($shortcode);
189
                // but first check if the shortcode has already
190
                // been added before assigning 'fallback_shortcode_processor'
191
                if ( ! shortcode_exists($shortcode_tag)) {
192
                    // NOTE: this shortcode declaration will get overridden if the shortcode
193
                    // is successfully detected in the post content in initializeShortcode()
194
                    add_shortcode($shortcode_tag, array($shortcode_class, 'fallback_shortcode_processor'));
195
                }
196
            }
197
        }
198
    }
199
200
201
202
    /**
203
     * callback for the WP "get_header" hook point
204
     * checks posts for EE shortcodes, and initializes them,
205
     * then toggles filter switch that loads core default assets
206
     *
207
     * @param \WP_Query $wp_query
208
     * @return void
209
     */
210
    public function initializeShortcodes(WP_Query $wp_query)
211
    {
212
        if (empty($this->registry->shortcodes) || ! $wp_query->is_main_query() || is_admin()) {
213
            return;
214
        }
215
        global $wp;
216
        /** @var EE_Front_controller $Front_Controller */
217
        $Front_Controller = $this->registry->load_core('Front_Controller', array(), false);
218
        do_action('AHEE__EE_Front_Controller__initialize_shortcodes__begin', $wp, $Front_Controller);
219
        $Front_Controller->Request_Handler()->set_request_vars();
220
        // grab post_name from request
221
        $current_post = apply_filters(
222
            'FHEE__EE_Front_Controller__initialize_shortcodes__current_post_name',
223
            $Front_Controller->Request_Handler()->get('post_name')
224
        );
225
        $show_on_front = get_option('show_on_front');
226
        // if it's not set, then check if frontpage is blog
227
        if (empty($current_post)) {
228
            // yup.. this is the posts page, prepare to load all shortcode modules
229
            $current_post = 'posts';
230
            // unless..
231
            if ($show_on_front === 'page') {
232
                // some other page is set as the homepage
233
                $page_on_front = get_option('page_on_front');
234
                if ($page_on_front) {
235
                    // k now we need to find the post_name for this page
236
                    global $wpdb;
237
                    $page_on_front = $wpdb->get_var(
238
                        $wpdb->prepare(
239
                            "SELECT post_name from {$wpdb->posts} WHERE post_type='page' AND post_status='publish' AND ID=%d",
240
                            $page_on_front
241
                        )
242
                    );
243
                    // set the current post slug to what it actually is
244
                    $current_post = $page_on_front ? $page_on_front : $current_post;
245
                }
246
            }
247
        }
248
        // in case $current_post is hierarchical like: /parent-page/current-page
249
        $current_post = basename($current_post);
250
        if (
251
            // is current page/post the "blog" page ?
252
            $current_post === EE_Config::get_page_for_posts()
253
            // or are we on a category page?
254
            || (
255
                is_array(term_exists($current_post, 'category'))
256
                || array_key_exists('category_name', $wp->query_vars)
257
            )
258
        ) {
259
            // initialize all legacy shortcodes
260
            $load_assets = $this->parseContentForShortcodes('', true);
261
        } else {
262
            global $wpdb;
263
            $post_content = $wpdb->get_var(
264
                $wpdb->prepare(
265
                    "SELECT post_content from {$wpdb->posts} WHERE post_status='publish' AND post_name=%s",
266
                    $current_post
267
                )
268
            );
269
            $load_assets = $this->parseContentForShortcodes($post_content);
270
        }
271
        if ($load_assets) {
272
            add_filter('FHEE_load_css', '__return_true');
273
            add_filter('FHEE_load_js', '__return_true');
274
        }
275
        do_action('AHEE__EE_Front_Controller__initialize_shortcodes__end', $Front_Controller);
276
    }
277
278
279
280
    /**
281
     * checks supplied content against list of legacy shortcodes,
282
     * then initializes any found shortcodes, and returns true.
283
     * returns false if no shortcodes found.
284
     *
285
     * @param string $content
286
     * @param bool   $load_all if true, then ALL active legacy shortcodes will be initialized
287
     * @return bool
288
     */
289
    public function parseContentForShortcodes($content = '', $load_all = false)
290
    {
291
        $has_shortcode = false;
292
        foreach ($this->registry->shortcodes as $shortcode_class => $shortcode) {
293
            if ($load_all || has_shortcode($content, $shortcode_class) ) {
294
                // load up the shortcode
295
                $this->initializeShortcode($shortcode_class);
296
                $has_shortcode = true;
297
            }
298
        }
299
        return $has_shortcode;
300
    }
301
302
303
304
    /**
305
     * given a shortcode name, will instantiate the shortcode and call it's run() method
306
     *
307
     * @param string $shortcode_class
308
     * @param WP     $wp
309
     */
310
    public function initializeShortcode($shortcode_class = '', WP $wp = null)
311
    {
312
        // don't do anything if shortcode is already initialized
313
        if (
314
            empty($this->registry->shortcodes->{$shortcode_class})
315
            || ! is_string($this->registry->shortcodes->{$shortcode_class})
316
        ) {
317
            return;
318
        }
319
        // let's pause to reflect on this...
320
        $sc_reflector = new ReflectionClass(LegacyShortcodesManager::addShortcodeClassPrefix($shortcode_class));
321
        // ensure that class is actually a shortcode
322
        if (
323
            defined('WP_DEBUG')
324
            && WP_DEBUG === true
325
            && ! $sc_reflector->isSubclassOf('EES_Shortcode')
326
        ) {
327
            EE_Error::add_error(
328
                sprintf(
329
                    __(
330
                        'The requested %s shortcode is not of the class "EES_Shortcode". Please check your files.',
331
                        'event_espresso'
332
                    ),
333
                    $shortcode_class
334
                ),
335
                __FILE__,
336
                __FUNCTION__,
337
                __LINE__
338
            );
339
            add_filter('FHEE_run_EE_the_content', '__return_true');
340
            return;
341
        }
342
        global $wp;
343
        // and pass the request object to the run method
344
        $this->registry->shortcodes->{$shortcode_class} = $sc_reflector->newInstance();
345
        // fire the shortcode class's run method, so that it can activate resources
346
        $this->registry->shortcodes->{$shortcode_class}->run($wp);
347
    }
348
349
350
351
    /**
352
     * get classname, remove EES_prefix, and convert to UPPERCASE
353
     *
354
     * @param string $class_name
355
     * @return string
356
     */
357
    public static function generateShortcodeTagFromClassName($class_name)
358
    {
359
        return strtoupper(str_replace('EES_', '', $class_name));
360
    }
361
362
363
364
    /**
365
     * add EES_prefix and Capitalize words
366
     *
367
     * @param string $tag
368
     * @return string
369
     */
370
    public static function generateShortcodeClassNameFromTag($tag)
371
    {
372
        // order of operation runs from inside to out
373
        // 5) maybe add prefix
374
        return LegacyShortcodesManager::addShortcodeClassPrefix(
375
        // 4) find spaces, replace with underscores
376
            str_replace(
377
                ' ',
378
                '_',
379
                // 3) capitalize first letter of each word
380
                ucwords(
381
                // 2) also change to lowercase so ucwords() will work
382
                    strtolower(
383
                    // 1) find underscores, replace with spaces so ucwords() will work
384
                        str_replace(
385
                            '_',
386
                            ' ',
387
                            $tag
388
                        )
389
                    )
390
                )
391
            )
392
        );
393
    }
394
395
396
397
    /**
398
     * maybe add EES_prefix
399
     *
400
     * @param string $class_name
401
     * @return string
402
     */
403
    public static function addShortcodeClassPrefix($class_name)
404
    {
405
        return strpos($class_name, 'EES_') === 0 ? $class_name : 'EES_' . $class_name;
406
    }
407
408
409
410
    /**
411
     * @return array
412
     */
413
    public function getEspressoShortcodeTags()
414
    {
415
        static $shortcode_tags = array();
416
        if (empty($shortcode_tags)) {
417
            $shortcode_tags = array_keys((array)$this->registry->shortcodes);
418
        }
419
        return $shortcode_tags;
420
    }
421
422
423
424
    /**
425
     * @param string $content
426
     * @return string
427
     */
428
    public function doShortcode($content)
429
    {
430
        foreach ($this->getEspressoShortcodeTags() as $shortcode_tag) {
431
            if (strpos($content, $shortcode_tag) !== false) {
432
                $shortcode_class = LegacyShortcodesManager::generateShortcodeClassNameFromTag($shortcode_tag);
433
                $this->initializeShortcode($shortcode_class);
434
            }
435
        }
436
        return do_shortcode($content);
437
    }
438
439
440
441
442
}
443
// End of file LegacyShortcodesManager.php
444
// Location: EventEspresso\core\services\shortcodes/LegacyShortcodesManager.php