Completed
Branch dev (2736f5)
by
unknown
01:56
created

_replyToEnqueueScripts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Admin Page Framework
4
 *
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2020, Michael Uno; Licensed MIT
7
 *
8
 */
9
10
/**
11
 * Provides methods to enqueue or insert resource elements.
12
 *
13
 * The class handles `<link>`, `<style>` and `<script>` tags to be inserted conditionally into the head tag or the footer of the page.
14
 *
15
 * @abstract
16
 * @since       2.1.5
17
 * @since       3.3.0       Changed the name from `AdminPageFramework_HeadTag_Base`.
18
 * @since       3.6.3       Changed it to extend `AdminPageFramework_WPUtility`.
19
 * @extends     AdminPageFramework_FrameworkUtility
20
 * @package     AdminPageFramework/Common/Factory/Resource
21
 * @internal
22
 * @extends     AdminPageFramework_FrameworkUtility
23
 */
24
abstract class AdminPageFramework_Resource_Base extends AdminPageFramework_FrameworkUtility {
25
26
    /**
27
     * Represents the structure of the array for enqueuing scripts and styles.
28
     *
29
     * @since       2.1.2
30
     * @since       2.1.5       Moved to the base class.
31
     * @since       3.0.0       Moved from the property class.
32
     * @since       3.3.0       Changed the name to `$_aStructure_EnqueuingResources` from `$_aStructure_EnqueuingScriptsAndStyles`.
33
     * @internal
34
     */
35
    protected static $_aStructure_EnqueuingResources = array(
36
37
        /* The system internal keys. */
38
        'sSRC'          => null,
39
        'aPostTypes'    => array(),     // for meta box class
40
        'sPageSlug'     => null,
41
        'sTabSlug'      => null,
42
        'sType'         => null,        // script or style
43
44
        /* The below keys are for users. */
45
        'handle_id'     => null,
46
        'dependencies'  => array(),
47
        'version'       => false,       // although the type should be string, the wp_enqueue_...() functions want false as the default value.
48
        'translation'   => array(),     // only for scripts
49
        'in_footer'     => false,       // only for scripts
50
        'media'         => 'all',       // only for styles
51
        'attributes'    => array(),     // 3.3.0+ - the attribute array
52
53
    );
54
55
    /**
56
     * Stores the class selector used for the class-specific style.
57
     *
58
     * @since       3.2.0
59
     * @remark      This value should be overridden in an extended class.
60
     * @internal
61
     */
62
    protected $_sClassSelector_Style    = 'admin-page-framework-style';
63
64
    /**
65
     * Stores the class selector used to the class-specific script.
66
     *
67
     * @since       3.2.0
68
     * @remark      This value should be overridden in an extended class.
69
     * @internal
70
     */
71
    protected $_sClassSelector_Script   = 'admin-page-framework-script';
72
73
    /**
74
     * Stores hand IDs by resource url to look up handle id and add custom arguments.
75
     * @since       3.3.0
76
     * @internal
77
     */
78
    protected $_aHandleIDs = array();
79
80
    /**
81
     * A property object.
82
     *
83
     * @remark      Set in the constructor.
84
     */
85
    public $oProp;
86
87
    /**
88
     * A utility object.
89
     *
90
     * @remark      Set in the constructor.
91
     * @deprecated  3.6.3
92
     * @remark      kept for backward compatibility.
93
     * @var         AdminPageFramework_WPUtility
94
     */
95
    public $oUtil;
96
97
    /**
98
     * Sets up properties and hooks.
99
     * @internal
100
     */
101
    public function __construct( $oProp ) {
102
103
        $this->oProp = $oProp;
104
105
        // for backward compatibility
106
        $this->oUtil = new AdminPageFramework_WPUtility;
107
108
        if ( $this->isDoingAjax() ) {
109
            return;
110
        }
111
112
        // Hook the admin header to insert custom admin stylesheets and scripts.
113
        add_action( 'admin_enqueue_scripts', array( $this, '_replyToEnqueueScripts' ) );
114
        add_action( 'admin_enqueue_scripts', array( $this, '_replyToEnqueueStyles' ) );
115
116
        /// A low priority is required to let dependencies loaded fast especially in customizer.php.
117
        add_action( did_action( 'admin_print_styles' ) ? 'admin_print_footer_scripts' : 'admin_print_styles', array( $this, '_replyToAddStyle' ), 999 );
118
        add_action( did_action( 'admin_print_scripts' ) ? 'admin_print_footer_scripts' : 'admin_print_scripts', array( $this, '_replyToAddScript' ), 999 );
119
120
        // Take care of items that could not be added in the head tag.
121
122
        /// For wp-admin/customizer.php
123
        add_action( 'customize_controls_print_footer_scripts', array( $this, '_replyToEnqueueScripts' ) );
124
        add_action( 'customize_controls_print_footer_scripts', array( $this, '_replyToEnqueueStyles' ) );
125
126
        /// For admin pages other than wp-admin/customizer.php
127
        add_action( 'admin_footer', array( $this, '_replyToEnqueueScripts' ) );
128
        add_action( 'admin_footer', array( $this, '_replyToEnqueueStyles' ) );
129
130
        /// For all admin pages.
131
        add_action( 'admin_print_footer_scripts', array( $this, '_replyToAddStyle' ), 999 );
132
        add_action( 'admin_print_footer_scripts', array( $this, '_replyToAddScript' ), 999 );
133
134
135
        // To add the custom attributes to the enqueued style and script tags.
136
        add_filter( 'script_loader_src', array( $this, '_replyToSetupArgumentCallback' ), 1, 2 );
137
        add_filter( 'style_loader_src', array( $this, '_replyToSetupArgumentCallback' ), 1, 2 );
138
139
    }
140
141
    /*
142
     * Methods that should be overridden in extended classes.
143
     * @internal
144
     */
145
146
    public function _forceToEnqueueStyle( $sSRC, $aCustomArgs=array() ) {}
147
    public function _forceToEnqueueScript( $sSRC, $aCustomArgs=array() ) {}
148
149
    /**
150
     * A helper function for the _replyToEnqueueScripts() and the `_replyToEnqueueStyle()` methods.
151
     *
152
     * @since       2.1.5
153
     * @since       3.7.0      Fixed a typo in the method name.
154
     * @internal
155
     * @remark      The widget fields type does not have conditions unlike the meta-box type that requires to check currently loaded post type.
156
     * @remark      This method should be redefined in the extended class.
157
     */
158
    protected function _enqueueSRCByCondition( $aEnqueueItem ) {
159
        return $this->_enqueueSRC( $aEnqueueItem );
160
    }
161
162
    /*
163
     * Shared methods
164
     */
165
    	/**
166
         * Checks the src url of the enqueued script/style to determine whether or not to set up a attribute modification callback.
167
         *
168
         * If it is one of the framework added item, the method sets up a hook to modify the url to add custom attributes.
169
         *
170
         * @since       3.3.0
171
         * @internal
172
         * @callback    action      script_loader_src
173
         * @callback    action      style_loader_src
174
         */
175
        public function _replyToSetupArgumentCallback( $sSRC, $sHandleID ) {
176
177
            if ( isset( $this->oProp->aResourceAttributes[ $sHandleID ] ) ) {
178
                $this->_aHandleIDs[ $sSRC ] = $sHandleID;
179
                add_filter( 'clean_url', array( $this, '_replyToModifyEnqueuedAttributes' ), 1, 3 );
180
                remove_filter( current_filter(), array( $this, '_replyToSetupArgumentCallback' ), 1 );
181
            }
182
            return $sSRC;
183
184
        }
185
            /**
186
             * Modifies the attributes of the enqueued script tag.
187
             *
188
             * @since   3.3.0
189
             * @internal
190
             */
191
            public function _replyToModifyEnqueuedAttributes( $sSanitizedURL, $sOriginalURL, $sContext ) {
192
193
                if ( 'display' !== $sContext ) {
194
                    return $sSanitizedURL;
195
                }
196
197
                // Returns the modified url which attributes are embedded at the end.
198
                if ( isset( $this->_aHandleIDs[ $sOriginalURL ] ) ) {
199
200
                    $_sHandleID     = $this->_aHandleIDs[ $sOriginalURL ];
201
                    $_aAttributes   = $this->oProp->aResourceAttributes[ $_sHandleID ];
202
203
                    if ( empty( $_aAttributes ) ) {
204
                        return $sSanitizedURL;
205
                    }
206
207
                    $_sAttributes   = $this->getAttributes( $_aAttributes );
208
                    return $sSanitizedURL . "' " . rtrim( $_sAttributes, "'\"" );
209
210
                }
211
212
                return $sSanitizedURL;
213
214
            }
215
216
    /**
217
     * Prints the inline stylesheet of the meta-box common CSS rules with the style tag.
218
     *
219
     * @internal
220
     * @since       3.0.0
221
     * @since       3.2.0       Moved to the base class from the meta box class.
222
     * @remark      The meta box class may be instantiated multiple times so prevent echoing the same styles multiple times.
223
     * @parameter   string      $sIDPrefix   The id selector embedded in the script tag.
224
     * @parameter   string      $sClassName  The class name that identify the call group. This is important for the meta-box class because it can be instantiated multiple times in one particular page.
225
     */
226
    protected function _printCommonStyles( $sIDPrefix, $sClassName ) {
0 ignored issues
show
Unused Code introduced by
The parameter $sClassName 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...
227
228
        if ( $this->hasBeenCalled( 'COMMON_STYLES: ' . get_class( $this ) . '::' . __METHOD__ ) ) {
229
            return;
230
        }
231
        $_oCaller = $this->oProp->oCaller;
232
        echo $this->___getCommonStyleTag( $_oCaller, $sIDPrefix );
233
        echo $this->___getCommonIEStyleTag( $_oCaller, $sIDPrefix );
234
235
    }
236
        /**
237
         * @internal
238
         * @since       3.5.7
239
         * @since       3.8.22  Renamed from `_getStyleTag()`.
240
         * @return      string
241
         */
242
        private function ___getCommonStyleTag( $oCaller, $sIDPrefix ) {
243
244
            $_sStyle     = $this->addAndApplyFilters(
245
                $oCaller,
246
                array(
247
                    "style_common_admin_page_framework",            // 3.2.1+
248
                    "style_common_{$this->oProp->sClassName}",
249
                ),
250
                AdminPageFramework_CSS::getDefaultCSS()
251
            );
252
            $_sStyle     = $this->isDebugMode() ? $_sStyle : $this->getCSSMinified( $_sStyle );
253
            $_sStyle     = trim( $_sStyle );
254
            if ( $_sStyle ) {
255
                echo "<style type='text/css' id='" . esc_attr( strtolower( $sIDPrefix ) ) . "'>"
256
                        . $_sStyle
257
                    . "</style>";
258
            }
259
260
261
        }
262
        /**
263
         * @internal
264
         * @since       3.5.7
265
         * @since       3.8.22  Renamed from `_getIEStyleTag()`.
266
         * @return      string
267
         */
268
        private function ___getCommonIEStyleTag( $oCaller, $sIDPrefix ) {
269
270
            $_sStyleIE   = $this->addAndApplyFilters(
271
                $oCaller,
272
                array(
273
                    "style_ie_common_admin_page_framework",         // 3.2.1+
274
                    "style_ie_common_{$this->oProp->sClassName}",
275
                ),
276
                AdminPageFramework_CSS::getDefaultCSSIE()
277
            );
278
            $_sStyleIE  = $this->isDebugMode() ? $_sStyleIE : $this->getCSSMinified( $_sStyleIE );
279
            $_sStyleIE  = trim( $_sStyleIE );
280
            return $_sStyleIE
281
                ? "<!--[if IE]><style type='text/css' id='" . esc_attr( strtolower( $sIDPrefix . "-ie" ) ) . "'>"
282
                        . $_sStyleIE
283
                    . "</style><![endif]-->"
284
                : '';
285
286
        }
287
288
    /**
289
     * Prints the inline scripts of the meta-box common scripts.
290
     *
291
     * @internal
292
     * @since       3.0.0
293
     * @since       3.2.0       Moved to the base class from the meta box class.
294
     * @remark      The meta box class may be instantiated multiple times so prevent echoing the same styles multiple times.
295
     * @parametr    string      $sIDPrefix      The id selector embedded in the script tag.
296
     * @parametr    string      $sClassName     The class name that identify the call group. This is important for the meta-box class because it can be instantiated multiple times in one particular page.
297
     */
298
    protected function _printCommonScripts( $sIDPrefix, $sClassName ) {
0 ignored issues
show
Unused Code introduced by
The parameter $sClassName 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...
299
300
        if ( $this->hasBeenCalled( 'COMMON_SCRIPT: ' . get_class( $this ) . '::' . __METHOD__ ) ) {
301
            return;
302
        }
303
304
        $_sScript = $this->addAndApplyFilters(
305
            $this->oProp->oCaller,
306
            array(
307
                "script_common_admin_page_framework",       // 3.2.1+
308
                "script_common_{$this->oProp->sClassName}",
309
            ),
310
            AdminPageFramework_Property_Base::$_sDefaultScript
311
        );
312
        $_sScript = trim( $_sScript );
313
        if ( ! $_sScript ) {
314
            return;
315
        }
316
        echo "<script type='text/javascript' id='" . esc_attr( strtolower( $sIDPrefix ) ) . "'>"
317
                . '/* <![CDATA[ */'
318
                . $_sScript
319
                . '/* ]]> */'
320
            . "</script>";
321
322
    }
323
324
    /**
325
     * Prints the inline stylesheet of this class stored in this class property.
326
     *
327
     * @since       3.0.0
328
     * @since       3.2.0       Made the properties storing styles empty. Moved to the base class.
329
     * @internal
330
     * @return      void
331
     */
332
    protected function _printClassSpecificStyles( $sIDPrefix ) {
333
334
        $_oCaller   = $this->oProp->oCaller;
335
        echo $this->_getClassSpecificStyleTag( $_oCaller, $sIDPrefix );
336
        echo $this->_getClassSpecificIEStyleTag( $_oCaller, $sIDPrefix );
337
338
        // As of 3.2.0, this method also gets called in the footer to ensure there is not any left styles.
339
        // This happens when a head tag item is added after the head tag is already rendered such as for widget forms.
340
        $this->oProp->sStyle    = '';
341
        $this->oProp->sStyleIE  = '';
342
343
    }
344
        /**
345
         *
346
         * @internal
347
         * @since       3.5.7
348
         * @return      string
349
         */
350
        private function _getClassSpecificStyleTag( $_oCaller, $sIDPrefix ) {
351
352
            static $_iCallCount = 0;
353
354
            $_sFilterName = "style_{$this->oProp->sClassName}";
355
            if ( $this->hasBeenCalled( 'FILTER: ' . $_sFilterName ) ) { // 3.8.22
356
                return '';
357
            }
358
            $_sStyle = $this->addAndApplyFilters( $_oCaller, $_sFilterName, $this->oProp->sStyle );
359
            $_sStyle = $this->isDebugMode() ? $_sStyle : $this->getCSSMinified( $_sStyle );
360
            $_sStyle = trim( $_sStyle );
361
            if ( ! $_sStyle ) {
362
                return '';
363
            }
364
            $_iCallCount++;
365
            $_sID = strtolower( "{$sIDPrefix}-" . $this->oProp->sClassName . "_{$_iCallCount}" );
366
            return "<style type='text/css' id='" . esc_attr( $_sID ) . "'>"
367
                    . $_sStyle
368
                . "</style>";
369
370
        }
371
        /**
372
         *
373
         * @internal
374
         * @since       3.5.7
375
         * @return      string
376
         */
377
        private function _getClassSpecificIEStyleTag( $_oCaller, $sIDPrefix ) {
378
379
            static $_iCallCountIE = 1;
380
381
            $_sFilterName = "style_ie_{$this->oProp->sClassName}";
382
            if ( $this->hasBeenCalled( 'FILTER: ' . $_sFilterName ) ) { // 3.8.22
383
                return '';
384
            }
385
            $_sStyleIE = $this->addAndApplyFilters( $_oCaller, $_sFilterName, $this->oProp->sStyleIE );
386
            $_sStyleIE = $this->isDebugMode() ? $_sStyleIE : $this->getCSSMinified( $_sStyleIE );
387
            $_sStyleIE = trim( $_sStyleIE );
388
            if ( ! $_sStyleIE ) {
389
                return '';
390
            }
391
            $_iCallCountIE++;
392
            $_sID  = strtolower( "{$sIDPrefix}-ie-{$this->oProp->sClassName}_{$_iCallCountIE}" );
393
            return "<!--[if IE]><style type='text/css' id='" . esc_attr( $_sID ) . "'>"
394
                    . $_sStyleIE
395
                . "</style><![endif]-->";
396
397
        }
398
399
    /**
400
     * Prints the inline scripts of this class stored in this class property.
401
     *
402
     * @since       3.0.0
403
     * @since       3.2.0       Made the property empty that stores scripts. Moved to the base class.
404
     * @internal
405
     */
406
    protected function _printClassSpecificScripts( $sIDPrefix ) {
407
408
        static $_iCallCount = 1;
409
        $_sFilterName = "script_{$this->oProp->sClassName}";
410
        if ( $this->hasBeenCalled( 'FILTER: ' . $_sFilterName ) ) { // 3.8.22
411
            return '';
412
        }
413
        $_sScript = $this->addAndApplyFilters( $this->oProp->oCaller, $_sFilterName, $this->oProp->sScript );
414
        $_sScript = trim( $_sScript );
415
        if ( ! $_sScript ) {
416
            return '';
417
        }
418
419
        $_iCallCount++;
420
        $_sID = strtolower( "{$sIDPrefix}-{$this->oProp->sClassName}_{$_iCallCount}" );
421
        echo "<script type='text/javascript' id='" . esc_attr( $_sID ) . "'>"
422
                . '/* <![CDATA[ */'
423
                . $_sScript
424
                . '/* ]]> */'
425
            . "</script>";
426
427
        // As of 3.2.0, this method also gets called in the footer to ensure there is not any left scripts.
428
        // This happens when a head tag item is added after the head tag is already rendered such as for widget forms.
429
        $this->oProp->sScript = '';
430
431
    }
432
433
434
    /**
435
     * Appends the CSS rules of the framework in the head tag.
436
     *
437
     * @since       2.0.0
438
     * @since       2.1.5       Moved from `AdminPageFramework_MetaBox`. Changed the name from `addAtyle()` to `replyToAddStyle()`.
439
     * @callback    action      admin_head
440
     * @internal
441
     */
442
    public function _replyToAddStyle() {
443
444
        $_oCaller = $this->oProp->oCaller;
445
        if ( ! $_oCaller->isInThePage() ) {
446
            return;
447
        }
448
449
        $this->_printCommonStyles( 'admin-page-framework-style-common', get_class() );
450
        $this->_printClassSpecificStyles( $this->_sClassSelector_Style . '-' . $this->oProp->sStructureType );
451
452
    }
453
    /**
454
     * Appends the JavaScript script of the framework in the head tag.
455
     *
456
     * @callback    action      admin_head
457
     * @since       2.0.0
458
     * @since       2.1.5       Moved from AdminPageFramework_MetaBox. Changed the name from `addScript()` to `replyToAddScript()`.
459
     * @since       3.2.0       Moved from AdminPageFramework_Resource_post_meta_box.
460
     * @internal
461
     */
462
    public function _replyToAddScript() {
463
464
        $_oCaller = $this->oProp->oCaller;
465
        if ( ! $_oCaller->isInThePage() ) {
466
            return;
467
        }
468
469
        $this->_printCommonScripts( 'admin-page-framework-script-common', get_class() );
470
        $this->_printClassSpecificScripts( $this->_sClassSelector_Script . '-' . $this->oProp->sStructureType );
471
472
    }
473
474
475
    /**
476
     * Performs actual enqueuing items.
477
     *
478
     * @since       2.1.2
479
     * @since       2.1.5       Moved from the main class.
480
     * @internal
481
     */
482
    protected function _enqueueSRC( $aEnqueueItem ) {
483
484
        // For styles
485
        if ( 'style' === $aEnqueueItem[ 'sType' ] ) {
486
            wp_enqueue_style(
487
                $aEnqueueItem[ 'handle_id' ],
488
                $aEnqueueItem[ 'sSRC' ],
489
                $aEnqueueItem[ 'dependencies' ],
490
                $aEnqueueItem[ 'version' ],
491
                $aEnqueueItem[ 'media' ]
492
            );
493
            return;
494
        }
495
496
        // For scripts
497
        wp_enqueue_script(
498
            $aEnqueueItem[ 'handle_id' ],
499
            $aEnqueueItem[ 'sSRC' ],
500
            $aEnqueueItem[ 'dependencies' ],
501
            $aEnqueueItem[ 'version' ],
502
            did_action( 'admin_body_class' ) ? true : $aEnqueueItem[ 'in_footer' ]
503
        );
504
505
        if ( $aEnqueueItem[ 'translation' ] ) {
506
            wp_localize_script( $aEnqueueItem[ 'handle_id' ], $aEnqueueItem[ 'handle_id' ], $aEnqueueItem[ 'translation' ] );
507
        }
508
509
    }
510
511
    /**
512
     * Takes care of added enqueuing scripts by checking the currently loading page.
513
     *
514
     * @remark      A callback for the admin_enqueue_scripts hook.
515
     * @since       2.1.2
516
     * @since       2.1.5   Moved from the main class. Changed the name from `enqueueStylesCalback` to `replyToEnqueueStyles()`.
517
     * @since       3.0.0   Changed the name to `_replyToEnqueueStyles()`.
518
     * @since       3.2.0   Changed it unset the enqueued item so that the method can be called multiple times.
519
     * @internal
520
     */
521
    public function _replyToEnqueueStyles() {
522
        foreach( $this->oProp->aEnqueuingStyles as $_sKey => $_aEnqueuingStyle ) {
523
            $this->_enqueueSRCByCondition( $_aEnqueuingStyle );
524
            unset( $this->oProp->aEnqueuingStyles[ $_sKey ] );
525
        }
526
    }
527
528
    /**
529
     * Takes care of added enqueuing scripts by page slug and tab slug.
530
     *
531
     * @remark      A callback for the admin_enqueue_scripts hook.
532
     * @since       2.1.2
533
     * @since       2.1.5   Moved from the main class. Changed the name from `enqueueScriptsCallback` to `callbackEnqueueScripts()`.
534
     * @since       3.0.0   Changed the name to `_replyToEnqueueScripts()`.
535
     * @since       3.2.0   Changed it unset the enqueued item so that the method can be called multiple times.
536
     * @internal
537
     */
538
    public function _replyToEnqueueScripts() {
539
        foreach( $this->oProp->aEnqueuingScripts as $_sKey => $_aEnqueuingScript ) {
540
            $this->_enqueueSRCByCondition( $_aEnqueuingScript );
541
            unset( $this->oProp->aEnqueuingScripts[ $_sKey ] );
542
        }
543
    }
544
545
}