Completed
Push — master ( b4100c...ed2097 )
by frank
01:49
created

autoptimizeCriticalCSSEnqueue::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
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();
15
        foreach ( $all_options as $_option => $_value ) {
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'] ) {
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_path        = strtok( $_SERVER['REQUEST_URI'], '?' );
45
            $req_type        = $self->ao_ccss_get_type();
46
            $job_qualify     = false;
47
            $target_rule     = false;
48
            $rule_properties = false;
49
            $queue_update    = false;
50
51
            // Match for paths in rules.
52
            foreach ( $ao_ccss_rules['paths'] as $path => $props ) {
53
54
                // Prepare rule target and log.
55
                $target_rule = 'paths|' . $path;
56
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Qualifying path <' . $req_path . '> for job submission by rule <' . $target_rule . '>', 3 );
57
58
                // Path match
59
                // -> exact match needed for AUTO rules
60
                // -> partial match OK for MANUAL rules (which have empty hash and a file with CCSS).
61
                if ( $path === $req_path || ( false == $props['hash'] && false != $props['file'] && preg_match( '|' . $path . '|', $req_path ) ) ) {
62
63
                    // There's a path match in the rule, so job QUALIFIES with a path rule match.
64
                    $job_qualify     = true;
65
                    $rule_properties = $props;
66
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Path <' . $req_path . '> QUALIFIED for job submission by rule <' . $target_rule . '>', 3 );
67
68
                    // Stop processing other path rules.
69
                    break;
70
                }
71
            }
72
73
            // Match for types in rules if no path rule matches and if we're not enforcing paths.
74
            if ( ! $job_qualify && ( ! $ao_ccss_forcepath || ! in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) ) ) {
75
                foreach ( $ao_ccss_rules['types'] as $type => $props ) {
76
77
                    // Prepare rule target and log.
78
                    $target_rule = 'types|' . $type;
79
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Qualifying page type <' . $req_type . '> on path <' . $req_path . '> for job submission by rule <' . $target_rule . '>', 3 );
80
81
                    if ( $req_type == $type ) {
82
                        // Type match.
83
                        // There's a type match in the rule, so job QUALIFIES with a type rule match.
84
                        $job_qualify     = true;
85
                        $rule_properties = $props;
86
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Page type <' . $req_type . '> on path <' . $req_path . '> QUALIFIED for job submission by rule <' . $target_rule . '>', 3 );
87
88
                        // Stop processing other type rules.
89
                        break;
90
                    }
91
                }
92
            }
93
94
            if ( $job_qualify && false == $rule_properties['hash'] && false != $rule_properties['file'] ) {
95
                // If job qualifies but rule hash is false and file isn't false  (MANUAL rule), job does not qualify despite what previous evaluations says.
96
                $job_qualify = false;
97
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission DISQUALIFIED by MANUAL rule <' . $target_rule . '> with hash <' . $rule_properties['hash'] . '> and file <' . $rule_properties['file'] . '>', 3 );
98
            } elseif ( ! $job_qualify && empty( $rule_properties ) ) {
99
                // But if job does not qualify and rule properties are set, job qualifies as there is no matching rule for it yet
100
                // Fill-in the new target rule.
101
                $job_qualify = true;
102
103
                // Should we switch to path-base AUTO-rules? Conditions:
104
                // 1. forcepath option has to be enabled (off by default)
105
                // 2. request type should be (by default, but filterable) one of is_page (removed for now: woo_is_product or woo_is_product_category).
106
                if ( $ao_ccss_forcepath && in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) ) {
107
                    if ( '/' !== $req_path ) {
108
                        $target_rule = 'paths|' . $req_path;
109
                    } else {
110
                        // 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.
111
                        $target_rule = 'types|' . 'is_front_page';
112
                    }
113
                } else {
114
                    $target_rule = 'types|' . $req_type;
115
                }
116
                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 );
117
            } else {
118
                // Or just log a job qualified by a matching rule.
119
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission QUALIFIED by AUTO rule <' . $target_rule . '> with hash <' . $rule_properties['hash'] . '> and file <' . $rule_properties['file'] . '>', 3 );
120
            }
121
122
            // Submit job.
123
            if ( $job_qualify ) {
124
                if ( ! array_key_exists( $req_path, $ao_ccss_queue ) ) {
125
                    // This is a NEW job
126
                    // Merge job into the queue.
127
                    $ao_ccss_queue[ $req_path ] = $self->ao_ccss_define_job(
128
                        $req_path,
129
                        $target_rule,
130
                        $req_type,
131
                        $hash,
132
                        null,
133
                        null,
134
                        null,
135
                        null,
136
                        true
137
                    );
138
                    // Set update flag.
139
                    $queue_update = true;
140
                } else {
141
                    // This is an existing job
142
                    // The job is still NEW, most likely this is extra CSS file for the same page that needs a hash.
143
                    if ( 'NEW' == $ao_ccss_queue[ $req_path ]['jqstat'] ) {
144
                        // Add hash if it's not already in the job.
145
                        if ( ! in_array( $hash, $ao_ccss_queue[ $req_path ]['hashes'] ) ) {
146
                            // Push new hash to its array and update flag.
147
                            $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...
148
149
                            // Log job update.
150
                            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 );
151
152
                            // Return from here as the hash array is already updated.
153
                            return true;
154
                        }
155
                    } elseif ( 'NEW' != $ao_ccss_queue[ $req_path ]['jqstat'] && 'JOB_QUEUED' != $ao_ccss_queue[ $req_path ]['jqstat'] && 'JOB_ONGOING' != $ao_ccss_queue[ $req_path ]['jqstat'] ) {
156
                        // Allow requeuing jobs that are not NEW, JOB_QUEUED or JOB_ONGOING
157
                        // Merge new job keeping some previous job values.
158
                        $ao_ccss_queue[ $req_path ] = $self->ao_ccss_define_job(
159
                            $req_path,
160
                            $target_rule,
161
                            $req_type,
162
                            $hash,
163
                            $ao_ccss_queue[ $req_path ]['file'],
164
                            $ao_ccss_queue[ $req_path ]['jid'],
165
                            $ao_ccss_queue[ $req_path ]['jrstat'],
166
                            $ao_ccss_queue[ $req_path ]['jvstat'],
167
                            false
168
                        );
169
                        // Set update flag.
170
                        $queue_update = true;
171
                    }
172
                }
173
174
                if ( $queue_update ) {
175
                    // Persist the job to the queue and return.
176
                    $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
177
                    update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
178
                    return true;
179
                } else {
180
                    // Or just return false if no job was added.
181
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'A job for path <' . $req_path . '> already exist with NEW or PENDING status, skipping job creation', 3 );
182
                    return false;
183
                }
184
            }
185
        }
186
    }
187
188
    public function ao_ccss_get_type() {
189
        // Get the type of a page
190
        // Attach the conditional tags array.
191
        global $ao_ccss_types;
192
193
        // By default, a page type is false.
194
        $page_type = false;
195
196
        // Iterates over the array to match a type.
197
        foreach ( $ao_ccss_types as $type ) {
198
            if ( strpos( $type, 'custom_post_' ) !== false ) {
199
                // Match custom post types.
200
                if ( get_post_type( get_the_ID() ) === substr( $type, 12 ) ) {
201
                    $page_type = $type;
202
                    break;
203
                }
204
            } elseif ( strpos( $type, 'template_' ) !== false ) {
205
                // If templates; don't break, templates become manual-only rules.
206
            } else {
207
                // Match all other existing types
208
                // but remove prefix to be able to check if the function exists & returns true.
209
                $_type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type );
210
                if ( function_exists( $_type ) && call_user_func( $_type ) ) {
211
                    // Make sure we only return is_front_page (and is_home) for one page, not for the "paged frontpage" (/page/2 ..).
212
                    if ( ( 'is_front_page' !== $_type && 'is_home' !== $_type ) || ! is_paged() ) {
213
                        $page_type = $type;
214
                        break;
215
                    }
216
                }
217
            }
218
        }
219
220
        // Return the page type.
221
        return $page_type;
222
    }
223
224
    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...
225
        // Define a job entry to be created or updated
226
        // Define commom job properties.
227
        $path            = array();
228
        $path['ljid']    = $this->ao_ccss_job_id();
229
        $path['rtarget'] = $target;
230
        $path['ptype']   = $type;
231
        $path['hashes']  = array( $hash );
232
        $path['hash']    = $hash;
233
        $path['file']    = $file;
234
        $path['jid']     = $jid;
235
        $path['jqstat']  = 'NEW';
236
        $path['jrstat']  = $jrstat;
237
        $path['jvstat']  = $jvstat;
238
        $path['jctime']  = microtime( true );
239
        $path['jftime']  = null;
240
241
        // Set operation requested.
242
        if ( $create ) {
243
            $operation = 'CREATED';
244
        } else {
245
            $operation = 'UPDATED';
246
        }
247
248
        // Log job creation.
249
        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job ' . $operation . ' with local job id <' . $path['ljid'] . '> for target rule <' . $target . '>', 3 );
250
251
        return $path;
252
    }
253
254
    public function ao_ccss_job_id( $length = 6 ) {
255
        // Generate random strings for the local job ID
256
        // Based on https://stackoverflow.com/a/4356295 .
257
        $characters        = '0123456789abcdefghijklmnopqrstuvwxyz';
258
        $characters_length = strlen( $characters );
259
        $random_string     = 'j-';
260
        for ( $i = 0; $i < $length; $i++ ) {
261
            $random_string .= $characters[ rand( 0, $characters_length - 1 ) ];
262
        }
263
        return $random_string;
264
    }
265
266
    public function ao_ccss_ua() {
267
        // Check for criticalcss.com user agent.
268
        $agent = '';
269
        if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
270
            $agent = $_SERVER['HTTP_USER_AGENT'];
271
        }
272
273
        // Check for UA and return TRUE when criticalcss.com is the detected UA, false when not.
274
        $rtn = strpos( $agent, AO_CCSS_URL );
275
        if ( 0 === $rtn ) {
276
            $rtn = true;
277
        } else {
278
            $rtn = false;
279
        }
280
        return ( $rtn );
281
    }
282
}
283