autoptimizeCriticalCSSEnqueue::ao_ccss_enqueue()   F
last analyzed

Complexity

Conditions 44
Paths 3602

Size

Total Lines 180

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 44
nc 3602
nop 1
dl 0
loc 180
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * Critical CSS job enqueue logic.
4
 */
5
6
if ( ! defined( 'ABSPATH' ) ) {
7
    exit;
8
}
9
10
class autoptimizeCriticalCSSEnqueue {
11
    public function __construct()
12
    {
13
        // fetch all options at once and populate them individually explicitely as globals.
14
        $all_options = autoptimizeCriticalCSSBase::fetch_options();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $all_options is correct as \autoptimizeCriticalCSSBase::fetch_options() (which targets autoptimizeCriticalCSSBase::fetch_options()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
15
        foreach ( $all_options as $_option => $_value ) {
0 ignored issues
show
Bug introduced by
The expression $all_options of type null is not traversable.
Loading history...
16
            global ${$_option};
17
            ${$_option} = $_value;
18
        }
19
    }
20
21
    public static function ao_ccss_enqueue( $hash ) {
22
        $self = new self();
23
        // Get key status.
24
        $key = autoptimizeCriticalCSSCore::ao_ccss_key_status( false );
25
26
        // Queue is available to anyone...
27
        $enqueue = true;
28
29
        // ... which are not the ones below.
30
        if ( is_user_logged_in() || is_feed() || is_404() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || $self->ao_ccss_ua() || 'nokey' == $key['status'] || 'invalid' == $key['status'] || false === apply_filters( 'autoptimize_filter_ccss_enqueue_should_enqueue', true ) ) {
31
            $enqueue = false;
32
            autoptimizeCriticalCSSCore::ao_ccss_log( "Job queuing is not available for WordPress's logged in users, feeds, error pages, ajax calls, to criticalcss.com itself or when a valid API key is not found", 3 );
33
        }
34
35
        if ( $enqueue ) {
36
            // Continue if queue is available
37
            // Attach required arrays/ vars.
38
            global $ao_ccss_rules;
39
            global $ao_ccss_queue_raw;
40
            global $ao_ccss_queue;
41
            global $ao_ccss_forcepath;
42
43
            // Get request path and page type, and initialize the queue update flag.
44
            $req_orig        = $_SERVER['REQUEST_URI'];
45
            $req_path        = strtok( $req_orig, '?' );
46
47
            // Check if we have a lang param. we need to keep as WPML can switch languages based on that
48
            // and that includes RTL -> LTR so diff. structure, so rules would be RTL vs LTR
49
            // but this needs changes in the structur of the rule object so off by default for now
50
            // as now this will simply result in conditional rules being overwritten.
51
            if ( apply_filters( 'autoptimize_filter_ccss_coreenqueue_honor_lang', false ) && strpos( $req_orig, 'lang=' ) !== false ) {
52
                $req_params = strtok( '?' );
53
                parse_str( $req_params, $req_params_arr );
54
                if ( array_key_exists( 'lang', $req_params_arr ) && !empty( $req_params_arr['lang'] ) ) {
55
                    $req_path .= '?lang=' . $req_params_arr['lang'];
56
                }
57
            }
58
59
            $req_type        = $self->ao_ccss_get_type();
60
            $job_qualify     = false;
61
            $target_rule     = false;
62
            $rule_properties = false;
63
            $queue_update    = false;
64
65
            // Match for paths in rules.
66
            foreach ( $ao_ccss_rules['paths'] as $path => $props ) {
67
68
                // Prepare rule target and log.
69
                $target_rule = 'paths|' . $path;
70
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Qualifying path <' . $req_path . '> for job submission by rule <' . $target_rule . '>', 3 );
71
72
                // Path match
73
                // -> exact match needed for AUTO rules
74
                // -> partial match OK for MANUAL rules (which have empty hash and a file with CCSS).
75
                if ( $path === $req_path || ( false == $props['hash'] && false != $props['file'] && preg_match( '|' . $path . '|', $req_path ) ) ) {
76
77
                    // There's a path match in the rule, so job QUALIFIES with a path rule match.
78
                    $job_qualify     = true;
79
                    $rule_properties = $props;
80
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Path <' . $req_path . '> QUALIFIED for job submission by rule <' . $target_rule . '>', 3 );
81
82
                    // Stop processing other path rules.
83
                    break;
84
                }
85
            }
86
87
            // Match for types in rules if no path rule matches and if we're not enforcing paths.
88
            if ( ! $job_qualify && ( ! $ao_ccss_forcepath || ! in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) || ! apply_filters( 'autoptimize_filter_ccss_coreenqueue_ignorealltypes', false ) ) ) {
89
                foreach ( $ao_ccss_rules['types'] as $type => $props ) {
90
91
                    // Prepare rule target and log.
92
                    $target_rule = 'types|' . $type;
93
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Qualifying page type <' . $req_type . '> on path <' . $req_path . '> for job submission by rule <' . $target_rule . '>', 3 );
94
95
                    if ( $req_type == $type ) {
96
                        // Type match.
97
                        // There's a type match in the rule, so job QUALIFIES with a type rule match.
98
                        $job_qualify     = true;
99
                        $rule_properties = $props;
100
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Page type <' . $req_type . '> on path <' . $req_path . '> QUALIFIED for job submission by rule <' . $target_rule . '>', 3 );
101
102
                        // Stop processing other type rules.
103
                        break;
104
                    }
105
                }
106
            }
107
108
            if ( $job_qualify && ( ( false == $rule_properties['hash'] && false != $rule_properties['file'] ) || strpos( $req_type, 'template_' ) !== false ) ) {
109
                // If job qualifies but rule hash is false and file isn't false (MANUAL rule) or if template, job does not qualify despite what previous evaluations says.
110
                $job_qualify = false;
111
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission DISQUALIFIED by MANUAL rule <' . $target_rule . '> with hash <' . $rule_properties['hash'] . '> and file <' . $rule_properties['file'] . '>', 3 );
112
            } elseif ( ! $job_qualify && empty( $rule_properties ) ) {
113
                // But if job does not qualify and rule properties are set, job qualifies as there is no matching rule for it yet
114
                // Fill-in the new target rule.
115
                $job_qualify = true;
116
117
                // Should we switch to path-base AUTO-rules? Conditions:
118
                // 1. forcepath option has to be enabled (off by default)
119
                // 2. request type should be (by default, but filterable) one of is_page (removed for now: woo_is_product or woo_is_product_category).
120
                if ( ( $ao_ccss_forcepath && in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) ) || apply_filters( 'autoptimize_filter_ccss_coreenqueue_ignorealltypes', false ) ) {
121
                    if ( '/' !== $req_path ) {
122
                        $target_rule = 'paths|' . $req_path;
123
                    } else {
124
                        // Exception; we don't want a path-based rule for "/" as that messes things up, hard-switch this to a type-based is_front_page rule.
125
                        $target_rule = 'types|' . 'is_front_page';
126
                    }
127
                } else {
128
                    $target_rule = 'types|' . $req_type;
129
                }
130
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission QUALIFIED by MISSING rule for page type <' . $req_type . '> on path <' . $req_path . '>, new rule target is <' . $target_rule . '>', 3 );
131
            } else {
132
                // Or just log a job qualified by a matching rule.
133
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission QUALIFIED by AUTO rule <' . $target_rule . '> with hash <' . $rule_properties['hash'] . '> and file <' . $rule_properties['file'] . '>', 3 );
134
            }
135
136
            // Submit job.
137
            if ( $job_qualify ) {
138
                if ( ! array_key_exists( $req_path, $ao_ccss_queue ) ) {
139
                    // This is a NEW job
140
                    // Merge job into the queue.
141
                    $ao_ccss_queue[ $req_path ] = $self->ao_ccss_define_job(
142
                        $req_path,
143
                        $target_rule,
144
                        $req_type,
145
                        $hash,
146
                        null,
147
                        null,
148
                        null,
149
                        null,
150
                        true
151
                    );
152
                    // Set update flag.
153
                    $queue_update = true;
154
                } else {
155
                    // This is an existing job
156
                    // The job is still NEW, most likely this is extra CSS file for the same page that needs a hash.
157
                    if ( 'NEW' == $ao_ccss_queue[ $req_path ]['jqstat'] ) {
158
                        // Add hash if it's not already in the job.
159
                        if ( ! in_array( $hash, $ao_ccss_queue[ $req_path ]['hashes'] ) ) {
160
                            // Push new hash to its array and update flag.
161
                            $queue_update = array_push( $ao_ccss_queue[ $req_path ]['hashes'], $hash );
0 ignored issues
show
Unused Code introduced by
$queue_update is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
162
163
                            // Log job update.
164
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Hashes UPDATED on local job id <' . $ao_ccss_queue[ $req_path ]['ljid'] . '>, job status NEW, target rule <' . $ao_ccss_queue[ $req_path ]['rtarget'] . '>, hash added: ' . $hash, 3 );
165
166
                            // Return from here as the hash array is already updated.
167
                            return true;
168
                        }
169
                    } elseif ( 'NEW' != $ao_ccss_queue[ $req_path ]['jqstat'] && 'JOB_QUEUED' != $ao_ccss_queue[ $req_path ]['jqstat'] && 'JOB_ONGOING' != $ao_ccss_queue[ $req_path ]['jqstat'] ) {
170
                        // Allow requeuing jobs that are not NEW, JOB_QUEUED or JOB_ONGOING
171
                        // Merge new job keeping some previous job values.
172
                        $ao_ccss_queue[ $req_path ] = $self->ao_ccss_define_job(
173
                            $req_path,
174
                            $target_rule,
175
                            $req_type,
176
                            $hash,
177
                            $ao_ccss_queue[ $req_path ]['file'],
178
                            $ao_ccss_queue[ $req_path ]['jid'],
179
                            $ao_ccss_queue[ $req_path ]['jrstat'],
180
                            $ao_ccss_queue[ $req_path ]['jvstat'],
181
                            false
182
                        );
183
                        // Set update flag.
184
                        $queue_update = true;
185
                    }
186
                }
187
188
                if ( $queue_update ) {
189
                    // Persist the job to the queue and return.
190
                    $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
191
                    update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
192
                    return true;
193
                } else {
194
                    // Or just return false if no job was added.
195
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'A job for path <' . $req_path . '> already exist with NEW or PENDING status, skipping job creation', 3 );
196
                    return false;
197
                }
198
            }
199
        }
200
    }
201
202
    public function ao_ccss_get_type() {
203
        // Get the type of a page
204
        // Attach the conditional tags array.
205
        global $ao_ccss_types;
206
        global $ao_ccss_forcepath;
207
208
        // By default, a page type is false.
209
        $page_type = false;
210
211
        // Iterates over the array to match a type.
212
        foreach ( $ao_ccss_types as $type ) {
213
            if ( is_404() ) {
214
                $page_type = 'is_404';
215
                break;
216
            } elseif ( is_front_page() ) {
217
                // identify frontpage immediately to avoid it also matching a CPT or template.
218
                $page_type = 'is_front_page';
219
                break;
220
            } elseif ( strpos( $type, 'custom_post_' ) !== false && ( ! $ao_ccss_forcepath || ! is_page() ) ) {
221
                // Match custom post types and not page or page not forced to path-based.
222
                if ( get_post_type( get_the_ID() ) === substr( $type, 12 ) ) {
223
                    $page_type = $type;
224
                    break;
225
                }
226
            } elseif ( strpos( $type, 'template_' ) !== false && ( ! $ao_ccss_forcepath || ! is_page() ) ) {
227
                // Match templates if not page or if page is not forced to path-based.
228
                if ( is_page_template( substr( $type, 9 ) ) ) {
229
                    $page_type = $type;
230
                    break;
231
                }
232
            } else {
233
                // Match all other existing types
234
                // but remove prefix to be able to check if the function exists & returns true.
235
                $_type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type );
236
                if ( function_exists( $_type ) && call_user_func( $_type ) ) {
237
                    // Make sure we only return for one page, not for the "paged pages" (/page/2 ..).
238
                    if ( ! is_page() || ! is_paged() ) {
239
                        $page_type = $type;
240
                        break;
241
                    }
242
                }
243
            }
244
        }
245
246
        // Return the page type.
247
        return $page_type;
248
    }
249
250
    public function ao_ccss_define_job( $path, $target, $type, $hash, $file, $jid, $jrstat, $jvstat, $create ) {
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
251
        // Define a job entry to be created or updated
252
        // Define commom job properties.
253
        $path            = array();
254
        $path['ljid']    = $this->ao_ccss_job_id();
255
        $path['rtarget'] = $target;
256
        $path['ptype']   = $type;
257
        $path['hashes']  = array( $hash );
258
        $path['hash']    = $hash;
259
        $path['file']    = $file;
260
        $path['jid']     = $jid;
261
        $path['jqstat']  = 'NEW';
262
        $path['jrstat']  = $jrstat;
263
        $path['jvstat']  = $jvstat;
264
        $path['jctime']  = microtime( true );
265
        $path['jftime']  = null;
266
267
        // Set operation requested.
268
        if ( $create ) {
269
            $operation = 'CREATED';
270
        } else {
271
            $operation = 'UPDATED';
272
        }
273
274
        // Log job creation.
275
        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job ' . $operation . ' with local job id <' . $path['ljid'] . '> for target rule <' . $target . '>', 3 );
276
277
        return $path;
278
    }
279
280
    public function ao_ccss_job_id( $length = 6 ) {
281
        // Generate random strings for the local job ID
282
        // Based on https://stackoverflow.com/a/4356295 .
283
        $characters        = '0123456789abcdefghijklmnopqrstuvwxyz';
284
        $characters_length = strlen( $characters );
285
        $random_string     = 'j-';
286
        for ( $i = 0; $i < $length; $i++ ) {
287
            $random_string .= $characters[ rand( 0, $characters_length - 1 ) ];
288
        }
289
        return $random_string;
290
    }
291
292
    public function ao_ccss_ua() {
293
        // Check for criticalcss.com user agent.
294
        $agent = '';
295
        if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
296
            $agent = $_SERVER['HTTP_USER_AGENT'];
297
        }
298
299
        // Check for UA and return TRUE when criticalcss.com is the detected UA, false when not.
300
        $rtn = strpos( $agent, AO_CCSS_URL );
301
        if ( 0 === $rtn ) {
302
            $rtn = true;
303
        } else {
304
            $rtn = false;
305
        }
306
        return ( $rtn );
307
    }
308
}
309