Version Description
Download this release
Release Info
Developer | artbees |
Plugin | Jupiter X Core |
Version | 1.11.0 |
Comparing to | |
See all releases |
Code changes from version 1.10.1 to 1.11.0
- assets/images/warning-badge.svg +0 -0
- includes/admin/options.php +62 -62
- includes/admin/tgmpa/tgmpa-plugin-list.php +203 -185
- includes/admin/update-plugins/class-update-plugins.php +102 -102
- includes/compiler/class-compiler.php +1018 -1018
- includes/compiler/functions.php +411 -411
- includes/compiler/preprocess-aliases.ini +277 -277
- includes/compiler/vendors/js-minifier.php +395 -395
- includes/compiler/vendors/lessc.php +3694 -3694
- includes/control-panel/functions.php +159 -158
- includes/control-panel/includes/class-browser.php +1193 -1193
- includes/control-panel/includes/class-customizer-option.php +33 -33
- includes/control-panel/includes/class-db-manager.php +691 -691
- includes/control-panel/includes/class-db-php-manager.php +250 -0
- includes/control-panel/includes/class-export-import-content.php +80 -0
- includes/control-panel/includes/class-filesystem.php +613 -613
- includes/control-panel/includes/class-helpers.php +510 -510
- includes/control-panel/includes/class-image-sizes.php +152 -98
- includes/control-panel/includes/class-install-plugins.php +492 -506
- includes/control-panel/includes/class-install-template.php +43 -19
- includes/control-panel/includes/class-settings.php +118 -118
- includes/control-panel/includes/class-system-status.php +378 -378
- includes/control-panel/includes/class-validator.php +166 -166
- includes/control-panel/includes/importer/class-jupiterx-importer.php +155 -155
- includes/control-panel/includes/importer/class-logger-serversentevents.php +57 -57
- includes/control-panel/includes/importer/class-logger.php +138 -138
- includes/control-panel/includes/importer/class-wxr-import-info.php +35 -35
- includes/control-panel/includes/importer/class-wxr-importer.php +2076 -2076
- includes/control-panel/includes/logic-messages.php +456 -456
- includes/control-panel/views/export-import-content.php +77 -70
- includes/control-panel/views/image-sizes.php +68 -64
- includes/control-panel/views/install-plugins.php +62 -56
- includes/control-panel/views/install-templates.php +61 -61
- includes/control-panel/views/settings.php +104 -103
- includes/control-panel/views/system-status.php +929 -929
- includes/custom-fields/title-bar.php +33 -33
- includes/customizer/api/classes/class-multilingual.php +448 -448
- includes/customizer/api/classes/class-status.php +64 -64
- includes/customizer/api/customizer.php +295 -295
- includes/customizer/api/includes/base/class-control.php +243 -243
- includes/customizer/api/includes/base/class-group-control.php +264 -264
- includes/customizer/api/includes/base/class-input-group.php +103 -103
- includes/customizer/api/includes/class-autoloader.php +119 -119
- includes/customizer/api/includes/class-templates.php +163 -163
- includes/customizer/api/includes/control/class-alert.php +89 -89
- includes/customizer/api/includes/control/class-box-model.php +126 -210
assets/images/warning-badge.svg
CHANGED
File without changes
|
includes/admin/options.php
CHANGED
@@ -1,62 +1,62 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Add Jupiter X admin options.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Admin
|
6 |
-
*
|
7 |
-
* @since 1.9.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
add_filter( 'upload_mimes', 'jupiterx_add_extra_mime_types' );
|
11 |
-
|
12 |
-
if ( ! function_exists( 'jupiterx_add_extra_mime_types' ) ) {
|
13 |
-
/**
|
14 |
-
* Add more mime type.
|
15 |
-
*
|
16 |
-
* @since 1.9.0
|
17 |
-
*
|
18 |
-
* @param array $mimes Current array of mime types..
|
19 |
-
*
|
20 |
-
* @return array Updated array of mime types.
|
21 |
-
*/
|
22 |
-
function jupiterx_add_extra_mime_types( $mimes ) {
|
23 |
-
|
24 |
-
if ( ! empty( jupiterx_get_option( 'svg_support' ) ) ) {
|
25 |
-
$mimes['svg'] = 'image/svg+xml';
|
26 |
-
}
|
27 |
-
|
28 |
-
$mimes['zip'] = 'application/zip';
|
29 |
-
|
30 |
-
return $mimes;
|
31 |
-
}
|
32 |
-
}
|
33 |
-
|
34 |
-
add_filter( 'wp_check_filetype_and_ext', 'jupiterx_fix_filetype_check', 10, 4 );
|
35 |
-
/**
|
36 |
-
* Fix the mime type filtering issue.
|
37 |
-
*
|
38 |
-
* @since 1.9.0
|
39 |
-
*
|
40 |
-
* @param array $data file data.
|
41 |
-
* @param string $file Full path to the file.
|
42 |
-
* @param string $filename The name of the file (may differ from $file due to $file being in a tmp.
|
43 |
-
* @param array $mimes Key is the file extension with value as the mime type.
|
44 |
-
* @return array Filetype data.
|
45 |
-
*
|
46 |
-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
47 |
-
*/
|
48 |
-
function jupiterx_fix_filetype_check( $data, $file, $filename, $mimes ) {
|
49 |
-
if ( ! empty( $data['ext'] ) && ! empty( $data['type'] ) ) {
|
50 |
-
return $data;
|
51 |
-
}
|
52 |
-
|
53 |
-
$wp_filetype = wp_check_filetype( $filename, $mimes );
|
54 |
-
|
55 |
-
if ( 'svg' === $wp_filetype['ext'] || 'svgz' === $wp_filetype['ext'] ) {
|
56 |
-
$data['ext'] = $wp_filetype['ext'];
|
57 |
-
$data['type'] = 'image/svg+xml';
|
58 |
-
}
|
59 |
-
|
60 |
-
return $data;
|
61 |
-
}
|
62 |
-
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Add Jupiter X admin options.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Admin
|
6 |
+
*
|
7 |
+
* @since 1.9.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
add_filter( 'upload_mimes', 'jupiterx_add_extra_mime_types' );
|
11 |
+
|
12 |
+
if ( ! function_exists( 'jupiterx_add_extra_mime_types' ) ) {
|
13 |
+
/**
|
14 |
+
* Add more mime type.
|
15 |
+
*
|
16 |
+
* @since 1.9.0
|
17 |
+
*
|
18 |
+
* @param array $mimes Current array of mime types..
|
19 |
+
*
|
20 |
+
* @return array Updated array of mime types.
|
21 |
+
*/
|
22 |
+
function jupiterx_add_extra_mime_types( $mimes ) {
|
23 |
+
|
24 |
+
if ( ! empty( jupiterx_get_option( 'svg_support' ) ) ) {
|
25 |
+
$mimes['svg'] = 'image/svg+xml';
|
26 |
+
}
|
27 |
+
|
28 |
+
$mimes['zip'] = 'application/zip';
|
29 |
+
|
30 |
+
return $mimes;
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
add_filter( 'wp_check_filetype_and_ext', 'jupiterx_fix_filetype_check', 10, 4 );
|
35 |
+
/**
|
36 |
+
* Fix the mime type filtering issue.
|
37 |
+
*
|
38 |
+
* @since 1.9.0
|
39 |
+
*
|
40 |
+
* @param array $data file data.
|
41 |
+
* @param string $file Full path to the file.
|
42 |
+
* @param string $filename The name of the file (may differ from $file due to $file being in a tmp.
|
43 |
+
* @param array $mimes Key is the file extension with value as the mime type.
|
44 |
+
* @return array Filetype data.
|
45 |
+
*
|
46 |
+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
47 |
+
*/
|
48 |
+
function jupiterx_fix_filetype_check( $data, $file, $filename, $mimes ) {
|
49 |
+
if ( ! empty( $data['ext'] ) && ! empty( $data['type'] ) ) {
|
50 |
+
return $data;
|
51 |
+
}
|
52 |
+
|
53 |
+
$wp_filetype = wp_check_filetype( $filename, $mimes );
|
54 |
+
|
55 |
+
if ( 'svg' === $wp_filetype['ext'] || 'svgz' === $wp_filetype['ext'] ) {
|
56 |
+
$data['ext'] = $wp_filetype['ext'];
|
57 |
+
$data['type'] = 'image/svg+xml';
|
58 |
+
}
|
59 |
+
|
60 |
+
return $data;
|
61 |
+
}
|
62 |
+
|
includes/admin/tgmpa/tgmpa-plugin-list.php
CHANGED
@@ -1,185 +1,203 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Add Jupiter X pro plugins.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Admin
|
6 |
-
*
|
7 |
-
* @since 1.9.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
add_filter( 'jupiterx_tgmpa_plugins', 'jupiterx_pro_plugins' );
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Add Jupiter X Pro plugins.
|
14 |
-
*
|
15 |
-
* @since 1.9.0
|
16 |
-
*
|
17 |
-
* @param array $plugins Array of free Jupiter x plugins.
|
18 |
-
* @return array Array af free and pro plugins.
|
19 |
-
*/
|
20 |
-
function jupiterx_pro_plugins( $plugins ) {
|
21 |
-
|
22 |
-
$pro_plugins = [
|
23 |
-
[
|
24 |
-
'name' => __( 'Raven', 'jupiterx-core' ),
|
25 |
-
'slug' => 'raven',
|
26 |
-
'required' => false,
|
27 |
-
'force_activation' => false,
|
28 |
-
'force_deactivation' => false,
|
29 |
-
'pro' => true,
|
30 |
-
'source' => 'external',
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
'
|
35 |
-
'
|
36 |
-
'
|
37 |
-
'
|
38 |
-
'
|
39 |
-
'
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
'
|
45 |
-
'
|
46 |
-
'
|
47 |
-
'
|
48 |
-
'
|
49 |
-
|
50 |
-
|
51 |
-
'
|
52 |
-
|
53 |
-
|
54 |
-
'
|
55 |
-
'
|
56 |
-
'
|
57 |
-
'
|
58 |
-
|
59 |
-
|
60 |
-
'
|
61 |
-
'
|
62 |
-
|
63 |
-
|
64 |
-
'
|
65 |
-
'
|
66 |
-
'
|
67 |
-
|
68 |
-
|
69 |
-
'
|
70 |
-
'
|
71 |
-
'
|
72 |
-
|
73 |
-
|
74 |
-
'
|
75 |
-
'
|
76 |
-
|
77 |
-
|
78 |
-
'
|
79 |
-
'
|
80 |
-
'
|
81 |
-
'
|
82 |
-
|
83 |
-
|
84 |
-
'
|
85 |
-
|
86 |
-
|
87 |
-
'
|
88 |
-
'
|
89 |
-
'
|
90 |
-
'
|
91 |
-
'
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
'
|
97 |
-
'
|
98 |
-
'
|
99 |
-
'
|
100 |
-
'
|
101 |
-
'
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
'
|
106 |
-
'
|
107 |
-
'
|
108 |
-
'
|
109 |
-
'
|
110 |
-
'
|
111 |
-
'
|
112 |
-
],
|
113 |
-
[
|
114 |
-
'name' => __( 'Jet
|
115 |
-
'slug' => 'jet-
|
116 |
-
'required' => false,
|
117 |
-
'force_activation' => false,
|
118 |
-
'force_deactivation' => false,
|
119 |
-
'pro' => true,
|
120 |
-
'source' => 'external',
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
'
|
125 |
-
'
|
126 |
-
'
|
127 |
-
'
|
128 |
-
'
|
129 |
-
'
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
'
|
135 |
-
'
|
136 |
-
'
|
137 |
-
'
|
138 |
-
'
|
139 |
-
|
140 |
-
|
141 |
-
'
|
142 |
-
|
143 |
-
|
144 |
-
'
|
145 |
-
'
|
146 |
-
'
|
147 |
-
'
|
148 |
-
|
149 |
-
|
150 |
-
'
|
151 |
-
'
|
152 |
-
|
153 |
-
|
154 |
-
'
|
155 |
-
'
|
156 |
-
'
|
157 |
-
|
158 |
-
|
159 |
-
'
|
160 |
-
'
|
161 |
-
'
|
162 |
-
|
163 |
-
|
164 |
-
'
|
165 |
-
'
|
166 |
-
|
167 |
-
|
168 |
-
'
|
169 |
-
'
|
170 |
-
'
|
171 |
-
'
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
'
|
177 |
-
'
|
178 |
-
'
|
179 |
-
'
|
180 |
-
'
|
181 |
-
'
|
182 |
-
],
|
183 |
-
|
184 |
-
|
185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Add Jupiter X pro plugins.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Admin
|
6 |
+
*
|
7 |
+
* @since 1.9.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
add_filter( 'jupiterx_tgmpa_plugins', 'jupiterx_pro_plugins' );
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Add Jupiter X Pro plugins.
|
14 |
+
*
|
15 |
+
* @since 1.9.0
|
16 |
+
*
|
17 |
+
* @param array $plugins Array of free Jupiter x plugins.
|
18 |
+
* @return array Array af free and pro plugins.
|
19 |
+
*/
|
20 |
+
function jupiterx_pro_plugins( $plugins ) {
|
21 |
+
|
22 |
+
$pro_plugins = [
|
23 |
+
[
|
24 |
+
'name' => __( 'Raven', 'jupiterx-core' ),
|
25 |
+
'slug' => 'raven',
|
26 |
+
'required' => false,
|
27 |
+
'force_activation' => false,
|
28 |
+
'force_deactivation' => false,
|
29 |
+
'pro' => true,
|
30 |
+
'source' => 'external',
|
31 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
32 |
+
],
|
33 |
+
[
|
34 |
+
'name' => __( 'Jupiter Donut', 'jupiterx-core' ),
|
35 |
+
'slug' => 'jupiter-donut',
|
36 |
+
'required' => false,
|
37 |
+
'force_activation' => false,
|
38 |
+
'force_deactivation' => false,
|
39 |
+
'pro' => true,
|
40 |
+
'source' => 'external',
|
41 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
42 |
+
],
|
43 |
+
[
|
44 |
+
'name' => __( 'Jet Elements', 'jupiterx-core' ),
|
45 |
+
'slug' => 'jet-elements',
|
46 |
+
'required' => false,
|
47 |
+
'force_activation' => false,
|
48 |
+
'force_deactivation' => false,
|
49 |
+
'pro' => true,
|
50 |
+
'source' => 'external',
|
51 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
52 |
+
],
|
53 |
+
[
|
54 |
+
'name' => __( 'Jet Blog', 'jupiterx-core' ),
|
55 |
+
'slug' => 'jet-blog',
|
56 |
+
'required' => false,
|
57 |
+
'force_activation' => false,
|
58 |
+
'force_deactivation' => false,
|
59 |
+
'pro' => true,
|
60 |
+
'source' => 'external',
|
61 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
62 |
+
],
|
63 |
+
[
|
64 |
+
'name' => __( 'Jet Menu', 'jupiterx-core' ),
|
65 |
+
'slug' => 'jet-menu',
|
66 |
+
'required' => false,
|
67 |
+
'force_activation' => false,
|
68 |
+
'force_deactivation' => false,
|
69 |
+
'pro' => true,
|
70 |
+
'source' => 'external',
|
71 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
72 |
+
],
|
73 |
+
[
|
74 |
+
'name' => __( 'Jet Popup', 'jupiterx-core' ),
|
75 |
+
'slug' => 'jet-popup',
|
76 |
+
'required' => false,
|
77 |
+
'force_activation' => false,
|
78 |
+
'force_deactivation' => false,
|
79 |
+
'pro' => true,
|
80 |
+
'source' => 'external',
|
81 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
82 |
+
],
|
83 |
+
[
|
84 |
+
'name' => __( 'Jet Tabs', 'jupiterx-core' ),
|
85 |
+
'slug' => 'jet-tabs',
|
86 |
+
'required' => false,
|
87 |
+
'force_activation' => false,
|
88 |
+
'force_deactivation' => false,
|
89 |
+
'pro' => true,
|
90 |
+
'source' => 'external',
|
91 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
92 |
+
],
|
93 |
+
[
|
94 |
+
'name' => __( 'Jet WooBuilder', 'jupiterx-core' ),
|
95 |
+
'slug' => 'jet-woo-builder',
|
96 |
+
'required' => false,
|
97 |
+
'force_activation' => false,
|
98 |
+
'force_deactivation' => false,
|
99 |
+
'pro' => true,
|
100 |
+
'source' => 'external',
|
101 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
102 |
+
],
|
103 |
+
[
|
104 |
+
'name' => __( 'Jet Tricks', 'jupiterx-core' ),
|
105 |
+
'slug' => 'jet-tricks',
|
106 |
+
'required' => false,
|
107 |
+
'force_activation' => false,
|
108 |
+
'force_deactivation' => false,
|
109 |
+
'pro' => true,
|
110 |
+
'source' => 'external',
|
111 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
112 |
+
],
|
113 |
+
[
|
114 |
+
'name' => __( 'Jet Engine', 'jupiterx-core' ),
|
115 |
+
'slug' => 'jet-engine',
|
116 |
+
'required' => false,
|
117 |
+
'force_activation' => false,
|
118 |
+
'force_deactivation' => false,
|
119 |
+
'pro' => true,
|
120 |
+
'source' => 'external',
|
121 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
122 |
+
],
|
123 |
+
[
|
124 |
+
'name' => __( 'Jet SmartFilters', 'jupiterx-core' ),
|
125 |
+
'slug' => 'jet-smart-filters',
|
126 |
+
'required' => false,
|
127 |
+
'force_activation' => false,
|
128 |
+
'force_deactivation' => false,
|
129 |
+
'pro' => true,
|
130 |
+
'source' => 'external',
|
131 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
132 |
+
],
|
133 |
+
[
|
134 |
+
'name' => __( 'Advanced Custom Fields PRO', 'jupiterx-core' ),
|
135 |
+
'slug' => 'advanced-custom-fields-pro',
|
136 |
+
'required' => false,
|
137 |
+
'force_activation' => false,
|
138 |
+
'force_deactivation' => false,
|
139 |
+
'pro' => true,
|
140 |
+
'source' => 'external',
|
141 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
142 |
+
],
|
143 |
+
[
|
144 |
+
'name' => __( 'Slider Revolution', 'jupiterx-core' ),
|
145 |
+
'slug' => 'revslider',
|
146 |
+
'required' => false,
|
147 |
+
'force_activation' => false,
|
148 |
+
'force_deactivation' => false,
|
149 |
+
'pro' => true,
|
150 |
+
'source' => 'external',
|
151 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
152 |
+
],
|
153 |
+
[
|
154 |
+
'name' => __( 'Master Slider', 'jupiterx-core' ),
|
155 |
+
'slug' => 'masterslider',
|
156 |
+
'required' => false,
|
157 |
+
'force_activation' => false,
|
158 |
+
'force_deactivation' => false,
|
159 |
+
'pro' => true,
|
160 |
+
'source' => 'external',
|
161 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
162 |
+
],
|
163 |
+
[
|
164 |
+
'name' => __( 'Layer Slider', 'jupiterx-core' ),
|
165 |
+
'slug' => 'layerslider',
|
166 |
+
'required' => false,
|
167 |
+
'force_activation' => false,
|
168 |
+
'force_deactivation' => false,
|
169 |
+
'pro' => true,
|
170 |
+
'source' => 'external',
|
171 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
172 |
+
],
|
173 |
+
[
|
174 |
+
'name' => __( 'WPBakery Page Builder', 'jupiterx-core' ),
|
175 |
+
'slug' => 'raven',
|
176 |
+
'required' => false,
|
177 |
+
'force_activation' => false,
|
178 |
+
'force_deactivation' => false,
|
179 |
+
'pro' => true,
|
180 |
+
'source' => 'external',
|
181 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
182 |
+
],
|
183 |
+
[
|
184 |
+
'name' => __( 'Customizer Reset', 'jupiterx-core' ),
|
185 |
+
'slug' => 'customizer-reset-by-wpzoom',
|
186 |
+
'required' => false,
|
187 |
+
'force_activation' => false,
|
188 |
+
'force_deactivation' => false,
|
189 |
+
'pro' => false,
|
190 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
191 |
+
],
|
192 |
+
[
|
193 |
+
'name' => __( 'Customizer Export/Import', 'jupiterx-core' ),
|
194 |
+
'slug' => 'customizer-export-import',
|
195 |
+
'required' => false,
|
196 |
+
'force_activation' => false,
|
197 |
+
'force_deactivation' => false,
|
198 |
+
'pro' => false,
|
199 |
+
'label_type' => __( 'Optional', 'jupiterx-core' ),
|
200 |
+
],
|
201 |
+
];
|
202 |
+
return array_merge( $pro_plugins, $plugins );
|
203 |
+
}
|
includes/admin/update-plugins/class-update-plugins.php
CHANGED
@@ -1,102 +1,102 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* JupiterX_Core_Update_Plugins class filters the update plugins.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Admin
|
6 |
-
*
|
7 |
-
* @since 1.9.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
if ( ! class_exists( 'JupiterX_Core_Update_Plugins' ) ) {
|
11 |
-
/**
|
12 |
-
* Filter Update Plugins.
|
13 |
-
*
|
14 |
-
* @since 1.9.0
|
15 |
-
*/
|
16 |
-
class JupiterX_Core_Update_Plugins {
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Constructor.
|
20 |
-
*
|
21 |
-
* @since 1.9.0
|
22 |
-
*/
|
23 |
-
public function __construct() {
|
24 |
-
add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'update_plugins' ], 999, 1 );
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Filter updates for managed pro plugins.
|
29 |
-
*
|
30 |
-
* @SuppressWarnings(PHPMD.NPathComplexity)
|
31 |
-
*
|
32 |
-
* @since 1.9.0
|
33 |
-
*
|
34 |
-
* @param array $transient Transient object.
|
35 |
-
* @return object
|
36 |
-
*/
|
37 |
-
public function update_plugins( $transient ) {
|
38 |
-
if ( ! is_object( $transient ) ) {
|
39 |
-
return $transient;
|
40 |
-
}
|
41 |
-
|
42 |
-
if ( ! isset( $transient->response ) ) {
|
43 |
-
return $transient;
|
44 |
-
}
|
45 |
-
|
46 |
-
if ( ! function_exists( 'jupiterx_get_managed_plugins' ) ) {
|
47 |
-
return $transient;
|
48 |
-
}
|
49 |
-
|
50 |
-
$force_check = ! empty( jupiterx_get( 'force-check' ) );
|
51 |
-
$installed_plugins = $this->get_plugins();
|
52 |
-
$managed_plugins = jupiterx_get_managed_plugins( $force_check );
|
53 |
-
|
54 |
-
foreach ( $managed_plugins as $managed_plugin ) {
|
55 |
-
if ( empty( $managed_plugin->source ) || 'false' === $managed_plugin->pro ) {
|
56 |
-
continue;
|
57 |
-
}
|
58 |
-
|
59 |
-
foreach ( $installed_plugins as $basename => $installed_plugin ) {
|
60 |
-
if ( strpos( $basename, $managed_plugin->slug ) === false ) {
|
61 |
-
continue;
|
62 |
-
}
|
63 |
-
|
64 |
-
if ( version_compare( $managed_plugin->version, $installed_plugin['Version'] ) <= 0 ) {
|
65 |
-
unset( $transient->response[ $basename ] );
|
66 |
-
|
67 |
-
continue;
|
68 |
-
}
|
69 |
-
|
70 |
-
$update = new stdClass();
|
71 |
-
|
72 |
-
$update->slug = $managed_plugin->slug;
|
73 |
-
$update->plugin = $basename;
|
74 |
-
$update->new_version = $managed_plugin->version;
|
75 |
-
$update->url = false;
|
76 |
-
$update->package = $managed_plugin->source;
|
77 |
-
|
78 |
-
$transient->response[ $basename ] = $update;
|
79 |
-
}
|
80 |
-
}
|
81 |
-
|
82 |
-
return $transient;
|
83 |
-
}
|
84 |
-
|
85 |
-
/**
|
86 |
-
* Wrapper around the core WP get_plugins function, making sure it's actually available.
|
87 |
-
*
|
88 |
-
* @since 1.9.0
|
89 |
-
*
|
90 |
-
* @return array Array of installed plugins with plugin information.
|
91 |
-
*/
|
92 |
-
public function get_plugins() {
|
93 |
-
if ( ! function_exists( 'get_plugins' ) ) {
|
94 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
95 |
-
}
|
96 |
-
|
97 |
-
return get_plugins();
|
98 |
-
}
|
99 |
-
}
|
100 |
-
|
101 |
-
new JupiterX_Core_Update_Plugins();
|
102 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* JupiterX_Core_Update_Plugins class filters the update plugins.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Admin
|
6 |
+
*
|
7 |
+
* @since 1.9.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
if ( ! class_exists( 'JupiterX_Core_Update_Plugins' ) ) {
|
11 |
+
/**
|
12 |
+
* Filter Update Plugins.
|
13 |
+
*
|
14 |
+
* @since 1.9.0
|
15 |
+
*/
|
16 |
+
class JupiterX_Core_Update_Plugins {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Constructor.
|
20 |
+
*
|
21 |
+
* @since 1.9.0
|
22 |
+
*/
|
23 |
+
public function __construct() {
|
24 |
+
add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'update_plugins' ], 999, 1 );
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Filter updates for managed pro plugins.
|
29 |
+
*
|
30 |
+
* @SuppressWarnings(PHPMD.NPathComplexity)
|
31 |
+
*
|
32 |
+
* @since 1.9.0
|
33 |
+
*
|
34 |
+
* @param array $transient Transient object.
|
35 |
+
* @return object
|
36 |
+
*/
|
37 |
+
public function update_plugins( $transient ) {
|
38 |
+
if ( ! is_object( $transient ) ) {
|
39 |
+
return $transient;
|
40 |
+
}
|
41 |
+
|
42 |
+
if ( ! isset( $transient->response ) ) {
|
43 |
+
return $transient;
|
44 |
+
}
|
45 |
+
|
46 |
+
if ( ! function_exists( 'jupiterx_get_managed_plugins' ) ) {
|
47 |
+
return $transient;
|
48 |
+
}
|
49 |
+
|
50 |
+
$force_check = ! empty( jupiterx_get( 'force-check' ) );
|
51 |
+
$installed_plugins = $this->get_plugins();
|
52 |
+
$managed_plugins = jupiterx_get_managed_plugins( $force_check );
|
53 |
+
|
54 |
+
foreach ( $managed_plugins as $managed_plugin ) {
|
55 |
+
if ( empty( $managed_plugin->source ) || 'false' === $managed_plugin->pro ) {
|
56 |
+
continue;
|
57 |
+
}
|
58 |
+
|
59 |
+
foreach ( $installed_plugins as $basename => $installed_plugin ) {
|
60 |
+
if ( strpos( $basename, $managed_plugin->slug ) === false ) {
|
61 |
+
continue;
|
62 |
+
}
|
63 |
+
|
64 |
+
if ( version_compare( $managed_plugin->version, $installed_plugin['Version'] ) <= 0 ) {
|
65 |
+
unset( $transient->response[ $basename ] );
|
66 |
+
|
67 |
+
continue;
|
68 |
+
}
|
69 |
+
|
70 |
+
$update = new stdClass();
|
71 |
+
|
72 |
+
$update->slug = $managed_plugin->slug;
|
73 |
+
$update->plugin = $basename;
|
74 |
+
$update->new_version = $managed_plugin->version;
|
75 |
+
$update->url = false;
|
76 |
+
$update->package = $managed_plugin->source;
|
77 |
+
|
78 |
+
$transient->response[ $basename ] = $update;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
return $transient;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Wrapper around the core WP get_plugins function, making sure it's actually available.
|
87 |
+
*
|
88 |
+
* @since 1.9.0
|
89 |
+
*
|
90 |
+
* @return array Array of installed plugins with plugin information.
|
91 |
+
*/
|
92 |
+
public function get_plugins() {
|
93 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
94 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
95 |
+
}
|
96 |
+
|
97 |
+
return get_plugins();
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
new JupiterX_Core_Update_Plugins();
|
102 |
+
}
|
includes/compiler/class-compiler.php
CHANGED
@@ -1,1018 +1,1018 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class compiles and minifies CSS, LESS and JS.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Compiler
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
/**
|
11 |
-
* Compiles and minifies CSS, LESS and JS.
|
12 |
-
*
|
13 |
-
* @since 1.0.0
|
14 |
-
* @ignore
|
15 |
-
* @access private
|
16 |
-
*
|
17 |
-
* @package JupiterX\Framework\API\Compiler
|
18 |
-
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
19 |
-
* @SuppressWarnings(PHPMD.ExcessiveClassLength)
|
20 |
-
*/
|
21 |
-
final class _JupiterX_Compiler {
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Compiler's runtime configuration parameters.
|
25 |
-
*
|
26 |
-
* @var array
|
27 |
-
*/
|
28 |
-
private $config;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Cache dir.
|
32 |
-
*
|
33 |
-
* @var string
|
34 |
-
*/
|
35 |
-
private $dir;
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Cache url.
|
39 |
-
*
|
40 |
-
* @var string
|
41 |
-
*/
|
42 |
-
private $url;
|
43 |
-
|
44 |
-
/**
|
45 |
-
* The fragment currently being processed.
|
46 |
-
*
|
47 |
-
* @var string
|
48 |
-
*/
|
49 |
-
private $current_fragment;
|
50 |
-
|
51 |
-
/**
|
52 |
-
* The compiled content.
|
53 |
-
*
|
54 |
-
* @var string
|
55 |
-
*/
|
56 |
-
private $compiled_content;
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Compiled content's filename.
|
60 |
-
*
|
61 |
-
* @var string
|
62 |
-
*/
|
63 |
-
private $filename;
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Create a new Compiler.
|
67 |
-
*
|
68 |
-
* @since 1.0.0
|
69 |
-
*
|
70 |
-
* @param array $config Runtime configuration parameters for the Compiler.
|
71 |
-
*/
|
72 |
-
public function __construct( array $config ) {
|
73 |
-
$this->config = $this->init_config( $config );
|
74 |
-
$this->dir = jupiterx_get_compiler_dir( is_admin() ) . $this->config['id'];
|
75 |
-
$this->url = jupiterx_get_compiler_url( is_admin() ) . $this->config['id'];
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* Run the compiler.
|
80 |
-
*
|
81 |
-
* @since 1.0.0
|
82 |
-
*
|
83 |
-
* @return void
|
84 |
-
*/
|
85 |
-
public function run_compiler() {
|
86 |
-
// Modify the WP Filesystem method.
|
87 |
-
add_filter( 'filesystem_method', array( $this, 'modify_filesystem_method' ) );
|
88 |
-
|
89 |
-
$this->set_fragments();
|
90 |
-
$this->set_filename();
|
91 |
-
|
92 |
-
if ( ! $this->cache_file_exist() ) {
|
93 |
-
$this->filesystem();
|
94 |
-
$this->maybe_make_dir();
|
95 |
-
$this->combine_fragments();
|
96 |
-
$this->cache_file();
|
97 |
-
}
|
98 |
-
|
99 |
-
if ( $this->config['enqueue'] ) {
|
100 |
-
$this->enqueue_file();
|
101 |
-
}
|
102 |
-
|
103 |
-
// Keep it safe and reset the WP Filesystem method.
|
104 |
-
remove_filter( 'filesystem_method', array( $this, 'modify_filesystem_method' ) );
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Callback to set the WP Filesystem method.
|
109 |
-
*
|
110 |
-
* @since 1.0.0
|
111 |
-
*
|
112 |
-
* @return string
|
113 |
-
*/
|
114 |
-
public function modify_filesystem_method() {
|
115 |
-
return 'direct';
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* Initialise the WP Filesystem.
|
120 |
-
*
|
121 |
-
* @since 1.0.0
|
122 |
-
*
|
123 |
-
* @return bool|void
|
124 |
-
*/
|
125 |
-
public function filesystem() {
|
126 |
-
|
127 |
-
// If the WP_Filesystem is not already loaded, load it.
|
128 |
-
if ( ! function_exists( 'WP_Filesystem' ) ) {
|
129 |
-
require_once ABSPATH . '/wp-admin/includes/file.php';
|
130 |
-
}
|
131 |
-
|
132 |
-
// If the WP_Filesystem is not initialized or is not set to WP_Filesystem_Direct, then initialize it.
|
133 |
-
if ( $this->is_wp_filesystem_direct() ) {
|
134 |
-
return true;
|
135 |
-
}
|
136 |
-
|
137 |
-
// Initialize the filesystem.
|
138 |
-
$response = WP_Filesystem();
|
139 |
-
|
140 |
-
// If the filesystem did not initialize, then generate a report and exit.
|
141 |
-
if ( true !== $response || ! $this->is_wp_filesystem_direct() ) {
|
142 |
-
return $this->kill();
|
143 |
-
}
|
144 |
-
|
145 |
-
return true;
|
146 |
-
}
|
147 |
-
|
148 |
-
/**
|
149 |
-
* Check if the filesystem is set to "direct".
|
150 |
-
*
|
151 |
-
* @since 1.0.0
|
152 |
-
*
|
153 |
-
* @return bool
|
154 |
-
*/
|
155 |
-
private function is_wp_filesystem_direct() {
|
156 |
-
return isset( $GLOBALS['wp_filesystem'] ) && is_a( $GLOBALS['wp_filesystem'], 'WP_Filesystem_Direct' );
|
157 |
-
}
|
158 |
-
|
159 |
-
/**
|
160 |
-
* Make directory.
|
161 |
-
*
|
162 |
-
* @since 1.0.0
|
163 |
-
*
|
164 |
-
* @return bool
|
165 |
-
*/
|
166 |
-
private function maybe_make_dir() {
|
167 |
-
|
168 |
-
if ( ! @is_dir( $this->dir ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- This is a valid use case.
|
169 |
-
wp_mkdir_p( $this->dir );
|
170 |
-
}
|
171 |
-
|
172 |
-
return is_writable( $this->dir );
|
173 |
-
}
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Set class fragments.
|
177 |
-
*
|
178 |
-
* @since 1.0.0
|
179 |
-
*
|
180 |
-
* @return void
|
181 |
-
*/
|
182 |
-
public function set_fragments() {
|
183 |
-
global $_jupiterx_compiler_added_fragments;
|
184 |
-
|
185 |
-
$added_fragments = jupiterx_get( $this->config['id'], $_jupiterx_compiler_added_fragments[ $this->config['format'] ] );
|
186 |
-
|
187 |
-
if ( $added_fragments ) {
|
188 |
-
$this->config['fragments'] = array_merge( $this->config['fragments'], $added_fragments );
|
189 |
-
}
|
190 |
-
|
191 |
-
/**
|
192 |
-
* Filter the compiler fragment files.
|
193 |
-
*
|
194 |
-
* The dynamic portion of the hook name, $this->config['id'], refers to the compiler id used as a reference.
|
195 |
-
*
|
196 |
-
* @since 1.0.0
|
197 |
-
*
|
198 |
-
* @param array $fragments An array of fragment files.
|
199 |
-
*/
|
200 |
-
$this->config['fragments'] = apply_filters( 'jupiterx_compiler_fragments_' . $this->config['id'], $this->config['fragments'] );
|
201 |
-
}
|
202 |
-
|
203 |
-
/**
|
204 |
-
* Set the filename for the compiled asset.
|
205 |
-
*
|
206 |
-
* @since 1.0.0
|
207 |
-
*
|
208 |
-
* @return void
|
209 |
-
*/
|
210 |
-
public function set_filename() {
|
211 |
-
$hash = $this->hash( $this->config );
|
212 |
-
|
213 |
-
if ( empty( _jupiterx_get_cache_busting() ) ) {
|
214 |
-
$this->config['version'] = $hash;
|
215 |
-
|
216 |
-
$hash = 'style';
|
217 |
-
|
218 |
-
if ( 'script' === $this->config['type'] ) {
|
219 |
-
$hash = 'script';
|
220 |
-
}
|
221 |
-
}
|
222 |
-
|
223 |
-
$this->filename = $hash . '.' . $this->get_extension();
|
224 |
-
}
|
225 |
-
|
226 |
-
/**
|
227 |
-
* Hash the given array.
|
228 |
-
*
|
229 |
-
* @since 1.0.0
|
230 |
-
*
|
231 |
-
* @param array $given_array Given array to be hashed.
|
232 |
-
*
|
233 |
-
* @return string
|
234 |
-
*/
|
235 |
-
public function hash( array $given_array ) {
|
236 |
-
return substr( md5( @serialize( $given_array ) ), 0, 7 ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- Valid use case.
|
237 |
-
}
|
238 |
-
|
239 |
-
/**
|
240 |
-
* Checks if the file exists on the filesystem, meaning it's been cached.
|
241 |
-
*
|
242 |
-
* @since 1.0.0
|
243 |
-
*
|
244 |
-
* @return bool
|
245 |
-
*/
|
246 |
-
public function cache_file_exist() {
|
247 |
-
$filename = $this->get_filename();
|
248 |
-
|
249 |
-
if ( ( _jupiterx_is_compiler_dev_mode() ) || is_preview() ) {
|
250 |
-
return false;
|
251 |
-
}
|
252 |
-
|
253 |
-
if ( empty( $filename ) ) {
|
254 |
-
return false;
|
255 |
-
}
|
256 |
-
|
257 |
-
return file_exists( $filename );
|
258 |
-
}
|
259 |
-
|
260 |
-
/**
|
261 |
-
* Get the absolute path of the cached and compiled file.
|
262 |
-
*
|
263 |
-
* @since 1.0.0
|
264 |
-
*
|
265 |
-
* @return string
|
266 |
-
*/
|
267 |
-
public function get_filename() {
|
268 |
-
if ( isset( $this->filename ) ) {
|
269 |
-
return $this->dir . '/' . $this->filename;
|
270 |
-
}
|
271 |
-
|
272 |
-
return '';
|
273 |
-
}
|
274 |
-
|
275 |
-
/**
|
276 |
-
* Create cached file.
|
277 |
-
*
|
278 |
-
* @since 1.0.0
|
279 |
-
*
|
280 |
-
* @return bool
|
281 |
-
*/
|
282 |
-
public function cache_file() {
|
283 |
-
$filename = $this->get_filename();
|
284 |
-
|
285 |
-
if ( empty( $filename ) ) {
|
286 |
-
return false;
|
287 |
-
}
|
288 |
-
|
289 |
-
// It is safe to access the filesystem because we made sure it was set.
|
290 |
-
return $GLOBALS['wp_filesystem']->put_contents( $filename, $this->compiled_content, FS_CHMOD_FILE );
|
291 |
-
}
|
292 |
-
|
293 |
-
/**
|
294 |
-
* Enqueue cached file.
|
295 |
-
*
|
296 |
-
* @since 1.0.0
|
297 |
-
*
|
298 |
-
* @return void|bool
|
299 |
-
*/
|
300 |
-
private function enqueue_file() {
|
301 |
-
|
302 |
-
// Enqueue CSS file.
|
303 |
-
if ( 'style' === $this->config['type'] ) {
|
304 |
-
return wp_enqueue_style(
|
305 |
-
$this->config['id'],
|
306 |
-
$this->get_url(),
|
307 |
-
$this->config['dependencies'],
|
308 |
-
$this->config['version']
|
309 |
-
);
|
310 |
-
}
|
311 |
-
|
312 |
-
// Enqueue JS file.
|
313 |
-
if ( 'script' === $this->config['type'] ) {
|
314 |
-
return wp_enqueue_script(
|
315 |
-
$this->config['id'],
|
316 |
-
$this->get_url(),
|
317 |
-
$this->config['dependencies'],
|
318 |
-
$this->config['version'],
|
319 |
-
$this->config['in_footer']
|
320 |
-
);
|
321 |
-
}
|
322 |
-
|
323 |
-
return false;
|
324 |
-
}
|
325 |
-
|
326 |
-
/**
|
327 |
-
* Get cached file url.
|
328 |
-
*
|
329 |
-
* @since 1.0.0
|
330 |
-
*
|
331 |
-
* @return string
|
332 |
-
*/
|
333 |
-
public function get_url() {
|
334 |
-
$url = trailingslashit( $this->url ) . $this->filename;
|
335 |
-
|
336 |
-
if ( is_ssl() ) {
|
337 |
-
$url = str_replace( 'http://', 'https://', $url );
|
338 |
-
}
|
339 |
-
|
340 |
-
return $url;
|
341 |
-
}
|
342 |
-
|
343 |
-
/**
|
344 |
-
* Get the file extension from the configured "type".
|
345 |
-
*
|
346 |
-
* @since 1.0.0
|
347 |
-
*
|
348 |
-
* @return string|null
|
349 |
-
*/
|
350 |
-
public function get_extension() {
|
351 |
-
|
352 |
-
if ( 'style' === $this->config['type'] ) {
|
353 |
-
return 'css';
|
354 |
-
}
|
355 |
-
|
356 |
-
if ( 'script' === $this->config['type'] ) {
|
357 |
-
return 'js';
|
358 |
-
}
|
359 |
-
}
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Combine content of the fragments.
|
363 |
-
*
|
364 |
-
* @since 1.0.0
|
365 |
-
*
|
366 |
-
* @return void
|
367 |
-
*/
|
368 |
-
public function combine_fragments() {
|
369 |
-
$content = '';
|
370 |
-
|
371 |
-
// Loop through fragments.
|
372 |
-
foreach ( $this->config['fragments'] as $fragment ) {
|
373 |
-
|
374 |
-
// Stop here if the fragment is empty.
|
375 |
-
if ( empty( $fragment ) ) {
|
376 |
-
continue;
|
377 |
-
}
|
378 |
-
|
379 |
-
$fragment_content = $this->get_content( $fragment );
|
380 |
-
|
381 |
-
// Stop here if no content or content is an html page.
|
382 |
-
if ( ! $fragment_content || preg_match( '#^\s*\<#', $fragment_content ) ) {
|
383 |
-
continue;
|
384 |
-
}
|
385 |
-
|
386 |
-
// Continue processing style.
|
387 |
-
if ( 'style' === $this->config['type'] ) {
|
388 |
-
$fragment_content = $this->replace_css_url( $fragment_content );
|
389 |
-
$fragment_content = $this->add_content_media_query( $fragment_content );
|
390 |
-
}
|
391 |
-
|
392 |
-
// If there's content, start a new line.
|
393 |
-
if ( $content ) {
|
394 |
-
$content .= "\n\n";
|
395 |
-
}
|
396 |
-
|
397 |
-
$content .= $fragment_content;
|
398 |
-
}
|
399 |
-
|
400 |
-
$this->compiled_content = ! empty( $content ) ? $this->format_content( $content ) : '';
|
401 |
-
}
|
402 |
-
|
403 |
-
/**
|
404 |
-
* Get the fragment's content.
|
405 |
-
*
|
406 |
-
* @since 1.0.0
|
407 |
-
*
|
408 |
-
* @param string|callable $fragment The given fragment from which to get the content.
|
409 |
-
*
|
410 |
-
* @return bool|string
|
411 |
-
*/
|
412 |
-
private function get_content( $fragment ) {
|
413 |
-
// Set the current fragment used by other functions.
|
414 |
-
$this->current_fragment = $fragment;
|
415 |
-
|
416 |
-
// If the fragment is callable, call it to get the content.
|
417 |
-
if ( $this->is_function( $fragment ) ) {
|
418 |
-
return $this->get_function_content();
|
419 |
-
}
|
420 |
-
|
421 |
-
$content = $this->get_internal_content();
|
422 |
-
|
423 |
-
// Try remote content if the internal content returned false.
|
424 |
-
if ( empty( $content ) ) {
|
425 |
-
$content = $this->get_remote_content();
|
426 |
-
}
|
427 |
-
|
428 |
-
return $content;
|
429 |
-
}
|
430 |
-
|
431 |
-
/**
|
432 |
-
* Get internal file content.
|
433 |
-
*
|
434 |
-
* @since 1.0.0
|
435 |
-
*
|
436 |
-
* @return string|bool
|
437 |
-
*/
|
438 |
-
public function get_internal_content() {
|
439 |
-
$fragment = $this->current_fragment;
|
440 |
-
|
441 |
-
if ( ! file_exists( $fragment ) ) {
|
442 |
-
|
443 |
-
// Replace URL with path.
|
444 |
-
$fragment = jupiterx_url_to_path( $fragment );
|
445 |
-
|
446 |
-
// Stop here if it isn't a valid file.
|
447 |
-
if ( ! file_exists( $fragment ) || 0 === @filesize( $fragment ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
448 |
-
return false;
|
449 |
-
}
|
450 |
-
}
|
451 |
-
|
452 |
-
// It is safe to access the filesystem because we made sure it was set.
|
453 |
-
return $GLOBALS['wp_filesystem']->get_contents( $fragment );
|
454 |
-
}
|
455 |
-
|
456 |
-
/**
|
457 |
-
* Get external file content.
|
458 |
-
*
|
459 |
-
* @since 1.0.0
|
460 |
-
*
|
461 |
-
* @return string|bool
|
462 |
-
*/
|
463 |
-
public function get_remote_content() {
|
464 |
-
$fragment = $this->current_fragment;
|
465 |
-
|
466 |
-
if ( empty( $fragment ) ) {
|
467 |
-
return false;
|
468 |
-
}
|
469 |
-
|
470 |
-
// For a relative URL, add http: to it.
|
471 |
-
if ( substr( $fragment, 0, 2 ) === '//' ) {
|
472 |
-
$fragment = 'http:' . $fragment;
|
473 |
-
} elseif ( substr( $fragment, 0, 1 ) === '/' ) { // Add domain if it is local but could not be fetched as a file.
|
474 |
-
$fragment = site_url( $fragment );
|
475 |
-
}
|
476 |
-
|
477 |
-
$request = wp_remote_get( $fragment );
|
478 |
-
|
479 |
-
if ( is_wp_error( $request ) ) {
|
480 |
-
return '';
|
481 |
-
}
|
482 |
-
|
483 |
-
// If no content was received and the URL is not https, then convert the URL to SSL and retry.
|
484 |
-
if (
|
485 |
-
( ! isset( $request['body'] ) || 200 !== $request['response']['code'] ) &&
|
486 |
-
( substr( $fragment, 0, 8 ) !== 'https://' )
|
487 |
-
) {
|
488 |
-
$fragment = str_replace( 'http://', 'https://', $fragment );
|
489 |
-
$request = wp_remote_get( $fragment );
|
490 |
-
|
491 |
-
if ( is_wp_error( $request ) ) {
|
492 |
-
return '';
|
493 |
-
}
|
494 |
-
}
|
495 |
-
|
496 |
-
if ( ( ! isset( $request['body'] ) || 200 !== $request['response']['code'] ) ) {
|
497 |
-
return false;
|
498 |
-
}
|
499 |
-
|
500 |
-
return wp_remote_retrieve_body( $request );
|
501 |
-
}
|
502 |
-
|
503 |
-
/**
|
504 |
-
* Get function content.
|
505 |
-
*
|
506 |
-
* @since 1.0.0
|
507 |
-
*
|
508 |
-
* @return string|bool
|
509 |
-
*/
|
510 |
-
public function get_function_content() {
|
511 |
-
|
512 |
-
if ( ! is_callable( $this->current_fragment ) ) {
|
513 |
-
return false;
|
514 |
-
}
|
515 |
-
|
516 |
-
return call_user_func( $this->current_fragment );
|
517 |
-
}
|
518 |
-
|
519 |
-
/**
|
520 |
-
* Wrap content in query.
|
521 |
-
*
|
522 |
-
* @since 1.0.0
|
523 |
-
*
|
524 |
-
* @param string $content Given content to process.
|
525 |
-
*
|
526 |
-
* @return string
|
527 |
-
*/
|
528 |
-
public function add_content_media_query( $content ) {
|
529 |
-
|
530 |
-
// Ignore if the fragment is a function.
|
531 |
-
if ( $this->is_function( $this->current_fragment ) ) {
|
532 |
-
return $content;
|
533 |
-
}
|
534 |
-
|
535 |
-
$query = wp_parse_url( $this->current_fragment, PHP_URL_QUERY );
|
536 |
-
|
537 |
-
// Bail out if there are no query args or no media query.
|
538 |
-
if ( empty( $query ) || false === stripos( $query, 'jupiterx_compiler_media_query' ) ) {
|
539 |
-
return $content;
|
540 |
-
}
|
541 |
-
|
542 |
-
// Wrap the content in the query.
|
543 |
-
return sprintf(
|
544 |
-
"@media %s {\n%s\n}\n",
|
545 |
-
jupiterx_get( 'jupiterx_compiler_media_query', wp_parse_args( $query ) ),
|
546 |
-
$content
|
547 |
-
);
|
548 |
-
}
|
549 |
-
|
550 |
-
/**
|
551 |
-
* Format CSS, LESS and JS content.
|
552 |
-
*
|
553 |
-
* @since 1.0.0
|
554 |
-
*
|
555 |
-
* @param string $content Given content to process.
|
556 |
-
*
|
557 |
-
* @return string
|
558 |
-
*/
|
559 |
-
public function format_content( $content ) {
|
560 |
-
|
561 |
-
if ( 'style' === $this->config['type'] ) {
|
562 |
-
|
563 |
-
if ( 'less' === $this->config['format'] ) {
|
564 |
-
|
565 |
-
if ( ! class_exists( 'JupiterX_Lessc' ) ) {
|
566 |
-
jupiterx_core()->load_files( [ 'compiler/vendors/lessc' ] );
|
567 |
-
}
|
568 |
-
|
569 |
-
$parser = new JupiterX_Lessc();
|
570 |
-
|
571 |
-
$parser = $this->register_less_functions( $parser );
|
572 |
-
|
573 |
-
$parser->setVariables( $this->config['variables'] );
|
574 |
-
|
575 |
-
$content = $parser->compile( $content );
|
576 |
-
}
|
577 |
-
|
578 |
-
if ( ! function_exists( 'jupiterx_parse_css' ) ) {
|
579 |
-
return $content;
|
580 |
-
}
|
581 |
-
|
582 |
-
$content = jupiterx_parse_css( $content );
|
583 |
-
|
584 |
-
if ( ! _jupiterx_is_compiler_dev_mode() ) {
|
585 |
-
$content = $this->minify_style( $content );
|
586 |
-
}
|
587 |
-
|
588 |
-
return $content;
|
589 |
-
}
|
590 |
-
|
591 |
-
if ( 'script' === $this->config['type'] && ! _jupiterx_is_compiler_dev_mode() && $this->config['minify_js'] ) {
|
592 |
-
|
593 |
-
if ( ! class_exists( 'JSMin' ) ) {
|
594 |
-
jupiterx_core()->load_files( [ 'compiler/vendors/js-minifier' ] );
|
595 |
-
}
|
596 |
-
|
597 |
-
$js_min = new JSMin( $content );
|
598 |
-
return $js_min->min();
|
599 |
-
}
|
600 |
-
|
601 |
-
return $content;
|
602 |
-
}
|
603 |
-
|
604 |
-
/**
|
605 |
-
* Replace CSS URL shortcuts with a valid URL.
|
606 |
-
*
|
607 |
-
* @since 1.0.0
|
608 |
-
*
|
609 |
-
* @param string $content Given content to process.
|
610 |
-
*
|
611 |
-
* @return string
|
612 |
-
*/
|
613 |
-
public function replace_css_url( $content ) {
|
614 |
-
return preg_replace_callback(
|
615 |
-
'#url\s*\(\s*[\'"]*?([^\'"\)]+)[\'"]*\s*\)#i',
|
616 |
-
array( $this, 'replace_css_url_callback' ),
|
617 |
-
$content
|
618 |
-
);
|
619 |
-
}
|
620 |
-
|
621 |
-
/**
|
622 |
-
* Convert any CSS URL relative paths to absolute URLs.
|
623 |
-
*
|
624 |
-
* @since 1.0.0
|
625 |
-
*
|
626 |
-
* @param array $matches Matches to process, where 0 is the CSS' URL() and 1 is the URI.
|
627 |
-
*
|
628 |
-
* @return string
|
629 |
-
*/
|
630 |
-
public function replace_css_url_callback( $matches ) {
|
631 |
-
|
632 |
-
// If the URI is absolute, bail out and return the CSS.
|
633 |
-
if ( _jupiterx_is_uri( $matches[1] ) ) {
|
634 |
-
return $matches[0];
|
635 |
-
}
|
636 |
-
|
637 |
-
$base = $this->current_fragment;
|
638 |
-
|
639 |
-
// Separate the placeholders and path.
|
640 |
-
$paths = explode( '../', $matches[1] );
|
641 |
-
|
642 |
-
/**
|
643 |
-
* Walk backwards through each of the the fragment's directories, one-by-one. The `foreach` loop
|
644 |
-
* provides us with a performant way to walk the fragment back to its base path based upon the
|
645 |
-
* number of placeholders.
|
646 |
-
*/
|
647 |
-
foreach ( $paths as $path ) {
|
648 |
-
$base = dirname( $base );
|
649 |
-
}
|
650 |
-
|
651 |
-
// Make sure it is a valid base.
|
652 |
-
if ( '.' === $base ) {
|
653 |
-
$base = '';
|
654 |
-
}
|
655 |
-
|
656 |
-
// Rebuild the URL and make sure it is valid using the jupiterx_path_to_url function.
|
657 |
-
$url = jupiterx_path_to_url( trailingslashit( $base ) . ltrim( end( $paths ), '/\\' ) );
|
658 |
-
|
659 |
-
// Return the rebuilt path converted to an URL.
|
660 |
-
return 'url("' . $url . '")';
|
661 |
-
}
|
662 |
-
|
663 |
-
/**
|
664 |
-
* Register LESS_PHP functions.
|
665 |
-
*
|
666 |
-
* @since 1.0.0
|
667 |
-
*
|
668 |
-
* @param object $parser The LESS parser.
|
669 |
-
*
|
670 |
-
* @todo Refactoring is required.
|
671 |
-
*
|
672 |
-
* @return object
|
673 |
-
*/
|
674 |
-
private function register_less_functions( $parser ) {
|
675 |
-
$parser->registerFunction( 'jupiterx_value', function( $arg ) {
|
676 |
-
$output = '';
|
677 |
-
|
678 |
-
if ( isset( $arg[2][1][2][0] ) ) {
|
679 |
-
$output = $arg[2][1][2][0]; // Default.
|
680 |
-
}
|
681 |
-
|
682 |
-
if ( ! empty( $arg[2][0][2][1][1] ) ) {
|
683 |
-
return $arg[2][0][2][1][1]; // E.g. ~"@{@{var}-width}".
|
684 |
-
}
|
685 |
-
|
686 |
-
if ( ! empty( $arg[2][0][1] ) ) {
|
687 |
-
$value = $arg[2][0][1]; // E.g. @text-size.
|
688 |
-
$unit = empty( $arg[2][0][2] ) ? '' : $arg[2][0][2]; // E.g. @text-size unit.
|
689 |
-
|
690 |
-
return $value . $unit;
|
691 |
-
}
|
692 |
-
|
693 |
-
return $output;
|
694 |
-
} );
|
695 |
-
|
696 |
-
$parser->registerFunction( 'jupiterx_value_pattern', function( $arg ) {
|
697 |
-
if ( 0 === strlen( $arg[2][0][1] ) ) {
|
698 |
-
return '';
|
699 |
-
}
|
700 |
-
|
701 |
-
list($type, $value, $unit) = $arg[2][0];
|
702 |
-
|
703 |
-
$format = $arg[2][1][2][0];
|
704 |
-
|
705 |
-
// When value is 0px, parser automatically remove px (but not %) from it.
|
706 |
-
if ( 0 == $arg[2][0][1] ) { // @codingStandardsIgnoreLine
|
707 |
-
$unit = '%';
|
708 |
-
}
|
709 |
-
|
710 |
-
return sprintf( $format, $value . $unit );
|
711 |
-
} );
|
712 |
-
|
713 |
-
$parser->registerFunction( 'jupiterx_replace', function( $args ) {
|
714 |
-
list( $string, $search, $replace ) = $args[2];
|
715 |
-
|
716 |
-
// Arrange if string is from a variable use the true condition. e.g. @{var-name}.
|
717 |
-
$string = isset( $string[2][1][1] ) ? $string[2][1][1] : $string[2][0];
|
718 |
-
$search = $search[2][0];
|
719 |
-
$replace = $replace[2][0];
|
720 |
-
|
721 |
-
return str_replace( $search, $replace, $string );
|
722 |
-
} );
|
723 |
-
|
724 |
-
return $parser;
|
725 |
-
}
|
726 |
-
|
727 |
-
/**
|
728 |
-
* Initialize the configuration.
|
729 |
-
*
|
730 |
-
* @since 1.0.0
|
731 |
-
*
|
732 |
-
* @param array $config Runtime configuration parameters for the Compiler.
|
733 |
-
*
|
734 |
-
* @return array
|
735 |
-
*/
|
736 |
-
private function init_config( array $config ) {
|
737 |
-
// Fix dependencies, if "depedencies" is specified.
|
738 |
-
if ( isset( $config['depedencies'] ) ) {
|
739 |
-
$config['dependencies'] = $config['depedencies'];
|
740 |
-
unset( $config['depedencies'] );
|
741 |
-
}
|
742 |
-
|
743 |
-
$defaults = [
|
744 |
-
'id' => false,
|
745 |
-
'type' => false,
|
746 |
-
'format' => false,
|
747 |
-
'fragments' => [],
|
748 |
-
'variables' => apply_filters( 'jupiterx_compiler_less_variables', [] ),
|
749 |
-
'dependencies' => false,
|
750 |
-
'in_footer' => false,
|
751 |
-
'minify_js' => true,
|
752 |
-
'version' => JUPITERX_VERSION,
|
753 |
-
'enqueue' => true,
|
754 |
-
];
|
755 |
-
|
756 |
-
return array_merge( $defaults, $config );
|
757 |
-
}
|
758 |
-
|
759 |
-
/**
|
760 |
-
* Get the fragments' modification times.
|
761 |
-
*
|
762 |
-
* @since 1.0.0
|
763 |
-
*
|
764 |
-
* @return array
|
765 |
-
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
|
766 |
-
*/
|
767 |
-
private function get_fragments_filemtime() {
|
768 |
-
$fragments_filemtime = array();
|
769 |
-
|
770 |
-
foreach ( $this->config['fragments'] as $index => $fragment ) {
|
771 |
-
|
772 |
-
// Skip this one if the fragment is a function.
|
773 |
-
if ( $this->is_function( $fragment ) ) {
|
774 |
-
if ( ! is_callable( $fragment ) ) {
|
775 |
-
continue;
|
776 |
-
}
|
777 |
-
|
778 |
-
$fragments_filemtime[ $index ] = $this->hash( [ call_user_func( $fragment ) ] );
|
779 |
-
|
780 |
-
}
|
781 |
-
|
782 |
-
if ( file_exists( $fragment ) ) {
|
783 |
-
$fragments_filemtime[ $index ] = @filemtime( $fragment ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
784 |
-
}
|
785 |
-
}
|
786 |
-
|
787 |
-
return $fragments_filemtime;
|
788 |
-
}
|
789 |
-
|
790 |
-
/**
|
791 |
-
* Get the new hash for the given fragments' modification times.
|
792 |
-
*
|
793 |
-
* @since 1.0.0
|
794 |
-
*
|
795 |
-
* @param string $hash The original hash to modify.
|
796 |
-
* @param array $fragments_filemtime Array of fragments' modification times.
|
797 |
-
*
|
798 |
-
* @return string
|
799 |
-
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
|
800 |
-
*/
|
801 |
-
private function get_new_hash( $hash, array $fragments_filemtime ) {
|
802 |
-
|
803 |
-
if ( empty( $fragments_filemtime ) ) {
|
804 |
-
return $hash;
|
805 |
-
}
|
806 |
-
|
807 |
-
// Set filemtime hash.
|
808 |
-
$_hash = $this->hash( $fragments_filemtime );
|
809 |
-
|
810 |
-
$this->remove_modified_files( $hash, $_hash );
|
811 |
-
|
812 |
-
// Set the new hash which will trigger a new compiling.
|
813 |
-
return $hash . '-' . $_hash;
|
814 |
-
}
|
815 |
-
|
816 |
-
/**
|
817 |
-
* Remove any modified files. A file is considered modified when:
|
818 |
-
*
|
819 |
-
* 1. It has both a base hash and filemtime hash, separated by '-'.
|
820 |
-
* 2. Its base hash matches the given hash.
|
821 |
-
* 3. Its filemtime hash does not match the given filemtime hash.
|
822 |
-
*
|
823 |
-
* @since 1.0.0
|
824 |
-
*
|
825 |
-
* @param string $hash Base hash.
|
826 |
-
* @param string $filemtime_hash The filemtime hash (from hashing the fragments).
|
827 |
-
*
|
828 |
-
* @return void
|
829 |
-
*/
|
830 |
-
private function remove_modified_files( $hash, $filemtime_hash ) {
|
831 |
-
|
832 |
-
if ( ! is_dir( $this->dir ) ) {
|
833 |
-
return;
|
834 |
-
}
|
835 |
-
|
836 |
-
$items = @scandir( $this->dir ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
837 |
-
unset( $items[0], $items[1] );
|
838 |
-
|
839 |
-
if ( empty( $items ) ) {
|
840 |
-
return;
|
841 |
-
}
|
842 |
-
|
843 |
-
foreach ( $items as $item ) {
|
844 |
-
|
845 |
-
// Skip this one if it's a directory.
|
846 |
-
if ( @is_dir( $item ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
847 |
-
continue;
|
848 |
-
}
|
849 |
-
|
850 |
-
// Skip this one if it's not the same type.
|
851 |
-
if ( pathinfo( $item, PATHINFO_EXTENSION ) !== $this->get_extension() ) {
|
852 |
-
continue;
|
853 |
-
}
|
854 |
-
|
855 |
-
// Skip this one if it does not have a '-' in the filename.
|
856 |
-
if ( strpos( $item, '-' ) === false ) {
|
857 |
-
continue;
|
858 |
-
}
|
859 |
-
|
860 |
-
$hash_parts = explode( '-', pathinfo( $item, PATHINFO_FILENAME ) );
|
861 |
-
|
862 |
-
// Skip this one if it does not match the given base hash.
|
863 |
-
if ( $hash_parts[0] !== $hash ) {
|
864 |
-
continue;
|
865 |
-
}
|
866 |
-
|
867 |
-
// Skip this one if it does match the given filemtime's hash.
|
868 |
-
if ( $hash_parts[1] === $filemtime_hash ) {
|
869 |
-
continue;
|
870 |
-
}
|
871 |
-
|
872 |
-
// Clean up other modified files.
|
873 |
-
@unlink( $this->dir . '/' . $item ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
874 |
-
}
|
875 |
-
}
|
876 |
-
|
877 |
-
/**
|
878 |
-
* Minify the CSS.
|
879 |
-
*
|
880 |
-
* @since 1.0.0
|
881 |
-
*
|
882 |
-
* @param string $content Given content to process.
|
883 |
-
*
|
884 |
-
* @return string
|
885 |
-
*/
|
886 |
-
private function minify_style( $content ) {
|
887 |
-
$replace = array(
|
888 |
-
'/([^\r\n{}]+)(,(?=[^}]*{)|\s*{)}/' => '', // Strip empty selectors.
|
889 |
-
'/@media\s\(.*\).*{}/' => '', // Strip empty @media.
|
890 |
-
'#/\*.*?\*/#s' => '', // Strip comments.
|
891 |
-
'#\s\s+#' => ' ', // Strip excess whitespace.
|
892 |
-
);
|
893 |
-
|
894 |
-
$search = array_keys( $replace );
|
895 |
-
$content = preg_replace( $search, $replace, $content );
|
896 |
-
|
897 |
-
$replace = array(
|
898 |
-
': ' => ':',
|
899 |
-
'; ' => ';',
|
900 |
-
' {' => '{',
|
901 |
-
' }' => '}',
|
902 |
-
', ' => ',',
|
903 |
-
'{ ' => '{',
|
904 |
-
',\n' => ',', // Don't wrap multiple selectors.
|
905 |
-
'\n}' => '}', // Don't wrap closing braces.
|
906 |
-
'} ' => "}\n", // Put each rule on it's own line.
|
907 |
-
'\n' => '', // Remove all line breaks.
|
908 |
-
);
|
909 |
-
|
910 |
-
$search = array_keys( $replace );
|
911 |
-
|
912 |
-
return trim( str_replace( $search, $replace, $content ) );
|
913 |
-
}
|
914 |
-
|
915 |
-
/**
|
916 |
-
* Check if the given fragment is a callable.
|
917 |
-
*
|
918 |
-
* @since 1.0.0
|
919 |
-
*
|
920 |
-
* @param mixed $fragment Given fragment to check.
|
921 |
-
*
|
922 |
-
* @return bool
|
923 |
-
*/
|
924 |
-
private function is_function( $fragment ) {
|
925 |
-
return ( is_array( $fragment ) || is_callable( $fragment ) );
|
926 |
-
}
|
927 |
-
|
928 |
-
/**
|
929 |
-
* Kill it :(
|
930 |
-
*
|
931 |
-
* @since 1.0.0
|
932 |
-
*
|
933 |
-
* @return void
|
934 |
-
*/
|
935 |
-
private function kill() {
|
936 |
-
|
937 |
-
// Send report if set.
|
938 |
-
if ( jupiterx_get( 'jupiterx_send_compiler_report' ) ) { // @codingStandardsIgnoreLine
|
939 |
-
// $this->report(); // @codingStandardsIgnoreLine
|
940 |
-
}
|
941 |
-
|
942 |
-
$html = jupiterx_output( 'jupiterx_compiler_error_title_text', sprintf(
|
943 |
-
'<h2>%s</h2>',
|
944 |
-
__( 'Not cool, Jupiter cannot work its magic :(', 'jupiterx-core' )
|
945 |
-
) );
|
946 |
-
|
947 |
-
$html .= jupiterx_output( 'jupiterx_compiler_error_message_text', sprintf(
|
948 |
-
'<p>%s</p>',
|
949 |
-
__( 'Your current install or file permission prevents Jupiter from working its magic. Please get in touch with Jupiter support. We will gladly get you started within 24 - 48 hours (working days).', 'jupiterx-core' )
|
950 |
-
) );
|
951 |
-
|
952 |
-
$html .= jupiterx_output( 'jupiterx_compiler_error_contact_text', sprintf(
|
953 |
-
'<a class="button" href="https://themes.artbees.net/support/" target="_blank">%s</a>',
|
954 |
-
__( 'Contact Jupiter Support', 'jupiterx-core' )
|
955 |
-
) );
|
956 |
-
|
957 |
-
$html .= jupiterx_output( 'jupiterx_compiler_error_report_text', sprintf(
|
958 |
-
'<p style="margin-top: 12px; font-size: 12px;"><a href="' . add_query_arg( 'jupiterx_send_compiler_report', true ) . '">%1$s</a>. %2$s</p>',
|
959 |
-
__( 'Send us an automatic report', 'jupiterx-core' ),
|
960 |
-
__( 'We respect your time and understand you might not be able to contact us.', 'jupiterx-core' )
|
961 |
-
) );
|
962 |
-
|
963 |
-
wp_die( wp_kses_post( $html ) );
|
964 |
-
}
|
965 |
-
|
966 |
-
/**
|
967 |
-
* Send report.
|
968 |
-
*
|
969 |
-
* @since 1.0.0
|
970 |
-
*
|
971 |
-
* @todo Decide if we want to use and change the report recipient.
|
972 |
-
*
|
973 |
-
* @return void
|
974 |
-
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
|
975 |
-
*/
|
976 |
-
private function report() {
|
977 |
-
// Send report.
|
978 |
-
wp_mail(
|
979 |
-
'hello@getjupiter.io',
|
980 |
-
'Compiler error',
|
981 |
-
'Compiler error reported by ' . home_url(),
|
982 |
-
array(
|
983 |
-
'MIME-Version: 1.0' . "\r\n",
|
984 |
-
'Content-type: text/html; charset=utf-8' . "\r\n",
|
985 |
-
"X-Mailer: PHP \r\n",
|
986 |
-
'From: ' . wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) . ' < ' . get_option( 'admin_email' ) . '>' . "\r\n",
|
987 |
-
'Reply-To: ' . get_option( 'admin_email' ) . "\r\n",
|
988 |
-
)
|
989 |
-
);
|
990 |
-
|
991 |
-
// Die and display message.
|
992 |
-
$message = jupiterx_output(
|
993 |
-
'jupiterx_compiler_report_error_text',
|
994 |
-
sprintf(
|
995 |
-
'<p>%s<p>',
|
996 |
-
__( 'Thanks for your contribution by reporting this issue. We hope to hear from you again.', 'jupiterx-core' )
|
997 |
-
)
|
998 |
-
);
|
999 |
-
|
1000 |
-
wp_die( wp_kses_post( $message ) );
|
1001 |
-
}
|
1002 |
-
|
1003 |
-
/**
|
1004 |
-
* Get the property's value.
|
1005 |
-
*
|
1006 |
-
* @since 1.0.0
|
1007 |
-
*
|
1008 |
-
* @param string $property Name of the property to get.
|
1009 |
-
*
|
1010 |
-
* @return mixed
|
1011 |
-
*/
|
1012 |
-
public function __get( $property ) {
|
1013 |
-
|
1014 |
-
if ( property_exists( $this, $property ) ) {
|
1015 |
-
return $this->{$property};
|
1016 |
-
}
|
1017 |
-
}
|
1018 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class compiles and minifies CSS, LESS and JS.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Compiler
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Compiles and minifies CSS, LESS and JS.
|
12 |
+
*
|
13 |
+
* @since 1.0.0
|
14 |
+
* @ignore
|
15 |
+
* @access private
|
16 |
+
*
|
17 |
+
* @package JupiterX\Framework\API\Compiler
|
18 |
+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
19 |
+
* @SuppressWarnings(PHPMD.ExcessiveClassLength)
|
20 |
+
*/
|
21 |
+
final class _JupiterX_Compiler {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Compiler's runtime configuration parameters.
|
25 |
+
*
|
26 |
+
* @var array
|
27 |
+
*/
|
28 |
+
private $config;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Cache dir.
|
32 |
+
*
|
33 |
+
* @var string
|
34 |
+
*/
|
35 |
+
private $dir;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Cache url.
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
private $url;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* The fragment currently being processed.
|
46 |
+
*
|
47 |
+
* @var string
|
48 |
+
*/
|
49 |
+
private $current_fragment;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* The compiled content.
|
53 |
+
*
|
54 |
+
* @var string
|
55 |
+
*/
|
56 |
+
private $compiled_content;
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Compiled content's filename.
|
60 |
+
*
|
61 |
+
* @var string
|
62 |
+
*/
|
63 |
+
private $filename;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Create a new Compiler.
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @param array $config Runtime configuration parameters for the Compiler.
|
71 |
+
*/
|
72 |
+
public function __construct( array $config ) {
|
73 |
+
$this->config = $this->init_config( $config );
|
74 |
+
$this->dir = jupiterx_get_compiler_dir( is_admin() ) . $this->config['id'];
|
75 |
+
$this->url = jupiterx_get_compiler_url( is_admin() ) . $this->config['id'];
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Run the compiler.
|
80 |
+
*
|
81 |
+
* @since 1.0.0
|
82 |
+
*
|
83 |
+
* @return void
|
84 |
+
*/
|
85 |
+
public function run_compiler() {
|
86 |
+
// Modify the WP Filesystem method.
|
87 |
+
add_filter( 'filesystem_method', array( $this, 'modify_filesystem_method' ) );
|
88 |
+
|
89 |
+
$this->set_fragments();
|
90 |
+
$this->set_filename();
|
91 |
+
|
92 |
+
if ( ! $this->cache_file_exist() ) {
|
93 |
+
$this->filesystem();
|
94 |
+
$this->maybe_make_dir();
|
95 |
+
$this->combine_fragments();
|
96 |
+
$this->cache_file();
|
97 |
+
}
|
98 |
+
|
99 |
+
if ( $this->config['enqueue'] ) {
|
100 |
+
$this->enqueue_file();
|
101 |
+
}
|
102 |
+
|
103 |
+
// Keep it safe and reset the WP Filesystem method.
|
104 |
+
remove_filter( 'filesystem_method', array( $this, 'modify_filesystem_method' ) );
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Callback to set the WP Filesystem method.
|
109 |
+
*
|
110 |
+
* @since 1.0.0
|
111 |
+
*
|
112 |
+
* @return string
|
113 |
+
*/
|
114 |
+
public function modify_filesystem_method() {
|
115 |
+
return 'direct';
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Initialise the WP Filesystem.
|
120 |
+
*
|
121 |
+
* @since 1.0.0
|
122 |
+
*
|
123 |
+
* @return bool|void
|
124 |
+
*/
|
125 |
+
public function filesystem() {
|
126 |
+
|
127 |
+
// If the WP_Filesystem is not already loaded, load it.
|
128 |
+
if ( ! function_exists( 'WP_Filesystem' ) ) {
|
129 |
+
require_once ABSPATH . '/wp-admin/includes/file.php';
|
130 |
+
}
|
131 |
+
|
132 |
+
// If the WP_Filesystem is not initialized or is not set to WP_Filesystem_Direct, then initialize it.
|
133 |
+
if ( $this->is_wp_filesystem_direct() ) {
|
134 |
+
return true;
|
135 |
+
}
|
136 |
+
|
137 |
+
// Initialize the filesystem.
|
138 |
+
$response = WP_Filesystem();
|
139 |
+
|
140 |
+
// If the filesystem did not initialize, then generate a report and exit.
|
141 |
+
if ( true !== $response || ! $this->is_wp_filesystem_direct() ) {
|
142 |
+
return $this->kill();
|
143 |
+
}
|
144 |
+
|
145 |
+
return true;
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Check if the filesystem is set to "direct".
|
150 |
+
*
|
151 |
+
* @since 1.0.0
|
152 |
+
*
|
153 |
+
* @return bool
|
154 |
+
*/
|
155 |
+
private function is_wp_filesystem_direct() {
|
156 |
+
return isset( $GLOBALS['wp_filesystem'] ) && is_a( $GLOBALS['wp_filesystem'], 'WP_Filesystem_Direct' );
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Make directory.
|
161 |
+
*
|
162 |
+
* @since 1.0.0
|
163 |
+
*
|
164 |
+
* @return bool
|
165 |
+
*/
|
166 |
+
private function maybe_make_dir() {
|
167 |
+
|
168 |
+
if ( ! @is_dir( $this->dir ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- This is a valid use case.
|
169 |
+
wp_mkdir_p( $this->dir );
|
170 |
+
}
|
171 |
+
|
172 |
+
return is_writable( $this->dir );
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Set class fragments.
|
177 |
+
*
|
178 |
+
* @since 1.0.0
|
179 |
+
*
|
180 |
+
* @return void
|
181 |
+
*/
|
182 |
+
public function set_fragments() {
|
183 |
+
global $_jupiterx_compiler_added_fragments;
|
184 |
+
|
185 |
+
$added_fragments = jupiterx_get( $this->config['id'], $_jupiterx_compiler_added_fragments[ $this->config['format'] ] );
|
186 |
+
|
187 |
+
if ( $added_fragments ) {
|
188 |
+
$this->config['fragments'] = array_merge( $this->config['fragments'], $added_fragments );
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Filter the compiler fragment files.
|
193 |
+
*
|
194 |
+
* The dynamic portion of the hook name, $this->config['id'], refers to the compiler id used as a reference.
|
195 |
+
*
|
196 |
+
* @since 1.0.0
|
197 |
+
*
|
198 |
+
* @param array $fragments An array of fragment files.
|
199 |
+
*/
|
200 |
+
$this->config['fragments'] = apply_filters( 'jupiterx_compiler_fragments_' . $this->config['id'], $this->config['fragments'] );
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Set the filename for the compiled asset.
|
205 |
+
*
|
206 |
+
* @since 1.0.0
|
207 |
+
*
|
208 |
+
* @return void
|
209 |
+
*/
|
210 |
+
public function set_filename() {
|
211 |
+
$hash = $this->hash( $this->config );
|
212 |
+
|
213 |
+
if ( empty( _jupiterx_get_cache_busting() ) ) {
|
214 |
+
$this->config['version'] = $hash;
|
215 |
+
|
216 |
+
$hash = 'style';
|
217 |
+
|
218 |
+
if ( 'script' === $this->config['type'] ) {
|
219 |
+
$hash = 'script';
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
$this->filename = $hash . '.' . $this->get_extension();
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Hash the given array.
|
228 |
+
*
|
229 |
+
* @since 1.0.0
|
230 |
+
*
|
231 |
+
* @param array $given_array Given array to be hashed.
|
232 |
+
*
|
233 |
+
* @return string
|
234 |
+
*/
|
235 |
+
public function hash( array $given_array ) {
|
236 |
+
return substr( md5( @serialize( $given_array ) ), 0, 7 ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- Valid use case.
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Checks if the file exists on the filesystem, meaning it's been cached.
|
241 |
+
*
|
242 |
+
* @since 1.0.0
|
243 |
+
*
|
244 |
+
* @return bool
|
245 |
+
*/
|
246 |
+
public function cache_file_exist() {
|
247 |
+
$filename = $this->get_filename();
|
248 |
+
|
249 |
+
if ( ( _jupiterx_is_compiler_dev_mode() ) || is_preview() ) {
|
250 |
+
return false;
|
251 |
+
}
|
252 |
+
|
253 |
+
if ( empty( $filename ) ) {
|
254 |
+
return false;
|
255 |
+
}
|
256 |
+
|
257 |
+
return file_exists( $filename );
|
258 |
+
}
|
259 |
+
|
260 |
+
/**
|
261 |
+
* Get the absolute path of the cached and compiled file.
|
262 |
+
*
|
263 |
+
* @since 1.0.0
|
264 |
+
*
|
265 |
+
* @return string
|
266 |
+
*/
|
267 |
+
public function get_filename() {
|
268 |
+
if ( isset( $this->filename ) ) {
|
269 |
+
return $this->dir . '/' . $this->filename;
|
270 |
+
}
|
271 |
+
|
272 |
+
return '';
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Create cached file.
|
277 |
+
*
|
278 |
+
* @since 1.0.0
|
279 |
+
*
|
280 |
+
* @return bool
|
281 |
+
*/
|
282 |
+
public function cache_file() {
|
283 |
+
$filename = $this->get_filename();
|
284 |
+
|
285 |
+
if ( empty( $filename ) ) {
|
286 |
+
return false;
|
287 |
+
}
|
288 |
+
|
289 |
+
// It is safe to access the filesystem because we made sure it was set.
|
290 |
+
return $GLOBALS['wp_filesystem']->put_contents( $filename, $this->compiled_content, FS_CHMOD_FILE );
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Enqueue cached file.
|
295 |
+
*
|
296 |
+
* @since 1.0.0
|
297 |
+
*
|
298 |
+
* @return void|bool
|
299 |
+
*/
|
300 |
+
private function enqueue_file() {
|
301 |
+
|
302 |
+
// Enqueue CSS file.
|
303 |
+
if ( 'style' === $this->config['type'] ) {
|
304 |
+
return wp_enqueue_style(
|
305 |
+
$this->config['id'],
|
306 |
+
$this->get_url(),
|
307 |
+
$this->config['dependencies'],
|
308 |
+
$this->config['version']
|
309 |
+
);
|
310 |
+
}
|
311 |
+
|
312 |
+
// Enqueue JS file.
|
313 |
+
if ( 'script' === $this->config['type'] ) {
|
314 |
+
return wp_enqueue_script(
|
315 |
+
$this->config['id'],
|
316 |
+
$this->get_url(),
|
317 |
+
$this->config['dependencies'],
|
318 |
+
$this->config['version'],
|
319 |
+
$this->config['in_footer']
|
320 |
+
);
|
321 |
+
}
|
322 |
+
|
323 |
+
return false;
|
324 |
+
}
|
325 |
+
|
326 |
+
/**
|
327 |
+
* Get cached file url.
|
328 |
+
*
|
329 |
+
* @since 1.0.0
|
330 |
+
*
|
331 |
+
* @return string
|
332 |
+
*/
|
333 |
+
public function get_url() {
|
334 |
+
$url = trailingslashit( $this->url ) . $this->filename;
|
335 |
+
|
336 |
+
if ( is_ssl() ) {
|
337 |
+
$url = str_replace( 'http://', 'https://', $url );
|
338 |
+
}
|
339 |
+
|
340 |
+
return $url;
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Get the file extension from the configured "type".
|
345 |
+
*
|
346 |
+
* @since 1.0.0
|
347 |
+
*
|
348 |
+
* @return string|null
|
349 |
+
*/
|
350 |
+
public function get_extension() {
|
351 |
+
|
352 |
+
if ( 'style' === $this->config['type'] ) {
|
353 |
+
return 'css';
|
354 |
+
}
|
355 |
+
|
356 |
+
if ( 'script' === $this->config['type'] ) {
|
357 |
+
return 'js';
|
358 |
+
}
|
359 |
+
}
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Combine content of the fragments.
|
363 |
+
*
|
364 |
+
* @since 1.0.0
|
365 |
+
*
|
366 |
+
* @return void
|
367 |
+
*/
|
368 |
+
public function combine_fragments() {
|
369 |
+
$content = '';
|
370 |
+
|
371 |
+
// Loop through fragments.
|
372 |
+
foreach ( $this->config['fragments'] as $fragment ) {
|
373 |
+
|
374 |
+
// Stop here if the fragment is empty.
|
375 |
+
if ( empty( $fragment ) ) {
|
376 |
+
continue;
|
377 |
+
}
|
378 |
+
|
379 |
+
$fragment_content = $this->get_content( $fragment );
|
380 |
+
|
381 |
+
// Stop here if no content or content is an html page.
|
382 |
+
if ( ! $fragment_content || preg_match( '#^\s*\<#', $fragment_content ) ) {
|
383 |
+
continue;
|
384 |
+
}
|
385 |
+
|
386 |
+
// Continue processing style.
|
387 |
+
if ( 'style' === $this->config['type'] ) {
|
388 |
+
$fragment_content = $this->replace_css_url( $fragment_content );
|
389 |
+
$fragment_content = $this->add_content_media_query( $fragment_content );
|
390 |
+
}
|
391 |
+
|
392 |
+
// If there's content, start a new line.
|
393 |
+
if ( $content ) {
|
394 |
+
$content .= "\n\n";
|
395 |
+
}
|
396 |
+
|
397 |
+
$content .= $fragment_content;
|
398 |
+
}
|
399 |
+
|
400 |
+
$this->compiled_content = ! empty( $content ) ? $this->format_content( $content ) : '';
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Get the fragment's content.
|
405 |
+
*
|
406 |
+
* @since 1.0.0
|
407 |
+
*
|
408 |
+
* @param string|callable $fragment The given fragment from which to get the content.
|
409 |
+
*
|
410 |
+
* @return bool|string
|
411 |
+
*/
|
412 |
+
private function get_content( $fragment ) {
|
413 |
+
// Set the current fragment used by other functions.
|
414 |
+
$this->current_fragment = $fragment;
|
415 |
+
|
416 |
+
// If the fragment is callable, call it to get the content.
|
417 |
+
if ( $this->is_function( $fragment ) ) {
|
418 |
+
return $this->get_function_content();
|
419 |
+
}
|
420 |
+
|
421 |
+
$content = $this->get_internal_content();
|
422 |
+
|
423 |
+
// Try remote content if the internal content returned false.
|
424 |
+
if ( empty( $content ) ) {
|
425 |
+
$content = $this->get_remote_content();
|
426 |
+
}
|
427 |
+
|
428 |
+
return $content;
|
429 |
+
}
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Get internal file content.
|
433 |
+
*
|
434 |
+
* @since 1.0.0
|
435 |
+
*
|
436 |
+
* @return string|bool
|
437 |
+
*/
|
438 |
+
public function get_internal_content() {
|
439 |
+
$fragment = $this->current_fragment;
|
440 |
+
|
441 |
+
if ( ! file_exists( $fragment ) ) {
|
442 |
+
|
443 |
+
// Replace URL with path.
|
444 |
+
$fragment = jupiterx_url_to_path( $fragment );
|
445 |
+
|
446 |
+
// Stop here if it isn't a valid file.
|
447 |
+
if ( ! file_exists( $fragment ) || 0 === @filesize( $fragment ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
448 |
+
return false;
|
449 |
+
}
|
450 |
+
}
|
451 |
+
|
452 |
+
// It is safe to access the filesystem because we made sure it was set.
|
453 |
+
return $GLOBALS['wp_filesystem']->get_contents( $fragment );
|
454 |
+
}
|
455 |
+
|
456 |
+
/**
|
457 |
+
* Get external file content.
|
458 |
+
*
|
459 |
+
* @since 1.0.0
|
460 |
+
*
|
461 |
+
* @return string|bool
|
462 |
+
*/
|
463 |
+
public function get_remote_content() {
|
464 |
+
$fragment = $this->current_fragment;
|
465 |
+
|
466 |
+
if ( empty( $fragment ) ) {
|
467 |
+
return false;
|
468 |
+
}
|
469 |
+
|
470 |
+
// For a relative URL, add http: to it.
|
471 |
+
if ( substr( $fragment, 0, 2 ) === '//' ) {
|
472 |
+
$fragment = 'http:' . $fragment;
|
473 |
+
} elseif ( substr( $fragment, 0, 1 ) === '/' ) { // Add domain if it is local but could not be fetched as a file.
|
474 |
+
$fragment = site_url( $fragment );
|
475 |
+
}
|
476 |
+
|
477 |
+
$request = wp_remote_get( $fragment );
|
478 |
+
|
479 |
+
if ( is_wp_error( $request ) ) {
|
480 |
+
return '';
|
481 |
+
}
|
482 |
+
|
483 |
+
// If no content was received and the URL is not https, then convert the URL to SSL and retry.
|
484 |
+
if (
|
485 |
+
( ! isset( $request['body'] ) || 200 !== $request['response']['code'] ) &&
|
486 |
+
( substr( $fragment, 0, 8 ) !== 'https://' )
|
487 |
+
) {
|
488 |
+
$fragment = str_replace( 'http://', 'https://', $fragment );
|
489 |
+
$request = wp_remote_get( $fragment );
|
490 |
+
|
491 |
+
if ( is_wp_error( $request ) ) {
|
492 |
+
return '';
|
493 |
+
}
|
494 |
+
}
|
495 |
+
|
496 |
+
if ( ( ! isset( $request['body'] ) || 200 !== $request['response']['code'] ) ) {
|
497 |
+
return false;
|
498 |
+
}
|
499 |
+
|
500 |
+
return wp_remote_retrieve_body( $request );
|
501 |
+
}
|
502 |
+
|
503 |
+
/**
|
504 |
+
* Get function content.
|
505 |
+
*
|
506 |
+
* @since 1.0.0
|
507 |
+
*
|
508 |
+
* @return string|bool
|
509 |
+
*/
|
510 |
+
public function get_function_content() {
|
511 |
+
|
512 |
+
if ( ! is_callable( $this->current_fragment ) ) {
|
513 |
+
return false;
|
514 |
+
}
|
515 |
+
|
516 |
+
return call_user_func( $this->current_fragment );
|
517 |
+
}
|
518 |
+
|
519 |
+
/**
|
520 |
+
* Wrap content in query.
|
521 |
+
*
|
522 |
+
* @since 1.0.0
|
523 |
+
*
|
524 |
+
* @param string $content Given content to process.
|
525 |
+
*
|
526 |
+
* @return string
|
527 |
+
*/
|
528 |
+
public function add_content_media_query( $content ) {
|
529 |
+
|
530 |
+
// Ignore if the fragment is a function.
|
531 |
+
if ( $this->is_function( $this->current_fragment ) ) {
|
532 |
+
return $content;
|
533 |
+
}
|
534 |
+
|
535 |
+
$query = wp_parse_url( $this->current_fragment, PHP_URL_QUERY );
|
536 |
+
|
537 |
+
// Bail out if there are no query args or no media query.
|
538 |
+
if ( empty( $query ) || false === stripos( $query, 'jupiterx_compiler_media_query' ) ) {
|
539 |
+
return $content;
|
540 |
+
}
|
541 |
+
|
542 |
+
// Wrap the content in the query.
|
543 |
+
return sprintf(
|
544 |
+
"@media %s {\n%s\n}\n",
|
545 |
+
jupiterx_get( 'jupiterx_compiler_media_query', wp_parse_args( $query ) ),
|
546 |
+
$content
|
547 |
+
);
|
548 |
+
}
|
549 |
+
|
550 |
+
/**
|
551 |
+
* Format CSS, LESS and JS content.
|
552 |
+
*
|
553 |
+
* @since 1.0.0
|
554 |
+
*
|
555 |
+
* @param string $content Given content to process.
|
556 |
+
*
|
557 |
+
* @return string
|
558 |
+
*/
|
559 |
+
public function format_content( $content ) {
|
560 |
+
|
561 |
+
if ( 'style' === $this->config['type'] ) {
|
562 |
+
|
563 |
+
if ( 'less' === $this->config['format'] ) {
|
564 |
+
|
565 |
+
if ( ! class_exists( 'JupiterX_Lessc' ) ) {
|
566 |
+
jupiterx_core()->load_files( [ 'compiler/vendors/lessc' ] );
|
567 |
+
}
|
568 |
+
|
569 |
+
$parser = new JupiterX_Lessc();
|
570 |
+
|
571 |
+
$parser = $this->register_less_functions( $parser );
|
572 |
+
|
573 |
+
$parser->setVariables( $this->config['variables'] );
|
574 |
+
|
575 |
+
$content = $parser->compile( $content );
|
576 |
+
}
|
577 |
+
|
578 |
+
if ( ! function_exists( 'jupiterx_parse_css' ) ) {
|
579 |
+
return $content;
|
580 |
+
}
|
581 |
+
|
582 |
+
$content = jupiterx_parse_css( $content );
|
583 |
+
|
584 |
+
if ( ! _jupiterx_is_compiler_dev_mode() ) {
|
585 |
+
$content = $this->minify_style( $content );
|
586 |
+
}
|
587 |
+
|
588 |
+
return $content;
|
589 |
+
}
|
590 |
+
|
591 |
+
if ( 'script' === $this->config['type'] && ! _jupiterx_is_compiler_dev_mode() && $this->config['minify_js'] ) {
|
592 |
+
|
593 |
+
if ( ! class_exists( 'JSMin' ) ) {
|
594 |
+
jupiterx_core()->load_files( [ 'compiler/vendors/js-minifier' ] );
|
595 |
+
}
|
596 |
+
|
597 |
+
$js_min = new JSMin( $content );
|
598 |
+
return $js_min->min();
|
599 |
+
}
|
600 |
+
|
601 |
+
return $content;
|
602 |
+
}
|
603 |
+
|
604 |
+
/**
|
605 |
+
* Replace CSS URL shortcuts with a valid URL.
|
606 |
+
*
|
607 |
+
* @since 1.0.0
|
608 |
+
*
|
609 |
+
* @param string $content Given content to process.
|
610 |
+
*
|
611 |
+
* @return string
|
612 |
+
*/
|
613 |
+
public function replace_css_url( $content ) {
|
614 |
+
return preg_replace_callback(
|
615 |
+
'#url\s*\(\s*[\'"]*?([^\'"\)]+)[\'"]*\s*\)#i',
|
616 |
+
array( $this, 'replace_css_url_callback' ),
|
617 |
+
$content
|
618 |
+
);
|
619 |
+
}
|
620 |
+
|
621 |
+
/**
|
622 |
+
* Convert any CSS URL relative paths to absolute URLs.
|
623 |
+
*
|
624 |
+
* @since 1.0.0
|
625 |
+
*
|
626 |
+
* @param array $matches Matches to process, where 0 is the CSS' URL() and 1 is the URI.
|
627 |
+
*
|
628 |
+
* @return string
|
629 |
+
*/
|
630 |
+
public function replace_css_url_callback( $matches ) {
|
631 |
+
|
632 |
+
// If the URI is absolute, bail out and return the CSS.
|
633 |
+
if ( _jupiterx_is_uri( $matches[1] ) ) {
|
634 |
+
return $matches[0];
|
635 |
+
}
|
636 |
+
|
637 |
+
$base = $this->current_fragment;
|
638 |
+
|
639 |
+
// Separate the placeholders and path.
|
640 |
+
$paths = explode( '../', $matches[1] );
|
641 |
+
|
642 |
+
/**
|
643 |
+
* Walk backwards through each of the the fragment's directories, one-by-one. The `foreach` loop
|
644 |
+
* provides us with a performant way to walk the fragment back to its base path based upon the
|
645 |
+
* number of placeholders.
|
646 |
+
*/
|
647 |
+
foreach ( $paths as $path ) {
|
648 |
+
$base = dirname( $base );
|
649 |
+
}
|
650 |
+
|
651 |
+
// Make sure it is a valid base.
|
652 |
+
if ( '.' === $base ) {
|
653 |
+
$base = '';
|
654 |
+
}
|
655 |
+
|
656 |
+
// Rebuild the URL and make sure it is valid using the jupiterx_path_to_url function.
|
657 |
+
$url = jupiterx_path_to_url( trailingslashit( $base ) . ltrim( end( $paths ), '/\\' ) );
|
658 |
+
|
659 |
+
// Return the rebuilt path converted to an URL.
|
660 |
+
return 'url("' . $url . '")';
|
661 |
+
}
|
662 |
+
|
663 |
+
/**
|
664 |
+
* Register LESS_PHP functions.
|
665 |
+
*
|
666 |
+
* @since 1.0.0
|
667 |
+
*
|
668 |
+
* @param object $parser The LESS parser.
|
669 |
+
*
|
670 |
+
* @todo Refactoring is required.
|
671 |
+
*
|
672 |
+
* @return object
|
673 |
+
*/
|
674 |
+
private function register_less_functions( $parser ) {
|
675 |
+
$parser->registerFunction( 'jupiterx_value', function( $arg ) {
|
676 |
+
$output = '';
|
677 |
+
|
678 |
+
if ( isset( $arg[2][1][2][0] ) ) {
|
679 |
+
$output = $arg[2][1][2][0]; // Default.
|
680 |
+
}
|
681 |
+
|
682 |
+
if ( ! empty( $arg[2][0][2][1][1] ) ) {
|
683 |
+
return $arg[2][0][2][1][1]; // E.g. ~"@{@{var}-width}".
|
684 |
+
}
|
685 |
+
|
686 |
+
if ( ! empty( $arg[2][0][1] ) ) {
|
687 |
+
$value = $arg[2][0][1]; // E.g. @text-size.
|
688 |
+
$unit = empty( $arg[2][0][2] ) ? '' : $arg[2][0][2]; // E.g. @text-size unit.
|
689 |
+
|
690 |
+
return $value . $unit;
|
691 |
+
}
|
692 |
+
|
693 |
+
return $output;
|
694 |
+
} );
|
695 |
+
|
696 |
+
$parser->registerFunction( 'jupiterx_value_pattern', function( $arg ) {
|
697 |
+
if ( 0 === strlen( $arg[2][0][1] ) ) {
|
698 |
+
return '';
|
699 |
+
}
|
700 |
+
|
701 |
+
list($type, $value, $unit) = $arg[2][0];
|
702 |
+
|
703 |
+
$format = $arg[2][1][2][0];
|
704 |
+
|
705 |
+
// When value is 0px, parser automatically remove px (but not %) from it.
|
706 |
+
if ( 0 == $arg[2][0][1] ) { // @codingStandardsIgnoreLine
|
707 |
+
$unit = '%';
|
708 |
+
}
|
709 |
+
|
710 |
+
return sprintf( $format, $value . $unit );
|
711 |
+
} );
|
712 |
+
|
713 |
+
$parser->registerFunction( 'jupiterx_replace', function( $args ) {
|
714 |
+
list( $string, $search, $replace ) = $args[2];
|
715 |
+
|
716 |
+
// Arrange if string is from a variable use the true condition. e.g. @{var-name}.
|
717 |
+
$string = isset( $string[2][1][1] ) ? $string[2][1][1] : $string[2][0];
|
718 |
+
$search = $search[2][0];
|
719 |
+
$replace = $replace[2][0];
|
720 |
+
|
721 |
+
return str_replace( $search, $replace, $string );
|
722 |
+
} );
|
723 |
+
|
724 |
+
return $parser;
|
725 |
+
}
|
726 |
+
|
727 |
+
/**
|
728 |
+
* Initialize the configuration.
|
729 |
+
*
|
730 |
+
* @since 1.0.0
|
731 |
+
*
|
732 |
+
* @param array $config Runtime configuration parameters for the Compiler.
|
733 |
+
*
|
734 |
+
* @return array
|
735 |
+
*/
|
736 |
+
private function init_config( array $config ) {
|
737 |
+
// Fix dependencies, if "depedencies" is specified.
|
738 |
+
if ( isset( $config['depedencies'] ) ) {
|
739 |
+
$config['dependencies'] = $config['depedencies'];
|
740 |
+
unset( $config['depedencies'] );
|
741 |
+
}
|
742 |
+
|
743 |
+
$defaults = [
|
744 |
+
'id' => false,
|
745 |
+
'type' => false,
|
746 |
+
'format' => false,
|
747 |
+
'fragments' => [],
|
748 |
+
'variables' => apply_filters( 'jupiterx_compiler_less_variables', [] ),
|
749 |
+
'dependencies' => false,
|
750 |
+
'in_footer' => false,
|
751 |
+
'minify_js' => true,
|
752 |
+
'version' => JUPITERX_VERSION,
|
753 |
+
'enqueue' => true,
|
754 |
+
];
|
755 |
+
|
756 |
+
return array_merge( $defaults, $config );
|
757 |
+
}
|
758 |
+
|
759 |
+
/**
|
760 |
+
* Get the fragments' modification times.
|
761 |
+
*
|
762 |
+
* @since 1.0.0
|
763 |
+
*
|
764 |
+
* @return array
|
765 |
+
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
|
766 |
+
*/
|
767 |
+
private function get_fragments_filemtime() {
|
768 |
+
$fragments_filemtime = array();
|
769 |
+
|
770 |
+
foreach ( $this->config['fragments'] as $index => $fragment ) {
|
771 |
+
|
772 |
+
// Skip this one if the fragment is a function.
|
773 |
+
if ( $this->is_function( $fragment ) ) {
|
774 |
+
if ( ! is_callable( $fragment ) ) {
|
775 |
+
continue;
|
776 |
+
}
|
777 |
+
|
778 |
+
$fragments_filemtime[ $index ] = $this->hash( [ call_user_func( $fragment ) ] );
|
779 |
+
|
780 |
+
}
|
781 |
+
|
782 |
+
if ( file_exists( $fragment ) ) {
|
783 |
+
$fragments_filemtime[ $index ] = @filemtime( $fragment ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
784 |
+
}
|
785 |
+
}
|
786 |
+
|
787 |
+
return $fragments_filemtime;
|
788 |
+
}
|
789 |
+
|
790 |
+
/**
|
791 |
+
* Get the new hash for the given fragments' modification times.
|
792 |
+
*
|
793 |
+
* @since 1.0.0
|
794 |
+
*
|
795 |
+
* @param string $hash The original hash to modify.
|
796 |
+
* @param array $fragments_filemtime Array of fragments' modification times.
|
797 |
+
*
|
798 |
+
* @return string
|
799 |
+
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
|
800 |
+
*/
|
801 |
+
private function get_new_hash( $hash, array $fragments_filemtime ) {
|
802 |
+
|
803 |
+
if ( empty( $fragments_filemtime ) ) {
|
804 |
+
return $hash;
|
805 |
+
}
|
806 |
+
|
807 |
+
// Set filemtime hash.
|
808 |
+
$_hash = $this->hash( $fragments_filemtime );
|
809 |
+
|
810 |
+
$this->remove_modified_files( $hash, $_hash );
|
811 |
+
|
812 |
+
// Set the new hash which will trigger a new compiling.
|
813 |
+
return $hash . '-' . $_hash;
|
814 |
+
}
|
815 |
+
|
816 |
+
/**
|
817 |
+
* Remove any modified files. A file is considered modified when:
|
818 |
+
*
|
819 |
+
* 1. It has both a base hash and filemtime hash, separated by '-'.
|
820 |
+
* 2. Its base hash matches the given hash.
|
821 |
+
* 3. Its filemtime hash does not match the given filemtime hash.
|
822 |
+
*
|
823 |
+
* @since 1.0.0
|
824 |
+
*
|
825 |
+
* @param string $hash Base hash.
|
826 |
+
* @param string $filemtime_hash The filemtime hash (from hashing the fragments).
|
827 |
+
*
|
828 |
+
* @return void
|
829 |
+
*/
|
830 |
+
private function remove_modified_files( $hash, $filemtime_hash ) {
|
831 |
+
|
832 |
+
if ( ! is_dir( $this->dir ) ) {
|
833 |
+
return;
|
834 |
+
}
|
835 |
+
|
836 |
+
$items = @scandir( $this->dir ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
837 |
+
unset( $items[0], $items[1] );
|
838 |
+
|
839 |
+
if ( empty( $items ) ) {
|
840 |
+
return;
|
841 |
+
}
|
842 |
+
|
843 |
+
foreach ( $items as $item ) {
|
844 |
+
|
845 |
+
// Skip this one if it's a directory.
|
846 |
+
if ( @is_dir( $item ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
847 |
+
continue;
|
848 |
+
}
|
849 |
+
|
850 |
+
// Skip this one if it's not the same type.
|
851 |
+
if ( pathinfo( $item, PATHINFO_EXTENSION ) !== $this->get_extension() ) {
|
852 |
+
continue;
|
853 |
+
}
|
854 |
+
|
855 |
+
// Skip this one if it does not have a '-' in the filename.
|
856 |
+
if ( strpos( $item, '-' ) === false ) {
|
857 |
+
continue;
|
858 |
+
}
|
859 |
+
|
860 |
+
$hash_parts = explode( '-', pathinfo( $item, PATHINFO_FILENAME ) );
|
861 |
+
|
862 |
+
// Skip this one if it does not match the given base hash.
|
863 |
+
if ( $hash_parts[0] !== $hash ) {
|
864 |
+
continue;
|
865 |
+
}
|
866 |
+
|
867 |
+
// Skip this one if it does match the given filemtime's hash.
|
868 |
+
if ( $hash_parts[1] === $filemtime_hash ) {
|
869 |
+
continue;
|
870 |
+
}
|
871 |
+
|
872 |
+
// Clean up other modified files.
|
873 |
+
@unlink( $this->dir . '/' . $item ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
874 |
+
}
|
875 |
+
}
|
876 |
+
|
877 |
+
/**
|
878 |
+
* Minify the CSS.
|
879 |
+
*
|
880 |
+
* @since 1.0.0
|
881 |
+
*
|
882 |
+
* @param string $content Given content to process.
|
883 |
+
*
|
884 |
+
* @return string
|
885 |
+
*/
|
886 |
+
private function minify_style( $content ) {
|
887 |
+
$replace = array(
|
888 |
+
'/([^\r\n{}]+)(,(?=[^}]*{)|\s*{)}/' => '', // Strip empty selectors.
|
889 |
+
'/@media\s\(.*\).*{}/' => '', // Strip empty @media.
|
890 |
+
'#/\*.*?\*/#s' => '', // Strip comments.
|
891 |
+
'#\s\s+#' => ' ', // Strip excess whitespace.
|
892 |
+
);
|
893 |
+
|
894 |
+
$search = array_keys( $replace );
|
895 |
+
$content = preg_replace( $search, $replace, $content );
|
896 |
+
|
897 |
+
$replace = array(
|
898 |
+
': ' => ':',
|
899 |
+
'; ' => ';',
|
900 |
+
' {' => '{',
|
901 |
+
' }' => '}',
|
902 |
+
', ' => ',',
|
903 |
+
'{ ' => '{',
|
904 |
+
',\n' => ',', // Don't wrap multiple selectors.
|
905 |
+
'\n}' => '}', // Don't wrap closing braces.
|
906 |
+
'} ' => "}\n", // Put each rule on it's own line.
|
907 |
+
'\n' => '', // Remove all line breaks.
|
908 |
+
);
|
909 |
+
|
910 |
+
$search = array_keys( $replace );
|
911 |
+
|
912 |
+
return trim( str_replace( $search, $replace, $content ) );
|
913 |
+
}
|
914 |
+
|
915 |
+
/**
|
916 |
+
* Check if the given fragment is a callable.
|
917 |
+
*
|
918 |
+
* @since 1.0.0
|
919 |
+
*
|
920 |
+
* @param mixed $fragment Given fragment to check.
|
921 |
+
*
|
922 |
+
* @return bool
|
923 |
+
*/
|
924 |
+
private function is_function( $fragment ) {
|
925 |
+
return ( is_array( $fragment ) || is_callable( $fragment ) );
|
926 |
+
}
|
927 |
+
|
928 |
+
/**
|
929 |
+
* Kill it :(
|
930 |
+
*
|
931 |
+
* @since 1.0.0
|
932 |
+
*
|
933 |
+
* @return void
|
934 |
+
*/
|
935 |
+
private function kill() {
|
936 |
+
|
937 |
+
// Send report if set.
|
938 |
+
if ( jupiterx_get( 'jupiterx_send_compiler_report' ) ) { // @codingStandardsIgnoreLine
|
939 |
+
// $this->report(); // @codingStandardsIgnoreLine
|
940 |
+
}
|
941 |
+
|
942 |
+
$html = jupiterx_output( 'jupiterx_compiler_error_title_text', sprintf(
|
943 |
+
'<h2>%s</h2>',
|
944 |
+
__( 'Not cool, Jupiter cannot work its magic :(', 'jupiterx-core' )
|
945 |
+
) );
|
946 |
+
|
947 |
+
$html .= jupiterx_output( 'jupiterx_compiler_error_message_text', sprintf(
|
948 |
+
'<p>%s</p>',
|
949 |
+
__( 'Your current install or file permission prevents Jupiter from working its magic. Please get in touch with Jupiter support. We will gladly get you started within 24 - 48 hours (working days).', 'jupiterx-core' )
|
950 |
+
) );
|
951 |
+
|
952 |
+
$html .= jupiterx_output( 'jupiterx_compiler_error_contact_text', sprintf(
|
953 |
+
'<a class="button" href="https://themes.artbees.net/support/" target="_blank">%s</a>',
|
954 |
+
__( 'Contact Jupiter Support', 'jupiterx-core' )
|
955 |
+
) );
|
956 |
+
|
957 |
+
$html .= jupiterx_output( 'jupiterx_compiler_error_report_text', sprintf(
|
958 |
+
'<p style="margin-top: 12px; font-size: 12px;"><a href="' . add_query_arg( 'jupiterx_send_compiler_report', true ) . '">%1$s</a>. %2$s</p>',
|
959 |
+
__( 'Send us an automatic report', 'jupiterx-core' ),
|
960 |
+
__( 'We respect your time and understand you might not be able to contact us.', 'jupiterx-core' )
|
961 |
+
) );
|
962 |
+
|
963 |
+
wp_die( wp_kses_post( $html ) );
|
964 |
+
}
|
965 |
+
|
966 |
+
/**
|
967 |
+
* Send report.
|
968 |
+
*
|
969 |
+
* @since 1.0.0
|
970 |
+
*
|
971 |
+
* @todo Decide if we want to use and change the report recipient.
|
972 |
+
*
|
973 |
+
* @return void
|
974 |
+
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
|
975 |
+
*/
|
976 |
+
private function report() {
|
977 |
+
// Send report.
|
978 |
+
wp_mail(
|
979 |
+
'hello@getjupiter.io',
|
980 |
+
'Compiler error',
|
981 |
+
'Compiler error reported by ' . home_url(),
|
982 |
+
array(
|
983 |
+
'MIME-Version: 1.0' . "\r\n",
|
984 |
+
'Content-type: text/html; charset=utf-8' . "\r\n",
|
985 |
+
"X-Mailer: PHP \r\n",
|
986 |
+
'From: ' . wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) . ' < ' . get_option( 'admin_email' ) . '>' . "\r\n",
|
987 |
+
'Reply-To: ' . get_option( 'admin_email' ) . "\r\n",
|
988 |
+
)
|
989 |
+
);
|
990 |
+
|
991 |
+
// Die and display message.
|
992 |
+
$message = jupiterx_output(
|
993 |
+
'jupiterx_compiler_report_error_text',
|
994 |
+
sprintf(
|
995 |
+
'<p>%s<p>',
|
996 |
+
__( 'Thanks for your contribution by reporting this issue. We hope to hear from you again.', 'jupiterx-core' )
|
997 |
+
)
|
998 |
+
);
|
999 |
+
|
1000 |
+
wp_die( wp_kses_post( $message ) );
|
1001 |
+
}
|
1002 |
+
|
1003 |
+
/**
|
1004 |
+
* Get the property's value.
|
1005 |
+
*
|
1006 |
+
* @since 1.0.0
|
1007 |
+
*
|
1008 |
+
* @param string $property Name of the property to get.
|
1009 |
+
*
|
1010 |
+
* @return mixed
|
1011 |
+
*/
|
1012 |
+
public function __get( $property ) {
|
1013 |
+
|
1014 |
+
if ( property_exists( $this, $property ) ) {
|
1015 |
+
return $this->{$property};
|
1016 |
+
}
|
1017 |
+
}
|
1018 |
+
}
|
includes/compiler/functions.php
CHANGED
@@ -1,411 +1,411 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Compile and cache CSS, LESS and JS files.
|
4 |
-
*
|
5 |
-
* The Jupiter Compiler compiles multiple internal or external CSS, LESS and JS files on a
|
6 |
-
* per page basis. LESS content will automatically be converted to CSS.
|
7 |
-
*
|
8 |
-
* Internal file changes are automatically detected if development mode is enabled.
|
9 |
-
* Third party enqueued styles and scripts can be compiled and cached into a single file.
|
10 |
-
*
|
11 |
-
* @package API\Compiler
|
12 |
-
*/
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Compile CSS fragments and enqueue compiled file.
|
16 |
-
*
|
17 |
-
* This function should be used in a similar fashion to
|
18 |
-
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
19 |
-
*
|
20 |
-
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
21 |
-
*
|
22 |
-
* @since 1.0.0
|
23 |
-
*
|
24 |
-
* @param string $id A unique string used as a reference. Similar to the WordPress scripts
|
25 |
-
* $handle argument.
|
26 |
-
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
27 |
-
* compiling time.
|
28 |
-
* @param array $args {
|
29 |
-
* Optional. Array of arguments used by the compiler.
|
30 |
-
*
|
31 |
-
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
32 |
-
* }
|
33 |
-
*
|
34 |
-
* @return object Compiler object.
|
35 |
-
*/
|
36 |
-
function jupiterx_compile_css_fragments( $id, $fragments, $args = array() ) {
|
37 |
-
|
38 |
-
if ( empty( $fragments ) ) {
|
39 |
-
return false;
|
40 |
-
}
|
41 |
-
|
42 |
-
$params = array(
|
43 |
-
'id' => $id,
|
44 |
-
'type' => 'style',
|
45 |
-
'format' => 'css',
|
46 |
-
'fragments' => (array) $fragments,
|
47 |
-
);
|
48 |
-
|
49 |
-
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
50 |
-
$compiler->run_compiler();
|
51 |
-
|
52 |
-
return $compiler;
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Compile LESS fragments, convert to CSS and enqueue compiled file.
|
57 |
-
*
|
58 |
-
* This function should be used in a similar fashion to
|
59 |
-
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
60 |
-
*
|
61 |
-
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
62 |
-
*
|
63 |
-
* @since 1.0.0
|
64 |
-
*
|
65 |
-
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
66 |
-
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
67 |
-
* compiling time.
|
68 |
-
* @param array $args {
|
69 |
-
* Optional. Array of arguments used by the compiler.
|
70 |
-
*
|
71 |
-
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
72 |
-
* }
|
73 |
-
*
|
74 |
-
* @return object Compiler object.
|
75 |
-
*/
|
76 |
-
function jupiterx_compile_less_fragments( $id, $fragments, $args = array() ) {
|
77 |
-
|
78 |
-
if ( empty( $fragments ) ) {
|
79 |
-
return false;
|
80 |
-
}
|
81 |
-
|
82 |
-
$params = array(
|
83 |
-
'id' => $id,
|
84 |
-
'type' => 'style',
|
85 |
-
'format' => 'less',
|
86 |
-
'fragments' => (array) $fragments,
|
87 |
-
);
|
88 |
-
|
89 |
-
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
90 |
-
$compiler->run_compiler();
|
91 |
-
|
92 |
-
return $compiler;
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Compile LESS fragments, convert to CSS and enqueue compiled file.
|
97 |
-
*
|
98 |
-
* This function should be used in a similar fashion to
|
99 |
-
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
100 |
-
*
|
101 |
-
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
102 |
-
*
|
103 |
-
* @since 1.0.0
|
104 |
-
*
|
105 |
-
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
106 |
-
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
107 |
-
* compiling time.
|
108 |
-
* @param array $args {
|
109 |
-
* Optional. Array of arguments used by the compiler.
|
110 |
-
*
|
111 |
-
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
112 |
-
* }
|
113 |
-
*
|
114 |
-
* @return object Compiler object.
|
115 |
-
*/
|
116 |
-
function jupiterx_compile_scss_fragments( $id, $fragments, $args = array() ) {
|
117 |
-
|
118 |
-
if ( empty( $fragments ) ) {
|
119 |
-
return false;
|
120 |
-
}
|
121 |
-
|
122 |
-
$params = array(
|
123 |
-
'id' => $id,
|
124 |
-
'type' => 'style',
|
125 |
-
'format' => 'scss',
|
126 |
-
'fragments' => (array) $fragments,
|
127 |
-
);
|
128 |
-
|
129 |
-
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
130 |
-
$compiler->run_compiler();
|
131 |
-
|
132 |
-
return $compiler;
|
133 |
-
}
|
134 |
-
|
135 |
-
/**
|
136 |
-
* Compile JS fragments and enqueue compiled file.
|
137 |
-
*
|
138 |
-
* This function should be used in a similar fashion to
|
139 |
-
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
140 |
-
*
|
141 |
-
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
142 |
-
*
|
143 |
-
* @since 1.0.0
|
144 |
-
*
|
145 |
-
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
146 |
-
* @param string|array $fragments File(s) absolute path. Internal or external file(s) URL accepted but may increase
|
147 |
-
* compiling time.
|
148 |
-
* @param array $args {
|
149 |
-
* Optional. Array of arguments used by the compiler.
|
150 |
-
*
|
151 |
-
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
152 |
-
* @type bool $in_footer Whether to enqueue the script before </head> or before </body>. Default false.
|
153 |
-
* @type bool $minify_js Whether the JavaScript should be minified or not. Be aware that minifying
|
154 |
-
* the JavaScript can considerably slow down the process of compiling files.
|
155 |
-
* Default false.
|
156 |
-
* }
|
157 |
-
*
|
158 |
-
* @return object Compiler object.
|
159 |
-
*/
|
160 |
-
function jupiterx_compile_js_fragments( $id, $fragments, $args = array() ) {
|
161 |
-
|
162 |
-
if ( empty( $fragments ) ) {
|
163 |
-
return false;
|
164 |
-
}
|
165 |
-
|
166 |
-
$params = array(
|
167 |
-
'id' => $id,
|
168 |
-
'type' => 'script',
|
169 |
-
'format' => 'js',
|
170 |
-
'fragments' => (array) $fragments,
|
171 |
-
);
|
172 |
-
|
173 |
-
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
174 |
-
$compiler->run_compiler();
|
175 |
-
|
176 |
-
return $compiler;
|
177 |
-
}
|
178 |
-
|
179 |
-
/**
|
180 |
-
* Add CSS, LESS or JS fragments to a compiler.
|
181 |
-
*
|
182 |
-
* This function should be used in a similar fashion to
|
183 |
-
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
184 |
-
*
|
185 |
-
* @since 1.0.0
|
186 |
-
*
|
187 |
-
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
188 |
-
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
189 |
-
* compiling time.
|
190 |
-
* @param string $format Compiler format the fragments should be added to. Accepts 'css',
|
191 |
-
* 'less' or 'js'.
|
192 |
-
*
|
193 |
-
* @return void|bool
|
194 |
-
* @SuppressWarnings(PHPMD.ElseExpression)
|
195 |
-
*/
|
196 |
-
function jupiterx_compiler_add_fragment( $id, $fragments, $format ) {
|
197 |
-
|
198 |
-
if ( empty( $fragments ) ) {
|
199 |
-
return false;
|
200 |
-
}
|
201 |
-
|
202 |
-
global $_jupiterx_compiler_added_fragments;
|
203 |
-
|
204 |
-
foreach ( (array) $fragments as $key => $fragment ) {
|
205 |
-
|
206 |
-
// Stop here if the format isn't valid.
|
207 |
-
if ( ! isset( $_jupiterx_compiler_added_fragments[ $format ] ) ) {
|
208 |
-
continue;
|
209 |
-
}
|
210 |
-
|
211 |
-
// Register a new compiler ID if it doesn't exist and add fragment.
|
212 |
-
if ( ! isset( $_jupiterx_compiler_added_fragments[ $format ][ $id ] ) ) {
|
213 |
-
$_jupiterx_compiler_added_fragments[ $format ][ $id ] = array( $fragment );
|
214 |
-
} else { // Add fragment to existing compiler.
|
215 |
-
$_jupiterx_compiler_added_fragments[ $format ][ $id ][] = $fragment;
|
216 |
-
}
|
217 |
-
}
|
218 |
-
}
|
219 |
-
|
220 |
-
/**
|
221 |
-
* Flush cached compiler files.
|
222 |
-
*
|
223 |
-
* Each compiler has its own folder which contains the cached CSS and JS files. The file format
|
224 |
-
* of the cached file can be specified if needed.
|
225 |
-
*
|
226 |
-
* @since 1.0.0
|
227 |
-
*
|
228 |
-
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
229 |
-
* @param string|bool $file_format Optional. Define which file format(s) should be removed. Both CSS and JS
|
230 |
-
* files will be removed if set to false. Accepts 'false', 'css' or 'js'.
|
231 |
-
* @param bool $admin Optional. Whether it is an admin compiler or not.
|
232 |
-
*
|
233 |
-
* @return void|bool
|
234 |
-
*/
|
235 |
-
function jupiterx_flush_compiler( $id, $file_format = false, $admin = false ) {
|
236 |
-
static $jupiterx_flushed = false;
|
237 |
-
|
238 |
-
$cache_dir = jupiterx_get_compiler_dir( $admin );
|
239 |
-
|
240 |
-
// Always flush Jupiter' global cache.
|
241 |
-
if ( ! $jupiterx_flushed ) {
|
242 |
-
$jupiterx_flushed = true;
|
243 |
-
|
244 |
-
jupiterx_flush_compiler( 'jupiterx', $file_format, $admin );
|
245 |
-
}
|
246 |
-
|
247 |
-
$dir = trailingslashit( $cache_dir ) . $id;
|
248 |
-
|
249 |
-
// Stop here if directory doesn't exist.
|
250 |
-
if ( ! is_dir( $dir ) ) {
|
251 |
-
return;
|
252 |
-
}
|
253 |
-
|
254 |
-
// Remove only the specified file format.
|
255 |
-
if ( $file_format ) {
|
256 |
-
$items = scandir( $dir );
|
257 |
-
unset( $items[0], $items[1] );
|
258 |
-
|
259 |
-
foreach ( $items as $item ) {
|
260 |
-
if ( false !== stripos( $item, '.' . $file_format ) ) {
|
261 |
-
@unlink( trailingslashit( $dir ) . $item ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
262 |
-
}
|
263 |
-
}
|
264 |
-
|
265 |
-
return;
|
266 |
-
}
|
267 |
-
|
268 |
-
// Remove all file formats.
|
269 |
-
jupiterx_remove_dir( $dir );
|
270 |
-
|
271 |
-
jupiterx_flush_cache_plugins();
|
272 |
-
}
|
273 |
-
|
274 |
-
/**
|
275 |
-
* Flush admin cached compiler files.
|
276 |
-
*
|
277 |
-
* This function is a shortcut of {@see jupiterx_flush_compiler()}.
|
278 |
-
*
|
279 |
-
* @since 1.0.0
|
280 |
-
*
|
281 |
-
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
282 |
-
* @param string|bool $file_format Optional. Define which file formats should be removed. Both CSS and JS
|
283 |
-
* files will be removed if set to false. Accepts 'false', 'css' or 'js'.
|
284 |
-
*
|
285 |
-
* @return void
|
286 |
-
*/
|
287 |
-
function jupiterx_flush_admin_compiler( $id, $file_format = false ) {
|
288 |
-
jupiterx_flush_compiler( $id, $file_format, true );
|
289 |
-
}
|
290 |
-
|
291 |
-
/**
|
292 |
-
* Flush cache plugins
|
293 |
-
*
|
294 |
-
* @since 1.0.0
|
295 |
-
*
|
296 |
-
* @return void
|
297 |
-
*/
|
298 |
-
function jupiterx_flush_cache_plugins() {
|
299 |
-
|
300 |
-
if ( function_exists( 'w3tc_pgcache_flush' ) ) {
|
301 |
-
w3tc_pgcache_flush();
|
302 |
-
}
|
303 |
-
|
304 |
-
if ( function_exists( 'wp_cache_clear_cache' ) ) {
|
305 |
-
wp_cache_clear_cache();
|
306 |
-
}
|
307 |
-
|
308 |
-
if ( function_exists( 'rocket_clean_domain' ) ) {
|
309 |
-
rocket_clean_domain();
|
310 |
-
}
|
311 |
-
|
312 |
-
if ( class_exists( 'WpFastestCache' ) ) {
|
313 |
-
$GLOBALS['wp_fastest_cache']->deleteCache();
|
314 |
-
}
|
315 |
-
|
316 |
-
if ( class_exists( 'autoptimizeCache' ) ) {
|
317 |
-
autoptimizeCache::clearall();
|
318 |
-
}
|
319 |
-
}
|
320 |
-
|
321 |
-
/**
|
322 |
-
* Get absolute path to the Jupiter' compiler directory.
|
323 |
-
*
|
324 |
-
* @since 1.0.0
|
325 |
-
*
|
326 |
-
* @param bool $is_admin Optional. When true, gets the admin compiler directory. Default is false.
|
327 |
-
*
|
328 |
-
* @return string
|
329 |
-
*/
|
330 |
-
function jupiterx_get_compiler_dir( $is_admin = false ) {
|
331 |
-
$wp_upload_dir = wp_upload_dir();
|
332 |
-
$suffix = $is_admin ? 'jupiterx/admin-compiler/' : 'jupiterx/compiler/';
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Deprecated. Filter the Jupiter compiler directory.
|
336 |
-
*
|
337 |
-
* This filter is deprecated for security and compatibility purposes.
|
338 |
-
*
|
339 |
-
* @since 1.0.0
|
340 |
-
* @deprecated 1.3.0
|
341 |
-
*/
|
342 |
-
apply_filters( 'jupiterx_compiler_dir', false, $is_admin );
|
343 |
-
|
344 |
-
return wp_normalize_path( trailingslashit( $wp_upload_dir['basedir'] ) . $suffix );
|
345 |
-
}
|
346 |
-
|
347 |
-
/**
|
348 |
-
* Get absolute URL to the Jupiter' compiler directory.
|
349 |
-
*
|
350 |
-
* @since 1.0.0
|
351 |
-
*
|
352 |
-
* @param bool $is_admin Optional. When true, gets the admin compiler directory. Default is false.
|
353 |
-
*
|
354 |
-
* @return string
|
355 |
-
*/
|
356 |
-
function jupiterx_get_compiler_url( $is_admin = false ) {
|
357 |
-
$wp_upload_dir = wp_upload_dir();
|
358 |
-
$suffix = $is_admin ? 'jupiterx/admin-compiler/' : 'jupiterx/compiler/';
|
359 |
-
|
360 |
-
return trailingslashit( $wp_upload_dir['baseurl'] ) . $suffix;
|
361 |
-
}
|
362 |
-
|
363 |
-
/**
|
364 |
-
* Check if development mode is enabled.
|
365 |
-
*
|
366 |
-
* Takes legacy constant into consideration.
|
367 |
-
*
|
368 |
-
* @since 1.0.0
|
369 |
-
* @ignore
|
370 |
-
* @access private
|
371 |
-
*
|
372 |
-
* @return bool
|
373 |
-
*/
|
374 |
-
function _jupiterx_is_compiler_dev_mode() {
|
375 |
-
|
376 |
-
if ( defined( 'JUPITERX_COMPILER_DEV_MODE' ) ) {
|
377 |
-
return JUPITERX_COMPILER_DEV_MODE;
|
378 |
-
}
|
379 |
-
|
380 |
-
return jupiterx_get_option( 'dev_mode', false );
|
381 |
-
}
|
382 |
-
|
383 |
-
/**
|
384 |
-
* Get cache busting method.
|
385 |
-
*
|
386 |
-
* @since 1.0.0
|
387 |
-
* @access private
|
388 |
-
*
|
389 |
-
* @return bool
|
390 |
-
*/
|
391 |
-
function _jupiterx_get_cache_busting() {
|
392 |
-
return jupiterx_get_option( 'cache_busting', true );
|
393 |
-
}
|
394 |
-
|
395 |
-
/**
|
396 |
-
* Initialize added fragments global.
|
397 |
-
*
|
398 |
-
* @since 1.0.0
|
399 |
-
* @ignore
|
400 |
-
* @access private
|
401 |
-
*/
|
402 |
-
global $_jupiterx_compiler_added_fragments;
|
403 |
-
|
404 |
-
if ( ! isset( $_jupiterx_compiler_added_fragments ) ) {
|
405 |
-
$_jupiterx_compiler_added_fragments = array(
|
406 |
-
'css' => array(),
|
407 |
-
'less' => array(),
|
408 |
-
'scss' => array(),
|
409 |
-
'js' => array(),
|
410 |
-
);
|
411 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Compile and cache CSS, LESS and JS files.
|
4 |
+
*
|
5 |
+
* The Jupiter Compiler compiles multiple internal or external CSS, LESS and JS files on a
|
6 |
+
* per page basis. LESS content will automatically be converted to CSS.
|
7 |
+
*
|
8 |
+
* Internal file changes are automatically detected if development mode is enabled.
|
9 |
+
* Third party enqueued styles and scripts can be compiled and cached into a single file.
|
10 |
+
*
|
11 |
+
* @package API\Compiler
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Compile CSS fragments and enqueue compiled file.
|
16 |
+
*
|
17 |
+
* This function should be used in a similar fashion to
|
18 |
+
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
19 |
+
*
|
20 |
+
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
21 |
+
*
|
22 |
+
* @since 1.0.0
|
23 |
+
*
|
24 |
+
* @param string $id A unique string used as a reference. Similar to the WordPress scripts
|
25 |
+
* $handle argument.
|
26 |
+
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
27 |
+
* compiling time.
|
28 |
+
* @param array $args {
|
29 |
+
* Optional. Array of arguments used by the compiler.
|
30 |
+
*
|
31 |
+
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
32 |
+
* }
|
33 |
+
*
|
34 |
+
* @return object Compiler object.
|
35 |
+
*/
|
36 |
+
function jupiterx_compile_css_fragments( $id, $fragments, $args = array() ) {
|
37 |
+
|
38 |
+
if ( empty( $fragments ) ) {
|
39 |
+
return false;
|
40 |
+
}
|
41 |
+
|
42 |
+
$params = array(
|
43 |
+
'id' => $id,
|
44 |
+
'type' => 'style',
|
45 |
+
'format' => 'css',
|
46 |
+
'fragments' => (array) $fragments,
|
47 |
+
);
|
48 |
+
|
49 |
+
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
50 |
+
$compiler->run_compiler();
|
51 |
+
|
52 |
+
return $compiler;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Compile LESS fragments, convert to CSS and enqueue compiled file.
|
57 |
+
*
|
58 |
+
* This function should be used in a similar fashion to
|
59 |
+
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
60 |
+
*
|
61 |
+
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
62 |
+
*
|
63 |
+
* @since 1.0.0
|
64 |
+
*
|
65 |
+
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
66 |
+
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
67 |
+
* compiling time.
|
68 |
+
* @param array $args {
|
69 |
+
* Optional. Array of arguments used by the compiler.
|
70 |
+
*
|
71 |
+
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
72 |
+
* }
|
73 |
+
*
|
74 |
+
* @return object Compiler object.
|
75 |
+
*/
|
76 |
+
function jupiterx_compile_less_fragments( $id, $fragments, $args = array() ) {
|
77 |
+
|
78 |
+
if ( empty( $fragments ) ) {
|
79 |
+
return false;
|
80 |
+
}
|
81 |
+
|
82 |
+
$params = array(
|
83 |
+
'id' => $id,
|
84 |
+
'type' => 'style',
|
85 |
+
'format' => 'less',
|
86 |
+
'fragments' => (array) $fragments,
|
87 |
+
);
|
88 |
+
|
89 |
+
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
90 |
+
$compiler->run_compiler();
|
91 |
+
|
92 |
+
return $compiler;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Compile LESS fragments, convert to CSS and enqueue compiled file.
|
97 |
+
*
|
98 |
+
* This function should be used in a similar fashion to
|
99 |
+
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
100 |
+
*
|
101 |
+
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
102 |
+
*
|
103 |
+
* @since 1.0.0
|
104 |
+
*
|
105 |
+
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
106 |
+
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
107 |
+
* compiling time.
|
108 |
+
* @param array $args {
|
109 |
+
* Optional. Array of arguments used by the compiler.
|
110 |
+
*
|
111 |
+
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
112 |
+
* }
|
113 |
+
*
|
114 |
+
* @return object Compiler object.
|
115 |
+
*/
|
116 |
+
function jupiterx_compile_scss_fragments( $id, $fragments, $args = array() ) {
|
117 |
+
|
118 |
+
if ( empty( $fragments ) ) {
|
119 |
+
return false;
|
120 |
+
}
|
121 |
+
|
122 |
+
$params = array(
|
123 |
+
'id' => $id,
|
124 |
+
'type' => 'style',
|
125 |
+
'format' => 'scss',
|
126 |
+
'fragments' => (array) $fragments,
|
127 |
+
);
|
128 |
+
|
129 |
+
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
130 |
+
$compiler->run_compiler();
|
131 |
+
|
132 |
+
return $compiler;
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Compile JS fragments and enqueue compiled file.
|
137 |
+
*
|
138 |
+
* This function should be used in a similar fashion to
|
139 |
+
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
140 |
+
*
|
141 |
+
* Fragments can be added to the compiler using {@see jupiterx_compiler_add_fragment()}.
|
142 |
+
*
|
143 |
+
* @since 1.0.0
|
144 |
+
*
|
145 |
+
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
146 |
+
* @param string|array $fragments File(s) absolute path. Internal or external file(s) URL accepted but may increase
|
147 |
+
* compiling time.
|
148 |
+
* @param array $args {
|
149 |
+
* Optional. Array of arguments used by the compiler.
|
150 |
+
*
|
151 |
+
* @type array $depedencies An array of registered handles this script depends on. Default false.
|
152 |
+
* @type bool $in_footer Whether to enqueue the script before </head> or before </body>. Default false.
|
153 |
+
* @type bool $minify_js Whether the JavaScript should be minified or not. Be aware that minifying
|
154 |
+
* the JavaScript can considerably slow down the process of compiling files.
|
155 |
+
* Default false.
|
156 |
+
* }
|
157 |
+
*
|
158 |
+
* @return object Compiler object.
|
159 |
+
*/
|
160 |
+
function jupiterx_compile_js_fragments( $id, $fragments, $args = array() ) {
|
161 |
+
|
162 |
+
if ( empty( $fragments ) ) {
|
163 |
+
return false;
|
164 |
+
}
|
165 |
+
|
166 |
+
$params = array(
|
167 |
+
'id' => $id,
|
168 |
+
'type' => 'script',
|
169 |
+
'format' => 'js',
|
170 |
+
'fragments' => (array) $fragments,
|
171 |
+
);
|
172 |
+
|
173 |
+
$compiler = new _JupiterX_Compiler( array_merge( $params, $args ) );
|
174 |
+
$compiler->run_compiler();
|
175 |
+
|
176 |
+
return $compiler;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Add CSS, LESS or JS fragments to a compiler.
|
181 |
+
*
|
182 |
+
* This function should be used in a similar fashion to
|
183 |
+
* {@link http://codex.wordpress.org/Function_Reference/wp_enqueue_script wp_enqueue_script()}.
|
184 |
+
*
|
185 |
+
* @since 1.0.0
|
186 |
+
*
|
187 |
+
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
188 |
+
* @param string|array $fragments File(s) absolute path. Internal or external file(s) url accepted but may increase
|
189 |
+
* compiling time.
|
190 |
+
* @param string $format Compiler format the fragments should be added to. Accepts 'css',
|
191 |
+
* 'less' or 'js'.
|
192 |
+
*
|
193 |
+
* @return void|bool
|
194 |
+
* @SuppressWarnings(PHPMD.ElseExpression)
|
195 |
+
*/
|
196 |
+
function jupiterx_compiler_add_fragment( $id, $fragments, $format ) {
|
197 |
+
|
198 |
+
if ( empty( $fragments ) ) {
|
199 |
+
return false;
|
200 |
+
}
|
201 |
+
|
202 |
+
global $_jupiterx_compiler_added_fragments;
|
203 |
+
|
204 |
+
foreach ( (array) $fragments as $key => $fragment ) {
|
205 |
+
|
206 |
+
// Stop here if the format isn't valid.
|
207 |
+
if ( ! isset( $_jupiterx_compiler_added_fragments[ $format ] ) ) {
|
208 |
+
continue;
|
209 |
+
}
|
210 |
+
|
211 |
+
// Register a new compiler ID if it doesn't exist and add fragment.
|
212 |
+
if ( ! isset( $_jupiterx_compiler_added_fragments[ $format ][ $id ] ) ) {
|
213 |
+
$_jupiterx_compiler_added_fragments[ $format ][ $id ] = array( $fragment );
|
214 |
+
} else { // Add fragment to existing compiler.
|
215 |
+
$_jupiterx_compiler_added_fragments[ $format ][ $id ][] = $fragment;
|
216 |
+
}
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Flush cached compiler files.
|
222 |
+
*
|
223 |
+
* Each compiler has its own folder which contains the cached CSS and JS files. The file format
|
224 |
+
* of the cached file can be specified if needed.
|
225 |
+
*
|
226 |
+
* @since 1.0.0
|
227 |
+
*
|
228 |
+
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
229 |
+
* @param string|bool $file_format Optional. Define which file format(s) should be removed. Both CSS and JS
|
230 |
+
* files will be removed if set to false. Accepts 'false', 'css' or 'js'.
|
231 |
+
* @param bool $admin Optional. Whether it is an admin compiler or not.
|
232 |
+
*
|
233 |
+
* @return void|bool
|
234 |
+
*/
|
235 |
+
function jupiterx_flush_compiler( $id, $file_format = false, $admin = false ) {
|
236 |
+
static $jupiterx_flushed = false;
|
237 |
+
|
238 |
+
$cache_dir = jupiterx_get_compiler_dir( $admin );
|
239 |
+
|
240 |
+
// Always flush Jupiter' global cache.
|
241 |
+
if ( ! $jupiterx_flushed ) {
|
242 |
+
$jupiterx_flushed = true;
|
243 |
+
|
244 |
+
jupiterx_flush_compiler( 'jupiterx', $file_format, $admin );
|
245 |
+
}
|
246 |
+
|
247 |
+
$dir = trailingslashit( $cache_dir ) . $id;
|
248 |
+
|
249 |
+
// Stop here if directory doesn't exist.
|
250 |
+
if ( ! is_dir( $dir ) ) {
|
251 |
+
return;
|
252 |
+
}
|
253 |
+
|
254 |
+
// Remove only the specified file format.
|
255 |
+
if ( $file_format ) {
|
256 |
+
$items = scandir( $dir );
|
257 |
+
unset( $items[0], $items[1] );
|
258 |
+
|
259 |
+
foreach ( $items as $item ) {
|
260 |
+
if ( false !== stripos( $item, '.' . $file_format ) ) {
|
261 |
+
@unlink( trailingslashit( $dir ) . $item ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Valid use case.
|
262 |
+
}
|
263 |
+
}
|
264 |
+
|
265 |
+
return;
|
266 |
+
}
|
267 |
+
|
268 |
+
// Remove all file formats.
|
269 |
+
jupiterx_remove_dir( $dir );
|
270 |
+
|
271 |
+
jupiterx_flush_cache_plugins();
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Flush admin cached compiler files.
|
276 |
+
*
|
277 |
+
* This function is a shortcut of {@see jupiterx_flush_compiler()}.
|
278 |
+
*
|
279 |
+
* @since 1.0.0
|
280 |
+
*
|
281 |
+
* @param string $id The compiler ID. Similar to the WordPress scripts $handle argument.
|
282 |
+
* @param string|bool $file_format Optional. Define which file formats should be removed. Both CSS and JS
|
283 |
+
* files will be removed if set to false. Accepts 'false', 'css' or 'js'.
|
284 |
+
*
|
285 |
+
* @return void
|
286 |
+
*/
|
287 |
+
function jupiterx_flush_admin_compiler( $id, $file_format = false ) {
|
288 |
+
jupiterx_flush_compiler( $id, $file_format, true );
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Flush cache plugins
|
293 |
+
*
|
294 |
+
* @since 1.0.0
|
295 |
+
*
|
296 |
+
* @return void
|
297 |
+
*/
|
298 |
+
function jupiterx_flush_cache_plugins() {
|
299 |
+
|
300 |
+
if ( function_exists( 'w3tc_pgcache_flush' ) ) {
|
301 |
+
w3tc_pgcache_flush();
|
302 |
+
}
|
303 |
+
|
304 |
+
if ( function_exists( 'wp_cache_clear_cache' ) ) {
|
305 |
+
wp_cache_clear_cache();
|
306 |
+
}
|
307 |
+
|
308 |
+
if ( function_exists( 'rocket_clean_domain' ) ) {
|
309 |
+
rocket_clean_domain();
|
310 |
+
}
|
311 |
+
|
312 |
+
if ( class_exists( 'WpFastestCache' ) ) {
|
313 |
+
$GLOBALS['wp_fastest_cache']->deleteCache();
|
314 |
+
}
|
315 |
+
|
316 |
+
if ( class_exists( 'autoptimizeCache' ) ) {
|
317 |
+
autoptimizeCache::clearall();
|
318 |
+
}
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Get absolute path to the Jupiter' compiler directory.
|
323 |
+
*
|
324 |
+
* @since 1.0.0
|
325 |
+
*
|
326 |
+
* @param bool $is_admin Optional. When true, gets the admin compiler directory. Default is false.
|
327 |
+
*
|
328 |
+
* @return string
|
329 |
+
*/
|
330 |
+
function jupiterx_get_compiler_dir( $is_admin = false ) {
|
331 |
+
$wp_upload_dir = wp_upload_dir();
|
332 |
+
$suffix = $is_admin ? 'jupiterx/admin-compiler/' : 'jupiterx/compiler/';
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Deprecated. Filter the Jupiter compiler directory.
|
336 |
+
*
|
337 |
+
* This filter is deprecated for security and compatibility purposes.
|
338 |
+
*
|
339 |
+
* @since 1.0.0
|
340 |
+
* @deprecated 1.3.0
|
341 |
+
*/
|
342 |
+
apply_filters( 'jupiterx_compiler_dir', false, $is_admin );
|
343 |
+
|
344 |
+
return wp_normalize_path( trailingslashit( $wp_upload_dir['basedir'] ) . $suffix );
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Get absolute URL to the Jupiter' compiler directory.
|
349 |
+
*
|
350 |
+
* @since 1.0.0
|
351 |
+
*
|
352 |
+
* @param bool $is_admin Optional. When true, gets the admin compiler directory. Default is false.
|
353 |
+
*
|
354 |
+
* @return string
|
355 |
+
*/
|
356 |
+
function jupiterx_get_compiler_url( $is_admin = false ) {
|
357 |
+
$wp_upload_dir = wp_upload_dir();
|
358 |
+
$suffix = $is_admin ? 'jupiterx/admin-compiler/' : 'jupiterx/compiler/';
|
359 |
+
|
360 |
+
return trailingslashit( $wp_upload_dir['baseurl'] ) . $suffix;
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* Check if development mode is enabled.
|
365 |
+
*
|
366 |
+
* Takes legacy constant into consideration.
|
367 |
+
*
|
368 |
+
* @since 1.0.0
|
369 |
+
* @ignore
|
370 |
+
* @access private
|
371 |
+
*
|
372 |
+
* @return bool
|
373 |
+
*/
|
374 |
+
function _jupiterx_is_compiler_dev_mode() {
|
375 |
+
|
376 |
+
if ( defined( 'JUPITERX_COMPILER_DEV_MODE' ) ) {
|
377 |
+
return JUPITERX_COMPILER_DEV_MODE;
|
378 |
+
}
|
379 |
+
|
380 |
+
return jupiterx_get_option( 'dev_mode', false );
|
381 |
+
}
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Get cache busting method.
|
385 |
+
*
|
386 |
+
* @since 1.0.0
|
387 |
+
* @access private
|
388 |
+
*
|
389 |
+
* @return bool
|
390 |
+
*/
|
391 |
+
function _jupiterx_get_cache_busting() {
|
392 |
+
return jupiterx_get_option( 'cache_busting', true );
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Initialize added fragments global.
|
397 |
+
*
|
398 |
+
* @since 1.0.0
|
399 |
+
* @ignore
|
400 |
+
* @access private
|
401 |
+
*/
|
402 |
+
global $_jupiterx_compiler_added_fragments;
|
403 |
+
|
404 |
+
if ( ! isset( $_jupiterx_compiler_added_fragments ) ) {
|
405 |
+
$_jupiterx_compiler_added_fragments = array(
|
406 |
+
'css' => array(),
|
407 |
+
'less' => array(),
|
408 |
+
'scss' => array(),
|
409 |
+
'js' => array(),
|
410 |
+
);
|
411 |
+
}
|
includes/compiler/preprocess-aliases.ini
CHANGED
@@ -1,277 +1,277 @@
|
|
1 |
-
;----------------------------------------------------------------
|
2 |
-
;
|
3 |
-
; Add or delete aliases to suit your needs.
|
4 |
-
; Modified for Jupiter X.
|
5 |
-
;
|
6 |
-
; Sources:
|
7 |
-
; http://developer.mozilla.org/en-US/docs/CSS/CSS_Reference
|
8 |
-
; http://caniuse.com/#cats=CSS
|
9 |
-
;
|
10 |
-
;----------------------------------------------------------------
|
11 |
-
|
12 |
-
; Property aliases.
|
13 |
-
|
14 |
-
[properties]
|
15 |
-
|
16 |
-
; Animations.
|
17 |
-
animation[] = -webkit-animation
|
18 |
-
animation-delay[] = -webkit-animation-delay
|
19 |
-
animation-direction[] = -webkit-animation-direction
|
20 |
-
animation-duration[] = -webkit-animation-duration
|
21 |
-
animation-fill-mode[] = -webkit-animation-fill-mode
|
22 |
-
animation-iteration-count[] = -webkit-animation-iteration-count
|
23 |
-
animation-name[] = -webkit-animation-name
|
24 |
-
animation-play-state[] = -webkit-animation-play-state
|
25 |
-
animation-timing-function[] = -webkit-animation-timing-function
|
26 |
-
|
27 |
-
; Backface visibility.
|
28 |
-
backface-visibility[] = -webkit-backface-visibility
|
29 |
-
|
30 |
-
; Border-image.
|
31 |
-
border-image[] = -webkit-border-image
|
32 |
-
|
33 |
-
; Box decoration.
|
34 |
-
box-decoration-break[] = -webkit-box-decoration-break
|
35 |
-
|
36 |
-
; Box shadow.
|
37 |
-
; box-shadow[] = -webkit-box-shadow
|
38 |
-
|
39 |
-
; Box sizing.
|
40 |
-
; box-sizing[] = -webkit-box-sizing
|
41 |
-
; box-sizing[] = -moz-box-sizing
|
42 |
-
|
43 |
-
; Columns.
|
44 |
-
columns[] = -webkit-columns
|
45 |
-
columns[] = -moz-columns
|
46 |
-
column-count[] = -webkit-column-count
|
47 |
-
column-count[] = -moz-column-count
|
48 |
-
column-fill[] = -webkit-column-fill
|
49 |
-
column-fill[] = -moz-column-fill
|
50 |
-
column-gap[] = -webkit-column-gap
|
51 |
-
column-gap[] = -moz-column-gap
|
52 |
-
column-rule[] = -webkit-column-rule
|
53 |
-
column-rule[] = -moz-column-rule
|
54 |
-
column-rule-style[] = -webkit-column-rule-style
|
55 |
-
column-rule-style[] = -moz-column-rule-style
|
56 |
-
column-rule-width[] = -webkit-column-rule-width
|
57 |
-
column-rule-width[] = -moz-column-rule-width
|
58 |
-
column-rule-style[] = -webkit-column-rule-style
|
59 |
-
column-rule-style[] = -moz-column-rule-style
|
60 |
-
column-rule-color[] = -webkit-column-rule-color
|
61 |
-
column-rule-color[] = -moz-column-rule-color
|
62 |
-
column-span[] = -webkit-column-span
|
63 |
-
column-span[] = -moz-column-span
|
64 |
-
column-width[] = -webkit-column-width
|
65 |
-
column-width[] = -moz-column-width
|
66 |
-
|
67 |
-
; Filter.
|
68 |
-
filter[] = -webkit-filter
|
69 |
-
|
70 |
-
; Flexbox (2012).
|
71 |
-
;
|
72 |
-
; Merges two similar versions of the flexbox spec:
|
73 |
-
; - September 2012 (for non IE): http://www.w3.org/TR/2012/CR-css3-flexbox-20120918
|
74 |
-
; - March 2012 (for IE10): http://www.w3.org/TR/2012/WD-css3-flexbox-20120322
|
75 |
-
;
|
76 |
-
; The early 2012 spec mostly differs only in syntax to the later one, with the notable
|
77 |
-
; exception of not supporting seperate properties for <flex-grow>, <flex-shrink>
|
78 |
-
; and <flex-basis>. These properties are available in both 2012 implementations via
|
79 |
-
; <flex> shorthand.
|
80 |
-
;
|
81 |
-
; Support for the early 2012 syntax implemented in IE10 is achieved here in part with
|
82 |
-
; property aliases, and in part with declaration aliases later in this file.
|
83 |
-
;
|
84 |
-
; align-content[] = -webkit-align-content
|
85 |
-
; align-items[] = -webkit-align-items
|
86 |
-
; align-self[] = -webkit-align-self
|
87 |
-
; flex[] = -webkit-flex
|
88 |
-
flex[] = -ms-flexbox
|
89 |
-
; flex-basis[] = -webkit-flex-basis
|
90 |
-
; flex-direction[] = -webkit-flex-direction
|
91 |
-
flex-direction[] = -ms-flex-direction
|
92 |
-
; flex-flow[] = -webkit-flex-flow
|
93 |
-
flex-flow[] = -ms-flex-flow
|
94 |
-
; flex-grow[] = -webkit-flex-grow
|
95 |
-
; flex-shrink[] = -webkit-flex-shrink
|
96 |
-
; flex-wrap[] = -webkit-flex-wrap
|
97 |
-
; flex-wrap[] = -ms-flex-wrap
|
98 |
-
; justify-content[] = -webkit-justify-content
|
99 |
-
; order[] = -webkit-order
|
100 |
-
order[] = -ms-flex-order
|
101 |
-
|
102 |
-
; Hyphens.
|
103 |
-
hyphens[] = -webkit-hyphens
|
104 |
-
hyphens[] = -moz-hyphens
|
105 |
-
hyphens[] = -ms-hyphens
|
106 |
-
|
107 |
-
; Outline radius.
|
108 |
-
outline-radius[] = -moz-outline-radius
|
109 |
-
outline-top-left-radius[] = -moz-outline-radius-topleft
|
110 |
-
outline-top-right-radius[] = -moz-outline-radius-topright
|
111 |
-
outline-bottom-left-radius[] = -moz-outline-radius-bottomleft
|
112 |
-
outline-bottom-right-radius[] = -moz-outline-radius-bottomright
|
113 |
-
|
114 |
-
; Perspective.
|
115 |
-
perspective[] = -webkit-perspective
|
116 |
-
perspective-origin[] = -webkit-perspective-origin
|
117 |
-
|
118 |
-
; Shapes
|
119 |
-
shape-image-threshold[] = -webkit-shape-image-threshold
|
120 |
-
shape-outside[] = -webkit-shape-outside
|
121 |
-
shape-margin[] = -webkit-shape-margin
|
122 |
-
|
123 |
-
; Tab size.
|
124 |
-
tab-size[] = -moz-tab-size
|
125 |
-
tab-size[] = -o-tab-size
|
126 |
-
|
127 |
-
; Text align last.
|
128 |
-
text-align-last[] = -webkit-text-align-last
|
129 |
-
text-align-last[] = -moz-text-align-last
|
130 |
-
|
131 |
-
; Text decoration.
|
132 |
-
text-decoration-color[] = -moz-text-decoration-color
|
133 |
-
text-decoration-line[] = -moz-text-decoration-line
|
134 |
-
text-decoration-style[] = -moz-text-decoration-style
|
135 |
-
|
136 |
-
; Text overflow (Opera mini support).
|
137 |
-
text-overflow[] = -o-text-overflow
|
138 |
-
|
139 |
-
; Transforms.
|
140 |
-
transform[] = -webkit-transform
|
141 |
-
; transform[] = -ms-transform
|
142 |
-
transform-origin[] = -webkit-transform-origin
|
143 |
-
; transform-origin[] = -ms-transform-origin
|
144 |
-
transform-style[] = -webkit-transform-style
|
145 |
-
; transform-style[] = -ms-transform-style
|
146 |
-
|
147 |
-
; Transitions.
|
148 |
-
; transition[] = -webkit-transition
|
149 |
-
; transition-delay[] = -webkit-transition-delay
|
150 |
-
; transition-duration[] = -webkit-transition-duration
|
151 |
-
; transition-property[] = -webkit-transition-property
|
152 |
-
; transition-timing-function[] = -webkit-transition-timing-function
|
153 |
-
|
154 |
-
; User select (non standard).
|
155 |
-
user-select[] = -webkit-user-select
|
156 |
-
user-select[] = -moz-user-select
|
157 |
-
user-select[] = -ms-user-select
|
158 |
-
|
159 |
-
|
160 |
-
;----------------------------------------------------------------
|
161 |
-
; Declaration aliases.
|
162 |
-
|
163 |
-
[declarations]
|
164 |
-
|
165 |
-
; Flexbox (2012).
|
166 |
-
display:flex[] = display:-ms-flexbox
|
167 |
-
; display:flex[] = display:-webkit-flex
|
168 |
-
display:inline-flex[] = display:-ms-inline-flexbox
|
169 |
-
; display:inline-flex[] = display:-webkit-inline-flex
|
170 |
-
|
171 |
-
; Flexbox (early 2012).
|
172 |
-
align-content:flex-start[] = -ms-flex-line-pack:start
|
173 |
-
align-content:flex-end[] = -ms-flex-line-pack:end
|
174 |
-
align-content:center[] = -ms-flex-line-pack:center
|
175 |
-
align-content:space-between[] = -ms-flex-line-pack:justify
|
176 |
-
align-content:space-around[] = -ms-flex-line-pack:distribute
|
177 |
-
align-content:stretch[] = -ms-flex-line-pack:stretch
|
178 |
-
|
179 |
-
align-items:flex-start[] = -ms-flex-align:start
|
180 |
-
align-items:flex-end[] = -ms-flex-align:end
|
181 |
-
align-items:center[] = -ms-flex-align:center
|
182 |
-
align-items:baseline[] = -ms-flex-align:baseline
|
183 |
-
align-items:stretch[] = -ms-flex-align:stretch
|
184 |
-
|
185 |
-
align-self:auto[] = -ms-flex-item-align:auto
|
186 |
-
align-self:flex-start[] = -ms-flex-item-align:start
|
187 |
-
align-self:flex-end[] = -ms-flex-item-align:end
|
188 |
-
align-self:center[] = -ms-flex-item-align:center
|
189 |
-
align-self:baseline[] = -ms-flex-item-align:baseline
|
190 |
-
align-self:stretch[] = -ms-flex-item-align:stretch
|
191 |
-
|
192 |
-
justify-content:flex-start[] = -ms-flex-pack:start
|
193 |
-
justify-content:flex-end[] = -ms-flex-pack:end
|
194 |
-
justify-content:center[] = -ms-flex-pack:center
|
195 |
-
justify-content:space-between[] = -ms-flex-pack:justify
|
196 |
-
justify-content:space-around[] = -ms-flex-pack:distribute
|
197 |
-
|
198 |
-
; Cursor values (non-standard).
|
199 |
-
cursor:zoom-in[] = cursor:-webkit-zoom-in
|
200 |
-
cursor:zoom-in[] = cursor:-moz-zoom-in
|
201 |
-
cursor:zoom-out[] = cursor:-webkit-zoom-out
|
202 |
-
cursor:zoom-out[] = cursor:-moz-zoom-out
|
203 |
-
cursor:grab[] = cursor:-webkit-grab
|
204 |
-
cursor:grab[] = cursor:-moz-grab
|
205 |
-
cursor:grabbing[] = cursor:-webkit-grabbing
|
206 |
-
cursor:grabbing[] = cursor:-moz-grabbing
|
207 |
-
|
208 |
-
; Experimental width values.
|
209 |
-
width:max-content[] = width:intrinsic
|
210 |
-
width:max-content[] = width:-webkit-max-content
|
211 |
-
width:max-content[] = width:-moz-max-content
|
212 |
-
width:min-content[] = width:-webkit-min-content
|
213 |
-
width:min-content[] = width:-moz-min-content
|
214 |
-
width:available[] = width:-webkit-available
|
215 |
-
width:available[] = width:-moz-available
|
216 |
-
width:fit-content[] = width:-webkit-fit-content
|
217 |
-
width:fit-content[] = width:-moz-fit-content
|
218 |
-
|
219 |
-
max-width:max-content[] = max-width:intrinsic
|
220 |
-
max-width:max-content[] = max-width:-webkit-max-content
|
221 |
-
max-width:max-content[] = max-width:-moz-max-content
|
222 |
-
max-width:min-content[] = max-width:-webkit-min-content
|
223 |
-
max-width:min-content[] = max-width:-moz-min-content
|
224 |
-
max-width:available[] = max-width:-webkit-available
|
225 |
-
max-width:available[] = max-width:-moz-available
|
226 |
-
max-width:fit-content[] = max-width:-webkit-fit-content
|
227 |
-
max-width:fit-content[] = max-width:-moz-fit-content
|
228 |
-
|
229 |
-
min-width:max-content[] = min-width:intrinsic
|
230 |
-
min-width:max-content[] = min-width:-webkit-max-content
|
231 |
-
min-width:max-content[] = min-width:-moz-max-content
|
232 |
-
min-width:min-content[] = min-width:-webkit-min-content
|
233 |
-
min-width:min-content[] = min-width:-moz-min-content
|
234 |
-
min-width:available[] = min-width:-webkit-available
|
235 |
-
min-width:available[] = min-width:-moz-available
|
236 |
-
min-width:fit-content[] = min-width:-webkit-fit-content
|
237 |
-
min-width:fit-content[] = min-width:-moz-fit-content
|
238 |
-
|
239 |
-
; Appearance (non-standard).
|
240 |
-
appearance:none[] = -webkit-appearance:none
|
241 |
-
appearance:none[] = -moz-appearance:none
|
242 |
-
|
243 |
-
position:sticky[] = position:-webkit-sticky
|
244 |
-
|
245 |
-
|
246 |
-
;----------------------------------------------------------------
|
247 |
-
; Function aliases.
|
248 |
-
|
249 |
-
[functions]
|
250 |
-
|
251 |
-
; Calc.
|
252 |
-
; calc[] = -webkit-calc÷
|
253 |
-
|
254 |
-
|
255 |
-
[functions.gradients]
|
256 |
-
|
257 |
-
; Gradients.
|
258 |
-
; linear-gradient[] = -webkit-linear-gradient
|
259 |
-
; radial-gradient[] = -webkit-radial-gradient
|
260 |
-
|
261 |
-
; Repeating gradients.
|
262 |
-
; repeating-linear-gradient[] = -webkit-repeating-linear-gradient
|
263 |
-
; repeating-radial-gradient[] = -webkit-repeating-radial-gradient
|
264 |
-
|
265 |
-
|
266 |
-
;----------------------------------------------------------------
|
267 |
-
; @rule aliases.
|
268 |
-
|
269 |
-
[at-rules]
|
270 |
-
|
271 |
-
; Keyframes.
|
272 |
-
keyframes[] = -webkit-keyframes
|
273 |
-
|
274 |
-
; Viewport.
|
275 |
-
viewport[] = -webkit-viewport
|
276 |
-
viewport[] = -ms-viewport
|
277 |
-
viewport[] = -o-viewport
|
1 |
+
;----------------------------------------------------------------
|
2 |
+
;
|
3 |
+
; Add or delete aliases to suit your needs.
|
4 |
+
; Modified for Jupiter X.
|
5 |
+
;
|
6 |
+
; Sources:
|
7 |
+
; http://developer.mozilla.org/en-US/docs/CSS/CSS_Reference
|
8 |
+
; http://caniuse.com/#cats=CSS
|
9 |
+
;
|
10 |
+
;----------------------------------------------------------------
|
11 |
+
|
12 |
+
; Property aliases.
|
13 |
+
|
14 |
+
[properties]
|
15 |
+
|
16 |
+
; Animations.
|
17 |
+
animation[] = -webkit-animation
|
18 |
+
animation-delay[] = -webkit-animation-delay
|
19 |
+
animation-direction[] = -webkit-animation-direction
|
20 |
+
animation-duration[] = -webkit-animation-duration
|
21 |
+
animation-fill-mode[] = -webkit-animation-fill-mode
|
22 |
+
animation-iteration-count[] = -webkit-animation-iteration-count
|
23 |
+
animation-name[] = -webkit-animation-name
|
24 |
+
animation-play-state[] = -webkit-animation-play-state
|
25 |
+
animation-timing-function[] = -webkit-animation-timing-function
|
26 |
+
|
27 |
+
; Backface visibility.
|
28 |
+
backface-visibility[] = -webkit-backface-visibility
|
29 |
+
|
30 |
+
; Border-image.
|
31 |
+
border-image[] = -webkit-border-image
|
32 |
+
|
33 |
+
; Box decoration.
|
34 |
+
box-decoration-break[] = -webkit-box-decoration-break
|
35 |
+
|
36 |
+
; Box shadow.
|
37 |
+
; box-shadow[] = -webkit-box-shadow
|
38 |
+
|
39 |
+
; Box sizing.
|
40 |
+
; box-sizing[] = -webkit-box-sizing
|
41 |
+
; box-sizing[] = -moz-box-sizing
|
42 |
+
|
43 |
+
; Columns.
|
44 |
+
columns[] = -webkit-columns
|
45 |
+
columns[] = -moz-columns
|
46 |
+
column-count[] = -webkit-column-count
|
47 |
+
column-count[] = -moz-column-count
|
48 |
+
column-fill[] = -webkit-column-fill
|
49 |
+
column-fill[] = -moz-column-fill
|
50 |
+
column-gap[] = -webkit-column-gap
|
51 |
+
column-gap[] = -moz-column-gap
|
52 |
+
column-rule[] = -webkit-column-rule
|
53 |
+
column-rule[] = -moz-column-rule
|
54 |
+
column-rule-style[] = -webkit-column-rule-style
|
55 |
+
column-rule-style[] = -moz-column-rule-style
|
56 |
+
column-rule-width[] = -webkit-column-rule-width
|
57 |
+
column-rule-width[] = -moz-column-rule-width
|
58 |
+
column-rule-style[] = -webkit-column-rule-style
|
59 |
+
column-rule-style[] = -moz-column-rule-style
|
60 |
+
column-rule-color[] = -webkit-column-rule-color
|
61 |
+
column-rule-color[] = -moz-column-rule-color
|
62 |
+
column-span[] = -webkit-column-span
|
63 |
+
column-span[] = -moz-column-span
|
64 |
+
column-width[] = -webkit-column-width
|
65 |
+
column-width[] = -moz-column-width
|
66 |
+
|
67 |
+
; Filter.
|
68 |
+
filter[] = -webkit-filter
|
69 |
+
|
70 |
+
; Flexbox (2012).
|
71 |
+
;
|
72 |
+
; Merges two similar versions of the flexbox spec:
|
73 |
+
; - September 2012 (for non IE): http://www.w3.org/TR/2012/CR-css3-flexbox-20120918
|
74 |
+
; - March 2012 (for IE10): http://www.w3.org/TR/2012/WD-css3-flexbox-20120322
|
75 |
+
;
|
76 |
+
; The early 2012 spec mostly differs only in syntax to the later one, with the notable
|
77 |
+
; exception of not supporting seperate properties for <flex-grow>, <flex-shrink>
|
78 |
+
; and <flex-basis>. These properties are available in both 2012 implementations via
|
79 |
+
; <flex> shorthand.
|
80 |
+
;
|
81 |
+
; Support for the early 2012 syntax implemented in IE10 is achieved here in part with
|
82 |
+
; property aliases, and in part with declaration aliases later in this file.
|
83 |
+
;
|
84 |
+
; align-content[] = -webkit-align-content
|
85 |
+
; align-items[] = -webkit-align-items
|
86 |
+
; align-self[] = -webkit-align-self
|
87 |
+
; flex[] = -webkit-flex
|
88 |
+
flex[] = -ms-flexbox
|
89 |
+
; flex-basis[] = -webkit-flex-basis
|
90 |
+
; flex-direction[] = -webkit-flex-direction
|
91 |
+
flex-direction[] = -ms-flex-direction
|
92 |
+
; flex-flow[] = -webkit-flex-flow
|
93 |
+
flex-flow[] = -ms-flex-flow
|
94 |
+
; flex-grow[] = -webkit-flex-grow
|
95 |
+
; flex-shrink[] = -webkit-flex-shrink
|
96 |
+
; flex-wrap[] = -webkit-flex-wrap
|
97 |
+
; flex-wrap[] = -ms-flex-wrap
|
98 |
+
; justify-content[] = -webkit-justify-content
|
99 |
+
; order[] = -webkit-order
|
100 |
+
order[] = -ms-flex-order
|
101 |
+
|
102 |
+
; Hyphens.
|
103 |
+
hyphens[] = -webkit-hyphens
|
104 |
+
hyphens[] = -moz-hyphens
|
105 |
+
hyphens[] = -ms-hyphens
|
106 |
+
|
107 |
+
; Outline radius.
|
108 |
+
outline-radius[] = -moz-outline-radius
|
109 |
+
outline-top-left-radius[] = -moz-outline-radius-topleft
|
110 |
+
outline-top-right-radius[] = -moz-outline-radius-topright
|
111 |
+
outline-bottom-left-radius[] = -moz-outline-radius-bottomleft
|
112 |
+
outline-bottom-right-radius[] = -moz-outline-radius-bottomright
|
113 |
+
|
114 |
+
; Perspective.
|
115 |
+
perspective[] = -webkit-perspective
|
116 |
+
perspective-origin[] = -webkit-perspective-origin
|
117 |
+
|
118 |
+
; Shapes
|
119 |
+
shape-image-threshold[] = -webkit-shape-image-threshold
|
120 |
+
shape-outside[] = -webkit-shape-outside
|
121 |
+
shape-margin[] = -webkit-shape-margin
|
122 |
+
|
123 |
+
; Tab size.
|
124 |
+
tab-size[] = -moz-tab-size
|
125 |
+
tab-size[] = -o-tab-size
|
126 |
+
|
127 |
+
; Text align last.
|
128 |
+
text-align-last[] = -webkit-text-align-last
|
129 |
+
text-align-last[] = -moz-text-align-last
|
130 |
+
|
131 |
+
; Text decoration.
|
132 |
+
text-decoration-color[] = -moz-text-decoration-color
|
133 |
+
text-decoration-line[] = -moz-text-decoration-line
|
134 |
+
text-decoration-style[] = -moz-text-decoration-style
|
135 |
+
|
136 |
+
; Text overflow (Opera mini support).
|
137 |
+
text-overflow[] = -o-text-overflow
|
138 |
+
|
139 |
+
; Transforms.
|
140 |
+
transform[] = -webkit-transform
|
141 |
+
; transform[] = -ms-transform
|
142 |
+
transform-origin[] = -webkit-transform-origin
|
143 |
+
; transform-origin[] = -ms-transform-origin
|
144 |
+
transform-style[] = -webkit-transform-style
|
145 |
+
; transform-style[] = -ms-transform-style
|
146 |
+
|
147 |
+
; Transitions.
|
148 |
+
; transition[] = -webkit-transition
|
149 |
+
; transition-delay[] = -webkit-transition-delay
|
150 |
+
; transition-duration[] = -webkit-transition-duration
|
151 |
+
; transition-property[] = -webkit-transition-property
|
152 |
+
; transition-timing-function[] = -webkit-transition-timing-function
|
153 |
+
|
154 |
+
; User select (non standard).
|
155 |
+
user-select[] = -webkit-user-select
|
156 |
+
user-select[] = -moz-user-select
|
157 |
+
user-select[] = -ms-user-select
|
158 |
+
|
159 |
+
|
160 |
+
;----------------------------------------------------------------
|
161 |
+
; Declaration aliases.
|
162 |
+
|
163 |
+
[declarations]
|
164 |
+
|
165 |
+
; Flexbox (2012).
|
166 |
+
display:flex[] = display:-ms-flexbox
|
167 |
+
; display:flex[] = display:-webkit-flex
|
168 |
+
display:inline-flex[] = display:-ms-inline-flexbox
|
169 |
+
; display:inline-flex[] = display:-webkit-inline-flex
|
170 |
+
|
171 |
+
; Flexbox (early 2012).
|
172 |
+
align-content:flex-start[] = -ms-flex-line-pack:start
|
173 |
+
align-content:flex-end[] = -ms-flex-line-pack:end
|
174 |
+
align-content:center[] = -ms-flex-line-pack:center
|
175 |
+
align-content:space-between[] = -ms-flex-line-pack:justify
|
176 |
+
align-content:space-around[] = -ms-flex-line-pack:distribute
|
177 |
+
align-content:stretch[] = -ms-flex-line-pack:stretch
|
178 |
+
|
179 |
+
align-items:flex-start[] = -ms-flex-align:start
|
180 |
+
align-items:flex-end[] = -ms-flex-align:end
|
181 |
+
align-items:center[] = -ms-flex-align:center
|
182 |
+
align-items:baseline[] = -ms-flex-align:baseline
|
183 |
+
align-items:stretch[] = -ms-flex-align:stretch
|
184 |
+
|
185 |
+
align-self:auto[] = -ms-flex-item-align:auto
|
186 |
+
align-self:flex-start[] = -ms-flex-item-align:start
|
187 |
+
align-self:flex-end[] = -ms-flex-item-align:end
|
188 |
+
align-self:center[] = -ms-flex-item-align:center
|
189 |
+
align-self:baseline[] = -ms-flex-item-align:baseline
|
190 |
+
align-self:stretch[] = -ms-flex-item-align:stretch
|
191 |
+
|
192 |
+
justify-content:flex-start[] = -ms-flex-pack:start
|
193 |
+
justify-content:flex-end[] = -ms-flex-pack:end
|
194 |
+
justify-content:center[] = -ms-flex-pack:center
|
195 |
+
justify-content:space-between[] = -ms-flex-pack:justify
|
196 |
+
justify-content:space-around[] = -ms-flex-pack:distribute
|
197 |
+
|
198 |
+
; Cursor values (non-standard).
|
199 |
+
cursor:zoom-in[] = cursor:-webkit-zoom-in
|
200 |
+
cursor:zoom-in[] = cursor:-moz-zoom-in
|
201 |
+
cursor:zoom-out[] = cursor:-webkit-zoom-out
|
202 |
+
cursor:zoom-out[] = cursor:-moz-zoom-out
|
203 |
+
cursor:grab[] = cursor:-webkit-grab
|
204 |
+
cursor:grab[] = cursor:-moz-grab
|
205 |
+
cursor:grabbing[] = cursor:-webkit-grabbing
|
206 |
+
cursor:grabbing[] = cursor:-moz-grabbing
|
207 |
+
|
208 |
+
; Experimental width values.
|
209 |
+
width:max-content[] = width:intrinsic
|
210 |
+
width:max-content[] = width:-webkit-max-content
|
211 |
+
width:max-content[] = width:-moz-max-content
|
212 |
+
width:min-content[] = width:-webkit-min-content
|
213 |
+
width:min-content[] = width:-moz-min-content
|
214 |
+
width:available[] = width:-webkit-available
|
215 |
+
width:available[] = width:-moz-available
|
216 |
+
width:fit-content[] = width:-webkit-fit-content
|
217 |
+
width:fit-content[] = width:-moz-fit-content
|
218 |
+
|
219 |
+
max-width:max-content[] = max-width:intrinsic
|
220 |
+
max-width:max-content[] = max-width:-webkit-max-content
|
221 |
+
max-width:max-content[] = max-width:-moz-max-content
|
222 |
+
max-width:min-content[] = max-width:-webkit-min-content
|
223 |
+
max-width:min-content[] = max-width:-moz-min-content
|
224 |
+
max-width:available[] = max-width:-webkit-available
|
225 |
+
max-width:available[] = max-width:-moz-available
|
226 |
+
max-width:fit-content[] = max-width:-webkit-fit-content
|
227 |
+
max-width:fit-content[] = max-width:-moz-fit-content
|
228 |
+
|
229 |
+
min-width:max-content[] = min-width:intrinsic
|
230 |
+
min-width:max-content[] = min-width:-webkit-max-content
|
231 |
+
min-width:max-content[] = min-width:-moz-max-content
|
232 |
+
min-width:min-content[] = min-width:-webkit-min-content
|
233 |
+
min-width:min-content[] = min-width:-moz-min-content
|
234 |
+
min-width:available[] = min-width:-webkit-available
|
235 |
+
min-width:available[] = min-width:-moz-available
|
236 |
+
min-width:fit-content[] = min-width:-webkit-fit-content
|
237 |
+
min-width:fit-content[] = min-width:-moz-fit-content
|
238 |
+
|
239 |
+
; Appearance (non-standard).
|
240 |
+
appearance:none[] = -webkit-appearance:none
|
241 |
+
appearance:none[] = -moz-appearance:none
|
242 |
+
|
243 |
+
position:sticky[] = position:-webkit-sticky
|
244 |
+
|
245 |
+
|
246 |
+
;----------------------------------------------------------------
|
247 |
+
; Function aliases.
|
248 |
+
|
249 |
+
[functions]
|
250 |
+
|
251 |
+
; Calc.
|
252 |
+
; calc[] = -webkit-calc÷
|
253 |
+
|
254 |
+
|
255 |
+
[functions.gradients]
|
256 |
+
|
257 |
+
; Gradients.
|
258 |
+
; linear-gradient[] = -webkit-linear-gradient
|
259 |
+
; radial-gradient[] = -webkit-radial-gradient
|
260 |
+
|
261 |
+
; Repeating gradients.
|
262 |
+
; repeating-linear-gradient[] = -webkit-repeating-linear-gradient
|
263 |
+
; repeating-radial-gradient[] = -webkit-repeating-radial-gradient
|
264 |
+
|
265 |
+
|
266 |
+
;----------------------------------------------------------------
|
267 |
+
; @rule aliases.
|
268 |
+
|
269 |
+
[at-rules]
|
270 |
+
|
271 |
+
; Keyframes.
|
272 |
+
keyframes[] = -webkit-keyframes
|
273 |
+
|
274 |
+
; Viewport.
|
275 |
+
viewport[] = -webkit-viewport
|
276 |
+
viewport[] = -ms-viewport
|
277 |
+
viewport[] = -o-viewport
|
includes/compiler/vendors/js-minifier.php
CHANGED
@@ -1,396 +1,396 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* JavaScript compressor, minifies JavaScript.
|
4 |
-
* Based on JSMin (https://github.com/mrclay/minify, Ryan Grove <ryan@wonko.com>, Stephen Clay <steve@mrclay.org>, BSD License)
|
5 |
-
*
|
6 |
-
* @ignore
|
7 |
-
*/
|
8 |
-
class JSMin {
|
9 |
-
|
10 |
-
const ORD_LF = 10;
|
11 |
-
const ORD_SPACE = 32;
|
12 |
-
const ACTION_KEEP_A = 1;
|
13 |
-
const ACTION_DELETE_A = 2;
|
14 |
-
const ACTION_DELETE_A_B = 3;
|
15 |
-
|
16 |
-
protected $a = "\n";
|
17 |
-
protected $b = '';
|
18 |
-
protected $input = '';
|
19 |
-
protected $inputIndex = 0;
|
20 |
-
protected $inputLength = 0;
|
21 |
-
protected $lookAhead = null;
|
22 |
-
protected $output = '';
|
23 |
-
protected $lastByteOut = '';
|
24 |
-
protected $keptComment = '';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* @param string $input
|
28 |
-
*/
|
29 |
-
public function __construct($input)
|
30 |
-
{
|
31 |
-
$this->input = $input;
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Perform minification, return result
|
36 |
-
*
|
37 |
-
* @return string
|
38 |
-
*/
|
39 |
-
public function min()
|
40 |
-
{
|
41 |
-
if ($this->output !== '') { // min already run
|
42 |
-
return $this->output;
|
43 |
-
}
|
44 |
-
|
45 |
-
$mbIntEnc = null;
|
46 |
-
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
47 |
-
$mbIntEnc = mb_internal_encoding();
|
48 |
-
mb_internal_encoding('8bit');
|
49 |
-
}
|
50 |
-
$this->input = str_replace("\r\n", "\n", $this->input);
|
51 |
-
$this->inputLength = strlen($this->input);
|
52 |
-
|
53 |
-
$this->action(self::ACTION_DELETE_A_B);
|
54 |
-
|
55 |
-
while ($this->a !== null) {
|
56 |
-
// determine next command
|
57 |
-
$command = self::ACTION_KEEP_A; // default
|
58 |
-
if ($this->a === ' ') {
|
59 |
-
if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
|
60 |
-
&& ($this->b === $this->lastByteOut)) {
|
61 |
-
// Don't delete this space. If we do, the addition/subtraction
|
62 |
-
// could be parsed as a post-increment
|
63 |
-
} elseif (! $this->isAlphaNum($this->b)) {
|
64 |
-
$command = self::ACTION_DELETE_A;
|
65 |
-
}
|
66 |
-
} elseif ($this->a === "\n") {
|
67 |
-
if ($this->b === ' ') {
|
68 |
-
$command = self::ACTION_DELETE_A_B;
|
69 |
-
|
70 |
-
// in case of mbstring.func_overload & 2, must check for null b,
|
71 |
-
// otherwise mb_strpos will give WARNING
|
72 |
-
} elseif ($this->b === null
|
73 |
-
|| (false === strpos('{[(+-!~', $this->b)
|
74 |
-
&& ! $this->isAlphaNum($this->b))) {
|
75 |
-
$command = self::ACTION_DELETE_A;
|
76 |
-
}
|
77 |
-
} elseif (! $this->isAlphaNum($this->a)) {
|
78 |
-
if ($this->b === ' '
|
79 |
-
|| ($this->b === "\n"
|
80 |
-
&& (false === strpos('}])+-"\'', $this->a)))) {
|
81 |
-
$command = self::ACTION_DELETE_A_B;
|
82 |
-
}
|
83 |
-
}
|
84 |
-
$this->action($command);
|
85 |
-
}
|
86 |
-
$this->output = trim($this->output);
|
87 |
-
|
88 |
-
if ($mbIntEnc !== null) {
|
89 |
-
mb_internal_encoding($mbIntEnc);
|
90 |
-
}
|
91 |
-
return $this->output;
|
92 |
-
}
|
93 |
-
|
94 |
-
/**
|
95 |
-
* ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
|
96 |
-
* ACTION_DELETE_A = Copy B to A. Get the next B.
|
97 |
-
* ACTION_DELETE_A_B = Get the next B.
|
98 |
-
*
|
99 |
-
* @param int $command
|
100 |
-
* @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException
|
101 |
-
*/
|
102 |
-
protected function action($command)
|
103 |
-
{
|
104 |
-
// make sure we don't compress "a + ++b" to "a+++b", etc.
|
105 |
-
if ($command === self::ACTION_DELETE_A_B
|
106 |
-
&& $this->b === ' '
|
107 |
-
&& ($this->a === '+' || $this->a === '-')) {
|
108 |
-
// Note: we're at an addition/substraction operator; the inputIndex
|
109 |
-
// will certainly be a valid index
|
110 |
-
if ($this->input[$this->inputIndex] === $this->a) {
|
111 |
-
// This is "+ +" or "- -". Don't delete the space.
|
112 |
-
$command = self::ACTION_KEEP_A;
|
113 |
-
}
|
114 |
-
}
|
115 |
-
|
116 |
-
switch ($command) {
|
117 |
-
case self::ACTION_KEEP_A: // 1
|
118 |
-
$this->output .= $this->a;
|
119 |
-
|
120 |
-
if ($this->keptComment) {
|
121 |
-
$this->output = rtrim($this->output, "\n");
|
122 |
-
$this->output .= $this->keptComment;
|
123 |
-
$this->keptComment = '';
|
124 |
-
}
|
125 |
-
|
126 |
-
$this->lastByteOut = $this->a;
|
127 |
-
|
128 |
-
// fallthrough intentional
|
129 |
-
case self::ACTION_DELETE_A: // 2
|
130 |
-
$this->a = $this->b;
|
131 |
-
if ($this->a === "'" || $this->a === '"') { // string literal
|
132 |
-
$str = $this->a; // in case needed for exception
|
133 |
-
for(;;) {
|
134 |
-
$this->output .= $this->a;
|
135 |
-
$this->lastByteOut = $this->a;
|
136 |
-
|
137 |
-
$this->a = $this->get();
|
138 |
-
if ($this->a === $this->b) { // end quote
|
139 |
-
break;
|
140 |
-
}
|
141 |
-
if ($this->isEOF($this->a)) {
|
142 |
-
$byte = $this->inputIndex - 1;
|
143 |
-
throw new JSMin_UnterminatedStringException(
|
144 |
-
"JSMin: Unterminated String at byte {$byte}: {$str}");
|
145 |
-
}
|
146 |
-
$str .= $this->a;
|
147 |
-
if ($this->a === '\\') {
|
148 |
-
$this->output .= $this->a;
|
149 |
-
$this->lastByteOut = $this->a;
|
150 |
-
|
151 |
-
$this->a = $this->get();
|
152 |
-
$str .= $this->a;
|
153 |
-
}
|
154 |
-
}
|
155 |
-
}
|
156 |
-
|
157 |
-
// fallthrough intentional
|
158 |
-
case self::ACTION_DELETE_A_B: // 3
|
159 |
-
$this->b = $this->next();
|
160 |
-
if ($this->b === '/' && $this->isRegexpLiteral()) {
|
161 |
-
$this->output .= $this->a . $this->b;
|
162 |
-
$pattern = '/'; // keep entire pattern in case we need to report it in the exception
|
163 |
-
for(;;) {
|
164 |
-
$this->a = $this->get();
|
165 |
-
$pattern .= $this->a;
|
166 |
-
if ($this->a === '[') {
|
167 |
-
for(;;) {
|
168 |
-
$this->output .= $this->a;
|
169 |
-
$this->a = $this->get();
|
170 |
-
$pattern .= $this->a;
|
171 |
-
if ($this->a === ']') {
|
172 |
-
break;
|
173 |
-
}
|
174 |
-
if ($this->a === '\\') {
|
175 |
-
$this->output .= $this->a;
|
176 |
-
$this->a = $this->get();
|
177 |
-
$pattern .= $this->a;
|
178 |
-
}
|
179 |
-
if ($this->isEOF($this->a)) {
|
180 |
-
throw new JSMin_UnterminatedRegExpException(
|
181 |
-
"JSMin: Unterminated set in RegExp at byte "
|
182 |
-
. $this->inputIndex .": {$pattern}");
|
183 |
-
}
|
184 |
-
}
|
185 |
-
}
|
186 |
-
|
187 |
-
if ($this->a === '/') { // end pattern
|
188 |
-
break; // while (true)
|
189 |
-
} elseif ($this->a === '\\') {
|
190 |
-
$this->output .= $this->a;
|
191 |
-
$this->a = $this->get();
|
192 |
-
$pattern .= $this->a;
|
193 |
-
} elseif ($this->isEOF($this->a)) {
|
194 |
-
$byte = $this->inputIndex - 1;
|
195 |
-
throw new JSMin_UnterminatedRegExpException(
|
196 |
-
"JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
|
197 |
-
}
|
198 |
-
$this->output .= $this->a;
|
199 |
-
$this->lastByteOut = $this->a;
|
200 |
-
}
|
201 |
-
$this->b = $this->next();
|
202 |
-
}
|
203 |
-
// end case ACTION_DELETE_A_B
|
204 |
-
}
|
205 |
-
}
|
206 |
-
|
207 |
-
/**
|
208 |
-
* @return bool
|
209 |
-
*/
|
210 |
-
protected function isRegexpLiteral()
|
211 |
-
{
|
212 |
-
if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
|
213 |
-
// we obviously aren't dividing
|
214 |
-
return true;
|
215 |
-
}
|
216 |
-
|
217 |
-
// we have to check for a preceding keyword, and we don't need to pattern
|
218 |
-
// match over the whole output.
|
219 |
-
$recentOutput = substr($this->output, -10);
|
220 |
-
|
221 |
-
// check if return/typeof directly precede a pattern without a space
|
222 |
-
foreach (array('return', 'typeof') as $keyword) {
|
223 |
-
if ($this->a !== substr($keyword, -1)) {
|
224 |
-
// certainly wasn't keyword
|
225 |
-
continue;
|
226 |
-
}
|
227 |
-
if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) {
|
228 |
-
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
229 |
-
return true;
|
230 |
-
}
|
231 |
-
}
|
232 |
-
}
|
233 |
-
|
234 |
-
// check all keywords
|
235 |
-
if ($this->a === ' ' || $this->a === "\n") {
|
236 |
-
if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) {
|
237 |
-
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
238 |
-
return true;
|
239 |
-
}
|
240 |
-
}
|
241 |
-
}
|
242 |
-
|
243 |
-
return false;
|
244 |
-
}
|
245 |
-
|
246 |
-
/**
|
247 |
-
* Return the next character from stdin. Watch out for lookahead. If the character is a control character,
|
248 |
-
* translate it to a space or linefeed.
|
249 |
-
*
|
250 |
-
* @return string
|
251 |
-
*/
|
252 |
-
protected function get()
|
253 |
-
{
|
254 |
-
$c = $this->lookAhead;
|
255 |
-
$this->lookAhead = null;
|
256 |
-
if ($c === null) {
|
257 |
-
// getc(stdin)
|
258 |
-
if ($this->inputIndex < $this->inputLength) {
|
259 |
-
$c = $this->input[$this->inputIndex];
|
260 |
-
$this->inputIndex += 1;
|
261 |
-
} else {
|
262 |
-
$c = null;
|
263 |
-
}
|
264 |
-
}
|
265 |
-
if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
|
266 |
-
return $c;
|
267 |
-
}
|
268 |
-
if ($c === "\r") {
|
269 |
-
return "\n";
|
270 |
-
}
|
271 |
-
return ' ';
|
272 |
-
}
|
273 |
-
|
274 |
-
/**
|
275 |
-
* Does $a indicate end of input?
|
276 |
-
*
|
277 |
-
* @param string $a
|
278 |
-
* @return bool
|
279 |
-
*/
|
280 |
-
protected function isEOF($a)
|
281 |
-
{
|
282 |
-
return ord($a) <= self::ORD_LF;
|
283 |
-
}
|
284 |
-
|
285 |
-
/**
|
286 |
-
* Get next char (without getting it). If is ctrl character, translate to a space or newline.
|
287 |
-
*
|
288 |
-
* @return string
|
289 |
-
*/
|
290 |
-
protected function peek()
|
291 |
-
{
|
292 |
-
$this->lookAhead = $this->get();
|
293 |
-
return $this->lookAhead;
|
294 |
-
}
|
295 |
-
|
296 |
-
/**
|
297 |
-
* Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
|
298 |
-
*
|
299 |
-
* @param string $c
|
300 |
-
*
|
301 |
-
* @return bool
|
302 |
-
*/
|
303 |
-
protected function isAlphaNum($c)
|
304 |
-
{
|
305 |
-
return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
|
306 |
-
}
|
307 |
-
|
308 |
-
/**
|
309 |
-
* Consume a single line comment from input (possibly retaining it)
|
310 |
-
*/
|
311 |
-
protected function consumeSingleLineComment()
|
312 |
-
{
|
313 |
-
$comment = '';
|
314 |
-
while (true) {
|
315 |
-
$get = $this->get();
|
316 |
-
$comment .= $get;
|
317 |
-
if (ord($get) <= self::ORD_LF) { // end of line reached
|
318 |
-
// if IE conditional comment
|
319 |
-
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
320 |
-
$this->keptComment .= "/{$comment}";
|
321 |
-
}
|
322 |
-
return;
|
323 |
-
}
|
324 |
-
}
|
325 |
-
}
|
326 |
-
|
327 |
-
/**
|
328 |
-
* Consume a multiple line comment from input (possibly retaining it)
|
329 |
-
*
|
330 |
-
* @throws JSMin_UnterminatedCommentException
|
331 |
-
*/
|
332 |
-
protected function consumeMultipleLineComment()
|
333 |
-
{
|
334 |
-
$this->get();
|
335 |
-
$comment = '';
|
336 |
-
for(;;) {
|
337 |
-
$get = $this->get();
|
338 |
-
if ($get === '*') {
|
339 |
-
if ($this->peek() === '/') { // end of comment reached
|
340 |
-
$this->get();
|
341 |
-
if (0 === strpos($comment, '!')) {
|
342 |
-
// preserved by YUI Compressor
|
343 |
-
if (!$this->keptComment) {
|
344 |
-
// don't prepend a newline if two comments right after one another
|
345 |
-
$this->keptComment = "\n";
|
346 |
-
}
|
347 |
-
$this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
|
348 |
-
} else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
349 |
-
// IE conditional
|
350 |
-
$this->keptComment .= "/*{$comment}*/";
|
351 |
-
}
|
352 |
-
return;
|
353 |
-
}
|
354 |
-
} elseif ($get === null) {
|
355 |
-
throw new JSMin_UnterminatedCommentException(
|
356 |
-
"JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
|
357 |
-
}
|
358 |
-
$comment .= $get;
|
359 |
-
}
|
360 |
-
}
|
361 |
-
|
362 |
-
/**
|
363 |
-
* Get the next character, skipping over comments. Some comments may be preserved.
|
364 |
-
*
|
365 |
-
* @return string
|
366 |
-
*/
|
367 |
-
protected function next()
|
368 |
-
{
|
369 |
-
$get = $this->get();
|
370 |
-
if ($get === '/') {
|
371 |
-
switch ($this->peek()) {
|
372 |
-
case '/':
|
373 |
-
$this->consumeSingleLineComment();
|
374 |
-
$get = "\n";
|
375 |
-
break;
|
376 |
-
case '*':
|
377 |
-
$this->consumeMultipleLineComment();
|
378 |
-
$get = ' ';
|
379 |
-
break;
|
380 |
-
}
|
381 |
-
}
|
382 |
-
return $get;
|
383 |
-
}
|
384 |
-
}
|
385 |
-
/**
|
386 |
-
* @ignore
|
387 |
-
*/
|
388 |
-
class JSMin_UnterminatedStringException extends Exception {}
|
389 |
-
/**
|
390 |
-
* @ignore
|
391 |
-
*/
|
392 |
-
class JSMin_UnterminatedCommentException extends Exception {}
|
393 |
-
/**
|
394 |
-
* @ignore
|
395 |
-
*/
|
396 |
class JSMin_UnterminatedRegExpException extends Exception {}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* JavaScript compressor, minifies JavaScript.
|
4 |
+
* Based on JSMin (https://github.com/mrclay/minify, Ryan Grove <ryan@wonko.com>, Stephen Clay <steve@mrclay.org>, BSD License)
|
5 |
+
*
|
6 |
+
* @ignore
|
7 |
+
*/
|
8 |
+
class JSMin {
|
9 |
+
|
10 |
+
const ORD_LF = 10;
|
11 |
+
const ORD_SPACE = 32;
|
12 |
+
const ACTION_KEEP_A = 1;
|
13 |
+
const ACTION_DELETE_A = 2;
|
14 |
+
const ACTION_DELETE_A_B = 3;
|
15 |
+
|
16 |
+
protected $a = "\n";
|
17 |
+
protected $b = '';
|
18 |
+
protected $input = '';
|
19 |
+
protected $inputIndex = 0;
|
20 |
+
protected $inputLength = 0;
|
21 |
+
protected $lookAhead = null;
|
22 |
+
protected $output = '';
|
23 |
+
protected $lastByteOut = '';
|
24 |
+
protected $keptComment = '';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @param string $input
|
28 |
+
*/
|
29 |
+
public function __construct($input)
|
30 |
+
{
|
31 |
+
$this->input = $input;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Perform minification, return result
|
36 |
+
*
|
37 |
+
* @return string
|
38 |
+
*/
|
39 |
+
public function min()
|
40 |
+
{
|
41 |
+
if ($this->output !== '') { // min already run
|
42 |
+
return $this->output;
|
43 |
+
}
|
44 |
+
|
45 |
+
$mbIntEnc = null;
|
46 |
+
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
47 |
+
$mbIntEnc = mb_internal_encoding();
|
48 |
+
mb_internal_encoding('8bit');
|
49 |
+
}
|
50 |
+
$this->input = str_replace("\r\n", "\n", $this->input);
|
51 |
+
$this->inputLength = strlen($this->input);
|
52 |
+
|
53 |
+
$this->action(self::ACTION_DELETE_A_B);
|
54 |
+
|
55 |
+
while ($this->a !== null) {
|
56 |
+
// determine next command
|
57 |
+
$command = self::ACTION_KEEP_A; // default
|
58 |
+
if ($this->a === ' ') {
|
59 |
+
if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
|
60 |
+
&& ($this->b === $this->lastByteOut)) {
|
61 |
+
// Don't delete this space. If we do, the addition/subtraction
|
62 |
+
// could be parsed as a post-increment
|
63 |
+
} elseif (! $this->isAlphaNum($this->b)) {
|
64 |
+
$command = self::ACTION_DELETE_A;
|
65 |
+
}
|
66 |
+
} elseif ($this->a === "\n") {
|
67 |
+
if ($this->b === ' ') {
|
68 |
+
$command = self::ACTION_DELETE_A_B;
|
69 |
+
|
70 |
+
// in case of mbstring.func_overload & 2, must check for null b,
|
71 |
+
// otherwise mb_strpos will give WARNING
|
72 |
+
} elseif ($this->b === null
|
73 |
+
|| (false === strpos('{[(+-!~', $this->b)
|
74 |
+
&& ! $this->isAlphaNum($this->b))) {
|
75 |
+
$command = self::ACTION_DELETE_A;
|
76 |
+
}
|
77 |
+
} elseif (! $this->isAlphaNum($this->a)) {
|
78 |
+
if ($this->b === ' '
|
79 |
+
|| ($this->b === "\n"
|
80 |
+
&& (false === strpos('}])+-"\'', $this->a)))) {
|
81 |
+
$command = self::ACTION_DELETE_A_B;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
$this->action($command);
|
85 |
+
}
|
86 |
+
$this->output = trim($this->output);
|
87 |
+
|
88 |
+
if ($mbIntEnc !== null) {
|
89 |
+
mb_internal_encoding($mbIntEnc);
|
90 |
+
}
|
91 |
+
return $this->output;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
|
96 |
+
* ACTION_DELETE_A = Copy B to A. Get the next B.
|
97 |
+
* ACTION_DELETE_A_B = Get the next B.
|
98 |
+
*
|
99 |
+
* @param int $command
|
100 |
+
* @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException
|
101 |
+
*/
|
102 |
+
protected function action($command)
|
103 |
+
{
|
104 |
+
// make sure we don't compress "a + ++b" to "a+++b", etc.
|
105 |
+
if ($command === self::ACTION_DELETE_A_B
|
106 |
+
&& $this->b === ' '
|
107 |
+
&& ($this->a === '+' || $this->a === '-')) {
|
108 |
+
// Note: we're at an addition/substraction operator; the inputIndex
|
109 |
+
// will certainly be a valid index
|
110 |
+
if ($this->input[$this->inputIndex] === $this->a) {
|
111 |
+
// This is "+ +" or "- -". Don't delete the space.
|
112 |
+
$command = self::ACTION_KEEP_A;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
switch ($command) {
|
117 |
+
case self::ACTION_KEEP_A: // 1
|
118 |
+
$this->output .= $this->a;
|
119 |
+
|
120 |
+
if ($this->keptComment) {
|
121 |
+
$this->output = rtrim($this->output, "\n");
|
122 |
+
$this->output .= $this->keptComment;
|
123 |
+
$this->keptComment = '';
|
124 |
+
}
|
125 |
+
|
126 |
+
$this->lastByteOut = $this->a;
|
127 |
+
|
128 |
+
// fallthrough intentional
|
129 |
+
case self::ACTION_DELETE_A: // 2
|
130 |
+
$this->a = $this->b;
|
131 |
+
if ($this->a === "'" || $this->a === '"') { // string literal
|
132 |
+
$str = $this->a; // in case needed for exception
|
133 |
+
for(;;) {
|
134 |
+
$this->output .= $this->a;
|
135 |
+
$this->lastByteOut = $this->a;
|
136 |
+
|
137 |
+
$this->a = $this->get();
|
138 |
+
if ($this->a === $this->b) { // end quote
|
139 |
+
break;
|
140 |
+
}
|
141 |
+
if ($this->isEOF($this->a)) {
|
142 |
+
$byte = $this->inputIndex - 1;
|
143 |
+
throw new JSMin_UnterminatedStringException(
|
144 |
+
"JSMin: Unterminated String at byte {$byte}: {$str}");
|
145 |
+
}
|
146 |
+
$str .= $this->a;
|
147 |
+
if ($this->a === '\\') {
|
148 |
+
$this->output .= $this->a;
|
149 |
+
$this->lastByteOut = $this->a;
|
150 |
+
|
151 |
+
$this->a = $this->get();
|
152 |
+
$str .= $this->a;
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
// fallthrough intentional
|
158 |
+
case self::ACTION_DELETE_A_B: // 3
|
159 |
+
$this->b = $this->next();
|
160 |
+
if ($this->b === '/' && $this->isRegexpLiteral()) {
|
161 |
+
$this->output .= $this->a . $this->b;
|
162 |
+
$pattern = '/'; // keep entire pattern in case we need to report it in the exception
|
163 |
+
for(;;) {
|
164 |
+
$this->a = $this->get();
|
165 |
+
$pattern .= $this->a;
|
166 |
+
if ($this->a === '[') {
|
167 |
+
for(;;) {
|
168 |
+
$this->output .= $this->a;
|
169 |
+
$this->a = $this->get();
|
170 |
+
$pattern .= $this->a;
|
171 |
+
if ($this->a === ']') {
|
172 |
+
break;
|
173 |
+
}
|
174 |
+
if ($this->a === '\\') {
|
175 |
+
$this->output .= $this->a;
|
176 |
+
$this->a = $this->get();
|
177 |
+
$pattern .= $this->a;
|
178 |
+
}
|
179 |
+
if ($this->isEOF($this->a)) {
|
180 |
+
throw new JSMin_UnterminatedRegExpException(
|
181 |
+
"JSMin: Unterminated set in RegExp at byte "
|
182 |
+
. $this->inputIndex .": {$pattern}");
|
183 |
+
}
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
if ($this->a === '/') { // end pattern
|
188 |
+
break; // while (true)
|
189 |
+
} elseif ($this->a === '\\') {
|
190 |
+
$this->output .= $this->a;
|
191 |
+
$this->a = $this->get();
|
192 |
+
$pattern .= $this->a;
|
193 |
+
} elseif ($this->isEOF($this->a)) {
|
194 |
+
$byte = $this->inputIndex - 1;
|
195 |
+
throw new JSMin_UnterminatedRegExpException(
|
196 |
+
"JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
|
197 |
+
}
|
198 |
+
$this->output .= $this->a;
|
199 |
+
$this->lastByteOut = $this->a;
|
200 |
+
}
|
201 |
+
$this->b = $this->next();
|
202 |
+
}
|
203 |
+
// end case ACTION_DELETE_A_B
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* @return bool
|
209 |
+
*/
|
210 |
+
protected function isRegexpLiteral()
|
211 |
+
{
|
212 |
+
if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
|
213 |
+
// we obviously aren't dividing
|
214 |
+
return true;
|
215 |
+
}
|
216 |
+
|
217 |
+
// we have to check for a preceding keyword, and we don't need to pattern
|
218 |
+
// match over the whole output.
|
219 |
+
$recentOutput = substr($this->output, -10);
|
220 |
+
|
221 |
+
// check if return/typeof directly precede a pattern without a space
|
222 |
+
foreach (array('return', 'typeof') as $keyword) {
|
223 |
+
if ($this->a !== substr($keyword, -1)) {
|
224 |
+
// certainly wasn't keyword
|
225 |
+
continue;
|
226 |
+
}
|
227 |
+
if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) {
|
228 |
+
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
229 |
+
return true;
|
230 |
+
}
|
231 |
+
}
|
232 |
+
}
|
233 |
+
|
234 |
+
// check all keywords
|
235 |
+
if ($this->a === ' ' || $this->a === "\n") {
|
236 |
+
if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) {
|
237 |
+
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
238 |
+
return true;
|
239 |
+
}
|
240 |
+
}
|
241 |
+
}
|
242 |
+
|
243 |
+
return false;
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Return the next character from stdin. Watch out for lookahead. If the character is a control character,
|
248 |
+
* translate it to a space or linefeed.
|
249 |
+
*
|
250 |
+
* @return string
|
251 |
+
*/
|
252 |
+
protected function get()
|
253 |
+
{
|
254 |
+
$c = $this->lookAhead;
|
255 |
+
$this->lookAhead = null;
|
256 |
+
if ($c === null) {
|
257 |
+
// getc(stdin)
|
258 |
+
if ($this->inputIndex < $this->inputLength) {
|
259 |
+
$c = $this->input[$this->inputIndex];
|
260 |
+
$this->inputIndex += 1;
|
261 |
+
} else {
|
262 |
+
$c = null;
|
263 |
+
}
|
264 |
+
}
|
265 |
+
if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
|
266 |
+
return $c;
|
267 |
+
}
|
268 |
+
if ($c === "\r") {
|
269 |
+
return "\n";
|
270 |
+
}
|
271 |
+
return ' ';
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Does $a indicate end of input?
|
276 |
+
*
|
277 |
+
* @param string $a
|
278 |
+
* @return bool
|
279 |
+
*/
|
280 |
+
protected function isEOF($a)
|
281 |
+
{
|
282 |
+
return ord($a) <= self::ORD_LF;
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Get next char (without getting it). If is ctrl character, translate to a space or newline.
|
287 |
+
*
|
288 |
+
* @return string
|
289 |
+
*/
|
290 |
+
protected function peek()
|
291 |
+
{
|
292 |
+
$this->lookAhead = $this->get();
|
293 |
+
return $this->lookAhead;
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
|
298 |
+
*
|
299 |
+
* @param string $c
|
300 |
+
*
|
301 |
+
* @return bool
|
302 |
+
*/
|
303 |
+
protected function isAlphaNum($c)
|
304 |
+
{
|
305 |
+
return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Consume a single line comment from input (possibly retaining it)
|
310 |
+
*/
|
311 |
+
protected function consumeSingleLineComment()
|
312 |
+
{
|
313 |
+
$comment = '';
|
314 |
+
while (true) {
|
315 |
+
$get = $this->get();
|
316 |
+
$comment .= $get;
|
317 |
+
if (ord($get) <= self::ORD_LF) { // end of line reached
|
318 |
+
// if IE conditional comment
|
319 |
+
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
320 |
+
$this->keptComment .= "/{$comment}";
|
321 |
+
}
|
322 |
+
return;
|
323 |
+
}
|
324 |
+
}
|
325 |
+
}
|
326 |
+
|
327 |
+
/**
|
328 |
+
* Consume a multiple line comment from input (possibly retaining it)
|
329 |
+
*
|
330 |
+
* @throws JSMin_UnterminatedCommentException
|
331 |
+
*/
|
332 |
+
protected function consumeMultipleLineComment()
|
333 |
+
{
|
334 |
+
$this->get();
|
335 |
+
$comment = '';
|
336 |
+
for(;;) {
|
337 |
+
$get = $this->get();
|
338 |
+
if ($get === '*') {
|
339 |
+
if ($this->peek() === '/') { // end of comment reached
|
340 |
+
$this->get();
|
341 |
+
if (0 === strpos($comment, '!')) {
|
342 |
+
// preserved by YUI Compressor
|
343 |
+
if (!$this->keptComment) {
|
344 |
+
// don't prepend a newline if two comments right after one another
|
345 |
+
$this->keptComment = "\n";
|
346 |
+
}
|
347 |
+
$this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
|
348 |
+
} else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
349 |
+
// IE conditional
|
350 |
+
$this->keptComment .= "/*{$comment}*/";
|
351 |
+
}
|
352 |
+
return;
|
353 |
+
}
|
354 |
+
} elseif ($get === null) {
|
355 |
+
throw new JSMin_UnterminatedCommentException(
|
356 |
+
"JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
|
357 |
+
}
|
358 |
+
$comment .= $get;
|
359 |
+
}
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Get the next character, skipping over comments. Some comments may be preserved.
|
364 |
+
*
|
365 |
+
* @return string
|
366 |
+
*/
|
367 |
+
protected function next()
|
368 |
+
{
|
369 |
+
$get = $this->get();
|
370 |
+
if ($get === '/') {
|
371 |
+
switch ($this->peek()) {
|
372 |
+
case '/':
|
373 |
+
$this->consumeSingleLineComment();
|
374 |
+
$get = "\n";
|
375 |
+
break;
|
376 |
+
case '*':
|
377 |
+
$this->consumeMultipleLineComment();
|
378 |
+
$get = ' ';
|
379 |
+
break;
|
380 |
+
}
|
381 |
+
}
|
382 |
+
return $get;
|
383 |
+
}
|
384 |
+
}
|
385 |
+
/**
|
386 |
+
* @ignore
|
387 |
+
*/
|
388 |
+
class JSMin_UnterminatedStringException extends Exception {}
|
389 |
+
/**
|
390 |
+
* @ignore
|
391 |
+
*/
|
392 |
+
class JSMin_UnterminatedCommentException extends Exception {}
|
393 |
+
/**
|
394 |
+
* @ignore
|
395 |
+
*/
|
396 |
class JSMin_UnterminatedRegExpException extends Exception {}
|
includes/compiler/vendors/lessc.php
CHANGED
@@ -1,3694 +1,3694 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* lessphp v0.4.0
|
4 |
-
* http://leafo.net/lessphp
|
5 |
-
*
|
6 |
-
* LESS css compiler, adapted from http://lesscss.org
|
7 |
-
*
|
8 |
-
* Copyright 2012, Leaf Corcoran <leafot@gmail.com>
|
9 |
-
* Licensed under MIT or GPLv3, see LICENSE
|
10 |
-
*
|
11 |
-
* @ignore
|
12 |
-
*/
|
13 |
-
|
14 |
-
|
15 |
-
/**
|
16 |
-
* The less compiler and parser.
|
17 |
-
*
|
18 |
-
* Converting LESS to CSS is a three stage process. The incoming file is parsed
|
19 |
-
* by `lessc_parser` into a syntax tree, then it is compiled into another tree
|
20 |
-
* representing the CSS structure by `lessc`. The CSS tree is fed into a
|
21 |
-
* formatter, like `lessc_formatter` which then outputs CSS as a string.
|
22 |
-
*
|
23 |
-
* During the first compile, all values are *reduced*, which means that their
|
24 |
-
* types are brought to the lowest form before being dump as strings. This
|
25 |
-
* handles math equations, variable dereferences, and the like.
|
26 |
-
*
|
27 |
-
* The `parse` function of `lessc` is the entry point.
|
28 |
-
*
|
29 |
-
* In summary:
|
30 |
-
*
|
31 |
-
* The `lessc` class creates an intstance of the parser, feeds it LESS code,
|
32 |
-
* then transforms the resulting tree to a CSS tree. This class also holds the
|
33 |
-
* evaluation context, such as all available mixins and variables at any given
|
34 |
-
* time.
|
35 |
-
*
|
36 |
-
* The `lessc_parser` class is only concerned with parsing its input.
|
37 |
-
*
|
38 |
-
* The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
|
39 |
-
* handling things like indentation.
|
40 |
-
*
|
41 |
-
* @ignore
|
42 |
-
*/
|
43 |
-
class JupiterX_Lessc {
|
44 |
-
static public $VERSION = "v0.4.0";
|
45 |
-
static protected $TRUE = array("keyword", "true");
|
46 |
-
static protected $FALSE = array("keyword", "false");
|
47 |
-
|
48 |
-
protected $libFunctions = array();
|
49 |
-
protected $registeredVars = array();
|
50 |
-
protected $preserveComments = false;
|
51 |
-
|
52 |
-
public $vPrefix = '@'; // prefix of abstract properties
|
53 |
-
public $mPrefix = '$'; // prefix of abstract blocks
|
54 |
-
public $parentSelector = '&';
|
55 |
-
|
56 |
-
public $importDisabled = false;
|
57 |
-
public $importDir = '';
|
58 |
-
|
59 |
-
protected $numberPrecision = null;
|
60 |
-
|
61 |
-
protected $allParsedFiles = array();
|
62 |
-
|
63 |
-
// set to the parser that generated the current line when compiling
|
64 |
-
// so we know how to create error messages
|
65 |
-
protected $sourceParser = null;
|
66 |
-
protected $sourceLoc = null;
|
67 |
-
|
68 |
-
static public $defaultValue = array("keyword", "");
|
69 |
-
|
70 |
-
static protected $nextImportId = 0; // uniquely identify imports
|
71 |
-
|
72 |
-
// attempts to find the path of an import url, returns null for css files
|
73 |
-
protected function findImport($url) {
|
74 |
-
foreach ((array)$this->importDir as $dir) {
|
75 |
-
$full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url;
|
76 |
-
if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) {
|
77 |
-
return $file;
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
return null;
|
82 |
-
}
|
83 |
-
|
84 |
-
protected function fileExists($name) {
|
85 |
-
return is_file($name);
|
86 |
-
}
|
87 |
-
|
88 |
-
static public function compressList($items, $delim) {
|
89 |
-
if (!isset($items[1]) && isset($items[0])) return $items[0];
|
90 |
-
else return array('list', $delim, $items);
|
91 |
-
}
|
92 |
-
|
93 |
-
static public function preg_quote($what) {
|
94 |
-
return preg_quote($what, '/');
|
95 |
-
}
|
96 |
-
|
97 |
-
protected function tryImport($importPath, $parentBlock, $out) {
|
98 |
-
if ($importPath[0] == "function" && $importPath[1] == "url") {
|
99 |
-
$importPath = $this->flattenList($importPath[2]);
|
100 |
-
}
|
101 |
-
|
102 |
-
$str = $this->coerceString($importPath);
|
103 |
-
if ($str === null) return false;
|
104 |
-
|
105 |
-
$url = $this->compileValue($this->lib_unquote($str));
|
106 |
-
|
107 |
-
// don't import if it ends in css
|
108 |
-
if (substr_compare($url, '.css', -4, 4) === 0) return false;
|
109 |
-
|
110 |
-
$realPath = $this->findImport($url);
|
111 |
-
|
112 |
-
if ($realPath === null) return false;
|
113 |
-
|
114 |
-
if ($this->importDisabled) {
|
115 |
-
return array(false, "/* import disabled */");
|
116 |
-
}
|
117 |
-
|
118 |
-
if (isset($this->allParsedFiles[realpath($realPath)])) {
|
119 |
-
return array(false, null);
|
120 |
-
}
|
121 |
-
|
122 |
-
$this->addParsedFile($realPath);
|
123 |
-
$parser = $this->makeParser($realPath);
|
124 |
-
$root = $parser->parse($GLOBALS['wp_filesystem']->get_contents($realPath));
|
125 |
-
|
126 |
-
// set the parents of all the block props
|
127 |
-
foreach ($root->props as $prop) {
|
128 |
-
if ($prop[0] == "block") {
|
129 |
-
$prop[1]->parent = $parentBlock;
|
130 |
-
}
|
131 |
-
}
|
132 |
-
|
133 |
-
// copy mixins into scope, set their parents
|
134 |
-
// bring blocks from import into current block
|
135 |
-
// TODO: need to mark the source parser these came from this file
|
136 |
-
foreach ($root->children as $childName => $child) {
|
137 |
-
if (isset($parentBlock->children[$childName])) {
|
138 |
-
$parentBlock->children[$childName] = array_merge(
|
139 |
-
$parentBlock->children[$childName],
|
140 |
-
$child);
|
141 |
-
} else {
|
142 |
-
$parentBlock->children[$childName] = $child;
|
143 |
-
}
|
144 |
-
}
|
145 |
-
|
146 |
-
$pi = pathinfo($realPath);
|
147 |
-
$dir = $pi["dirname"];
|
148 |
-
|
149 |
-
list($top, $bottom) = $this->sortProps($root->props, true);
|
150 |
-
$this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
|
151 |
-
|
152 |
-
return array(true, $bottom, $parser, $dir);
|
153 |
-
}
|
154 |
-
|
155 |
-
protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
|
156 |
-
$oldSourceParser = $this->sourceParser;
|
157 |
-
|
158 |
-
$oldImport = $this->importDir;
|
159 |
-
|
160 |
-
// TODO: this is because the importDir api is stupid
|
161 |
-
$this->importDir = (array)$this->importDir;
|
162 |
-
array_unshift($this->importDir, $importDir);
|
163 |
-
|
164 |
-
foreach ($props as $prop) {
|
165 |
-
$this->compileProp($prop, $block, $out);
|
166 |
-
}
|
167 |
-
|
168 |
-
$this->importDir = $oldImport;
|
169 |
-
$this->sourceParser = $oldSourceParser;
|
170 |
-
}
|
171 |
-
|
172 |
-
/**
|
173 |
-
* Recursively compiles a block.
|
174 |
-
*
|
175 |
-
* A block is analogous to a CSS block in most cases. A single LESS document
|
176 |
-
* is encapsulated in a block when parsed, but it does not have parent tags
|
177 |
-
* so all of it's children appear on the root level when compiled.
|
178 |
-
*
|
179 |
-
* Blocks are made up of props and children.
|
180 |
-
*
|
181 |
-
* Props are property instructions, array tuples which describe an action
|
182 |
-
* to be taken, eg. write a property, set a variable, mixin a block.
|
183 |
-
*
|
184 |
-
* The children of a block are just all the blocks that are defined within.
|
185 |
-
* This is used to look up mixins when performing a mixin.
|
186 |
-
*
|
187 |
-
* Compiling the block involves pushing a fresh environment on the stack,
|
188 |
-
* and iterating through the props, compiling each one.
|
189 |
-
*
|
190 |
-
* See lessc::compileProp()
|
191 |
-
*
|
192 |
-
*/
|
193 |
-
protected function compileBlock($block) {
|
194 |
-
switch ($block->type) {
|
195 |
-
case "root":
|
196 |
-
$this->compileRoot($block);
|
197 |
-
break;
|
198 |
-
case null:
|
199 |
-
$this->compileCSSBlock($block);
|
200 |
-
break;
|
201 |
-
case "media":
|
202 |
-
$this->compileMedia($block);
|
203 |
-
break;
|
204 |
-
case "directive":
|
205 |
-
$name = "@" . $block->name;
|
206 |
-
if (!empty($block->value)) {
|
207 |
-
$name .= " " . $this->compileValue($this->reduce($block->value));
|
208 |
-
}
|
209 |
-
|
210 |
-
$this->compileNestedBlock($block, array($name));
|
211 |
-
break;
|
212 |
-
default:
|
213 |
-
$this->throwError("unknown block type: $block->type\n");
|
214 |
-
}
|
215 |
-
}
|
216 |
-
|
217 |
-
protected function compileCSSBlock($block) {
|
218 |
-
$env = $this->pushEnv();
|
219 |
-
|
220 |
-
$selectors = $this->compileSelectors($block->tags);
|
221 |
-
$env->selectors = $this->multiplySelectors($selectors);
|
222 |
-
$out = $this->makeOutputBlock(null, $env->selectors);
|
223 |
-
|
224 |
-
$this->scope->children[] = $out;
|
225 |
-
$this->compileProps($block, $out);
|
226 |
-
|
227 |
-
$block->scope = $env; // mixins carry scope with them!
|
228 |
-
$this->popEnv();
|
229 |
-
}
|
230 |
-
|
231 |
-
protected function compileMedia($media) {
|
232 |
-
$env = $this->pushEnv($media);
|
233 |
-
$parentScope = $this->mediaParent($this->scope);
|
234 |
-
|
235 |
-
$query = $this->compileMediaQuery($this->multiplyMedia($env));
|
236 |
-
|
237 |
-
$this->scope = $this->makeOutputBlock($media->type, array($query));
|
238 |
-
$parentScope->children[] = $this->scope;
|
239 |
-
|
240 |
-
$this->compileProps($media, $this->scope);
|
241 |
-
|
242 |
-
if (count($this->scope->lines) > 0) {
|
243 |
-
$orphanSelelectors = $this->findClosestSelectors();
|
244 |
-
if (!is_null($orphanSelelectors)) {
|
245 |
-
$orphan = $this->makeOutputBlock(null, $orphanSelelectors);
|
246 |
-
$orphan->lines = $this->scope->lines;
|
247 |
-
array_unshift($this->scope->children, $orphan);
|
248 |
-
$this->scope->lines = array();
|
249 |
-
}
|
250 |
-
}
|
251 |
-
|
252 |
-
$this->scope = $this->scope->parent;
|
253 |
-
$this->popEnv();
|
254 |
-
}
|
255 |
-
|
256 |
-
protected function mediaParent($scope) {
|
257 |
-
while (!empty($scope->parent)) {
|
258 |
-
if (!empty($scope->type) && $scope->type != "media") {
|
259 |
-
break;
|
260 |
-
}
|
261 |
-
$scope = $scope->parent;
|
262 |
-
}
|
263 |
-
|
264 |
-
return $scope;
|
265 |
-
}
|
266 |
-
|
267 |
-
protected function compileNestedBlock($block, $selectors) {
|
268 |
-
$this->pushEnv($block);
|
269 |
-
$this->scope = $this->makeOutputBlock($block->type, $selectors);
|
270 |
-
$this->scope->parent->children[] = $this->scope;
|
271 |
-
|
272 |
-
$this->compileProps($block, $this->scope);
|
273 |
-
|
274 |
-
$this->scope = $this->scope->parent;
|
275 |
-
$this->popEnv();
|
276 |
-
}
|
277 |
-
|
278 |
-
protected function compileRoot($root) {
|
279 |
-
$this->pushEnv();
|
280 |
-
$this->scope = $this->makeOutputBlock($root->type);
|
281 |
-
$this->compileProps($root, $this->scope);
|
282 |
-
$this->popEnv();
|
283 |
-
}
|
284 |
-
|
285 |
-
protected function compileProps($block, $out) {
|
286 |
-
foreach ($this->sortProps($block->props) as $prop) {
|
287 |
-
$this->compileProp($prop, $block, $out);
|
288 |
-
}
|
289 |
-
|
290 |
-
$out->lines = array_values(array_unique($out->lines));
|
291 |
-
}
|
292 |
-
|
293 |
-
protected function sortProps($props, $split = false) {
|
294 |
-
$vars = array();
|
295 |
-
$imports = array();
|
296 |
-
$other = array();
|
297 |
-
|
298 |
-
foreach ($props as $prop) {
|
299 |
-
switch ($prop[0]) {
|
300 |
-
case "assign":
|
301 |
-
if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
|
302 |
-
$vars[] = $prop;
|
303 |
-
} else {
|
304 |
-
$other[] = $prop;
|
305 |
-
}
|
306 |
-
break;
|
307 |
-
case "import":
|
308 |
-
$id = self::$nextImportId++;
|
309 |
-
$prop[] = $id;
|
310 |
-
$imports[] = $prop;
|
311 |
-
$other[] = array("import_mixin", $id);
|
312 |
-
break;
|
313 |
-
default:
|
314 |
-
$other[] = $prop;
|
315 |
-
}
|
316 |
-
}
|
317 |
-
|
318 |
-
if ($split) {
|
319 |
-
return array(array_merge($vars, $imports), $other);
|
320 |
-
} else {
|
321 |
-
return array_merge($vars, $imports, $other);
|
322 |
-
}
|
323 |
-
}
|
324 |
-
|
325 |
-
protected function compileMediaQuery($queries) {
|
326 |
-
$compiledQueries = array();
|
327 |
-
foreach ($queries as $query) {
|
328 |
-
$parts = array();
|
329 |
-
foreach ($query as $q) {
|
330 |
-
switch ($q[0]) {
|
331 |
-
case "mediaType":
|
332 |
-
$parts[] = implode(" ", array_slice($q, 1));
|
333 |
-
break;
|
334 |
-
case "mediaExp":
|
335 |
-
if (isset($q[2])) {
|
336 |
-
$parts[] = "($q[1]: " .
|
337 |
-
$this->compileValue($this->reduce($q[2])) . ")";
|
338 |
-
} else {
|
339 |
-
$parts[] = "($q[1])";
|
340 |
-
}
|
341 |
-
break;
|
342 |
-
case "variable":
|
343 |
-
$parts[] = $this->compileValue($this->reduce($q));
|
344 |
-
break;
|
345 |
-
}
|
346 |
-
}
|
347 |
-
|
348 |
-
if (count($parts) > 0) {
|
349 |
-
$compiledQueries[] = implode(" and ", $parts);
|
350 |
-
}
|
351 |
-
}
|
352 |
-
|
353 |
-
$out = "@media";
|
354 |
-
if (!empty($parts)) {
|
355 |
-
$out .= " " .
|
356 |
-
implode($this->formatter->selectorSeparator, $compiledQueries);
|
357 |
-
}
|
358 |
-
return $out;
|
359 |
-
}
|
360 |
-
|
361 |
-
protected function multiplyMedia($env, $childQueries = null) {
|
362 |
-
if (is_null($env) ||
|
363 |
-
!empty($env->block->type) && $env->block->type != "media")
|
364 |
-
{
|
365 |
-
return $childQueries;
|
366 |
-
}
|
367 |
-
|
368 |
-
// plain old block, skip
|
369 |
-
if (empty($env->block->type)) {
|
370 |
-
return $this->multiplyMedia($env->parent, $childQueries);
|
371 |
-
}
|
372 |
-
|
373 |
-
$out = array();
|
374 |
-
$queries = $env->block->queries;
|
375 |
-
if (is_null($childQueries)) {
|
376 |
-
$out = $queries;
|
377 |
-
} else {
|
378 |
-
foreach ($queries as $parent) {
|
379 |
-
foreach ($childQueries as $child) {
|
380 |
-
$out[] = array_merge($parent, $child);
|
381 |
-
}
|
382 |
-
}
|
383 |
-
}
|
384 |
-
|
385 |
-
return $this->multiplyMedia($env->parent, $out);
|
386 |
-
}
|
387 |
-
|
388 |
-
protected function expandParentSelectors(&$tag, $replace) {
|
389 |
-
$parts = explode("$&$", $tag);
|
390 |
-
$count = 0;
|
391 |
-
foreach ($parts as &$part) {
|
392 |
-
$part = str_replace($this->parentSelector, $replace, $part, $c);
|
393 |
-
$count += $c;
|
394 |
-
}
|
395 |
-
$tag = implode($this->parentSelector, $parts);
|
396 |
-
return $count;
|
397 |
-
}
|
398 |
-
|
399 |
-
protected function findClosestSelectors() {
|
400 |
-
$env = $this->env;
|
401 |
-
$selectors = null;
|
402 |
-
while ($env !== null) {
|
403 |
-
if (isset($env->selectors)) {
|
404 |
-
$selectors = $env->selectors;
|
405 |
-
break;
|
406 |
-
}
|
407 |
-
$env = $env->parent;
|
408 |
-
}
|
409 |
-
|
410 |
-
return $selectors;
|
411 |
-
}
|
412 |
-
|
413 |
-
|
414 |
-
// multiply $selectors against the nearest selectors in env
|
415 |
-
protected function multiplySelectors($selectors) {
|
416 |
-
// find parent selectors
|
417 |
-
|
418 |
-
$parentSelectors = $this->findClosestSelectors();
|
419 |
-
if (is_null($parentSelectors)) {
|
420 |
-
// kill parent reference in top level selector
|
421 |
-
foreach ($selectors as &$s) {
|
422 |
-
$this->expandParentSelectors($s, "");
|
423 |
-
}
|
424 |
-
|
425 |
-
return $selectors;
|
426 |
-
}
|
427 |
-
|
428 |
-
$out = array();
|
429 |
-
foreach ($parentSelectors as $parent) {
|
430 |
-
foreach ($selectors as $child) {
|
431 |
-
$count = $this->expandParentSelectors($child, $parent);
|
432 |
-
|
433 |
-
// don't prepend the parent tag if & was used
|
434 |
-
if ($count > 0) {
|
435 |
-
$out[] = trim($child);
|
436 |
-
} else {
|
437 |
-
$out[] = trim($parent . ' ' . $child);
|
438 |
-
}
|
439 |
-
}
|
440 |
-
}
|
441 |
-
|
442 |
-
return $out;
|
443 |
-
}
|
444 |
-
|
445 |
-
// reduces selector expressions
|
446 |
-
protected function compileSelectors($selectors) {
|
447 |
-
$out = array();
|
448 |
-
|
449 |
-
foreach ($selectors as $s) {
|
450 |
-
if (is_array($s)) {
|
451 |
-
list(, $value) = $s;
|
452 |
-
$out[] = trim($this->compileValue($this->reduce($value)));
|
453 |
-
} else {
|
454 |
-
$out[] = $s;
|
455 |
-
}
|
456 |
-
}
|
457 |
-
|
458 |
-
return $out;
|
459 |
-
}
|
460 |
-
|
461 |
-
protected function eq($left, $right) {
|
462 |
-
return $left == $right;
|
463 |
-
}
|
464 |
-
|
465 |
-
protected function patternMatch($block, $orderedArgs, $keywordArgs) {
|
466 |
-
// match the guards if it has them
|
467 |
-
// any one of the groups must have all its guards pass for a match
|
468 |
-
if (!empty($block->guards)) {
|
469 |
-
$groupPassed = false;
|
470 |
-
foreach ($block->guards as $guardGroup) {
|
471 |
-
foreach ($guardGroup as $guard) {
|
472 |
-
$this->pushEnv();
|
473 |
-
$this->zipSetArgs($block->args, $orderedArgs, $keywordArgs);
|
474 |
-
|
475 |
-
$negate = false;
|
476 |
-
if ($guard[0] == "negate") {
|
477 |
-
$guard = $guard[1];
|
478 |
-
$negate = true;
|
479 |
-
}
|
480 |
-
|
481 |
-
$passed = $this->reduce($guard) == self::$TRUE;
|
482 |
-
if ($negate) $passed = !$passed;
|
483 |
-
|
484 |
-
$this->popEnv();
|
485 |
-
|
486 |
-
if ($passed) {
|
487 |
-
$groupPassed = true;
|
488 |
-
} else {
|
489 |
-
$groupPassed = false;
|
490 |
-
break;
|
491 |
-
}
|
492 |
-
}
|
493 |
-
|
494 |
-
if ($groupPassed) break;
|
495 |
-
}
|
496 |
-
|
497 |
-
if (!$groupPassed) {
|
498 |
-
return false;
|
499 |
-
}
|
500 |
-
}
|
501 |
-
|
502 |
-
if (empty($block->args)) {
|
503 |
-
return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
|
504 |
-
}
|
505 |
-
|
506 |
-
$remainingArgs = $block->args;
|
507 |
-
if ($keywordArgs) {
|
508 |
-
$remainingArgs = array();
|
509 |
-
foreach ($block->args as $arg) {
|
510 |
-
if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
|
511 |
-
continue;
|
512 |
-
}
|
513 |
-
|
514 |
-
$remainingArgs[] = $arg;
|
515 |
-
}
|
516 |
-
}
|
517 |
-
|
518 |
-
$i = -1; // no args
|
519 |
-
// try to match by arity or by argument literal
|
520 |
-
foreach ($remainingArgs as $i => $arg) {
|
521 |
-
switch ($arg[0]) {
|
522 |
-
case "lit":
|
523 |
-
if (empty($orderedArgs[$i]) || !$this->eq($arg[1], $orderedArgs[$i])) {
|
524 |
-
return false;
|
525 |
-
}
|
526 |
-
break;
|
527 |
-
case "arg":
|
528 |
-
// no arg and no default value
|
529 |
-
if (!isset($orderedArgs[$i]) && !isset($arg[2])) {
|
530 |
-
return false;
|
531 |
-
}
|
532 |
-
break;
|
533 |
-
case "rest":
|
534 |
-
$i--; // rest can be empty
|
535 |
-
break 2;
|
536 |
-
}
|
537 |
-
}
|
538 |
-
|
539 |
-
if ($block->isVararg) {
|
540 |
-
return true; // not having enough is handled above
|
541 |
-
} else {
|
542 |
-
$numMatched = $i + 1;
|
543 |
-
// greater than becuase default values always match
|
544 |
-
return $numMatched >= count($orderedArgs);
|
545 |
-
}
|
546 |
-
}
|
547 |
-
|
548 |
-
protected function patternMatchAll($blocks, $orderedArgs, $keywordArgs, $skip=array()) {
|
549 |
-
$matches = null;
|
550 |
-
foreach ($blocks as $block) {
|
551 |
-
// skip seen blocks that don't have arguments
|
552 |
-
if (isset($skip[$block->id]) && !isset($block->args)) {
|
553 |
-
continue;
|
554 |
-
}
|
555 |
-
|
556 |
-
if ($this->patternMatch($block, $orderedArgs, $keywordArgs)) {
|
557 |
-
$matches[] = $block;
|
558 |
-
}
|
559 |
-
}
|
560 |
-
|
561 |
-
return $matches;
|
562 |
-
}
|
563 |
-
|
564 |
-
// attempt to find blocks matched by path and args
|
565 |
-
protected function findBlocks($searchIn, $path, $orderedArgs, $keywordArgs, $seen=array()) {
|
566 |
-
if ($searchIn == null) return null;
|
567 |
-
if (isset($seen[$searchIn->id])) return null;
|
568 |
-
$seen[$searchIn->id] = true;
|
569 |
-
|
570 |
-
$name = $path[0];
|
571 |
-
|
572 |
-
if (isset($searchIn->children[$name])) {
|
573 |
-
$blocks = $searchIn->children[$name];
|
574 |
-
if (count($path) == 1) {
|
575 |
-
$matches = $this->patternMatchAll($blocks, $orderedArgs, $keywordArgs, $seen);
|
576 |
-
if (!empty($matches)) {
|
577 |
-
// This will return all blocks that match in the closest
|
578 |
-
// scope that has any matching block, like lessjs
|
579 |
-
return $matches;
|
580 |
-
}
|
581 |
-
} else {
|
582 |
-
$matches = array();
|
583 |
-
foreach ($blocks as $subBlock) {
|
584 |
-
$subMatches = $this->findBlocks($subBlock,
|
585 |
-
array_slice($path, 1), $orderedArgs, $keywordArgs, $seen);
|
586 |
-
|
587 |
-
if (!is_null($subMatches)) {
|
588 |
-
foreach ($subMatches as $sm) {
|
589 |
-
$matches[] = $sm;
|
590 |
-
}
|
591 |
-
}
|
592 |
-
}
|
593 |
-
|
594 |
-
return count($matches) > 0 ? $matches : null;
|
595 |
-
}
|
596 |
-
}
|
597 |
-
if ($searchIn->parent === $searchIn) return null;
|
598 |
-
return $this->findBlocks($searchIn->parent, $path, $orderedArgs, $keywordArgs, $seen);
|
599 |
-
}
|
600 |
-
|
601 |
-
// sets all argument names in $args to either the default value
|
602 |
-
// or the one passed in through $values
|
603 |
-
protected function zipSetArgs($args, $orderedValues, $keywordValues) {
|
604 |
-
$assignedValues = array();
|
605 |
-
|
606 |
-
$i = 0;
|
607 |
-
foreach ($args as $a) {
|
608 |
-
if ($a[0] == "arg") {
|
609 |
-
if (isset($keywordValues[$a[1]])) {
|
610 |
-
// has keyword arg
|
611 |
-
$value = $keywordValues[$a[1]];
|
612 |
-
} elseif (isset($orderedValues[$i])) {
|
613 |
-
// has ordered arg
|
614 |
-
$value = $orderedValues[$i];
|
615 |
-
$i++;
|
616 |
-
} elseif (isset($a[2])) {
|
617 |
-
// has default value
|
618 |
-
$value = $a[2];
|
619 |
-
} else {
|
620 |
-
$this->throwError("Failed to assign arg " . $a[1]);
|
621 |
-
$value = null; // :(
|
622 |
-
}
|
623 |
-
|
624 |
-
$value = $this->reduce($value);
|
625 |
-
$this->set($a[1], $value);
|
626 |
-
$assignedValues[] = $value;
|
627 |
-
} else {
|
628 |
-
// a lit
|
629 |
-
$i++;
|
630 |
-
}
|
631 |
-
}
|
632 |
-
|
633 |
-
// check for a rest
|
634 |
-
$last = end($args);
|
635 |
-
if ($last[0] == "rest") {
|
636 |
-
$rest = array_slice($orderedValues, count($args) - 1);
|
637 |
-
$this->set($last[1], $this->reduce(array("list", " ", $rest)));
|
638 |
-
}
|
639 |
-
|
640 |
-
// wow is this the only true use of PHP's + operator for arrays?
|
641 |
-
$this->env->arguments = $assignedValues + $orderedValues;
|
642 |
-
}
|
643 |
-
|
644 |
-
// compile a prop and update $lines or $blocks appropriately
|
645 |
-
protected function compileProp($prop, $block, $out) {
|
646 |
-
// set error position context
|
647 |
-
$this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
|
648 |
-
|
649 |
-
switch ($prop[0]) {
|
650 |
-
case 'assign':
|
651 |
-
list(, $name, $value) = $prop;
|
652 |
-
if ($name[0] == $this->vPrefix) {
|
653 |
-
$this->set($name, $value);
|
654 |
-
} else {
|
655 |
-
$out->lines[] = $this->formatter->property($name,
|
656 |
-
$this->compileValue($this->reduce($value)));
|
657 |
-
}
|
658 |
-
break;
|
659 |
-
case 'block':
|
660 |
-
list(, $child) = $prop;
|
661 |
-
$this->compileBlock($child);
|
662 |
-
break;
|
663 |
-
case 'mixin':
|
664 |
-
list(, $path, $args, $suffix) = $prop;
|
665 |
-
|
666 |
-
$orderedArgs = array();
|
667 |
-
$keywordArgs = array();
|
668 |
-
foreach ((array)$args as $arg) {
|
669 |
-
$argval = null;
|
670 |
-
switch ($arg[0]) {
|
671 |
-
case "arg":
|
672 |
-
if (!isset($arg[2])) {
|
673 |
-
$orderedArgs[] = $this->reduce(array("variable", $arg[1]));
|
674 |
-
} else {
|
675 |
-
$keywordArgs[$arg[1]] = $this->reduce($arg[2]);
|
676 |
-
}
|
677 |
-
break;
|
678 |
-
|
679 |
-
case "lit":
|
680 |
-
$orderedArgs[] = $this->reduce($arg[1]);
|
681 |
-
break;
|
682 |
-
default:
|
683 |
-
$this->throwError("Unknown arg type: " . $arg[0]);
|
684 |
-
}
|
685 |
-
}
|
686 |
-
|
687 |
-
$mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
|
688 |
-
|
689 |
-
if ($mixins === null) {
|
690 |
-
break; // throw error here??
|
691 |
-
}
|
692 |
-
|
693 |
-
foreach ($mixins as $mixin) {
|
694 |
-
if ($mixin === $block && !$orderedArgs) {
|
695 |
-
continue;
|
696 |
-
}
|
697 |
-
|
698 |
-
$haveScope = false;
|
699 |
-
if (isset($mixin->parent->scope)) {
|
700 |
-
$haveScope = true;
|
701 |
-
$mixinParentEnv = $this->pushEnv();
|
702 |
-
$mixinParentEnv->storeParent = $mixin->parent->scope;
|
703 |
-
}
|
704 |
-
|
705 |
-
$haveArgs = false;
|
706 |
-
if (isset($mixin->args)) {
|
707 |
-
$haveArgs = true;
|
708 |
-
$this->pushEnv();
|
709 |
-
$this->zipSetArgs($mixin->args, $orderedArgs, $keywordArgs);
|
710 |
-
}
|
711 |
-
|
712 |
-
$oldParent = $mixin->parent;
|
713 |
-
if ($mixin != $block) $mixin->parent = $block;
|
714 |
-
|
715 |
-
foreach ($this->sortProps($mixin->props) as $subProp) {
|
716 |
-
if ($suffix !== null &&
|
717 |
-
$subProp[0] == "assign" &&
|
718 |
-
is_string($subProp[1]) &&
|
719 |
-
$subProp[1]{0} != $this->vPrefix)
|
720 |
-
{
|
721 |
-
$subProp[2] = array(
|
722 |
-
'list', ' ',
|
723 |
-
array($subProp[2], array('keyword', $suffix))
|
724 |
-
);
|
725 |
-
}
|
726 |
-
|
727 |
-
$this->compileProp($subProp, $mixin, $out);
|
728 |
-
}
|
729 |
-
|
730 |
-
$mixin->parent = $oldParent;
|
731 |
-
|
732 |
-
if ($haveArgs) $this->popEnv();
|
733 |
-
if ($haveScope) $this->popEnv();
|
734 |
-
}
|
735 |
-
|
736 |
-
break;
|
737 |
-
case 'raw':
|
738 |
-
$out->lines[] = $prop[1];
|
739 |
-
break;
|
740 |
-
case "directive":
|
741 |
-
list(, $name, $value) = $prop;
|
742 |
-
$out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
|
743 |
-
break;
|
744 |
-
case "comment":
|
745 |
-
$out->lines[] = $prop[1];
|
746 |
-
break;
|
747 |
-
case "import";
|
748 |
-
list(, $importPath, $importId) = $prop;
|
749 |
-
$importPath = $this->reduce($importPath);
|
750 |
-
|
751 |
-
if (!isset($this->env->imports)) {
|
752 |
-
$this->env->imports = array();
|
753 |
-
}
|
754 |
-
|
755 |
-
$result = $this->tryImport($importPath, $block, $out);
|
756 |
-
|
757 |
-
$this->env->imports[$importId] = $result === false ?
|
758 |
-
array(false, "@import " . $this->compileValue($importPath).";") :
|
759 |
-
$result;
|
760 |
-
|
761 |
-
break;
|
762 |
-
case "import_mixin":
|
763 |
-
list(,$importId) = $prop;
|
764 |
-
$import = $this->env->imports[$importId];
|
765 |
-
if ($import[0] === false) {
|
766 |
-
if (isset($import[1])) {
|
767 |
-
$out->lines[] = $import[1];
|
768 |
-
}
|
769 |
-
} else {
|
770 |
-
list(, $bottom, $parser, $importDir) = $import;
|
771 |
-
$this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
|
772 |
-
}
|
773 |
-
|
774 |
-
break;
|
775 |
-
default:
|
776 |
-
$this->throwError("unknown op: {$prop[0]}\n");
|
777 |
-
}
|
778 |
-
}
|
779 |
-
|
780 |
-
|
781 |
-
/**
|
782 |
-
* Compiles a primitive value into a CSS property value.
|
783 |
-
*
|
784 |
-
* Values in lessphp are typed by being wrapped in arrays, their format is
|
785 |
-
* typically:
|
786 |
-
*
|
787 |
-
* array(type, contents [, additional_contents]*)
|
788 |
-
*
|
789 |
-
* The input is expected to be reduced. This function will not work on
|
790 |
-
* things like expressions and variables.
|
791 |
-
*/
|
792 |
-
protected function compileValue($value) {
|
793 |
-
switch ($value[0]) {
|
794 |
-
case 'list':
|
795 |
-
// [1] - delimiter
|
796 |
-
// [2] - array of values
|
797 |
-
return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
|
798 |
-
case 'raw_color':
|
799 |
-
if (!empty($this->formatter->compressColors)) {
|
800 |
-
return $this->compileValue($this->coerceColor($value));
|
801 |
-
}
|
802 |
-
return $value[1];
|
803 |
-
case 'keyword':
|
804 |
-
// [1] - the keyword
|
805 |
-
return $value[1];
|
806 |
-
case 'number':
|
807 |
-
list(, $num, $unit) = $value;
|
808 |
-
// [1] - the number
|
809 |
-
// [2] - the unit
|
810 |
-
if ($this->numberPrecision !== null) {
|
811 |
-
$num = round($num, $this->numberPrecision);
|
812 |
-
}
|
813 |
-
return $num . $unit;
|
814 |
-
case 'string':
|
815 |
-
// [1] - contents of string (includes quotes)
|
816 |
-
list(, $delim, $content) = $value;
|
817 |
-
foreach ($content as &$part) {
|
818 |
-
if (is_array($part)) {
|
819 |
-
$part = $this->compileValue($part);
|
820 |
-
}
|
821 |
-
}
|
822 |
-
return $delim . implode($content) . $delim;
|
823 |
-
case 'color':
|
824 |
-
// [1] - red component (either number or a %)
|
825 |
-
// [2] - green component
|
826 |
-
// [3] - blue component
|
827 |
-
// [4] - optional alpha component
|
828 |
-
list(, $r, $g, $b) = $value;
|
829 |
-
$r = round($r);
|
830 |
-
$g = round($g);
|
831 |
-
$b = round($b);
|
832 |
-
|
833 |
-
if (count($value) == 5 && $value[4] != 1) { // rgba
|
834 |
-
return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
|
835 |
-
}
|
836 |
-
|
837 |
-
$h = sprintf("#%02x%02x%02x", $r, $g, $b);
|
838 |
-
|
839 |
-
if (!empty($this->formatter->compressColors)) {
|
840 |
-
// Converting hex color to short notation (e.g. #003399 to #039)
|
841 |
-
if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
|
842 |
-
$h = '#' . $h[1] . $h[3] . $h[5];
|
843 |
-
}
|
844 |
-
}
|
845 |
-
|
846 |
-
return $h;
|
847 |
-
|
848 |
-
case 'function':
|
849 |
-
list(, $name, $args) = $value;
|
850 |
-
return $name.'('.$this->compileValue($args).')';
|
851 |
-
default: // assumed to be unit
|
852 |
-
$this->throwError("unknown value type: $value[0]");
|
853 |
-
}
|
854 |
-
}
|
855 |
-
|
856 |
-
protected function lib_pow($args) {
|
857 |
-
list($base, $exp) = $this->assertArgs($args, 2, "pow");
|
858 |
-
return pow($this->assertNumber($base), $this->assertNumber($exp));
|
859 |
-
}
|
860 |
-
|
861 |
-
protected function lib_pi() {
|
862 |
-
return pi();
|
863 |
-
}
|
864 |
-
|
865 |
-
protected function lib_mod($args) {
|
866 |
-
list($a, $b) = $this->assertArgs($args, 2, "mod");
|
867 |
-
return $this->assertNumber($a) % $this->assertNumber($b);
|
868 |
-
}
|
869 |
-
|
870 |
-
protected function lib_tan($num) {
|
871 |
-
return tan($this->assertNumber($num));
|
872 |
-
}
|
873 |
-
|
874 |
-
protected function lib_sin($num) {
|
875 |
-
return sin($this->assertNumber($num));
|
876 |
-
}
|
877 |
-
|
878 |
-
protected function lib_cos($num) {
|
879 |
-
return cos($this->assertNumber($num));
|
880 |
-
}
|
881 |
-
|
882 |
-
protected function lib_atan($num) {
|
883 |
-
$num = atan($this->assertNumber($num));
|
884 |
-
return array("number", $num, "rad");
|
885 |
-
}
|
886 |
-
|
887 |
-
protected function lib_asin($num) {
|
888 |
-
$num = asin($this->assertNumber($num));
|
889 |
-
return array("number", $num, "rad");
|
890 |
-
}
|
891 |
-
|
892 |
-
protected function lib_acos($num) {
|
893 |
-
$num = acos($this->assertNumber($num));
|
894 |
-
return array("number", $num, "rad");
|
895 |
-
}
|
896 |
-
|
897 |
-
protected function lib_sqrt($num) {
|
898 |
-
return sqrt($this->assertNumber($num));
|
899 |
-
}
|
900 |
-
|
901 |
-
protected function lib_extract($value) {
|
902 |
-
list($list, $idx) = $this->assertArgs($value, 2, "extract");
|
903 |
-
$idx = $this->assertNumber($idx);
|
904 |
-
// 1 indexed
|
905 |
-
if ($list[0] == "list" && isset($list[2][$idx - 1])) {
|
906 |
-
return $list[2][$idx - 1];
|
907 |
-
}
|
908 |
-
}
|
909 |
-
|
910 |
-
protected function lib_isnumber($value) {
|
911 |
-
return $this->toBool($value[0] == "number");
|
912 |
-
}
|
913 |
-
|
914 |
-
protected function lib_isstring($value) {
|
915 |
-
return $this->toBool($value[0] == "string");
|
916 |
-
}
|
917 |
-
|
918 |
-
protected function lib_iscolor($value) {
|
919 |
-
return $this->toBool($this->coerceColor($value));
|
920 |
-
}
|
921 |
-
|
922 |
-
protected function lib_iskeyword($value) {
|
923 |
-
return $this->toBool($value[0] == "keyword");
|
924 |
-
}
|
925 |
-
|
926 |
-
protected function lib_ispixel($value) {
|
927 |
-
return $this->toBool($value[0] == "number" && $value[2] == "px");
|
928 |
-
}
|
929 |
-
|
930 |
-
protected function lib_ispercentage($value) {
|
931 |
-
return $this->toBool($value[0] == "number" && $value[2] == "%");
|
932 |
-
}
|
933 |
-
|
934 |
-
protected function lib_isem($value) {
|
935 |
-
return $this->toBool($value[0] == "number" && $value[2] == "em");
|
936 |
-
}
|
937 |
-
|
938 |
-
protected function lib_isrem($value) {
|
939 |
-
return $this->toBool($value[0] == "number" && $value[2] == "rem");
|
940 |
-
}
|
941 |
-
|
942 |
-
protected function lib_rgbahex($color) {
|
943 |
-
$color = $this->coerceColor($color);
|
944 |
-
if (is_null($color))
|
945 |
-
$this->throwError("color expected for rgbahex");
|
946 |
-
|
947 |
-
return sprintf("#%02x%02x%02x%02x",
|
948 |
-
isset($color[4]) ? $color[4]*255 : 255,
|
949 |
-
$color[1],$color[2], $color[3]);
|
950 |
-
}
|
951 |
-
|
952 |
-
protected function lib_argb($color){
|
953 |
-
return $this->lib_rgbahex($color);
|
954 |
-
}
|
955 |
-
|
956 |
-
// utility func to unquote a string
|
957 |
-
// use func_get_arg to prevent Theme Checker triggering unrelated translation warning.
|
958 |
-
protected function lib_e() {
|
959 |
-
$arg = func_get_arg(0);
|
960 |
-
switch ($arg[0]) {
|
961 |
-
case "list":
|
962 |
-
$items = $arg[2];
|
963 |
-
if (isset($items[0])) {
|
964 |
-
return $this->lib_unquote($items[0]);
|
965 |
-
}
|
966 |
-
return self::$defaultValue;
|
967 |
-
case "string":
|
968 |
-
$arg[1] = "";
|
969 |
-
return $arg;
|
970 |
-
case "keyword":
|
971 |
-
return $arg;
|
972 |
-
default:
|
973 |
-
return array("keyword", $this->compileValue($arg));
|
974 |
-
}
|
975 |
-
}
|
976 |
-
|
977 |
-
// use func_get_arg to prevent Theme Checker triggering unrelated translation warning.
|
978 |
-
protected function lib_unquote($arg) {
|
979 |
-
return $this->lib_e(func_get_arg(0));
|
980 |
-
}
|
981 |
-
|
982 |
-
protected function lib__sprintf($args) {
|
983 |
-
if ($args[0] != "list") return $args;
|
984 |
-
$values = $args[2];
|
985 |
-
$string = array_shift($values);
|
986 |
-
$template = $this->compileValue($this->lib_unquote($string));
|
987 |
-
|
988 |
-
$i = 0;
|
989 |
-
if (preg_match_all('/%[dsa]/', $template, $m)) {
|
990 |
-
foreach ($m[0] as $match) {
|
991 |
-
$val = isset($values[$i]) ?
|
992 |
-
$this->reduce($values[$i]) : array('keyword', '');
|
993 |
-
|
994 |
-
// lessjs compat, renders fully expanded color, not raw color
|
995 |
-
if ($color = $this->coerceColor($val)) {
|
996 |
-
$val = $color;
|
997 |
-
}
|
998 |
-
|
999 |
-
$i++;
|
1000 |
-
$rep = $this->compileValue($this->lib_unquote($val));
|
1001 |
-
$template = preg_replace('/'.self::preg_quote($match).'/',
|
1002 |
-
$rep, $template, 1);
|
1003 |
-
}
|
1004 |
-
}
|
1005 |
-
|
1006 |
-
$d = $string[0] == "string" ? $string[1] : '"';
|
1007 |
-
return array("string", $d, array($template));
|
1008 |
-
}
|
1009 |
-
|
1010 |
-
protected function lib_floor($arg) {
|
1011 |
-
$value = $this->assertNumber($arg);
|
1012 |
-
return array("number", floor($value), $arg[2]);
|
1013 |
-
}
|
1014 |
-
|
1015 |
-
protected function lib_ceil($arg) {
|
1016 |
-
$value = $this->assertNumber($arg);
|
1017 |
-
return array("number", ceil($value), $arg[2]);
|
1018 |
-
}
|
1019 |
-
|
1020 |
-
protected function lib_round($arg) {
|
1021 |
-
$value = $this->assertNumber($arg);
|
1022 |
-
return array("number", round($value), $arg[2]);
|
1023 |
-
}
|
1024 |
-
|
1025 |
-
protected function lib_unit($arg) {
|
1026 |
-
if ($arg[0] == "list") {
|
1027 |
-
list($number, $newUnit) = $arg[2];
|
1028 |
-
return array("number", $this->assertNumber($number),
|
1029 |
-
$this->compileValue($this->lib_unquote($newUnit)));
|
1030 |
-
} else {
|
1031 |
-
return array("number", $this->assertNumber($arg), "");
|
1032 |
-
}
|
1033 |
-
}
|
1034 |
-
|
1035 |
-
/**
|
1036 |
-
* Helper function to get arguments for color manipulation functions.
|
1037 |
-
* takes a list that contains a color like thing and a percentage
|
1038 |
-
*/
|
1039 |
-
protected function colorArgs($args) {
|
1040 |
-
if ($args[0] != 'list' || count($args[2]) < 2) {
|
1041 |
-
return array(array('color', 0, 0, 0), 0);
|
1042 |
-
}
|
1043 |
-
list($color, $delta) = $args[2];
|
1044 |
-
$color = $this->assertColor($color);
|
1045 |
-
$delta = floatval($delta[1]);
|
1046 |
-
|
1047 |
-
return array($color, $delta);
|
1048 |
-
}
|
1049 |
-
|
1050 |
-
protected function lib_darken($args) {
|
1051 |
-
list($color, $delta) = $this->colorArgs($args);
|
1052 |
-
|
1053 |
-
$hsl = $this->toHSL($color);
|
1054 |
-
$hsl[3] = $this->clamp($hsl[3] - $delta, 100);
|
1055 |
-
return $this->toRGB($hsl);
|
1056 |
-
}
|
1057 |
-
|
1058 |
-
protected function lib_lighten($args) {
|
1059 |
-
list($color, $delta) = $this->colorArgs($args);
|
1060 |
-
|
1061 |
-
$hsl = $this->toHSL($color);
|
1062 |
-
$hsl[3] = $this->clamp($hsl[3] + $delta, 100);
|
1063 |
-
return $this->toRGB($hsl);
|
1064 |
-
}
|
1065 |
-
|
1066 |
-
protected function lib_saturate($args) {
|
1067 |
-
list($color, $delta) = $this->colorArgs($args);
|
1068 |
-
|
1069 |
-
$hsl = $this->toHSL($color);
|
1070 |
-
$hsl[2] = $this->clamp($hsl[2] + $delta, 100);
|
1071 |
-
return $this->toRGB($hsl);
|
1072 |
-
}
|
1073 |
-
|
1074 |
-
protected function lib_desaturate($args) {
|
1075 |
-
list($color, $delta) = $this->colorArgs($args);
|
1076 |
-
|
1077 |
-
$hsl = $this->toHSL($color);
|
1078 |
-
$hsl[2] = $this->clamp($hsl[2] - $delta, 100);
|
1079 |
-
return $this->toRGB($hsl);
|
1080 |
-
}
|
1081 |
-
|
1082 |
-
protected function lib_spin($args) {
|
1083 |
-
list($color, $delta) = $this->colorArgs($args);
|
1084 |
-
|
1085 |
-
$hsl = $this->toHSL($color);
|
1086 |
-
|
1087 |
-
$hsl[1] = $hsl[1] + $delta % 360;
|
1088 |
-
if ($hsl[1] < 0) $hsl[1] += 360;
|
1089 |
-
|
1090 |
-
return $this->toRGB($hsl);
|
1091 |
-
}
|
1092 |
-
|
1093 |
-
protected function lib_fadeout($args) {
|
1094 |
-
list($color, $delta) = $this->colorArgs($args);
|
1095 |
-
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100);
|
1096 |
-
return $color;
|
1097 |
-
}
|
1098 |
-
|
1099 |
-
protected function lib_fadein($args) {
|
1100 |
-
list($color, $delta) = $this->colorArgs($args);
|
1101 |
-
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100);
|
1102 |
-
return $color;
|
1103 |
-
}
|
1104 |
-
|
1105 |
-
protected function lib_hue($color) {
|
1106 |
-
$hsl = $this->toHSL($this->assertColor($color));
|
1107 |
-
return round($hsl[1]);
|
1108 |
-
}
|
1109 |
-
|
1110 |
-
protected function lib_saturation($color) {
|
1111 |
-
$hsl = $this->toHSL($this->assertColor($color));
|
1112 |
-
return round($hsl[2]);
|
1113 |
-
}
|
1114 |
-
|
1115 |
-
protected function lib_lightness($color) {
|
1116 |
-
$hsl = $this->toHSL($this->assertColor($color));
|
1117 |
-
return round($hsl[3]);
|
1118 |
-
}
|
1119 |
-
|
1120 |
-
// get the alpha of a color
|
1121 |
-
// defaults to 1 for non-colors or colors without an alpha
|
1122 |
-
protected function lib_alpha($value) {
|
1123 |
-
if (!is_null($color = $this->coerceColor($value))) {
|
1124 |
-
return isset($color[4]) ? $color[4] : 1;
|
1125 |
-
}
|
1126 |
-
}
|
1127 |
-
|
1128 |
-
// set the alpha of the color
|
1129 |
-
protected function lib_fade($args) {
|
1130 |
-
list($color, $alpha) = $this->colorArgs($args);
|
1131 |
-
$color[4] = $this->clamp($alpha / 100.0);
|
1132 |
-
return $color;
|
1133 |
-
}
|
1134 |
-
|
1135 |
-
protected function lib_percentage($arg) {
|
1136 |
-
$num = $this->assertNumber($arg);
|
1137 |
-
return array("number", $num*100, "%");
|
1138 |
-
}
|
1139 |
-
|
1140 |
-
// mixes two colors by weight
|
1141 |
-
// mix(@color1, @color2, [@weight: 50%]);
|
1142 |
-
// http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
|
1143 |
-
protected function lib_mix($args) {
|
1144 |
-
if ($args[0] != "list" || count($args[2]) < 2)
|
1145 |
-
$this->throwError("mix expects (color1, color2, weight)");
|
1146 |
-
|
1147 |
-
list($first, $second) = $args[2];
|
1148 |
-
$first = $this->assertColor($first);
|
1149 |
-
$second = $this->assertColor($second);
|
1150 |
-
|
1151 |
-
$first_a = $this->lib_alpha($first);
|
1152 |
-
$second_a = $this->lib_alpha($second);
|
1153 |
-
|
1154 |
-
if (isset($args[2][2])) {
|
1155 |
-
$weight = $args[2][2][1] / 100.0;
|
1156 |
-
} else {
|
1157 |
-
$weight = 0.5;
|
1158 |
-
}
|
1159 |
-
|
1160 |
-
$w = $weight * 2 - 1;
|
1161 |
-
$a = $first_a - $second_a;
|
1162 |
-
|
1163 |
-
$w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
|
1164 |
-
$w2 = 1.0 - $w1;
|
1165 |
-
|
1166 |
-
$new = array('color',
|
1167 |
-
$w1 * $first[1] + $w2 * $second[1],
|
1168 |
-
$w1 * $first[2] + $w2 * $second[2],
|
1169 |
-
$w1 * $first[3] + $w2 * $second[3],
|
1170 |
-
);
|
1171 |
-
|
1172 |
-
if ($first_a != 1.0 || $second_a != 1.0) {
|
1173 |
-
$new[] = $first_a * $weight + $second_a * ($weight - 1);
|
1174 |
-
}
|
1175 |
-
|
1176 |
-
return $this->fixColor($new);
|
1177 |
-
}
|
1178 |
-
|
1179 |
-
protected function lib_contrast($args) {
|
1180 |
-
if ($args[0] != 'list' || count($args[2]) < 3) {
|
1181 |
-
return array(array('color', 0, 0, 0), 0);
|
1182 |
-
}
|
1183 |
-
|
1184 |
-
list($inputColor, $darkColor, $lightColor) = $args[2];
|
1185 |
-
|
1186 |
-
$inputColor = $this->assertColor($inputColor);
|
1187 |
-
$darkColor = $this->assertColor($darkColor);
|
1188 |
-
$lightColor = $this->assertColor($lightColor);
|
1189 |
-
$hsl = $this->toHSL($inputColor);
|
1190 |
-
|
1191 |
-
if ($hsl[3] > 50) {
|
1192 |
-
return $darkColor;
|
1193 |
-
}
|
1194 |
-
|
1195 |
-
return $lightColor;
|
1196 |
-
}
|
1197 |
-
|
1198 |
-
protected function assertColor($value, $error = "expected color value") {
|
1199 |
-
$color = $this->coerceColor($value);
|
1200 |
-
if (is_null($color)) $this->throwError($error);
|
1201 |
-
return $color;
|
1202 |
-
}
|
1203 |
-
|
1204 |
-
protected function assertNumber($value, $error = "expecting number") {
|
1205 |
-
if ($value[0] == "number") return $value[1];
|
1206 |
-
$this->throwError($error);
|
1207 |
-
}
|
1208 |
-
|
1209 |
-
protected function assertArgs($value, $expectedArgs, $name="") {
|
1210 |
-
if ($expectedArgs == 1) {
|
1211 |
-
return $value;
|
1212 |
-
} else {
|
1213 |
-
if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
|
1214 |
-
$values = $value[2];
|
1215 |
-
$numValues = count($values);
|
1216 |
-
if ($expectedArgs != $numValues) {
|
1217 |
-
if ($name) {
|
1218 |
-
$name = $name . ": ";
|
1219 |
-
}
|
1220 |
-
|
1221 |
-
$this->throwError("${name}expecting $expectedArgs arguments, got $numValues");
|
1222 |
-
}
|
1223 |
-
|
1224 |
-
return $values;
|
1225 |
-
}
|
1226 |
-
}
|
1227 |
-
|
1228 |
-
protected function toHSL($color) {
|
1229 |
-
if ($color[0] == 'hsl') return $color;
|
1230 |
-
|
1231 |
-
$r = $color[1] / 255;
|
1232 |
-
$g = $color[2] / 255;
|
1233 |
-
$b = $color[3] / 255;
|
1234 |
-
|
1235 |
-
$min = min($r, $g, $b);
|
1236 |
-
$max = max($r, $g, $b);
|
1237 |
-
|
1238 |
-
$L = ($min + $max) / 2;
|
1239 |
-
if ($min == $max) {
|
1240 |
-
$S = $H = 0;
|
1241 |
-
} else {
|
1242 |
-
if ($L < 0.5)
|
1243 |
-
$S = ($max - $min)/($max + $min);
|
1244 |
-
else
|
1245 |
-
$S = ($max - $min)/(2.0 - $max - $min);
|
1246 |
-
|
1247 |
-
if ($r == $max) $H = ($g - $b)/($max - $min);
|
1248 |
-
elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
|
1249 |
-
elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
|
1250 |
-
|
1251 |
-
}
|
1252 |
-
|
1253 |
-
$out = array('hsl',
|
1254 |
-
($H < 0 ? $H + 6 : $H)*60,
|
1255 |
-
$S*100,
|
1256 |
-
$L*100,
|
1257 |
-
);
|
1258 |
-
|
1259 |
-
if (count($color) > 4) $out[] = $color[4]; // copy alpha
|
1260 |
-
return $out;
|
1261 |
-
}
|
1262 |
-
|
1263 |
-
protected function toRGB_helper($comp, $temp1, $temp2) {
|
1264 |
-
if ($comp < 0) $comp += 1.0;
|
1265 |
-
elseif ($comp > 1) $comp -= 1.0;
|
1266 |
-
|
1267 |
-
if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
|
1268 |
-
if (2 * $comp < 1) return $temp2;
|
1269 |
-
if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
|
1270 |
-
|
1271 |
-
return $temp1;
|
1272 |
-
}
|
1273 |
-
|
1274 |
-
/**
|
1275 |
-
* Converts a hsl array into a color value in rgb.
|
1276 |
-
* Expects H to be in range of 0 to 360, S and L in 0 to 100
|
1277 |
-
*/
|
1278 |
-
protected function toRGB($color) {
|
1279 |
-
if ($color[0] == 'color') return $color;
|
1280 |
-
|
1281 |
-
$H = $color[1] / 360;
|
1282 |
-
$S = $color[2] / 100;
|
1283 |
-
$L = $color[3] / 100;
|
1284 |
-
|
1285 |
-
if ($S == 0) {
|
1286 |
-
$r = $g = $b = $L;
|
1287 |
-
} else {
|
1288 |
-
$temp2 = $L < 0.5 ?
|
1289 |
-
$L*(1.0 + $S) :
|
1290 |
-
$L + $S - $L * $S;
|
1291 |
-
|
1292 |
-
$temp1 = 2.0 * $L - $temp2;
|
1293 |
-
|
1294 |
-
$r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
|
1295 |
-
$g = $this->toRGB_helper($H, $temp1, $temp2);
|
1296 |
-
$b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
|
1297 |
-
}
|
1298 |
-
|
1299 |
-
// $out = array('color', round($r*255), round($g*255), round($b*255));
|
1300 |
-
$out = array('color', $r*255, $g*255, $b*255);
|
1301 |
-
if (count($color) > 4) $out[] = $color[4]; // copy alpha
|
1302 |
-
return $out;
|
1303 |
-
}
|
1304 |
-
|
1305 |
-
protected function clamp($v, $max = 1, $min = 0) {
|
1306 |
-
return min($max, max($min, $v));
|
1307 |
-
}
|
1308 |
-
|
1309 |
-
/**
|
1310 |
-
* Convert the rgb, rgba, hsl color literals of function type
|
1311 |
-
* as returned by the parser into values of color type.
|
1312 |
-
*/
|
1313 |
-
protected function funcToColor($func) {
|
1314 |
-
$fname = $func[1];
|
1315 |
-
if ($func[2][0] != 'list') return false; // need a list of arguments
|
1316 |
-
$rawComponents = $func[2][2];
|
1317 |
-
|
1318 |
-
if ($fname == 'hsl' || $fname == 'hsla') {
|
1319 |
-
$hsl = array('hsl');
|
1320 |
-
$i = 0;
|
1321 |
-
foreach ($rawComponents as $c) {
|
1322 |
-
$val = $this->reduce($c);
|
1323 |
-
$val = isset($val[1]) ? floatval($val[1]) : 0;
|
1324 |
-
|
1325 |
-
if ($i == 0) $clamp = 360;
|
1326 |
-
elseif ($i < 3) $clamp = 100;
|
1327 |
-
else $clamp = 1;
|
1328 |
-
|
1329 |
-
$hsl[] = $this->clamp($val, $clamp);
|
1330 |
-
$i++;
|
1331 |
-
}
|
1332 |
-
|
1333 |
-
while (count($hsl) < 4) $hsl[] = 0;
|
1334 |
-
return $this->toRGB($hsl);
|
1335 |
-
|
1336 |
-
} elseif ($fname == 'rgb' || $fname == 'rgba') {
|
1337 |
-
$components = array();
|
1338 |
-
$i = 1;
|
1339 |
-
foreach ($rawComponents as $c) {
|
1340 |
-
$c = $this->reduce($c);
|
1341 |
-
if ($i < 4) {
|
1342 |
-
if ($c[0] == "number" && $c[2] == "%") {
|
1343 |
-
$components[] = 255 * ($c[1] / 100);
|
1344 |
-
} else {
|
1345 |
-
$components[] = floatval($c[1]);
|
1346 |
-
}
|
1347 |
-
} elseif ($i == 4) {
|
1348 |
-
if ($c[0] == "number" && $c[2] == "%") {
|
1349 |
-
$components[] = 1.0 * ($c[1] / 100);
|
1350 |
-
} else {
|
1351 |
-
$components[] = floatval($c[1]);
|
1352 |
-
}
|
1353 |
-
} else break;
|
1354 |
-
|
1355 |
-
$i++;
|
1356 |
-
}
|
1357 |
-
while (count($components) < 3) $components[] = 0;
|
1358 |
-
array_unshift($components, 'color');
|
1359 |
-
return $this->fixColor($components);
|
1360 |
-
}
|
1361 |
-
|
1362 |
-
return false;
|
1363 |
-
}
|
1364 |
-
|
1365 |
-
protected function reduce($value, $forExpression = false) {
|
1366 |
-
switch ($value[0]) {
|
1367 |
-
case "interpolate":
|
1368 |
-
$reduced = $this->reduce($value[1]);
|
1369 |
-
$var = $this->compileValue($reduced);
|
1370 |
-
$res = $this->reduce(array("variable", $this->vPrefix . $var));
|
1371 |
-
|
1372 |
-
if ($res[0] == "raw_color") {
|
1373 |
-
$res = $this->coerceColor($res);
|
1374 |
-
}
|
1375 |
-
|
1376 |
-
if (empty($value[2])) $res = $this->lib_unquote($res);
|
1377 |
-
|
1378 |
-
return $res;
|
1379 |
-
case "variable":
|
1380 |
-
$key = $value[1];
|
1381 |
-
if (is_array($key)) {
|
1382 |
-
$key = $this->reduce($key);
|
1383 |
-
$key = $this->vPrefix . $this->compileValue($this->lib_unquote($key));
|
1384 |
-
}
|
1385 |
-
|
1386 |
-
$seen =& $this->env->seenNames;
|
1387 |
-
|
1388 |
-
if (!empty($seen[$key])) {
|
1389 |
-
$this->throwError("infinite loop detected: $key");
|
1390 |
-
}
|
1391 |
-
|
1392 |
-
$seen[$key] = true;
|
1393 |
-
$out = $this->reduce($this->get($key, self::$defaultValue));
|
1394 |
-
$seen[$key] = false;
|
1395 |
-
return $out;
|
1396 |
-
case "list":
|
1397 |
-
foreach ($value[2] as &$item) {
|
1398 |
-
$item = $this->reduce($item, $forExpression);
|
1399 |
-
}
|
1400 |
-
return $value;
|
1401 |
-
case "expression":
|
1402 |
-
return $this->evaluate($value);
|
1403 |
-
case "string":
|
1404 |
-
foreach ($value[2] as &$part) {
|
1405 |
-
if (is_array($part)) {
|
1406 |
-
$strip = $part[0] == "variable";
|
1407 |
-
$part = $this->reduce($part);
|
1408 |
-
if ($strip) $part = $this->lib_unquote($part);
|
1409 |
-
}
|
1410 |
-
}
|
1411 |
-
return $value;
|
1412 |
-
case "escape":
|
1413 |
-
list(,$inner) = $value;
|
1414 |
-
return $this->lib_unquote($this->reduce($inner));
|
1415 |
-
case "function":
|
1416 |
-
$color = $this->funcToColor($value);
|
1417 |
-
if ($color) return $color;
|
1418 |
-
|
1419 |
-
list(, $name, $args) = $value;
|
1420 |
-
if ($name == "%") $name = "_sprintf";
|
1421 |
-
$f = isset($this->libFunctions[$name]) ?
|
1422 |
-
$this->libFunctions[$name] : array($this, 'lib_'.$name);
|
1423 |
-
|
1424 |
-
if (is_callable($f)) {
|
1425 |
-
if ($args[0] == 'list')
|
1426 |
-
$args = self::compressList($args[2], $args[1]);
|
1427 |
-
|
1428 |
-
$ret = call_user_func($f, $this->reduce($args, true), $this);
|
1429 |
-
|
1430 |
-
if (is_null($ret)) {
|
1431 |
-
return array("string", "", array(
|
1432 |
-
$name, "(", $args, ")"
|
1433 |
-
));
|
1434 |
-
}
|
1435 |
-
|
1436 |
-
// convert to a typed value if the result is a php primitive
|
1437 |
-
if (is_numeric($ret)) $ret = array('number', $ret, "");
|
1438 |
-
elseif (!is_array($ret)) $ret = array('keyword', $ret);
|
1439 |
-
|
1440 |
-
return $ret;
|
1441 |
-
}
|
1442 |
-
|
1443 |
-
// plain function, reduce args
|
1444 |
-
$value[2] = $this->reduce($value[2]);
|
1445 |
-
return $value;
|
1446 |
-
case "unary":
|
1447 |
-
list(, $op, $exp) = $value;
|
1448 |
-
$exp = $this->reduce($exp);
|
1449 |
-
|
1450 |
-
if ($exp[0] == "number") {
|
1451 |
-
switch ($op) {
|
1452 |
-
case "+":
|
1453 |
-
return $exp;
|
1454 |
-
case "-":
|
1455 |
-
$exp[1] *= -1;
|
1456 |
-
return $exp;
|
1457 |
-
}
|
1458 |
-
}
|
1459 |
-
return array("string", "", array($op, $exp));
|
1460 |
-
}
|
1461 |
-
|
1462 |
-
if ($forExpression) {
|
1463 |
-
switch ($value[0]) {
|
1464 |
-
case "keyword":
|
1465 |
-
if ($color = $this->coerceColor($value)) {
|
1466 |
-
return $color;
|
1467 |
-
}
|
1468 |
-
break;
|
1469 |
-
case "raw_color":
|
1470 |
-
return $this->coerceColor($value);
|
1471 |
-
}
|
1472 |
-
}
|
1473 |
-
|
1474 |
-
return $value;
|
1475 |
-
}
|
1476 |
-
|
1477 |
-
|
1478 |
-
// coerce a value for use in color operation
|
1479 |
-
protected function coerceColor($value) {
|
1480 |
-
switch($value[0]) {
|
1481 |
-
case 'color': return $value;
|
1482 |
-
case 'raw_color':
|
1483 |
-
$c = array("color", 0, 0, 0);
|
1484 |
-
$colorStr = substr($value[1], 1);
|
1485 |
-
$num = hexdec($colorStr);
|
1486 |
-
$width = strlen($colorStr) == 3 ? 16 : 256;
|
1487 |
-
|
1488 |
-
for ($i = 3; $i > 0; $i--) { // 3 2 1
|
1489 |
-
$t = $num % $width;
|
1490 |
-
$num /= $width;
|
1491 |
-
|
1492 |
-
$c[$i] = $t * (256/$width) + $t * floor(16/$width);
|
1493 |
-
}
|
1494 |
-
|
1495 |
-
return $c;
|
1496 |
-
case 'keyword':
|
1497 |
-
$name = $value[1];
|
1498 |
-
if (isset(self::$cssColors[$name])) {
|
1499 |
-
$rgba = explode(',', self::$cssColors[$name]);
|
1500 |
-
|
1501 |
-
if(isset($rgba[3]))
|
1502 |
-
return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
|
1503 |
-
|
1504 |
-
return array('color', $rgba[0], $rgba[1], $rgba[2]);
|
1505 |
-
}
|
1506 |
-
return null;
|
1507 |
-
}
|
1508 |
-
}
|
1509 |
-
|
1510 |
-
// make something string like into a string
|
1511 |
-
protected function coerceString($value) {
|
1512 |
-
switch ($value[0]) {
|
1513 |
-
case "string":
|
1514 |
-
return $value;
|
1515 |
-
case "keyword":
|
1516 |
-
return array("string", "", array($value[1]));
|
1517 |
-
}
|
1518 |
-
return null;
|
1519 |
-
}
|
1520 |
-
|
1521 |
-
// turn list of length 1 into value type
|
1522 |
-
protected function flattenList($value) {
|
1523 |
-
if ($value[0] == "list" && count($value[2]) == 1) {
|
1524 |
-
return $this->flattenList($value[2][0]);
|
1525 |
-
}
|
1526 |
-
return $value;
|
1527 |
-
}
|
1528 |
-
|
1529 |
-
protected function toBool($a) {
|
1530 |
-
if ($a) return self::$TRUE;
|
1531 |
-
else return self::$FALSE;
|
1532 |
-
}
|
1533 |
-
|
1534 |
-
// evaluate an expression
|
1535 |
-
protected function evaluate($exp) {
|
1536 |
-
list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
|
1537 |
-
|
1538 |
-
$left = $this->reduce($left, true);
|
1539 |
-
$right = $this->reduce($right, true);
|
1540 |
-
|
1541 |
-
if ($leftColor = $this->coerceColor($left)) {
|
1542 |
-
$left = $leftColor;
|
1543 |
-
}
|
1544 |
-
|
1545 |
-
if ($rightColor = $this->coerceColor($right)) {
|
1546 |
-
$right = $rightColor;
|
1547 |
-
}
|
1548 |
-
|
1549 |
-
$ltype = $left[0];
|
1550 |
-
$rtype = $right[0];
|
1551 |
-
|
1552 |
-
// operators that work on all types
|
1553 |
-
if ($op == "and") {
|
1554 |
-
return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
|
1555 |
-
}
|
1556 |
-
|
1557 |
-
if ($op == "=") {
|
1558 |
-
return $this->toBool($this->eq($left, $right) );
|
1559 |
-
}
|
1560 |
-
|
1561 |
-
if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
|
1562 |
-
return $str;
|
1563 |
-
}
|
1564 |
-
|
1565 |
-
// type based operators
|
1566 |
-
$fname = "op_${ltype}_${rtype}";
|
1567 |
-
if (is_callable(array($this, $fname))) {
|
1568 |
-
$out = $this->$fname($op, $left, $right);
|
1569 |
-
if (!is_null($out)) return $out;
|
1570 |
-
}
|
1571 |
-
|
1572 |
-
// make the expression look it did before being parsed
|
1573 |
-
$paddedOp = $op;
|
1574 |
-
if ($whiteBefore) $paddedOp = " " . $paddedOp;
|
1575 |
-
if ($whiteAfter) $paddedOp .= " ";
|
1576 |
-
|
1577 |
-
return array("string", "", array($left, $paddedOp, $right));
|
1578 |
-
}
|
1579 |
-
|
1580 |
-
protected function stringConcatenate($left, $right) {
|
1581 |
-
if ($strLeft = $this->coerceString($left)) {
|
1582 |
-
if ($right[0] == "string") {
|
1583 |
-
$right[1] = "";
|
1584 |
-
}
|
1585 |
-
$strLeft[2][] = $right;
|
1586 |
-
return $strLeft;
|
1587 |
-
}
|
1588 |
-
|
1589 |
-
if ($strRight = $this->coerceString($right)) {
|
1590 |
-
array_unshift($strRight[2], $left);
|
1591 |
-
return $strRight;
|
1592 |
-
}
|
1593 |
-
}
|
1594 |
-
|
1595 |
-
|
1596 |
-
// make sure a color's components don't go out of bounds
|
1597 |
-
protected function fixColor($c) {
|
1598 |
-
foreach (range(1, 3) as $i) {
|
1599 |
-
if ($c[$i] < 0) $c[$i] = 0;
|
1600 |
-
if ($c[$i] > 255) $c[$i] = 255;
|
1601 |
-
}
|
1602 |
-
|
1603 |
-
return $c;
|
1604 |
-
}
|
1605 |
-
|
1606 |
-
protected function op_number_color($op, $lft, $rgt) {
|
1607 |
-
if ($op == '+' || $op == '*') {
|
1608 |
-
return $this->op_color_number($op, $rgt, $lft);
|
1609 |
-
}
|
1610 |
-
}
|
1611 |
-
|
1612 |
-
protected function op_color_number($op, $lft, $rgt) {
|
1613 |
-
if ($rgt[0] == '%') $rgt[1] /= 100;
|
1614 |
-
|
1615 |
-
return $this->op_color_color($op, $lft,
|
1616 |
-
array_fill(1, count($lft) - 1, $rgt[1]));
|
1617 |
-
}
|
1618 |
-
|
1619 |
-
protected function op_color_color($op, $left, $right) {
|
1620 |
-
$out = array('color');
|
1621 |
-
$max = count($left) > count($right) ? count($left) : count($right);
|
1622 |
-
foreach (range(1, $max - 1) as $i) {
|
1623 |
-
$lval = isset($left[$i]) ? $left[$i] : 0;
|
1624 |
-
$rval = isset($right[$i]) ? $right[$i] : 0;
|
1625 |
-
switch ($op) {
|
1626 |
-
case '+':
|
1627 |
-
$out[] = $lval + $rval;
|
1628 |
-
break;
|
1629 |
-
case '-':
|
1630 |
-
$out[] = $lval - $rval;
|
1631 |
-
break;
|
1632 |
-
case '*':
|
1633 |
-
$out[] = $lval * $rval;
|
1634 |
-
break;
|
1635 |
-
case '%':
|
1636 |
-
$out[] = $lval % $rval;
|
1637 |
-
break;
|
1638 |
-
case '/':
|
1639 |
-
if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
|
1640 |
-
$out[] = $lval / $rval;
|
1641 |
-
break;
|
1642 |
-
default:
|
1643 |
-
$this->throwError('evaluate error: color op number failed on op '.$op);
|
1644 |
-
}
|
1645 |
-
}
|
1646 |
-
return $this->fixColor($out);
|
1647 |
-
}
|
1648 |
-
|
1649 |
-
function lib_red($color){
|
1650 |
-
$color = $this->coerceColor($color);
|
1651 |
-
if (is_null($color)) {
|
1652 |
-
$this->throwError('color expected for red()');
|
1653 |
-
}
|
1654 |
-
|
1655 |
-
return $color[1];
|
1656 |
-
}
|
1657 |
-
|
1658 |
-
function lib_green($color){
|
1659 |
-
$color = $this->coerceColor($color);
|
1660 |
-
if (is_null($color)) {
|
1661 |
-
$this->throwError('color expected for green()');
|
1662 |
-
}
|
1663 |
-
|
1664 |
-
return $color[2];
|
1665 |
-
}
|
1666 |
-
|
1667 |
-
function lib_blue($color){
|
1668 |
-
$color = $this->coerceColor($color);
|
1669 |
-
if (is_null($color)) {
|
1670 |
-
$this->throwError('color expected for blue()');
|
1671 |
-
}
|
1672 |
-
|
1673 |
-
return $color[3];
|
1674 |
-
}
|
1675 |
-
|
1676 |
-
|
1677 |
-
// operator on two numbers
|
1678 |
-
protected function op_number_number($op, $left, $right) {
|
1679 |
-
$unit = empty($left[2]) ? $right[2] : $left[2];
|
1680 |
-
|
1681 |
-
$value = 0;
|
1682 |
-
switch ($op) {
|
1683 |
-
case '+':
|
1684 |
-
$value = $left[1] + $right[1];
|
1685 |
-
break;
|
1686 |
-
case '*':
|
1687 |
-
$value = $left[1] * $right[1];
|
1688 |
-
break;
|
1689 |
-
case '-':
|
1690 |
-
$value = $left[1] - $right[1];
|
1691 |
-
break;
|
1692 |
-
case '%':
|
1693 |
-
$value = $left[1] % $right[1];
|
1694 |
-
break;
|
1695 |
-
case '/':
|
1696 |
-
if ($right[1] == 0) $this->throwError('parse error: divide by zero');
|
1697 |
-
$value = $left[1] / $right[1];
|
1698 |
-
break;
|
1699 |
-
case '<':
|
1700 |
-
return $this->toBool($left[1] < $right[1]);
|
1701 |
-
case '>':
|
1702 |
-
return $this->toBool($left[1] > $right[1]);
|
1703 |
-
case '>=':
|
1704 |
-
return $this->toBool($left[1] >= $right[1]);
|
1705 |
-
case '=<':
|
1706 |
-
return $this->toBool($left[1] <= $right[1]);
|
1707 |
-
default:
|
1708 |
-
$this->throwError('parse error: unknown number operator: '.$op);
|
1709 |
-
}
|
1710 |
-
|
1711 |
-
return array("number", $value, $unit);
|
1712 |
-
}
|
1713 |
-
|
1714 |
-
|
1715 |
-
/* environment functions */
|
1716 |
-
|
1717 |
-
protected function makeOutputBlock($type, $selectors = null) {
|
1718 |
-
$b = new stdclass;
|
1719 |
-
$b->lines = array();
|
1720 |
-
$b->children = array();
|
1721 |
-
$b->selectors = $selectors;
|
1722 |
-
$b->type = $type;
|
1723 |
-
$b->parent = $this->scope;
|
1724 |
-
return $b;
|
1725 |
-
}
|
1726 |
-
|
1727 |
-
// the state of execution
|
1728 |
-
protected function pushEnv($block = null) {
|
1729 |
-
$e = new stdclass;
|
1730 |
-
$e->parent = $this->env;
|
1731 |
-
$e->store = array();
|
1732 |
-
$e->block = $block;
|
1733 |
-
|
1734 |
-
$this->env = $e;
|
1735 |
-
return $e;
|
1736 |
-
}
|
1737 |
-
|
1738 |
-
// pop something off the stack
|
1739 |
-
protected function popEnv() {
|
1740 |
-
$old = $this->env;
|
1741 |
-
$this->env = $this->env->parent;
|
1742 |
-
return $old;
|
1743 |
-
}
|
1744 |
-
|
1745 |
-
// set something in the current env
|
1746 |
-
protected function set($name, $value) {
|
1747 |
-
$this->env->store[$name] = $value;
|
1748 |
-
}
|
1749 |
-
|
1750 |
-
|
1751 |
-
// get the highest occurrence entry for a name
|
1752 |
-
protected function get($name, $default=null) {
|
1753 |
-
$current = $this->env;
|
1754 |
-
|
1755 |
-
$isArguments = $name == $this->vPrefix . 'arguments';
|
1756 |
-
while ($current) {
|
1757 |
-
if ($isArguments && isset($current->arguments)) {
|
1758 |
-
return array('list', ' ', $current->arguments);
|
1759 |
-
}
|
1760 |
-
|
1761 |
-
if (isset($current->store[$name]))
|
1762 |
-
return $current->store[$name];
|
1763 |
-
else {
|
1764 |
-
$current = isset($current->storeParent) ?
|
1765 |
-
$current->storeParent : $current->parent;
|
1766 |
-
}
|
1767 |
-
}
|
1768 |
-
|
1769 |
-
return $default;
|
1770 |
-
}
|
1771 |
-
|
1772 |
-
// inject array of unparsed strings into environment as variables
|
1773 |
-
protected function injectVariables($args) {
|
1774 |
-
$this->pushEnv();
|
1775 |
-
$parser = new lessc_parser($this, __METHOD__);
|
1776 |
-
foreach ($args as $name => $strValue) {
|
1777 |
-
if ($name{0} != '@') $name = '@'.$name;
|
1778 |
-
$parser->count = 0;
|
1779 |
-
$parser->buffer = (string)$strValue;
|
1780 |
-
if (!$parser->propertyValue($value)) {
|
1781 |
-
throw new Exception("failed to parse passed in variable $name: $strValue");
|
1782 |
-
}
|
1783 |
-
|
1784 |
-
$this->set($name, $value);
|
1785 |
-
}
|
1786 |
-
}
|
1787 |
-
|
1788 |
-
/**
|
1789 |
-
* Initialize any static state, can initialize parser for a file
|
1790 |
-
* $opts isn't used yet
|
1791 |
-
*/
|
1792 |
-
public function __construct($fname = null) {
|
1793 |
-
if ($fname !== null) {
|
1794 |
-
// used for deprecated parse method
|
1795 |
-
$this->_parseFile = $fname;
|
1796 |
-
}
|
1797 |
-
}
|
1798 |
-
|
1799 |
-
public function compile($string, $name = null) {
|
1800 |
-
$locale = setlocale(LC_NUMERIC, 0);
|
1801 |
-
setlocale(LC_NUMERIC, "C");
|
1802 |
-
|
1803 |
-
$this->parser = $this->makeParser($name);
|
1804 |
-
$root = $this->parser->parse($string);
|
1805 |
-
|
1806 |
-
$this->env = null;
|
1807 |
-
$this->scope = null;
|
1808 |
-
|
1809 |
-
$this->formatter = $this->newFormatter();
|
1810 |
-
|
1811 |
-
if (!empty($this->registeredVars)) {
|
1812 |
-
$this->injectVariables($this->registeredVars);
|
1813 |
-
}
|
1814 |
-
|
1815 |
-
$this->sourceParser = $this->parser; // used for error messages
|
1816 |
-
$this->compileBlock($root);
|
1817 |
-
|
1818 |
-
ob_start();
|
1819 |
-
$this->formatter->block($this->scope);
|
1820 |
-
$out = ob_get_clean();
|
1821 |
-
setlocale(LC_NUMERIC, $locale);
|
1822 |
-
return $out;
|
1823 |
-
}
|
1824 |
-
|
1825 |
-
public function compileFile($fname, $outFname = null) {
|
1826 |
-
if (!is_readable($fname)) {
|
1827 |
-
throw new Exception('load error: failed to find '.$fname);
|
1828 |
-
}
|
1829 |
-
|
1830 |
-
$pi = pathinfo($fname);
|
1831 |
-
|
1832 |
-
$oldImport = $this->importDir;
|
1833 |
-
|
1834 |
-
$this->importDir = (array)$this->importDir;
|
1835 |
-
$this->importDir[] = $pi['dirname'].'/';
|
1836 |
-
|
1837 |
-
$this->addParsedFile($fname);
|
1838 |
-
|
1839 |
-
$out = $this->compile($GLOBALS['wp_filesystem']->get_contents($fname), $fname);
|
1840 |
-
|
1841 |
-
$this->importDir = $oldImport;
|
1842 |
-
|
1843 |
-
if ($outFname !== null) {
|
1844 |
-
return $GLOBALS['wp_filesystem']->put_contents($outFname, $out);
|
1845 |
-
}
|
1846 |
-
|
1847 |
-
return $out;
|
1848 |
-
}
|
1849 |
-
|
1850 |
-
// compile only if changed input has changed or output doesn't exist
|
1851 |
-
public function checkedCompile($in, $out) {
|
1852 |
-
if (!is_file($out) || filemtime($in) > filemtime($out)) {
|
1853 |
-
$this->compileFile($in, $out);
|
1854 |
-
return true;
|
1855 |
-
}
|
1856 |
-
return false;
|
1857 |
-
}
|
1858 |
-
|
1859 |
-
/**
|
1860 |
-
* Execute lessphp on a .less file or a lessphp cache structure
|
1861 |
-
*
|
1862 |
-
* The lessphp cache structure contains information about a specific
|
1863 |
-
* less file having been parsed. It can be used as a hint for future
|
1864 |
-
* calls to determine whether or not a rebuild is required.
|
1865 |
-
*
|
1866 |
-
* The cache structure contains two important keys that may be used
|
1867 |
-
* externally:
|
1868 |
-
*
|
1869 |
-
* compiled: The final compiled CSS
|
1870 |
-
* updated: The time (in seconds) the CSS was last compiled
|
1871 |
-
*
|
1872 |
-
* The cache structure is a plain-ol' PHP associative array and can
|
1873 |
-
* be serialized and unserialized without a hitch.
|
1874 |
-
*
|
1875 |
-
* @param mixed $in Input
|
1876 |
-
* @param bool $force Force rebuild?
|
1877 |
-
* @return array lessphp cache structure
|
1878 |
-
*/
|
1879 |
-
public function cachedCompile($in, $force = false) {
|
1880 |
-
// assume no root
|
1881 |
-
$root = null;
|
1882 |
-
|
1883 |
-
if (is_string($in)) {
|
1884 |
-
$root = $in;
|
1885 |
-
} elseif (is_array($in) and isset($in['root'])) {
|
1886 |
-
if ($force or ! isset($in['files'])) {
|
1887 |
-
// If we are forcing a recompile or if for some reason the
|
1888 |
-
// structure does not contain any file information we should
|
1889 |
-
// specify the root to trigger a rebuild.
|
1890 |
-
$root = $in['root'];
|
1891 |
-
} elseif (isset($in['files']) and is_array($in['files'])) {
|
1892 |
-
foreach ($in['files'] as $fname => $ftime ) {
|
1893 |
-
if (!file_exists($fname) or filemtime($fname) > $ftime) {
|
1894 |
-
// One of the files we knew about previously has changed
|
1895 |
-
// so we should look at our incoming root again.
|
1896 |
-
$root = $in['root'];
|
1897 |
-
break;
|
1898 |
-
}
|
1899 |
-
}
|
1900 |
-
}
|
1901 |
-
} else {
|
1902 |
-
// TODO: Throw an exception? We got neither a string nor something
|
1903 |
-
// that looks like a compatible lessphp cache structure.
|
1904 |
-
return null;
|
1905 |
-
}
|
1906 |
-
|
1907 |
-
if ($root !== null) {
|
1908 |
-
// If we have a root value which means we should rebuild.
|
1909 |
-
$out = array();
|
1910 |
-
$out['root'] = $root;
|
1911 |
-
$out['compiled'] = $this->compileFile($root);
|
1912 |
-
$out['files'] = $this->allParsedFiles();
|
1913 |
-
$out['updated'] = time();
|
1914 |
-
return $out;
|
1915 |
-
} else {
|
1916 |
-
// No changes, pass back the structure
|
1917 |
-
// we were given initially.
|
1918 |
-
return $in;
|
1919 |
-
}
|
1920 |
-
|
1921 |
-
}
|
1922 |
-
|
1923 |
-
// parse and compile buffer
|
1924 |
-
// This is deprecated
|
1925 |
-
public function parse($str = null, $initialVariables = null) {
|
1926 |
-
if (is_array($str)) {
|
1927 |
-
$initialVariables = $str;
|
1928 |
-
$str = null;
|
1929 |
-
}
|
1930 |
-
|
1931 |
-
$oldVars = $this->registeredVars;
|
1932 |
-
if ($initialVariables !== null) {
|
1933 |
-
$this->setVariables($initialVariables);
|
1934 |
-
}
|
1935 |
-
|
1936 |
-
if ($str == null) {
|
1937 |
-
if (empty($this->_parseFile)) {
|
1938 |
-
throw new exception("nothing to parse");
|
1939 |
-
}
|
1940 |
-
|
1941 |
-
$out = $this->compileFile($this->_parseFile);
|
1942 |
-
} else {
|
1943 |
-
$out = $this->compile($str);
|
1944 |
-
}
|
1945 |
-
|
1946 |
-
$this->registeredVars = $oldVars;
|
1947 |
-
return $out;
|
1948 |
-
}
|
1949 |
-
|
1950 |
-
protected function makeParser($name) {
|
1951 |
-
$parser = new lessc_parser($this, $name);
|
1952 |
-
$parser->writeComments = $this->preserveComments;
|
1953 |
-
|
1954 |
-
return $parser;
|
1955 |
-
}
|
1956 |
-
|
1957 |
-
public function setFormatter($name) {
|
1958 |
-
$this->formatterName = $name;
|
1959 |
-
}
|
1960 |
-
|
1961 |
-
protected function newFormatter() {
|
1962 |
-
$className = "lessc_formatter_lessjs";
|
1963 |
-
if (!empty($this->formatterName)) {
|
1964 |
-
if (!is_string($this->formatterName))
|
1965 |
-
return $this->formatterName;
|
1966 |
-
$className = "lessc_formatter_$this->formatterName";
|
1967 |
-
}
|
1968 |
-
|
1969 |
-
return new $className;
|
1970 |
-
}
|
1971 |
-
|
1972 |
-
public function setPreserveComments($preserve) {
|
1973 |
-
$this->preserveComments = $preserve;
|
1974 |
-
}
|
1975 |
-
|
1976 |
-
public function registerFunction($name, $func) {
|
1977 |
-
$this->libFunctions[$name] = $func;
|
1978 |
-
}
|
1979 |
-
|
1980 |
-
public function unregisterFunction($name) {
|
1981 |
-
unset($this->libFunctions[$name]);
|
1982 |
-
}
|
1983 |
-
|
1984 |
-
public function setVariables($variables) {
|
1985 |
-
$this->registeredVars = array_merge($this->registeredVars, $variables);
|
1986 |
-
}
|
1987 |
-
|
1988 |
-
public function unsetVariable($name) {
|
1989 |
-
unset($this->registeredVars[$name]);
|
1990 |
-
}
|
1991 |
-
|
1992 |
-
public function setImportDir($dirs) {
|
1993 |
-
$this->importDir = (array)$dirs;
|
1994 |
-
}
|
1995 |
-
|
1996 |
-
public function addImportDir($dir) {
|
1997 |
-
$this->importDir = (array)$this->importDir;
|
1998 |
-
$this->importDir[] = $dir;
|
1999 |
-
}
|
2000 |
-
|
2001 |
-
public function allParsedFiles() {
|
2002 |
-
return $this->allParsedFiles;
|
2003 |
-
}
|
2004 |
-
|
2005 |
-
protected function addParsedFile($file) {
|
2006 |
-
$this->allParsedFiles[realpath($file)] = filemtime($file);
|
2007 |
-
}
|
2008 |
-
|
2009 |
-
/**
|
2010 |
-
* Uses the current value of $this->count to show line and line number
|
2011 |
-
*/
|
2012 |
-
protected function throwError($msg = null) {
|
2013 |
-
if ($this->sourceLoc >= 0) {
|
2014 |
-
$this->sourceParser->throwError($msg, $this->sourceLoc);
|
2015 |
-
}
|
2016 |
-
throw new exception($msg);
|
2017 |
-
}
|
2018 |
-
|
2019 |
-
// compile file $in to file $out if $in is newer than $out
|
2020 |
-
// returns true when it compiles, false otherwise
|
2021 |
-
public static function ccompile($in, $out, $less = null) {
|
2022 |
-
if ($less === null) {
|
2023 |
-
$less = new self;
|
2024 |
-
}
|
2025 |
-
return $less->checkedCompile($in, $out);
|
2026 |
-
}
|
2027 |
-
|
2028 |
-
public static function cexecute($in, $force = false, $less = null) {
|
2029 |
-
if ($less === null) {
|
2030 |
-
$less = new self;
|
2031 |
-
}
|
2032 |
-
return $less->cachedCompile($in, $force);
|
2033 |
-
}
|
2034 |
-
|
2035 |
-
static protected $cssColors = array(
|
2036 |
-
'aliceblue' => '240,248,255',
|
2037 |
-
'antiquewhite' => '250,235,215',
|
2038 |
-
'aqua' => '0,255,255',
|
2039 |
-
'aquamarine' => '127,255,212',
|
2040 |
-
'azure' => '240,255,255',
|
2041 |
-
'beige' => '245,245,220',
|
2042 |
-
'bisque' => '255,228,196',
|
2043 |
-
'black' => '0,0,0',
|
2044 |
-
'blanchedalmond' => '255,235,205',
|
2045 |
-
'blue' => '0,0,255',
|
2046 |
-
'blueviolet' => '138,43,226',
|
2047 |
-
'brown' => '165,42,42',
|
2048 |
-
'burlywood' => '222,184,135',
|
2049 |
-
'cadetblue' => '95,158,160',
|
2050 |
-
'chartreuse' => '127,255,0',
|
2051 |
-
'chocolate' => '210,105,30',
|
2052 |
-
'coral' => '255,127,80',
|
2053 |
-
'cornflowerblue' => '100,149,237',
|
2054 |
-
'cornsilk' => '255,248,220',
|
2055 |
-
'crimson' => '220,20,60',
|
2056 |
-
'cyan' => '0,255,255',
|
2057 |
-
'darkblue' => '0,0,139',
|
2058 |
-
'darkcyan' => '0,139,139',
|
2059 |
-
'darkgoldenrod' => '184,134,11',
|
2060 |
-
'darkgray' => '169,169,169',
|
2061 |
-
'darkgreen' => '0,100,0',
|
2062 |
-
'darkgrey' => '169,169,169',
|
2063 |
-
'darkkhaki' => '189,183,107',
|
2064 |
-
'darkmagenta' => '139,0,139',
|
2065 |
-
'darkolivegreen' => '85,107,47',
|
2066 |
-
'darkorange' => '255,140,0',
|
2067 |
-
'darkorchid' => '153,50,204',
|
2068 |
-
'darkred' => '139,0,0',
|
2069 |
-
'darksalmon' => '233,150,122',
|
2070 |
-
'darkseagreen' => '143,188,143',
|
2071 |
-
'darkslateblue' => '72,61,139',
|
2072 |
-
'darkslategray' => '47,79,79',
|
2073 |
-
'darkslategrey' => '47,79,79',
|
2074 |
-
'darkturquoise' => '0,206,209',
|
2075 |
-
'darkviolet' => '148,0,211',
|
2076 |
-
'deeppink' => '255,20,147',
|
2077 |
-
'deepskyblue' => '0,191,255',
|
2078 |
-
'dimgray' => '105,105,105',
|
2079 |
-
'dimgrey' => '105,105,105',
|
2080 |
-
'dodgerblue' => '30,144,255',
|
2081 |
-
'firebrick' => '178,34,34',
|
2082 |
-
'floralwhite' => '255,250,240',
|
2083 |
-
'forestgreen' => '34,139,34',
|
2084 |
-
'fuchsia' => '255,0,255',
|
2085 |
-
'gainsboro' => '220,220,220',
|
2086 |
-
'ghostwhite' => '248,248,255',
|
2087 |
-
'gold' => '255,215,0',
|
2088 |
-
'goldenrod' => '218,165,32',
|
2089 |
-
'gray' => '128,128,128',
|
2090 |
-
'green' => '0,128,0',
|
2091 |
-
'greenyellow' => '173,255,47',
|
2092 |
-
'grey' => '128,128,128',
|
2093 |
-
'honeydew' => '240,255,240',
|
2094 |
-
'hotpink' => '255,105,180',
|
2095 |
-
'indianred' => '205,92,92',
|
2096 |
-
'indigo' => '75,0,130',
|
2097 |
-
'ivory' => '255,255,240',
|
2098 |
-
'khaki' => '240,230,140',
|
2099 |
-
'lavender' => '230,230,250',
|
2100 |
-
'lavenderblush' => '255,240,245',
|
2101 |
-
'lawngreen' => '124,252,0',
|
2102 |
-
'lemonchiffon' => '255,250,205',
|
2103 |
-
'lightblue' => '173,216,230',
|
2104 |
-
'lightcoral' => '240,128,128',
|
2105 |
-
'lightcyan' => '224,255,255',
|
2106 |
-
'lightgoldenrodyellow' => '250,250,210',
|
2107 |
-
'lightgray' => '211,211,211',
|
2108 |
-
'lightgreen' => '144,238,144',
|
2109 |
-
'lightgrey' => '211,211,211',
|
2110 |
-
'lightpink' => '255,182,193',
|
2111 |
-
'lightsalmon' => '255,160,122',
|
2112 |
-
'lightseagreen' => '32,178,170',
|
2113 |
-
'lightskyblue' => '135,206,250',
|
2114 |
-
'lightslategray' => '119,136,153',
|
2115 |
-
'lightslategrey' => '119,136,153',
|
2116 |
-
'lightsteelblue' => '176,196,222',
|
2117 |
-
'lightyellow' => '255,255,224',
|
2118 |
-
'lime' => '0,255,0',
|
2119 |
-
'limegreen' => '50,205,50',
|
2120 |
-
'linen' => '250,240,230',
|
2121 |
-
'magenta' => '255,0,255',
|
2122 |
-
'maroon' => '128,0,0',
|
2123 |
-
'mediumaquamarine' => '102,205,170',
|
2124 |
-
'mediumblue' => '0,0,205',
|
2125 |
-
'mediumorchid' => '186,85,211',
|
2126 |
-
'mediumpurple' => '147,112,219',
|
2127 |
-
'mediumseagreen' => '60,179,113',
|
2128 |
-
'mediumslateblue' => '123,104,238',
|
2129 |
-
'mediumspringgreen' => '0,250,154',
|
2130 |
-
'mediumturquoise' => '72,209,204',
|
2131 |
-
'mediumvioletred' => '199,21,133',
|
2132 |
-
'midnightblue' => '25,25,112',
|
2133 |
-
'mintcream' => '245,255,250',
|
2134 |
-
'mistyrose' => '255,228,225',
|
2135 |
-
'moccasin' => '255,228,181',
|
2136 |
-
'navajowhite' => '255,222,173',
|
2137 |
-
'navy' => '0,0,128',
|
2138 |
-
'oldlace' => '253,245,230',
|
2139 |
-
'olive' => '128,128,0',
|
2140 |
-
'olivedrab' => '107,142,35',
|
2141 |
-
'orange' => '255,165,0',
|
2142 |
-
'orangered' => '255,69,0',
|
2143 |
-
'orchid' => '218,112,214',
|
2144 |
-
'palegoldenrod' => '238,232,170',
|
2145 |
-
'palegreen' => '152,251,152',
|
2146 |
-
'paleturquoise' => '175,238,238',
|
2147 |
-
'palevioletred' => '219,112,147',
|
2148 |
-
'papayawhip' => '255,239,213',
|
2149 |
-
'peachpuff' => '255,218,185',
|
2150 |
-
'peru' => '205,133,63',
|
2151 |
-
'pink' => '255,192,203',
|
2152 |
-
'plum' => '221,160,221',
|
2153 |
-
'powderblue' => '176,224,230',
|
2154 |
-
'purple' => '128,0,128',
|
2155 |
-
'red' => '255,0,0',
|
2156 |
-
'rosybrown' => '188,143,143',
|
2157 |
-
'royalblue' => '65,105,225',
|
2158 |
-
'saddlebrown' => '139,69,19',
|
2159 |
-
'salmon' => '250,128,114',
|
2160 |
-
'sandybrown' => '244,164,96',
|
2161 |
-
'seagreen' => '46,139,87',
|
2162 |
-
'seashell' => '255,245,238',
|
2163 |
-
'sienna' => '160,82,45',
|
2164 |
-
'silver' => '192,192,192',
|
2165 |
-
'skyblue' => '135,206,235',
|
2166 |
-
'slateblue' => '106,90,205',
|
2167 |
-
'slategray' => '112,128,144',
|
2168 |
-
'slategrey' => '112,128,144',
|
2169 |
-
'snow' => '255,250,250',
|
2170 |
-
'springgreen' => '0,255,127',
|
2171 |
-
'steelblue' => '70,130,180',
|
2172 |
-
'tan' => '210,180,140',
|
2173 |
-
'teal' => '0,128,128',
|
2174 |
-
'thistle' => '216,191,216',
|
2175 |
-
'tomato' => '255,99,71',
|
2176 |
-
'transparent' => '0,0,0,0',
|
2177 |
-
'turquoise' => '64,224,208',
|
2178 |
-
'violet' => '238,130,238',
|
2179 |
-
'wheat' => '245,222,179',
|
2180 |
-
'white' => '255,255,255',
|
2181 |
-
'whitesmoke' => '245,245,245',
|
2182 |
-
'yellow' => '255,255,0',
|
2183 |
-
'yellowgreen' => '154,205,50'
|
2184 |
-
);
|
2185 |
-
}
|
2186 |
-
|
2187 |
-
// responsible for taking a string of LESS code and converting it into a
|
2188 |
-
// syntax tree
|
2189 |
-
/**
|
2190 |
-
* @ignore
|
2191 |
-
*/
|
2192 |
-
class lessc_parser {
|
2193 |
-
static protected $nextBlockId = 0; // used to uniquely identify blocks
|
2194 |
-
|
2195 |
-
static protected $precedence = array(
|
2196 |
-
'=<' => 0,
|
2197 |
-
'>=' => 0,
|
2198 |
-
'=' => 0,
|
2199 |
-
'<' => 0,
|
2200 |
-
'>' => 0,
|
2201 |
-
|
2202 |
-
'+' => 1,
|
2203 |
-
'-' => 1,
|
2204 |
-
'*' => 2,
|
2205 |
-
'/' => 2,
|
2206 |
-
'%' => 2,
|
2207 |
-
);
|
2208 |
-
|
2209 |
-
static protected $whitePattern;
|
2210 |
-
static protected $commentMulti;
|
2211 |
-
|
2212 |
-
static protected $commentSingle = "//";
|
2213 |
-
static protected $commentMultiLeft = "/*";
|
2214 |
-
static protected $commentMultiRight = "*/";
|
2215 |
-
|
2216 |
-
// regex string to match any of the operators
|
2217 |
-
static protected $operatorString;
|
2218 |
-
|
2219 |
-
// these properties will supress division unless it's inside parenthases
|
2220 |
-
static protected $supressDivisionProps =
|
2221 |
-
array('/border-radius$/i', '/^font$/i');
|
2222 |
-
|
2223 |
-
protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport");
|
2224 |
-
protected $lineDirectives = array("charset");
|
2225 |
-
|
2226 |
-
/**
|
2227 |
-
* if we are in parens we can be more liberal with whitespace around
|
2228 |
-
* operators because it must evaluate to a single value and thus is less
|
2229 |
-
* ambiguous.
|
2230 |
-
*
|
2231 |
-
* Consider:
|
2232 |
-
* property1: 10 -5; // is two numbers, 10 and -5
|
2233 |
-
* property2: (10 -5); // should evaluate to 5
|
2234 |
-
*/
|
2235 |
-
protected $inParens = false;
|
2236 |
-
|
2237 |
-
// caches preg escaped literals
|
2238 |
-
static protected $literalCache = array();
|
2239 |
-
|
2240 |
-
public function __construct($lessc, $sourceName = null) {
|
2241 |
-
$this->eatWhiteDefault = true;
|
2242 |
-
// reference to less needed for vPrefix, mPrefix, and parentSelector
|
2243 |
-
$this->lessc = $lessc;
|
2244 |
-
|
2245 |
-
$this->sourceName = $sourceName; // name used for error messages
|
2246 |
-
|
2247 |
-
$this->writeComments = false;
|
2248 |
-
|
2249 |
-
if (!self::$operatorString) {
|
2250 |
-
self::$operatorString =
|
2251 |
-
'('.implode('|', array_map(array('JupiterX_Lessc', 'preg_quote'),
|
2252 |
-
array_keys(self::$precedence))).')';
|
2253 |
-
|
2254 |
-
$commentSingle = JupiterX_Lessc::preg_quote(self::$commentSingle);
|
2255 |
-
$commentMultiLeft = JupiterX_Lessc::preg_quote(self::$commentMultiLeft);
|
2256 |
-
$commentMultiRight = JupiterX_Lessc::preg_quote(self::$commentMultiRight);
|
2257 |
-
|
2258 |
-
self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight;
|
2259 |
-
self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais';
|
2260 |
-
}
|
2261 |
-
}
|
2262 |
-
|
2263 |
-
public function parse($buffer) {
|
2264 |
-
$this->count = 0;
|
2265 |
-
$this->line = 1;
|
2266 |
-
|
2267 |
-
$this->env = null; // block stack
|
2268 |
-
$this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
|
2269 |
-
$this->pushSpecialBlock("root");
|
2270 |
-
$this->eatWhiteDefault = true;
|
2271 |
-
$this->seenComments = array();
|
2272 |
-
|
2273 |
-
// trim whitespace on head
|
2274 |
-
// if (preg_match('/^\s+/', $this->buffer, $m)) {
|
2275 |
-
// $this->line += substr_count($m[0], "\n");
|
2276 |
-
// $this->buffer = ltrim($this->buffer);
|
2277 |
-
// }
|
2278 |
-
$this->whitespace();
|
2279 |
-
|
2280 |
-
// parse the entire file
|
2281 |
-
$lastCount = $this->count;
|
2282 |
-
while (false !== $this->parseChunk());
|
2283 |
-
|
2284 |
-
if ($this->count != strlen($this->buffer))
|
2285 |
-
$this->throwError();
|
2286 |
-
|
2287 |
-
// TODO report where the block was opened
|
2288 |
-
if (!is_null($this->env->parent))
|
2289 |
-
throw new exception('parse error: unclosed block');
|
2290 |
-
|
2291 |
-
return $this->env;
|
2292 |
-
}
|
2293 |
-
|
2294 |
-
/**
|
2295 |
-
* Parse a single chunk off the head of the buffer and append it to the
|
2296 |
-
* current parse environment.
|
2297 |
-
* Returns false when the buffer is empty, or when there is an error.
|
2298 |
-
*
|
2299 |
-
* This function is called repeatedly until the entire document is
|
2300 |
-
* parsed.
|
2301 |
-
*
|
2302 |
-
* This parser is most similar to a recursive descent parser. Single
|
2303 |
-
* functions represent discrete grammatical rules for the language, and
|
2304 |
-
* they are able to capture the text that represents those rules.
|
2305 |
-
*
|
2306 |
-
* Consider the function lessc::keyword(). (all parse functions are
|
2307 |
-
* structured the same)
|
2308 |
-
*
|
2309 |
-
* The function takes a single reference argument. When calling the
|
2310 |
-
* function it will attempt to match a keyword on the head of the buffer.
|
2311 |
-
* If it is successful, it will place the keyword in the referenced
|
2312 |
-
* argument, advance the position in the buffer, and return true. If it
|
2313 |
-
* fails then it won't advance the buffer and it will return false.
|
2314 |
-
*
|
2315 |
-
* All of these parse functions are powered by lessc::match(), which behaves
|
2316 |
-
* the same way, but takes a literal regular expression. Sometimes it is
|
2317 |
-
* more convenient to use match instead of creating a new function.
|
2318 |
-
*
|
2319 |
-
* Because of the format of the functions, to parse an entire string of
|
2320 |
-
* grammatical rules, you can chain them together using &&.
|
2321 |
-
*
|
2322 |
-
* But, if some of the rules in the chain succeed before one fails, then
|
2323 |
-
* the buffer position will be left at an invalid state. In order to
|
2324 |
-
* avoid this, lessc::seek() is used to remember and set buffer positions.
|
2325 |
-
*
|
2326 |
-
* Before parsing a chain, use $s = $this->seek() to remember the current
|
2327 |
-
* position into $s. Then if a chain fails, use $this->seek($s) to
|
2328 |
-
* go back where we started.
|
2329 |
-
*/
|
2330 |
-
protected function parseChunk() {
|
2331 |
-
if (empty($this->buffer)) return false;
|
2332 |
-
$s = $this->seek();
|
2333 |
-
|
2334 |
-
// setting a property
|
2335 |
-
if ($this->keyword($key) && $this->assign() &&
|
2336 |
-
$this->propertyValue($value, $key) && $this->end())
|
2337 |
-
{
|
2338 |
-
$this->append(array('assign', $key, $value), $s);
|
2339 |
-
return true;
|
2340 |
-
} else {
|
2341 |
-
$this->seek($s);
|
2342 |
-
}
|
2343 |
-
|
2344 |
-
|
2345 |
-
// look for special css blocks
|
2346 |
-
if ($this->literal('@', false)) {
|
2347 |
-
$this->count--;
|
2348 |
-
|
2349 |
-
// media
|
2350 |
-
if ($this->literal('@media')) {
|
2351 |
-
if (($this->mediaQueryList($mediaQueries) || true)
|
2352 |
-
&& $this->literal('{'))
|
2353 |
-
{
|
2354 |
-
$media = $this->pushSpecialBlock("media");
|
2355 |
-
$media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
|
2356 |
-
return true;
|
2357 |
-
} else {
|
2358 |
-
$this->seek($s);
|
2359 |
-
return false;
|
2360 |
-
}
|
2361 |
-
}
|
2362 |
-
|
2363 |
-
if ($this->literal("@", false) && $this->keyword($dirName)) {
|
2364 |
-
if ($this->isDirective($dirName, $this->blockDirectives)) {
|
2365 |
-
if (($this->openString("{", $dirValue, null, array(";")) || true) &&
|
2366 |
-
$this->literal("{"))
|
2367 |
-
{
|
2368 |
-
$dir = $this->pushSpecialBlock("directive");
|
2369 |
-
$dir->name = $dirName;
|
2370 |
-
if (isset($dirValue)) $dir->value = $dirValue;
|
2371 |
-
return true;
|
2372 |
-
}
|
2373 |
-
} elseif ($this->isDirective($dirName, $this->lineDirectives)) {
|
2374 |
-
if ($this->propertyValue($dirValue) && $this->end()) {
|
2375 |
-
$this->append(array("directive", $dirName, $dirValue));
|
2376 |
-
return true;
|
2377 |
-
}
|
2378 |
-
}
|
2379 |
-
}
|
2380 |
-
|
2381 |
-
$this->seek($s);
|
2382 |
-
}
|
2383 |
-
|
2384 |
-
// setting a variable
|
2385 |
-
if ($this->variable($var) && $this->assign() &&
|
2386 |
-
$this->propertyValue($value) && $this->end())
|
2387 |
-
{
|
2388 |
-
$this->append(array('assign', $var, $value), $s);
|
2389 |
-
return true;
|
2390 |
-
} else {
|
2391 |
-
$this->seek($s);
|
2392 |
-
}
|
2393 |
-
|
2394 |
-
if ($this->import($importValue)) {
|
2395 |
-
$this->append($importValue, $s);
|
2396 |
-
return true;
|
2397 |
-
}
|
2398 |
-
|
2399 |
-
// opening parametric mixin
|
2400 |
-
if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) &&
|
2401 |
-
($this->guards($guards) || true) &&
|
2402 |
-
$this->literal('{'))
|
2403 |
-
{
|
2404 |
-
$block = $this->pushBlock($this->fixTags(array($tag)));
|
2405 |
-
$block->args = $args;
|
2406 |
-
$block->isVararg = $isVararg;
|
2407 |
-
if (!empty($guards)) $block->guards = $guards;
|
2408 |
-
return true;
|
2409 |
-
} else {
|
2410 |
-
$this->seek($s);
|
2411 |
-
}
|
2412 |
-
|
2413 |
-
// opening a simple block
|
2414 |
-
if ($this->tags($tags) && $this->literal('{')) {
|
2415 |
-
$tags = $this->fixTags($tags);
|
2416 |
-
$this->pushBlock($tags);
|
2417 |
-
return true;
|
2418 |
-
} else {
|
2419 |
-
$this->seek($s);
|
2420 |
-
}
|
2421 |
-
|
2422 |
-
// closing a block
|
2423 |
-
if ($this->literal('}', false)) {
|
2424 |
-
try {
|
2425 |
-
$block = $this->pop();
|
2426 |
-
} catch (exception $e) {
|
2427 |
-
$this->seek($s);
|
2428 |
-
$this->throwError($e->getMessage());
|
2429 |
-
}
|
2430 |
-
|
2431 |
-
$hidden = false;
|
2432 |
-
if (is_null($block->type)) {
|
2433 |
-
$hidden = true;
|
2434 |
-
if (!isset($block->args)) {
|
2435 |
-
foreach ($block->tags as $tag) {
|
2436 |
-
if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) {
|
2437 |
-
$hidden = false;
|
2438 |
-
break;
|
2439 |
-
}
|
2440 |
-
}
|
2441 |
-
}
|
2442 |
-
|
2443 |
-
foreach ($block->tags as $tag) {
|
2444 |
-
if (is_string($tag)) {
|
2445 |
-
$this->env->children[$tag][] = $block;
|
2446 |
-
}
|
2447 |
-
}
|
2448 |
-
}
|
2449 |
-
|
2450 |
-
if (!$hidden) {
|
2451 |
-
$this->append(array('block', $block), $s);
|
2452 |
-
}
|
2453 |
-
|
2454 |
-
// this is done here so comments aren't bundled into he block that
|
2455 |
-
// was just closed
|
2456 |
-
$this->whitespace();
|
2457 |
-
return true;
|
2458 |
-
}
|
2459 |
-
|
2460 |
-
// mixin
|
2461 |
-
if ($this->mixinTags($tags) &&
|
2462 |
-
($this->argumentDef($argv, $isVararg) || true) &&
|
2463 |
-
($this->keyword($suffix) || true) && $this->end())
|
2464 |
-
{
|
2465 |
-
$tags = $this->fixTags($tags);
|
2466 |
-
$this->append(array('mixin', $tags, $argv, $suffix), $s);
|
2467 |
-
return true;
|
2468 |
-
} else {
|
2469 |
-
$this->seek($s);
|
2470 |
-
}
|
2471 |
-
|
2472 |
-
// spare ;
|
2473 |
-
if ($this->literal(';')) return true;
|
2474 |
-
|
2475 |
-
return false; // got nothing, throw error
|
2476 |
-
}
|
2477 |
-
|
2478 |
-
protected function isDirective($dirname, $directives) {
|
2479 |
-
// TODO: cache pattern in parser
|
2480 |
-
$pattern = implode("|",
|
2481 |
-
array_map(array("JupiterX_Lessc", "preg_quote"), $directives));
|
2482 |
-
$pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
|
2483 |
-
|
2484 |
-
return preg_match($pattern, $dirname);
|
2485 |
-
}
|
2486 |
-
|
2487 |
-
protected function fixTags($tags) {
|
2488 |
-
// move @ tags out of variable namespace
|
2489 |
-
foreach ($tags as &$tag) {
|
2490 |
-
if ($tag{0} == $this->lessc->vPrefix)
|
2491 |
-
$tag[0] = $this->lessc->mPrefix;
|
2492 |
-
}
|
2493 |
-
return $tags;
|
2494 |
-
}
|
2495 |
-
|
2496 |
-
// a list of expressions
|
2497 |
-
protected function expressionList(&$exps) {
|
2498 |
-
$values = array();
|
2499 |
-
|
2500 |
-
while ($this->expression($exp)) {
|
2501 |
-
$values[] = $exp;
|
2502 |
-
}
|
2503 |
-
|
2504 |
-
if (count($values) == 0) return false;
|
2505 |
-
|
2506 |
-
$exps = JupiterX_Lessc::compressList($values, ' ');
|
2507 |
-
return true;
|
2508 |
-
}
|
2509 |
-
|
2510 |
-
/**
|
2511 |
-
* Attempt to consume an expression.
|
2512 |
-
* @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
|
2513 |
-
*/
|
2514 |
-
protected function expression(&$out) {
|
2515 |
-
if ($this->value($lhs)) {
|
2516 |
-
$out = $this->expHelper($lhs, 0);
|
2517 |
-
|
2518 |
-
// look for / shorthand
|
2519 |
-
if (!empty($this->env->supressedDivision)) {
|
2520 |
-
unset($this->env->supressedDivision);
|
2521 |
-
$s = $this->seek();
|
2522 |
-
if ($this->literal("/") && $this->value($rhs)) {
|
2523 |
-
$out = array("list", "",
|
2524 |
-
array($out, array("keyword", "/"), $rhs));
|
2525 |
-
} else {
|
2526 |
-
$this->seek($s);
|
2527 |
-
}
|
2528 |
-
}
|
2529 |
-
|
2530 |
-
return true;
|
2531 |
-
}
|
2532 |
-
return false;
|
2533 |
-
}
|
2534 |
-
|
2535 |
-
/**
|
2536 |
-
* recursively parse infix equation with $lhs at precedence $minP
|
2537 |
-
*/
|
2538 |
-
protected function expHelper($lhs, $minP) {
|
2539 |
-
$this->inExp = true;
|
2540 |
-
$ss = $this->seek();
|
2541 |
-
|
2542 |
-
while (true) {
|
2543 |
-
$whiteBefore = isset($this->buffer[$this->count - 1]) &&
|
2544 |
-
ctype_space($this->buffer[$this->count - 1]);
|
2545 |
-
|
2546 |
-
// If there is whitespace before the operator, then we require
|
2547 |
-
// whitespace after the operator for it to be an expression
|
2548 |
-
$needWhite = $whiteBefore && !$this->inParens;
|
2549 |
-
|
2550 |
-
if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
|
2551 |
-
if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
|
2552 |
-
foreach (self::$supressDivisionProps as $pattern) {
|
2553 |
-
if (preg_match($pattern, $this->env->currentProperty)) {
|
2554 |
-
$this->env->supressedDivision = true;
|
2555 |
-
break 2;
|
2556 |
-
}
|
2557 |
-
}
|
2558 |
-
}
|
2559 |
-
|
2560 |
-
|
2561 |
-
$whiteAfter = isset($this->buffer[$this->count - 1]) &&
|
2562 |
-
ctype_space($this->buffer[$this->count - 1]);
|
2563 |
-
|
2564 |
-
if (!$this->value($rhs)) break;
|
2565 |
-
|
2566 |
-
// peek for next operator to see what to do with rhs
|
2567 |
-
if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
|
2568 |
-
$rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
|
2569 |
-
}
|
2570 |
-
|
2571 |
-
$lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
|
2572 |
-
$ss = $this->seek();
|
2573 |
-
|
2574 |
-
continue;
|
2575 |
-
}
|
2576 |
-
|
2577 |
-
break;
|
2578 |
-
}
|
2579 |
-
|
2580 |
-
$this->seek($ss);
|
2581 |
-
|
2582 |
-
return $lhs;
|
2583 |
-
}
|
2584 |
-
|
2585 |
-
// consume a list of values for a property
|
2586 |
-
public function propertyValue(&$value, $keyName = null) {
|
2587 |
-
$values = array();
|
2588 |
-
|
2589 |
-
if ($keyName !== null) $this->env->currentProperty = $keyName;
|
2590 |
-
|
2591 |
-
$s = null;
|
2592 |
-
while ($this->expressionList($v)) {
|
2593 |
-
$values[] = $v;
|
2594 |
-
$s = $this->seek();
|
2595 |
-
if (!$this->literal(',')) break;
|
2596 |
-
}
|
2597 |
-
|
2598 |
-
if ($s) $this->seek($s);
|
2599 |
-
|
2600 |
-
if ($keyName !== null) unset($this->env->currentProperty);
|
2601 |
-
|
2602 |
-
if (count($values) == 0) return false;
|
2603 |
-
|
2604 |
-
$value = JupiterX_Lessc::compressList($values, ', ');
|
2605 |
-
return true;
|
2606 |
-
}
|
2607 |
-
|
2608 |
-
protected function parenValue(&$out) {
|
2609 |
-
$s = $this->seek();
|
2610 |
-
|
2611 |
-
// speed shortcut
|
2612 |
-
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
|
2613 |
-
return false;
|
2614 |
-
}
|
2615 |
-
|
2616 |
-
$inParens = $this->inParens;
|
2617 |
-
if ($this->literal("(") &&
|
2618 |
-
($this->inParens = true) && $this->expression($exp) &&
|
2619 |
-
$this->literal(")"))
|
2620 |
-
{
|
2621 |
-
$out = $exp;
|
2622 |
-
$this->inParens = $inParens;
|
2623 |
-
return true;
|
2624 |
-
} else {
|
2625 |
-
$this->inParens = $inParens;
|
2626 |
-
$this->seek($s);
|
2627 |
-
}
|
2628 |
-
|
2629 |
-
return false;
|
2630 |
-
}
|
2631 |
-
|
2632 |
-
// a single value
|
2633 |
-
protected function value(&$value) {
|
2634 |
-
$s = $this->seek();
|
2635 |
-
|
2636 |
-
// speed shortcut
|
2637 |
-
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
|
2638 |
-
// negation
|
2639 |
-
if ($this->literal("-", false) &&
|
2640 |
-
(($this->variable($inner) && $inner = array("variable", $inner)) ||
|
2641 |
-
$this->unit($inner) ||
|
2642 |
-
$this->parenValue($inner)))
|
2643 |
-
{
|
2644 |
-
$value = array("unary", "-", $inner);
|
2645 |
-
return true;
|
2646 |
-
} else {
|
2647 |
-
$this->seek($s);
|
2648 |
-
}
|
2649 |
-
}
|
2650 |
-
|
2651 |
-
if ($this->parenValue($value)) return true;
|
2652 |
-
if ($this->unit($value)) return true;
|
2653 |
-
if ($this->color($value)) return true;
|
2654 |
-
if ($this->func($value)) return true;
|
2655 |
-
if ($this->string($value)) return true;
|
2656 |
-
|
2657 |
-
if ($this->keyword($word)) {
|
2658 |
-
$value = array('keyword', $word);
|
2659 |
-
return true;
|
2660 |
-
}
|
2661 |
-
|
2662 |
-
// try a variable
|
2663 |
-
if ($this->variable($var)) {
|
2664 |
-
$value = array('variable', $var);
|
2665 |
-
return true;
|
2666 |
-
}
|
2667 |
-
|
2668 |
-
// unquote string (should this work on any type?
|
2669 |
-
if ($this->literal("~") && $this->string($str)) {
|
2670 |
-
$value = array("escape", $str);
|
2671 |
-
return true;
|
2672 |
-
} else {
|
2673 |
-
$this->seek($s);
|
2674 |
-
}
|
2675 |
-
|
2676 |
-
// css hack: \0
|
2677 |
-
if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
|
2678 |
-
$value = array('keyword', '\\'.$m[1]);
|
2679 |
-
return true;
|
2680 |
-
} else {
|
2681 |
-
$this->seek($s);
|
2682 |
-
}
|
2683 |
-
|
2684 |
-
return false;
|
2685 |
-
}
|
2686 |
-
|
2687 |
-
// an import statement
|
2688 |
-
protected function import(&$out) {
|
2689 |
-
$s = $this->seek();
|
2690 |
-
if (!$this->literal('@import')) return false;
|
2691 |
-
|
2692 |
-
// @import "something.css" media;
|
2693 |
-
// @import url("something.css") media;
|
2694 |
-
// @import url(something.css) media;
|
2695 |
-
|
2696 |
-
if ($this->propertyValue($value)) {
|
2697 |
-
$out = array("import", $value);
|
2698 |
-
return true;
|
2699 |
-
}
|
2700 |
-
}
|
2701 |
-
|
2702 |
-
protected function mediaQueryList(&$out) {
|
2703 |
-
if ($this->genericList($list, "mediaQuery", ",", false)) {
|
2704 |
-
$out = $list[2];
|
2705 |
-
return true;
|
2706 |
-
}
|
2707 |
-
return false;
|
2708 |
-
}
|
2709 |
-
|
2710 |
-
protected function mediaQuery(&$out) {
|
2711 |
-
$s = $this->seek();
|
2712 |
-
|
2713 |
-
$expressions = null;
|
2714 |
-
$parts = array();
|
2715 |
-
|
2716 |
-
if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
|
2717 |
-
$prop = array("mediaType");
|
2718 |
-
if (isset($only)) $prop[] = "only";
|
2719 |
-
if (isset($not)) $prop[] = "not";
|
2720 |
-
$prop[] = $mediaType;
|
2721 |
-
$parts[] = $prop;
|
2722 |
-
} else {
|
2723 |
-
$this->seek($s);
|
2724 |
-
}
|
2725 |
-
|
2726 |
-
|
2727 |
-
if (!empty($mediaType) && !$this->literal("and")) {
|
2728 |
-
// ~
|
2729 |
-
} else {
|
2730 |
-
$this->genericList($expressions, "mediaExpression", "and", false);
|
2731 |
-
if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
|
2732 |
-
}
|
2733 |
-
|
2734 |
-
if (count($parts) == 0) {
|
2735 |
-
$this->seek($s);
|
2736 |
-
return false;
|
2737 |
-
}
|
2738 |
-
|
2739 |
-
$out = $parts;
|
2740 |
-
return true;
|
2741 |
-
}
|
2742 |
-
|
2743 |
-
protected function mediaExpression(&$out) {
|
2744 |
-
$s = $this->seek();
|
2745 |
-
$value = null;
|
2746 |
-
if ($this->literal("(") &&
|
2747 |
-
$this->keyword($feature) &&
|
2748 |
-
($this->literal(":") && $this->expression($value) || true) &&
|
2749 |
-
$this->literal(")"))
|
2750 |
-
{
|
2751 |
-
$out = array("mediaExp", $feature);
|
2752 |
-
if ($value) $out[] = $value;
|
2753 |
-
return true;
|
2754 |
-
} elseif ($this->variable($variable)) {
|
2755 |
-
$out = array('variable', $variable);
|
2756 |
-
return true;
|
2757 |
-
}
|
2758 |
-
|
2759 |
-
$this->seek($s);
|
2760 |
-
return false;
|
2761 |
-
}
|
2762 |
-
|
2763 |
-
// an unbounded string stopped by $end
|
2764 |
-
protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) {
|
2765 |
-
$oldWhite = $this->eatWhiteDefault;
|
2766 |
-
$this->eatWhiteDefault = false;
|
2767 |
-
|
2768 |
-
$stop = array("'", '"', "@{", $end);
|
2769 |
-
$stop = array_map(array("JupiterX_Lessc", "preg_quote"), $stop);
|
2770 |
-
// $stop[] = self::$commentMulti;
|
2771 |
-
|
2772 |
-
if (!is_null($rejectStrs)) {
|
2773 |
-
$stop = array_merge($stop, $rejectStrs);
|
2774 |
-
}
|
2775 |
-
|
2776 |
-
$patt = '(.*?)('.implode("|", $stop).')';
|
2777 |
-
|
2778 |
-
$nestingLevel = 0;
|
2779 |
-
|
2780 |
-
$content = array();
|
2781 |
-
while ($this->match($patt, $m, false)) {
|
2782 |
-
if (!empty($m[1])) {
|
2783 |
-
$content[] = $m[1];
|
2784 |
-
if ($nestingOpen) {
|
2785 |
-
$nestingLevel += substr_count($m[1], $nestingOpen);
|
2786 |
-
}
|
2787 |
-
}
|
2788 |
-
|
2789 |
-
$tok = $m[2];
|
2790 |
-
|
2791 |
-
$this->count-= strlen($tok);
|
2792 |
-
if ($tok == $end) {
|
2793 |
-
if ($nestingLevel == 0) {
|
2794 |
-
break;
|
2795 |
-
} else {
|
2796 |
-
$nestingLevel--;
|
2797 |
-
}
|
2798 |
-
}
|
2799 |
-
|
2800 |
-
if (($tok == "'" || $tok == '"') && $this->string($str)) {
|
2801 |
-
$content[] = $str;
|
2802 |
-
continue;
|
2803 |
-
}
|
2804 |
-
|
2805 |
-
if ($tok == "@{" && $this->interpolation($inter)) {
|
2806 |
-
$content[] = $inter;
|
2807 |
-
continue;
|
2808 |
-
}
|
2809 |
-
|
2810 |
-
if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
|
2811 |
-
break;
|
2812 |
-
}
|
2813 |
-
|
2814 |
-
$content[] = $tok;
|
2815 |
-
$this->count+= strlen($tok);
|
2816 |
-
}
|
2817 |
-
|
2818 |
-
$this->eatWhiteDefault = $oldWhite;
|
2819 |
-
|
2820 |
-
if (count($content) == 0) return false;
|
2821 |
-
|
2822 |
-
// trim the end
|
2823 |
-
if (is_string(end($content))) {
|
2824 |
-
$content[count($content) - 1] = rtrim(end($content));
|
2825 |
-
}
|
2826 |
-
|
2827 |
-
$out = array("string", "", $content);
|
2828 |
-
return true;
|
2829 |
-
}
|
2830 |
-
|
2831 |
-
protected function string(&$out) {
|
2832 |
-
$s = $this->seek();
|
2833 |
-
if ($this->literal('"', false)) {
|
2834 |
-
$delim = '"';
|
2835 |
-
} elseif ($this->literal("'", false)) {
|
2836 |
-
$delim = "'";
|
2837 |
-
} else {
|
2838 |
-
return false;
|
2839 |
-
}
|
2840 |
-
|
2841 |
-
$content = array();
|
2842 |
-
|
2843 |
-
// look for either ending delim , escape, or string interpolation
|
2844 |
-
$patt = '([^\n]*?)(@\{|\\\\|' .
|
2845 |
-
JupiterX_Lessc::preg_quote($delim).')';
|
2846 |
-
|
2847 |
-
$oldWhite = $this->eatWhiteDefault;
|
2848 |
-
$this->eatWhiteDefault = false;
|
2849 |
-
|
2850 |
-
while ($this->match($patt, $m, false)) {
|
2851 |
-
$content[] = $m[1];
|
2852 |
-
if ($m[2] == "@{") {
|
2853 |
-
$this->count -= strlen($m[2]);
|
2854 |
-
if ($this->interpolation($inter, false)) {
|
2855 |
-
$content[] = $inter;
|
2856 |
-
} else {
|
2857 |
-
$this->count += strlen($m[2]);
|
2858 |
-
$content[] = "@{"; // ignore it
|
2859 |
-
}
|
2860 |
-
} elseif ($m[2] == '\\') {
|
2861 |
-
$content[] = $m[2];
|
2862 |
-
if ($this->literal($delim, false)) {
|
2863 |
-
$content[] = $delim;
|
2864 |
-
}
|
2865 |
-
} else {
|
2866 |
-
$this->count -= strlen($delim);
|
2867 |
-
break; // delim
|
2868 |
-
}
|
2869 |
-
}
|
2870 |
-
|
2871 |
-
$this->eatWhiteDefault = $oldWhite;
|
2872 |
-
|
2873 |
-
if ($this->literal($delim)) {
|
2874 |
-
$out = array("string", $delim, $content);
|
2875 |
-
return true;
|
2876 |
-
}
|
2877 |
-
|
2878 |
-
$this->seek($s);
|
2879 |
-
return false;
|
2880 |
-
}
|
2881 |
-
|
2882 |
-
protected function interpolation(&$out) {
|
2883 |
-
$oldWhite = $this->eatWhiteDefault;
|
2884 |
-
$this->eatWhiteDefault = true;
|
2885 |
-
|
2886 |
-
$s = $this->seek();
|
2887 |
-
if ($this->literal("@{") &&
|
2888 |
-
$this->openString("}", $interp, null, array("'", '"', ";")) &&
|
2889 |
-
$this->literal("}", false))
|
2890 |
-
{
|
2891 |
-
$out = array("interpolate", $interp);
|
2892 |
-
$this->eatWhiteDefault = $oldWhite;
|
2893 |
-
if ($this->eatWhiteDefault) $this->whitespace();
|
2894 |
-
return true;
|
2895 |
-
}
|
2896 |
-
|
2897 |
-
$this->eatWhiteDefault = $oldWhite;
|
2898 |
-
$this->seek($s);
|
2899 |
-
return false;
|
2900 |
-
}
|
2901 |
-
|
2902 |
-
protected function unit(&$unit) {
|
2903 |
-
// speed shortcut
|
2904 |
-
if (isset($this->buffer[$this->count])) {
|
2905 |
-
$char = $this->buffer[$this->count];
|
2906 |
-
if (!ctype_digit($char) && $char != ".") return false;
|
2907 |
-
}
|
2908 |
-
|
2909 |
-
if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
|
2910 |
-
$unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
|
2911 |
-
return true;
|
2912 |
-
}
|
2913 |
-
return false;
|
2914 |
-
}
|
2915 |
-
|
2916 |
-
// a # color
|
2917 |
-
protected function color(&$out) {
|
2918 |
-
if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
|
2919 |
-
if (strlen($m[1]) > 7) {
|
2920 |
-
$out = array("string", "", array($m[1]));
|
2921 |
-
} else {
|
2922 |
-
$out = array("raw_color", $m[1]);
|
2923 |
-
}
|
2924 |
-
return true;
|
2925 |
-
}
|
2926 |
-
|
2927 |
-
return false;
|
2928 |
-
}
|
2929 |
-
|
2930 |
-
// consume an argument definition list surrounded by ()
|
2931 |
-
// each argument is a variable name with optional value
|
2932 |
-
// or at the end a ... or a variable named followed by ...
|
2933 |
-
// arguments are separated by , unless a ; is in the list, then ; is the
|
2934 |
-
// delimiter.
|
2935 |
-
protected function argumentDef(&$args, &$isVararg) {
|
2936 |
-
$s = $this->seek();
|
2937 |
-
if (!$this->literal('(')) return false;
|
2938 |
-
|
2939 |
-
$values = array();
|
2940 |
-
$delim = ",";
|
2941 |
-
$method = "expressionList";
|
2942 |
-
|
2943 |
-
$isVararg = false;
|
2944 |
-
while (true) {
|
2945 |
-
if ($this->literal("...")) {
|
2946 |
-
$isVararg = true;
|
2947 |
-
break;
|
2948 |
-
}
|
2949 |
-
|
2950 |
-
if ($this->$method($value)) {
|
2951 |
-
if ($value[0] == "variable") {
|
2952 |
-
$arg = array("arg", $value[1]);
|
2953 |
-
$ss = $this->seek();
|
2954 |
-
|
2955 |
-
if ($this->assign() && $this->$method($rhs)) {
|
2956 |
-
$arg[] = $rhs;
|
2957 |
-
} else {
|
2958 |
-
$this->seek($ss);
|
2959 |
-
if ($this->literal("...")) {
|
2960 |
-
$arg[0] = "rest";
|
2961 |
-
$isVararg = true;
|
2962 |
-
}
|
2963 |
-
}
|
2964 |
-
|
2965 |
-
$values[] = $arg;
|
2966 |
-
if ($isVararg) break;
|
2967 |
-
continue;
|
2968 |
-
} else {
|
2969 |
-
$values[] = array("lit", $value);
|
2970 |
-
}
|
2971 |
-
}
|
2972 |
-
|
2973 |
-
|
2974 |
-
if (!$this->literal($delim)) {
|
2975 |
-
if ($delim == "," && $this->literal(";")) {
|
2976 |
-
// found new delim, convert existing args
|
2977 |
-
$delim = ";";
|
2978 |
-
$method = "propertyValue";
|
2979 |
-
|
2980 |
-
// transform arg list
|
2981 |
-
if (isset($values[1])) { // 2 items
|
2982 |
-
$newList = array();
|
2983 |
-
foreach ($values as $i => $arg) {
|
2984 |
-
switch($arg[0]) {
|
2985 |
-
case "arg":
|
2986 |
-
if ($i) {
|
2987 |
-
$this->throwError("Cannot mix ; and , as delimiter types");
|
2988 |
-
}
|
2989 |
-
$newList[] = $arg[2];
|
2990 |
-
break;
|
2991 |
-
case "lit":
|
2992 |
-
$newList[] = $arg[1];
|
2993 |
-
break;
|
2994 |
-
case "rest":
|
2995 |
-
$this->throwError("Unexpected rest before semicolon");
|
2996 |
-
}
|
2997 |
-
}
|
2998 |
-
|
2999 |
-
$newList = array("list", ", ", $newList);
|
3000 |
-
|
3001 |
-
switch ($values[0][0]) {
|
3002 |
-
case "arg":
|
3003 |
-
$newArg = array("arg", $values[0][1], $newList);
|
3004 |
-
break;
|
3005 |
-
case "lit":
|
3006 |
-
$newArg = array("lit", $newList);
|
3007 |
-
break;
|
3008 |
-
}
|
3009 |
-
|
3010 |
-
} elseif ($values) { // 1 item
|
3011 |
-
$newArg = $values[0];
|
3012 |
-
}
|
3013 |
-
|
3014 |
-
if ($newArg) {
|
3015 |
-
$values = array($newArg);
|
3016 |
-
}
|
3017 |
-
} else {
|
3018 |
-
break;
|
3019 |
-
}
|
3020 |
-
}
|
3021 |
-
}
|
3022 |
-
|
3023 |
-
if (!$this->literal(')')) {
|
3024 |
-
$this->seek($s);
|
3025 |
-
return false;
|
3026 |
-
}
|
3027 |
-
|
3028 |
-
$args = $values;
|
3029 |
-
|
3030 |
-
return true;
|
3031 |
-
}
|
3032 |
-
|
3033 |
-
// consume a list of tags
|
3034 |
-
// this accepts a hanging delimiter
|
3035 |
-
protected function tags(&$tags, $simple = false, $delim = ',') {
|
3036 |
-
$tags = array();
|
3037 |
-
while ($this->tag($tt, $simple)) {
|
3038 |
-
$tags[] = $tt;
|
3039 |
-
if (!$this->literal($delim)) break;
|
3040 |
-
}
|
3041 |
-
if (count($tags) == 0) return false;
|
3042 |
-
|
3043 |
-
return true;
|
3044 |
-
}
|
3045 |
-
|
3046 |
-
// list of tags of specifying mixin path
|
3047 |
-
// optionally separated by > (lazy, accepts extra >)
|
3048 |
-
protected function mixinTags(&$tags) {
|
3049 |
-
$s = $this->seek();
|
3050 |
-
$tags = array();
|
3051 |
-
while ($this->tag($tt, true)) {
|
3052 |
-
$tags[] = $tt;
|
3053 |
-
$this->literal(">");
|
3054 |
-
}
|
3055 |
-
|
3056 |
-
if (count($tags) == 0) return false;
|
3057 |
-
|
3058 |
-
return true;
|
3059 |
-
}
|
3060 |
-
|
3061 |
-
// a bracketed value (contained within in a tag definition)
|
3062 |
-
protected function tagBracket(&$parts, &$hasExpression) {
|
3063 |
-
// speed shortcut
|
3064 |
-
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
|
3065 |
-
return false;
|
3066 |
-
}
|
3067 |
-
|
3068 |
-
$s = $this->seek();
|
3069 |
-
|
3070 |
-
$hasInterpolation = false;
|
3071 |
-
|
3072 |
-
if ($this->literal("[", false)) {
|
3073 |
-
$attrParts = array("[");
|
3074 |
-
// keyword, string, operator
|
3075 |
-
while (true) {
|
3076 |
-
if ($this->literal("]", false)) {
|
3077 |
-
$this->count--;
|
3078 |
-
break; // get out early
|
3079 |
-
}
|
3080 |
-
|
3081 |
-
if ($this->match('\s+', $m)) {
|
3082 |
-
$attrParts[] = " ";
|
3083 |
-
continue;
|
3084 |
-
}
|
3085 |
-
if ($this->string($str)) {
|
3086 |
-
// escape parent selector, (yuck)
|
3087 |
-
foreach ($str[2] as &$chunk) {
|
3088 |
-
$chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
|
3089 |
-
}
|
3090 |
-
|
3091 |
-
$attrParts[] = $str;
|
3092 |
-
$hasInterpolation = true;
|
3093 |
-
continue;
|
3094 |
-
}
|
3095 |
-
|
3096 |
-
if ($this->keyword($word)) {
|
3097 |
-
$attrParts[] = $word;
|
3098 |
-
continue;
|
3099 |
-
}
|
3100 |
-
|
3101 |
-
if ($this->interpolation($inter, false)) {
|
3102 |
-
$attrParts[] = $inter;
|
3103 |
-
$hasInterpolation = true;
|
3104 |
-
continue;
|
3105 |
-
}
|
3106 |
-
|
3107 |
-
// operator, handles attr namespace too
|
3108 |
-
if ($this->match('[|-~\$\*\^=]+', $m)) {
|
3109 |
-
$attrParts[] = $m[0];
|
3110 |
-
continue;
|
3111 |
-
}
|
3112 |
-
|
3113 |
-
break;
|
3114 |
-
}
|
3115 |
-
|
3116 |
-
if ($this->literal("]", false)) {
|
3117 |
-
$attrParts[] = "]";
|
3118 |
-
foreach ($attrParts as $part) {
|
3119 |
-
$parts[] = $part;
|
3120 |
-
}
|
3121 |
-
$hasExpression = $hasExpression || $hasInterpolation;
|
3122 |
-
return true;
|
3123 |
-
}
|
3124 |
-
$this->seek($s);
|
3125 |
-
}
|
3126 |
-
|
3127 |
-
$this->seek($s);
|
3128 |
-
return false;
|
3129 |
-
}
|
3130 |
-
|
3131 |
-
// a space separated list of selectors
|
3132 |
-
protected function tag(&$tag, $simple = false) {
|
3133 |
-
if ($simple)
|
3134 |
-
$chars = '^@,:;{}\][>\(\) "\'';
|
3135 |
-
else
|
3136 |
-
$chars = '^@,;{}["\'';
|
3137 |
-
|
3138 |
-
$s = $this->seek();
|
3139 |
-
|
3140 |
-
$hasExpression = false;
|
3141 |
-
$parts = array();
|
3142 |
-
while ($this->tagBracket($parts, $hasExpression));
|
3143 |
-
|
3144 |
-
$oldWhite = $this->eatWhiteDefault;
|
3145 |
-
$this->eatWhiteDefault = false;
|
3146 |
-
|
3147 |
-
while (true) {
|
3148 |
-
if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
|
3149 |
-
$parts[] = $m[1];
|
3150 |
-
if ($simple) break;
|
3151 |
-
|
3152 |
-
while ($this->tagBracket($parts, $hasExpression));
|
3153 |
-
continue;
|
3154 |
-
}
|
3155 |
-
|
3156 |
-
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
|
3157 |
-
if ($this->interpolation($interp)) {
|
3158 |
-
$hasExpression = true;
|
3159 |
-
$interp[2] = true; // don't unescape
|
3160 |
-
$parts[] = $interp;
|
3161 |
-
continue;
|
3162 |
-
}
|
3163 |
-
|
3164 |
-
if ($this->literal("@")) {
|
3165 |
-
$parts[] = "@";
|
3166 |
-
continue;
|
3167 |
-
}
|
3168 |
-
}
|
3169 |
-
|
3170 |
-
if ($this->unit($unit)) { // for keyframes
|
3171 |
-
$parts[] = $unit[1];
|
3172 |
-
$parts[] = $unit[2];
|
3173 |
-
continue;
|
3174 |
-
}
|
3175 |
-
|
3176 |
-
break;
|
3177 |
-
}
|
3178 |
-
|
3179 |
-
$this->eatWhiteDefault = $oldWhite;
|
3180 |
-
if (!$parts) {
|
3181 |
-
$this->seek($s);
|
3182 |
-
return false;
|
3183 |
-
}
|
3184 |
-
|
3185 |
-
if ($hasExpression) {
|
3186 |
-
$tag = array("exp", array("string", "", $parts));
|
3187 |
-
} else {
|
3188 |
-
$tag = trim(implode($parts));
|
3189 |
-
}
|
3190 |
-
|
3191 |
-
$this->whitespace();
|
3192 |
-
return true;
|
3193 |
-
}
|
3194 |
-
|
3195 |
-
// a css function
|
3196 |
-
protected function func(&$func) {
|
3197 |
-
$s = $this->seek();
|
3198 |
-
|
3199 |
-
if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
|
3200 |
-
$fname = $m[1];
|
3201 |
-
|
3202 |
-
$sPreArgs = $this->seek();
|
3203 |
-
|
3204 |
-
$args = array();
|
3205 |
-
while (true) {
|
3206 |
-
$ss = $this->seek();
|
3207 |
-
// this ugly nonsense is for ie filter properties
|
3208 |
-
if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
|
3209 |
-
$args[] = array("string", "", array($name, "=", $value));
|
3210 |
-
} else {
|
3211 |
-
$this->seek($ss);
|
3212 |
-
if ($this->expressionList($value)) {
|
3213 |
-
$args[] = $value;
|
3214 |
-
}
|
3215 |
-
}
|
3216 |
-
|
3217 |
-
if (!$this->literal(',')) break;
|
3218 |
-
}
|
3219 |
-
$args = array('list', ',', $args);
|
3220 |
-
|
3221 |
-
if ($this->literal(')')) {
|
3222 |
-
$func = array('function', $fname, $args);
|
3223 |
-
return true;
|
3224 |
-
} elseif ($fname == 'url') {
|
3225 |
-
// couldn't parse and in url? treat as string
|
3226 |
-
$this->seek($sPreArgs);
|
3227 |
-
if ($this->openString(")", $string) && $this->literal(")")) {
|
3228 |
-
$func = array('function', $fname, $string);
|
3229 |
-
return true;
|
3230 |
-
}
|
3231 |
-
}
|
3232 |
-
}
|
3233 |
-
|
3234 |
-
$this->seek($s);
|
3235 |
-
return false;
|
3236 |
-
}
|
3237 |
-
|
3238 |
-
// consume a less variable
|
3239 |
-
protected function variable(&$name) {
|
3240 |
-
$s = $this->seek();
|
3241 |
-
if ($this->literal($this->lessc->vPrefix, false) &&
|
3242 |
-
($this->variable($sub) || $this->keyword($name)))
|
3243 |
-
{
|
3244 |
-
if (!empty($sub)) {
|
3245 |
-
$name = array('variable', $sub);
|
3246 |
-
} else {
|
3247 |
-
$name = $this->lessc->vPrefix.$name;
|
3248 |
-
}
|
3249 |
-
return true;
|
3250 |
-
}
|
3251 |
-
|
3252 |
-
$name = null;
|
3253 |
-
$this->seek($s);
|
3254 |
-
return false;
|
3255 |
-
}
|
3256 |
-
|
3257 |
-
/**
|
3258 |
-
* Consume an assignment operator
|
3259 |
-
* Can optionally take a name that will be set to the current property name
|
3260 |
-
*/
|
3261 |
-
protected function assign($name = null) {
|
3262 |
-
if ($name) $this->currentProperty = $name;
|
3263 |
-
return $this->literal(':') || $this->literal('=');
|
3264 |
-
}
|
3265 |
-
|
3266 |
-
// consume a keyword
|
3267 |
-
protected function keyword(&$word) {
|
3268 |
-
if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
|
3269 |
-
$word = $m[1];
|
3270 |
-
return true;
|
3271 |
-
}
|
3272 |
-
return false;
|
3273 |
-
}
|
3274 |
-
|
3275 |
-
// consume an end of statement delimiter
|
3276 |
-
protected function end() {
|
3277 |
-
if ($this->literal(';')) {
|
3278 |
-
return true;
|
3279 |
-
} elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
|
3280 |
-
// if there is end of file or a closing block next then we don't need a ;
|
3281 |
-
return true;
|
3282 |
-
}
|
3283 |
-
return false;
|
3284 |
-
}
|
3285 |
-
|
3286 |
-
protected function guards(&$guards) {
|
3287 |
-
$s = $this->seek();
|
3288 |
-
|
3289 |
-
if (!$this->literal("when")) {
|
3290 |
-
$this->seek($s);
|
3291 |
-
return false;
|
3292 |
-
}
|
3293 |
-
|
3294 |
-
$guards = array();
|
3295 |
-
|
3296 |
-
while ($this->guardGroup($g)) {
|
3297 |
-
$guards[] = $g;
|
3298 |
-
if (!$this->literal(",")) break;
|
3299 |
-
}
|
3300 |
-
|
3301 |
-
if (count($guards) == 0) {
|
3302 |
-
$guards = null;
|
3303 |
-
$this->seek($s);
|
3304 |
-
return false;
|
3305 |
-
}
|
3306 |
-
|
3307 |
-
return true;
|
3308 |
-
}
|
3309 |
-
|
3310 |
-
// a bunch of guards that are and'd together
|
3311 |
-
// TODO rename to guardGroup
|
3312 |
-
protected function guardGroup(&$guardGroup) {
|
3313 |
-
$s = $this->seek();
|
3314 |
-
$guardGroup = array();
|
3315 |
-
while ($this->guard($guard)) {
|
3316 |
-
$guardGroup[] = $guard;
|
3317 |
-
if (!$this->literal("and")) break;
|
3318 |
-
}
|
3319 |
-
|
3320 |
-
if (count($guardGroup) == 0) {
|
3321 |
-
$guardGroup = null;
|
3322 |
-
$this->seek($s);
|
3323 |
-
return false;
|
3324 |
-
}
|
3325 |
-
|
3326 |
-
return true;
|
3327 |
-
}
|
3328 |
-
|
3329 |
-
protected function guard(&$guard) {
|
3330 |
-
$s = $this->seek();
|
3331 |
-
$negate = $this->literal("not");
|
3332 |
-
|
3333 |
-
if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
|
3334 |
-
$guard = $exp;
|
3335 |
-
if ($negate) $guard = array("negate", $guard);
|
3336 |
-
return true;
|
3337 |
-
}
|
3338 |
-
|
3339 |
-
$this->seek($s);
|
3340 |
-
return false;
|
3341 |
-
}
|
3342 |
-
|
3343 |
-
/* raw parsing functions */
|
3344 |
-
|
3345 |
-
protected function literal($what, $eatWhitespace = null) {
|
3346 |
-
if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
|
3347 |
-
|
3348 |
-
// shortcut on single letter
|
3349 |
-
if (!isset($what[1]) && isset($this->buffer[$this->count])) {
|
3350 |
-
if ($this->buffer[$this->count] == $what) {
|
3351 |
-
if (!$eatWhitespace) {
|
3352 |
-
$this->count++;
|
3353 |
-
return true;
|
3354 |
-
}
|
3355 |
-
// goes below...
|
3356 |
-
} else {
|
3357 |
-
return false;
|
3358 |
-
}
|
3359 |
-
}
|
3360 |
-
|
3361 |
-
if (!isset(self::$literalCache[$what])) {
|
3362 |
-
self::$literalCache[$what] = JupiterX_Lessc::preg_quote($what);
|
3363 |
-
}
|
3364 |
-
|
3365 |
-
return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
|
3366 |
-
}
|
3367 |
-
|
3368 |
-
protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
|
3369 |
-
$s = $this->seek();
|
3370 |
-
$items = array();
|
3371 |
-
while ($this->$parseItem($value)) {
|
3372 |
-
$items[] = $value;
|
3373 |
-
if ($delim) {
|
3374 |
-
if (!$this->literal($delim)) break;
|
3375 |
-
}
|
3376 |
-
}
|
3377 |
-
|
3378 |
-
if (count($items) == 0) {
|
3379 |
-
$this->seek($s);
|
3380 |
-
return false;
|
3381 |
-
}
|
3382 |
-
|
3383 |
-
if ($flatten && count($items) == 1) {
|
3384 |
-
$out = $items[0];
|
3385 |
-
} else {
|
3386 |
-
$out = array("list", $delim, $items);
|
3387 |
-
}
|
3388 |
-
|
3389 |
-
return true;
|
3390 |
-
}
|
3391 |
-
|
3392 |
-
|
3393 |
-
// advance counter to next occurrence of $what
|
3394 |
-
// $until - don't include $what in advance
|
3395 |
-
// $allowNewline, if string, will be used as valid char set
|
3396 |
-
protected function to($what, &$out, $until = false, $allowNewline = false) {
|
3397 |
-
if (is_string($allowNewline)) {
|
3398 |
-
$validChars = $allowNewline;
|
3399 |
-
} else {
|
3400 |
-
$validChars = $allowNewline ? "." : "[^\n]";
|
3401 |
-
}
|
3402 |
-
if (!$this->match('('.$validChars.'*?)'.JupiterX_Lessc::preg_quote($what), $m, !$until)) return false;
|
3403 |
-
if ($until) $this->count -= strlen($what); // give back $what
|
3404 |
-
$out = $m[1];
|
3405 |
-
return true;
|
3406 |
-
}
|
3407 |
-
|
3408 |
-
// try to match something on head of buffer
|
3409 |
-
protected function match($regex, &$out, $eatWhitespace = null) {
|
3410 |
-
if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
|
3411 |
-
|
3412 |
-
$r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
|
3413 |
-
if (preg_match($r, $this->buffer, $out, null, $this->count)) {
|
3414 |
-
$this->count += strlen($out[0]);
|
3415 |
-
if ($eatWhitespace && $this->writeComments) $this->whitespace();
|
3416 |
-
return true;
|
3417 |
-
}
|
3418 |
-
return false;
|
3419 |
-
}
|
3420 |
-
|
3421 |
-
// match some whitespace
|
3422 |
-
protected function whitespace() {
|
3423 |
-
if ($this->writeComments) {
|
3424 |
-
$gotWhite = false;
|
3425 |
-
while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
|
3426 |
-
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
|
3427 |
-
$this->append(array("comment", $m[1]));
|
3428 |
-
$this->commentsSeen[$this->count] = true;
|
3429 |
-
}
|
3430 |
-
$this->count += strlen($m[0]);
|
3431 |
-
$gotWhite = true;
|
3432 |
-
}
|
3433 |
-
return $gotWhite;
|
3434 |
-
} else {
|
3435 |
-
$this->match("", $m);
|
3436 |
-
return strlen($m[0]) > 0;
|
3437 |
-
}
|
3438 |
-
}
|
3439 |
-
|
3440 |
-
// match something without consuming it
|
3441 |
-
protected function peek($regex, &$out = null, $from=null) {
|
3442 |
-
if (is_null($from)) $from = $this->count;
|
3443 |
-
$r = '/'.$regex.'/Ais';
|
3444 |
-
$result = preg_match($r, $this->buffer, $out, null, $from);
|
3445 |
-
|
3446 |
-
return $result;
|
3447 |
-
}
|
3448 |
-
|
3449 |
-
// seek to a spot in the buffer or return where we are on no argument
|
3450 |
-
protected function seek($where = null) {
|
3451 |
-
if ($where === null) return $this->count;
|
3452 |
-
else $this->count = $where;
|
3453 |
-
return true;
|
3454 |
-
}
|
3455 |
-
|
3456 |
-
/* misc functions */
|
3457 |
-
|
3458 |
-
public function throwError($msg = "parse error", $count = null) {
|
3459 |
-
$count = is_null($count) ? $this->count : $count;
|
3460 |
-
|
3461 |
-
$line = $this->line +
|
3462 |
-
substr_count(substr($this->buffer, 0, $count), "\n");
|
3463 |
-
|
3464 |
-
if (!empty($this->sourceName)) {
|
3465 |
-
$loc = "$this->sourceName on line $line";
|
3466 |
-
} else {
|
3467 |
-
$loc = "line: $line";
|
3468 |
-
}
|
3469 |
-
|
3470 |
-
// TODO this depends on $this->count
|
3471 |
-
if ($this->peek("(.*?)(\n|$)", $m, $count)) {
|
3472 |
-
throw new exception("$msg: failed at `$m[1]` $loc");
|
3473 |
-
} else {
|
3474 |
-
throw new exception("$msg: $loc");
|
3475 |
-
}
|
3476 |
-
}
|
3477 |
-
|
3478 |
-
protected function pushBlock($selectors=null, $type=null) {
|
3479 |
-
$b = new stdclass;
|
3480 |
-
$b->parent = $this->env;
|
3481 |
-
|
3482 |
-
$b->type = $type;
|
3483 |
-
$b->id = self::$nextBlockId++;
|
3484 |
-
|
3485 |
-
$b->isVararg = false; // TODO: kill me from here
|
3486 |
-
$b->tags = $selectors;
|
3487 |
-
|
3488 |
-
$b->props = array();
|
3489 |
-
$b->children = array();
|
3490 |
-
|
3491 |
-
$this->env = $b;
|
3492 |
-
return $b;
|
3493 |
-
}
|
3494 |
-
|
3495 |
-
// push a block that doesn't multiply tags
|
3496 |
-
protected function pushSpecialBlock($type) {
|
3497 |
-
return $this->pushBlock(null, $type);
|
3498 |
-
}
|
3499 |
-
|
3500 |
-
// append a property to the current block
|
3501 |
-
protected function append($prop, $pos = null) {
|
3502 |
-
if ($pos !== null) $prop[-1] = $pos;
|
3503 |
-
$this->env->props[] = $prop;
|
3504 |
-
}
|
3505 |
-
|
3506 |
-
// pop something off the stack
|
3507 |
-
protected function pop() {
|
3508 |
-
$old = $this->env;
|
3509 |
-
$this->env = $this->env->parent;
|
3510 |
-
return $old;
|
3511 |
-
}
|
3512 |
-
|
3513 |
-
// remove comments from $text
|
3514 |
-
// todo: make it work for all functions, not just url
|
3515 |
-
protected function removeComments($text) {
|
3516 |
-
$look = array(
|
3517 |
-
'url(', '//', '/*', '"', "'"
|
3518 |
-
);
|
3519 |
-
|
3520 |
-
$out = '';
|
3521 |
-
$min = null;
|
3522 |
-
while (true) {
|
3523 |
-
// find the next item
|
3524 |
-
foreach ($look as $token) {
|
3525 |
-
$pos = strpos($text, $token);
|
3526 |
-
if ($pos !== false) {
|
3527 |
-
if (!isset($min) || $pos < $min[1]) $min = array($token, $pos);
|
3528 |
-
}
|
3529 |
-
}
|
3530 |
-
|
3531 |
-
if (is_null($min)) break;
|
3532 |
-
|
3533 |
-
$count = $min[1];
|
3534 |
-
$skip = 0;
|
3535 |
-
$newlines = 0;
|
3536 |
-
switch ($min[0]) {
|
3537 |
-
case 'url(':
|
3538 |
-
if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
|
3539 |
-
$count += strlen($m[0]) - strlen($min[0]);
|
3540 |
-
break;
|
3541 |
-
case '"':
|
3542 |
-
case "'":
|
3543 |
-
if (preg_match('/'.$min[0].'.*?(?<!\\\\)'.$min[0].'/', $text, $m, 0, $count))
|
3544 |
-
$count += strlen($m[0]) - 1;
|
3545 |
-
break;
|
3546 |
-
case '//':
|
3547 |
-
$skip = strpos($text, "\n", $count);
|
3548 |
-
if ($skip === false) $skip = strlen($text) - $count;
|
3549 |
-
else $skip -= $count;
|
3550 |
-
break;
|
3551 |
-
case '/*':
|
3552 |
-
if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
|
3553 |
-
$skip = strlen($m[0]);
|
3554 |
-
$newlines = substr_count($m[0], "\n");
|
3555 |
-
}
|
3556 |
-
break;
|
3557 |
-
}
|
3558 |
-
|
3559 |
-
if ($skip == 0) $count += strlen($min[0]);
|
3560 |
-
|
3561 |
-
$out .= substr($text, 0, $count).str_repeat("\n", $newlines);
|
3562 |
-
$text = substr($text, $count + $skip);
|
3563 |
-
|
3564 |
-
$min = null;
|
3565 |
-
}
|
3566 |
-
|
3567 |
-
return $out.$text;
|
3568 |
-
}
|
3569 |
-
|
3570 |
-
}
|
3571 |
-
|
3572 |
-
/**
|
3573 |
-
* @ignore
|
3574 |
-
*/
|
3575 |
-
class lessc_formatter_classic {
|
3576 |
-
public $indentChar = " ";
|
3577 |
-
|
3578 |
-
public $break = "\n";
|
3579 |
-
public $open = " {";
|
3580 |
-
public $close = "}";
|
3581 |
-
public $selectorSeparator = ", ";
|
3582 |
-
public $assignSeparator = ":";
|
3583 |
-
|
3584 |
-
public $openSingle = " { ";
|
3585 |
-
public $closeSingle = " }";
|
3586 |
-
|
3587 |
-
public $disableSingle = false;
|
3588 |
-
public $breakSelectors = false;
|
3589 |
-
|
3590 |
-
public $compressColors = false;
|
3591 |
-
|
3592 |
-
public function __construct() {
|
3593 |
-
$this->indentLevel = 0;
|
3594 |
-
}
|
3595 |
-
|
3596 |
-
public function indentStr($n = 0) {
|
3597 |
-
return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
|
3598 |
-
}
|
3599 |
-
|
3600 |
-
public function property($name, $value) {
|
3601 |
-
return $name . $this->assignSeparator . $value . ";";
|
3602 |
-
}
|
3603 |
-
|
3604 |
-
protected function isEmpty($block) {
|
3605 |
-
if (empty($block->lines)) {
|
3606 |
-
foreach ($block->children as $child) {
|
3607 |
-
if (!$this->isEmpty($child)) return false;
|
3608 |
-
}
|
3609 |
-
|
3610 |
-
return true;
|
3611 |
-
}
|
3612 |
-
return false;
|
3613 |
-
}
|
3614 |
-
|
3615 |
-
public function block($block) {
|
3616 |
-
if ($this->isEmpty($block)) return;
|
3617 |
-
|
3618 |
-
$inner = $pre = $this->indentStr();
|
3619 |
-
|
3620 |
-
$isSingle = !$this->disableSingle &&
|
3621 |
-
is_null($block->type) && count($block->lines) == 1;
|
3622 |
-
|
3623 |
-
if (!empty($block->selectors)) {
|
3624 |
-
$this->indentLevel++;
|
3625 |
-
|
3626 |
-
if ($this->breakSelectors) {
|
3627 |
-
$selectorSeparator = $this->selectorSeparator . $this->break . $pre;
|
3628 |
-
} else {
|
3629 |
-
$selectorSeparator = $this->selectorSeparator;
|
3630 |
-
}
|
3631 |
-
|
3632 |
-
echo $pre .
|
3633 |
-
implode($selectorSeparator, $block->selectors);
|
3634 |
-
if ($isSingle) {
|
3635 |
-
echo $this->openSingle;
|
3636 |
-
$inner = "";
|
3637 |
-
} else {
|
3638 |
-
echo $this->open . $this->break;
|
3639 |
-
$inner = $this->indentStr();
|
3640 |
-
}
|
3641 |
-
|
3642 |
-
}
|
3643 |
-
|
3644 |
-
if (!empty($block->lines)) {
|
3645 |
-
$glue = $this->break.$inner;
|
3646 |
-
echo $inner . implode($glue, $block->lines);
|
3647 |
-
if (!$isSingle && !empty($block->children)) {
|
3648 |
-
echo $this->break;
|
3649 |
-
}
|
3650 |
-
}
|
3651 |
-
|
3652 |
-
foreach ($block->children as $child) {
|
3653 |
-
$this->block($child);
|
3654 |
-
}
|
3655 |
-
|
3656 |
-
if (!empty($block->selectors)) {
|
3657 |
-
if (!$isSingle && empty($block->children)) echo $this->break;
|
3658 |
-
|
3659 |
-
if ($isSingle) {
|
3660 |
-
echo $this->closeSingle . $this->break;
|
3661 |
-
} else {
|
3662 |
-
echo $pre . $this->close . $this->break;
|
3663 |
-
}
|
3664 |
-
|
3665 |
-
$this->indentLevel--;
|
3666 |
-
}
|
3667 |
-
}
|
3668 |
-
}
|
3669 |
-
|
3670 |
-
/**
|
3671 |
-
* @ignore
|
3672 |
-
*/
|
3673 |
-
class lessc_formatter_compressed extends lessc_formatter_classic {
|
3674 |
-
public $disableSingle = true;
|
3675 |
-
public $open = "{";
|
3676 |
-
public $selectorSeparator = ",";
|
3677 |
-
public $assignSeparator = ":";
|
3678 |
-
public $break = "";
|
3679 |
-
public $compressColors = true;
|
3680 |
-
|
3681 |
-
public function indentStr($n = 0) {
|
3682 |
-
return "";
|
3683 |
-
}
|
3684 |
-
}
|
3685 |
-
|
3686 |
-
/**
|
3687 |
-
* @ignore
|
3688 |
-
*/
|
3689 |
-
class lessc_formatter_lessjs extends lessc_formatter_classic {
|
3690 |
-
public $disableSingle = true;
|
3691 |
-
public $breakSelectors = true;
|
3692 |
-
public $assignSeparator = ": ";
|
3693 |
-
public $selectorSeparator = ",";
|
3694 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* lessphp v0.4.0
|
4 |
+
* http://leafo.net/lessphp
|
5 |
+
*
|
6 |
+
* LESS css compiler, adapted from http://lesscss.org
|
7 |
+
*
|
8 |
+
* Copyright 2012, Leaf Corcoran <leafot@gmail.com>
|
9 |
+
* Licensed under MIT or GPLv3, see LICENSE
|
10 |
+
*
|
11 |
+
* @ignore
|
12 |
+
*/
|
13 |
+
|
14 |
+
|
15 |
+
/**
|
16 |
+
* The less compiler and parser.
|
17 |
+
*
|
18 |
+
* Converting LESS to CSS is a three stage process. The incoming file is parsed
|
19 |
+
* by `lessc_parser` into a syntax tree, then it is compiled into another tree
|
20 |
+
* representing the CSS structure by `lessc`. The CSS tree is fed into a
|
21 |
+
* formatter, like `lessc_formatter` which then outputs CSS as a string.
|
22 |
+
*
|
23 |
+
* During the first compile, all values are *reduced*, which means that their
|
24 |
+
* types are brought to the lowest form before being dump as strings. This
|
25 |
+
* handles math equations, variable dereferences, and the like.
|
26 |
+
*
|
27 |
+
* The `parse` function of `lessc` is the entry point.
|
28 |
+
*
|
29 |
+
* In summary:
|
30 |
+
*
|
31 |
+
* The `lessc` class creates an intstance of the parser, feeds it LESS code,
|
32 |
+
* then transforms the resulting tree to a CSS tree. This class also holds the
|
33 |
+
* evaluation context, such as all available mixins and variables at any given
|
34 |
+
* time.
|
35 |
+
*
|
36 |
+
* The `lessc_parser` class is only concerned with parsing its input.
|
37 |
+
*
|
38 |
+
* The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
|
39 |
+
* handling things like indentation.
|
40 |
+
*
|
41 |
+
* @ignore
|
42 |
+
*/
|
43 |
+
class JupiterX_Lessc {
|
44 |
+
static public $VERSION = "v0.4.0";
|
45 |
+
static protected $TRUE = array("keyword", "true");
|
46 |
+
static protected $FALSE = array("keyword", "false");
|
47 |
+
|
48 |
+
protected $libFunctions = array();
|
49 |
+
protected $registeredVars = array();
|
50 |
+
protected $preserveComments = false;
|
51 |
+
|
52 |
+
public $vPrefix = '@'; // prefix of abstract properties
|
53 |
+
public $mPrefix = '$'; // prefix of abstract blocks
|
54 |
+
public $parentSelector = '&';
|
55 |
+
|
56 |
+
public $importDisabled = false;
|
57 |
+
public $importDir = '';
|
58 |
+
|
59 |
+
protected $numberPrecision = null;
|
60 |
+
|
61 |
+
protected $allParsedFiles = array();
|
62 |
+
|
63 |
+
// set to the parser that generated the current line when compiling
|
64 |
+
// so we know how to create error messages
|
65 |
+
protected $sourceParser = null;
|
66 |
+
protected $sourceLoc = null;
|
67 |
+
|
68 |
+
static public $defaultValue = array("keyword", "");
|
69 |
+
|
70 |
+
static protected $nextImportId = 0; // uniquely identify imports
|
71 |
+
|
72 |
+
// attempts to find the path of an import url, returns null for css files
|
73 |
+
protected function findImport($url) {
|
74 |
+
foreach ((array)$this->importDir as $dir) {
|
75 |
+
$full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url;
|
76 |
+
if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) {
|
77 |
+
return $file;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
return null;
|
82 |
+
}
|
83 |
+
|
84 |
+
protected function fileExists($name) {
|
85 |
+
return is_file($name);
|
86 |
+
}
|
87 |
+
|
88 |
+
static public function compressList($items, $delim) {
|
89 |
+
if (!isset($items[1]) && isset($items[0])) return $items[0];
|
90 |
+
else return array('list', $delim, $items);
|
91 |
+
}
|
92 |
+
|
93 |
+
static public function preg_quote($what) {
|
94 |
+
return preg_quote($what, '/');
|
95 |
+
}
|
96 |
+
|
97 |
+
protected function tryImport($importPath, $parentBlock, $out) {
|
98 |
+
if ($importPath[0] == "function" && $importPath[1] == "url") {
|
99 |
+
$importPath = $this->flattenList($importPath[2]);
|
100 |
+
}
|
101 |
+
|
102 |
+
$str = $this->coerceString($importPath);
|
103 |
+
if ($str === null) return false;
|
104 |
+
|
105 |
+
$url = $this->compileValue($this->lib_unquote($str));
|
106 |
+
|
107 |
+
// don't import if it ends in css
|
108 |
+
if (substr_compare($url, '.css', -4, 4) === 0) return false;
|
109 |
+
|
110 |
+
$realPath = $this->findImport($url);
|
111 |
+
|
112 |
+
if ($realPath === null) return false;
|
113 |
+
|
114 |
+
if ($this->importDisabled) {
|
115 |
+
return array(false, "/* import disabled */");
|
116 |
+
}
|
117 |
+
|
118 |
+
if (isset($this->allParsedFiles[realpath($realPath)])) {
|
119 |
+
return array(false, null);
|
120 |
+
}
|
121 |
+
|
122 |
+
$this->addParsedFile($realPath);
|
123 |
+
$parser = $this->makeParser($realPath);
|
124 |
+
$root = $parser->parse($GLOBALS['wp_filesystem']->get_contents($realPath));
|
125 |
+
|
126 |
+
// set the parents of all the block props
|
127 |
+
foreach ($root->props as $prop) {
|
128 |
+
if ($prop[0] == "block") {
|
129 |
+
$prop[1]->parent = $parentBlock;
|
130 |
+
}
|
131 |
+
}
|
132 |
+
|
133 |
+
// copy mixins into scope, set their parents
|
134 |
+
// bring blocks from import into current block
|
135 |
+
// TODO: need to mark the source parser these came from this file
|
136 |
+
foreach ($root->children as $childName => $child) {
|
137 |
+
if (isset($parentBlock->children[$childName])) {
|
138 |
+
$parentBlock->children[$childName] = array_merge(
|
139 |
+
$parentBlock->children[$childName],
|
140 |
+
$child);
|
141 |
+
} else {
|
142 |
+
$parentBlock->children[$childName] = $child;
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
$pi = pathinfo($realPath);
|
147 |
+
$dir = $pi["dirname"];
|
148 |
+
|
149 |
+
list($top, $bottom) = $this->sortProps($root->props, true);
|
150 |
+
$this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
|
151 |
+
|
152 |
+
return array(true, $bottom, $parser, $dir);
|
153 |
+
}
|
154 |
+
|
155 |
+
protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
|
156 |
+
$oldSourceParser = $this->sourceParser;
|
157 |
+
|
158 |
+
$oldImport = $this->importDir;
|
159 |
+
|
160 |
+
// TODO: this is because the importDir api is stupid
|
161 |
+
$this->importDir = (array)$this->importDir;
|
162 |
+
array_unshift($this->importDir, $importDir);
|
163 |
+
|
164 |
+
foreach ($props as $prop) {
|
165 |
+
$this->compileProp($prop, $block, $out);
|
166 |
+
}
|
167 |
+
|
168 |
+
$this->importDir = $oldImport;
|
169 |
+
$this->sourceParser = $oldSourceParser;
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Recursively compiles a block.
|
174 |
+
*
|
175 |
+
* A block is analogous to a CSS block in most cases. A single LESS document
|
176 |
+
* is encapsulated in a block when parsed, but it does not have parent tags
|
177 |
+
* so all of it's children appear on the root level when compiled.
|
178 |
+
*
|
179 |
+
* Blocks are made up of props and children.
|
180 |
+
*
|
181 |
+
* Props are property instructions, array tuples which describe an action
|
182 |
+
* to be taken, eg. write a property, set a variable, mixin a block.
|
183 |
+
*
|
184 |
+
* The children of a block are just all the blocks that are defined within.
|
185 |
+
* This is used to look up mixins when performing a mixin.
|
186 |
+
*
|
187 |
+
* Compiling the block involves pushing a fresh environment on the stack,
|
188 |
+
* and iterating through the props, compiling each one.
|
189 |
+
*
|
190 |
+
* See lessc::compileProp()
|
191 |
+
*
|
192 |
+
*/
|
193 |
+
protected function compileBlock($block) {
|
194 |
+
switch ($block->type) {
|
195 |
+
case "root":
|
196 |
+
$this->compileRoot($block);
|
197 |
+
break;
|
198 |
+
case null:
|
199 |
+
$this->compileCSSBlock($block);
|
200 |
+
break;
|
201 |
+
case "media":
|
202 |
+
$this->compileMedia($block);
|
203 |
+
break;
|
204 |
+
case "directive":
|
205 |
+
$name = "@" . $block->name;
|
206 |
+
if (!empty($block->value)) {
|
207 |
+
$name .= " " . $this->compileValue($this->reduce($block->value));
|
208 |
+
}
|
209 |
+
|
210 |
+
$this->compileNestedBlock($block, array($name));
|
211 |
+
break;
|
212 |
+
default:
|
213 |
+
$this->throwError("unknown block type: $block->type\n");
|
214 |
+
}
|
215 |
+
}
|
216 |
+
|
217 |
+
protected function compileCSSBlock($block) {
|
218 |
+
$env = $this->pushEnv();
|
219 |
+
|
220 |
+
$selectors = $this->compileSelectors($block->tags);
|
221 |
+
$env->selectors = $this->multiplySelectors($selectors);
|
222 |
+
$out = $this->makeOutputBlock(null, $env->selectors);
|
223 |
+
|
224 |
+
$this->scope->children[] = $out;
|
225 |
+
$this->compileProps($block, $out);
|
226 |
+
|
227 |
+
$block->scope = $env; // mixins carry scope with them!
|
228 |
+
$this->popEnv();
|
229 |
+
}
|
230 |
+
|
231 |
+
protected function compileMedia($media) {
|
232 |
+
$env = $this->pushEnv($media);
|
233 |
+
$parentScope = $this->mediaParent($this->scope);
|
234 |
+
|
235 |
+
$query = $this->compileMediaQuery($this->multiplyMedia($env));
|
236 |
+
|
237 |
+
$this->scope = $this->makeOutputBlock($media->type, array($query));
|
238 |
+
$parentScope->children[] = $this->scope;
|
239 |
+
|
240 |
+
$this->compileProps($media, $this->scope);
|
241 |
+
|
242 |
+
if (count($this->scope->lines) > 0) {
|
243 |
+
$orphanSelelectors = $this->findClosestSelectors();
|
244 |
+
if (!is_null($orphanSelelectors)) {
|
245 |
+
$orphan = $this->makeOutputBlock(null, $orphanSelelectors);
|
246 |
+
$orphan->lines = $this->scope->lines;
|
247 |
+
array_unshift($this->scope->children, $orphan);
|
248 |
+
$this->scope->lines = array();
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
$this->scope = $this->scope->parent;
|
253 |
+
$this->popEnv();
|
254 |
+
}
|
255 |
+
|
256 |
+
protected function mediaParent($scope) {
|
257 |
+
while (!empty($scope->parent)) {
|
258 |
+
if (!empty($scope->type) && $scope->type != "media") {
|
259 |
+
break;
|
260 |
+
}
|
261 |
+
$scope = $scope->parent;
|
262 |
+
}
|
263 |
+
|
264 |
+
return $scope;
|
265 |
+
}
|
266 |
+
|
267 |
+
protected function compileNestedBlock($block, $selectors) {
|
268 |
+
$this->pushEnv($block);
|
269 |
+
$this->scope = $this->makeOutputBlock($block->type, $selectors);
|
270 |
+
$this->scope->parent->children[] = $this->scope;
|
271 |
+
|
272 |
+
$this->compileProps($block, $this->scope);
|
273 |
+
|
274 |
+
$this->scope = $this->scope->parent;
|
275 |
+
$this->popEnv();
|
276 |
+
}
|
277 |
+
|
278 |
+
protected function compileRoot($root) {
|
279 |
+
$this->pushEnv();
|
280 |
+
$this->scope = $this->makeOutputBlock($root->type);
|
281 |
+
$this->compileProps($root, $this->scope);
|
282 |
+
$this->popEnv();
|
283 |
+
}
|
284 |
+
|
285 |
+
protected function compileProps($block, $out) {
|
286 |
+
foreach ($this->sortProps($block->props) as $prop) {
|
287 |
+
$this->compileProp($prop, $block, $out);
|
288 |
+
}
|
289 |
+
|
290 |
+
$out->lines = array_values(array_unique($out->lines));
|
291 |
+
}
|
292 |
+
|
293 |
+
protected function sortProps($props, $split = false) {
|
294 |
+
$vars = array();
|
295 |
+
$imports = array();
|
296 |
+
$other = array();
|
297 |
+
|
298 |
+
foreach ($props as $prop) {
|
299 |
+
switch ($prop[0]) {
|
300 |
+
case "assign":
|
301 |
+
if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
|
302 |
+
$vars[] = $prop;
|
303 |
+
} else {
|
304 |
+
$other[] = $prop;
|
305 |
+
}
|
306 |
+
break;
|
307 |
+
case "import":
|
308 |
+
$id = self::$nextImportId++;
|
309 |
+
$prop[] = $id;
|
310 |
+
$imports[] = $prop;
|
311 |
+
$other[] = array("import_mixin", $id);
|
312 |
+
break;
|
313 |
+
default:
|
314 |
+
$other[] = $prop;
|
315 |
+
}
|
316 |
+
}
|
317 |
+
|
318 |
+
if ($split) {
|
319 |
+
return array(array_merge($vars, $imports), $other);
|
320 |
+
} else {
|
321 |
+
return array_merge($vars, $imports, $other);
|
322 |
+
}
|
323 |
+
}
|
324 |
+
|
325 |
+
protected function compileMediaQuery($queries) {
|
326 |
+
$compiledQueries = array();
|
327 |
+
foreach ($queries as $query) {
|
328 |
+
$parts = array();
|
329 |
+
foreach ($query as $q) {
|
330 |
+
switch ($q[0]) {
|
331 |
+
case "mediaType":
|
332 |
+
$parts[] = implode(" ", array_slice($q, 1));
|
333 |
+
break;
|
334 |
+
case "mediaExp":
|
335 |
+
if (isset($q[2])) {
|
336 |
+
$parts[] = "($q[1]: " .
|
337 |
+
$this->compileValue($this->reduce($q[2])) . ")";
|
338 |
+
} else {
|
339 |
+
$parts[] = "($q[1])";
|
340 |
+
}
|
341 |
+
break;
|
342 |
+
case "variable":
|
343 |
+
$parts[] = $this->compileValue($this->reduce($q));
|
344 |
+
break;
|
345 |
+
}
|
346 |
+
}
|
347 |
+
|
348 |
+
if (count($parts) > 0) {
|
349 |
+
$compiledQueries[] = implode(" and ", $parts);
|
350 |
+
}
|
351 |
+
}
|
352 |
+
|
353 |
+
$out = "@media";
|
354 |
+
if (!empty($parts)) {
|
355 |
+
$out .= " " .
|
356 |
+
implode($this->formatter->selectorSeparator, $compiledQueries);
|
357 |
+
}
|
358 |
+
return $out;
|
359 |
+
}
|
360 |
+
|
361 |
+
protected function multiplyMedia($env, $childQueries = null) {
|
362 |
+
if (is_null($env) ||
|
363 |
+
!empty($env->block->type) && $env->block->type != "media")
|
364 |
+
{
|
365 |
+
return $childQueries;
|
366 |
+
}
|
367 |
+
|
368 |
+
// plain old block, skip
|
369 |
+
if (empty($env->block->type)) {
|
370 |
+
return $this->multiplyMedia($env->parent, $childQueries);
|
371 |
+
}
|
372 |
+
|
373 |
+
$out = array();
|
374 |
+
$queries = $env->block->queries;
|
375 |
+
if (is_null($childQueries)) {
|
376 |
+
$out = $queries;
|
377 |
+
} else {
|
378 |
+
foreach ($queries as $parent) {
|
379 |
+
foreach ($childQueries as $child) {
|
380 |
+
$out[] = array_merge($parent, $child);
|
381 |
+
}
|
382 |
+
}
|
383 |
+
}
|
384 |
+
|
385 |
+
return $this->multiplyMedia($env->parent, $out);
|
386 |
+
}
|
387 |
+
|
388 |
+
protected function expandParentSelectors(&$tag, $replace) {
|
389 |
+
$parts = explode("$&$", $tag);
|
390 |
+
$count = 0;
|
391 |
+
foreach ($parts as &$part) {
|
392 |
+
$part = str_replace($this->parentSelector, $replace, $part, $c);
|
393 |
+
$count += $c;
|
394 |
+
}
|
395 |
+
$tag = implode($this->parentSelector, $parts);
|
396 |
+
return $count;
|
397 |
+
}
|
398 |
+
|
399 |
+
protected function findClosestSelectors() {
|
400 |
+
$env = $this->env;
|
401 |
+
$selectors = null;
|
402 |
+
while ($env !== null) {
|
403 |
+
if (isset($env->selectors)) {
|
404 |
+
$selectors = $env->selectors;
|
405 |
+
break;
|
406 |
+
}
|
407 |
+
$env = $env->parent;
|
408 |
+
}
|
409 |
+
|
410 |
+
return $selectors;
|
411 |
+
}
|
412 |
+
|
413 |
+
|
414 |
+
// multiply $selectors against the nearest selectors in env
|
415 |
+
protected function multiplySelectors($selectors) {
|
416 |
+
// find parent selectors
|
417 |
+
|
418 |
+
$parentSelectors = $this->findClosestSelectors();
|
419 |
+
if (is_null($parentSelectors)) {
|
420 |
+
// kill parent reference in top level selector
|
421 |
+
foreach ($selectors as &$s) {
|
422 |
+
$this->expandParentSelectors($s, "");
|
423 |
+
}
|
424 |
+
|
425 |
+
return $selectors;
|
426 |
+
}
|
427 |
+
|
428 |
+
$out = array();
|
429 |
+
foreach ($parentSelectors as $parent) {
|
430 |
+
foreach ($selectors as $child) {
|
431 |
+
$count = $this->expandParentSelectors($child, $parent);
|
432 |
+
|
433 |
+
// don't prepend the parent tag if & was used
|
434 |
+
if ($count > 0) {
|
435 |
+
$out[] = trim($child);
|
436 |
+
} else {
|
437 |
+
$out[] = trim($parent . ' ' . $child);
|
438 |
+
}
|
439 |
+
}
|
440 |
+
}
|
441 |
+
|
442 |
+
return $out;
|
443 |
+
}
|
444 |
+
|
445 |
+
// reduces selector expressions
|
446 |
+
protected function compileSelectors($selectors) {
|
447 |
+
$out = array();
|
448 |
+
|
449 |
+
foreach ($selectors as $s) {
|
450 |
+
if (is_array($s)) {
|
451 |
+
list(, $value) = $s;
|
452 |
+
$out[] = trim($this->compileValue($this->reduce($value)));
|
453 |
+
} else {
|
454 |
+
$out[] = $s;
|
455 |
+
}
|
456 |
+
}
|
457 |
+
|
458 |
+
return $out;
|
459 |
+
}
|
460 |
+
|
461 |
+
protected function eq($left, $right) {
|
462 |
+
return $left == $right;
|
463 |
+
}
|
464 |
+
|
465 |
+
protected function patternMatch($block, $orderedArgs, $keywordArgs) {
|
466 |
+
// match the guards if it has them
|
467 |
+
// any one of the groups must have all its guards pass for a match
|
468 |
+
if (!empty($block->guards)) {
|
469 |
+
$groupPassed = false;
|
470 |
+
foreach ($block->guards as $guardGroup) {
|
471 |
+
foreach ($guardGroup as $guard) {
|
472 |
+
$this->pushEnv();
|
473 |
+
$this->zipSetArgs($block->args, $orderedArgs, $keywordArgs);
|
474 |
+
|
475 |
+
$negate = false;
|
476 |
+
if ($guard[0] == "negate") {
|
477 |
+
$guard = $guard[1];
|
478 |
+
$negate = true;
|
479 |
+
}
|
480 |
+
|
481 |
+
$passed = $this->reduce($guard) == self::$TRUE;
|
482 |
+
if ($negate) $passed = !$passed;
|
483 |
+
|
484 |
+
$this->popEnv();
|
485 |
+
|
486 |
+
if ($passed) {
|
487 |
+
$groupPassed = true;
|
488 |
+
} else {
|
489 |
+
$groupPassed = false;
|
490 |
+
break;
|
491 |
+
}
|
492 |
+
}
|
493 |
+
|
494 |
+
if ($groupPassed) break;
|
495 |
+
}
|
496 |
+
|
497 |
+
if (!$groupPassed) {
|
498 |
+
return false;
|
499 |
+
}
|
500 |
+
}
|
501 |
+
|
502 |
+
if (empty($block->args)) {
|
503 |
+
return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
|
504 |
+
}
|
505 |
+
|
506 |
+
$remainingArgs = $block->args;
|
507 |
+
if ($keywordArgs) {
|
508 |
+
$remainingArgs = array();
|
509 |
+
foreach ($block->args as $arg) {
|
510 |
+
if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
|
511 |
+
continue;
|
512 |
+
}
|
513 |
+
|
514 |
+
$remainingArgs[] = $arg;
|
515 |
+
}
|
516 |
+
}
|
517 |
+
|
518 |
+
$i = -1; // no args
|
519 |
+
// try to match by arity or by argument literal
|
520 |
+
foreach ($remainingArgs as $i => $arg) {
|
521 |
+
switch ($arg[0]) {
|
522 |
+
case "lit":
|
523 |
+
if (empty($orderedArgs[$i]) || !$this->eq($arg[1], $orderedArgs[$i])) {
|
524 |
+
return false;
|
525 |
+
}
|
526 |
+
break;
|
527 |
+
case "arg":
|
528 |
+
// no arg and no default value
|
529 |
+
if (!isset($orderedArgs[$i]) && !isset($arg[2])) {
|
530 |
+
return false;
|
531 |
+
}
|
532 |
+
break;
|
533 |
+
case "rest":
|
534 |
+
$i--; // rest can be empty
|
535 |
+
break 2;
|
536 |
+
}
|
537 |
+
}
|
538 |
+
|
539 |
+
if ($block->isVararg) {
|
540 |
+
return true; // not having enough is handled above
|
541 |
+
} else {
|
542 |
+
$numMatched = $i + 1;
|
543 |
+
// greater than becuase default values always match
|
544 |
+
return $numMatched >= count($orderedArgs);
|
545 |
+
}
|
546 |
+
}
|
547 |
+
|
548 |
+
protected function patternMatchAll($blocks, $orderedArgs, $keywordArgs, $skip=array()) {
|
549 |
+
$matches = null;
|
550 |
+
foreach ($blocks as $block) {
|
551 |
+
// skip seen blocks that don't have arguments
|
552 |
+
if (isset($skip[$block->id]) && !isset($block->args)) {
|
553 |
+
continue;
|
554 |
+
}
|
555 |
+
|
556 |
+
if ($this->patternMatch($block, $orderedArgs, $keywordArgs)) {
|
557 |
+
$matches[] = $block;
|
558 |
+
}
|
559 |
+
}
|
560 |
+
|
561 |
+
return $matches;
|
562 |
+
}
|
563 |
+
|
564 |
+
// attempt to find blocks matched by path and args
|
565 |
+
protected function findBlocks($searchIn, $path, $orderedArgs, $keywordArgs, $seen=array()) {
|
566 |
+
if ($searchIn == null) return null;
|
567 |
+
if (isset($seen[$searchIn->id])) return null;
|
568 |
+
$seen[$searchIn->id] = true;
|
569 |
+
|
570 |
+
$name = $path[0];
|
571 |
+
|
572 |
+
if (isset($searchIn->children[$name])) {
|
573 |
+
$blocks = $searchIn->children[$name];
|
574 |
+
if (count($path) == 1) {
|
575 |
+
$matches = $this->patternMatchAll($blocks, $orderedArgs, $keywordArgs, $seen);
|
576 |
+
if (!empty($matches)) {
|
577 |
+
// This will return all blocks that match in the closest
|
578 |
+
// scope that has any matching block, like lessjs
|
579 |
+
return $matches;
|
580 |
+
}
|
581 |
+
} else {
|
582 |
+
$matches = array();
|
583 |
+
foreach ($blocks as $subBlock) {
|
584 |
+
$subMatches = $this->findBlocks($subBlock,
|
585 |
+
array_slice($path, 1), $orderedArgs, $keywordArgs, $seen);
|
586 |
+
|
587 |
+
if (!is_null($subMatches)) {
|
588 |
+
foreach ($subMatches as $sm) {
|
589 |
+
$matches[] = $sm;
|
590 |
+
}
|
591 |
+
}
|
592 |
+
}
|
593 |
+
|
594 |
+
return count($matches) > 0 ? $matches : null;
|
595 |
+
}
|
596 |
+
}
|
597 |
+
if ($searchIn->parent === $searchIn) return null;
|
598 |
+
return $this->findBlocks($searchIn->parent, $path, $orderedArgs, $keywordArgs, $seen);
|
599 |
+
}
|
600 |
+
|
601 |
+
// sets all argument names in $args to either the default value
|
602 |
+
// or the one passed in through $values
|
603 |
+
protected function zipSetArgs($args, $orderedValues, $keywordValues) {
|
604 |
+
$assignedValues = array();
|
605 |
+
|
606 |
+
$i = 0;
|
607 |
+
foreach ($args as $a) {
|
608 |
+
if ($a[0] == "arg") {
|
609 |
+
if (isset($keywordValues[$a[1]])) {
|
610 |
+
// has keyword arg
|
611 |
+
$value = $keywordValues[$a[1]];
|
612 |
+
} elseif (isset($orderedValues[$i])) {
|
613 |
+
// has ordered arg
|
614 |
+
$value = $orderedValues[$i];
|
615 |
+
$i++;
|
616 |
+
} elseif (isset($a[2])) {
|
617 |
+
// has default value
|
618 |
+
$value = $a[2];
|
619 |
+
} else {
|
620 |
+
$this->throwError("Failed to assign arg " . $a[1]);
|
621 |
+
$value = null; // :(
|
622 |
+
}
|
623 |
+
|
624 |
+
$value = $this->reduce($value);
|
625 |
+
$this->set($a[1], $value);
|
626 |
+
$assignedValues[] = $value;
|
627 |
+
} else {
|
628 |
+
// a lit
|
629 |
+
$i++;
|
630 |
+
}
|
631 |
+
}
|
632 |
+
|
633 |
+
// check for a rest
|
634 |
+
$last = end($args);
|
635 |
+
if ($last[0] == "rest") {
|
636 |
+
$rest = array_slice($orderedValues, count($args) - 1);
|
637 |
+
$this->set($last[1], $this->reduce(array("list", " ", $rest)));
|
638 |
+
}
|
639 |
+
|
640 |
+
// wow is this the only true use of PHP's + operator for arrays?
|
641 |
+
$this->env->arguments = $assignedValues + $orderedValues;
|
642 |
+
}
|
643 |
+
|
644 |
+
// compile a prop and update $lines or $blocks appropriately
|
645 |
+
protected function compileProp($prop, $block, $out) {
|
646 |
+
// set error position context
|
647 |
+
$this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
|
648 |
+
|
649 |
+
switch ($prop[0]) {
|
650 |
+
case 'assign':
|
651 |
+
list(, $name, $value) = $prop;
|
652 |
+
if ($name[0] == $this->vPrefix) {
|
653 |
+
$this->set($name, $value);
|
654 |
+
} else {
|
655 |
+
$out->lines[] = $this->formatter->property($name,
|
656 |
+
$this->compileValue($this->reduce($value)));
|
657 |
+
}
|
658 |
+
break;
|
659 |
+
case 'block':
|
660 |
+
list(, $child) = $prop;
|
661 |
+
$this->compileBlock($child);
|
662 |
+
break;
|
663 |
+
case 'mixin':
|
664 |
+
list(, $path, $args, $suffix) = $prop;
|
665 |
+
|
666 |
+
$orderedArgs = array();
|
667 |
+
$keywordArgs = array();
|
668 |
+
foreach ((array)$args as $arg) {
|
669 |
+
$argval = null;
|
670 |
+
switch ($arg[0]) {
|
671 |
+
case "arg":
|
672 |
+
if (!isset($arg[2])) {
|
673 |
+
$orderedArgs[] = $this->reduce(array("variable", $arg[1]));
|
674 |
+
} else {
|
675 |
+
$keywordArgs[$arg[1]] = $this->reduce($arg[2]);
|
676 |
+
}
|
677 |
+
break;
|
678 |
+
|
679 |
+
case "lit":
|
680 |
+
$orderedArgs[] = $this->reduce($arg[1]);
|
681 |
+
break;
|
682 |
+
default:
|
683 |
+
$this->throwError("Unknown arg type: " . $arg[0]);
|
684 |
+
}
|
685 |
+
}
|
686 |
+
|
687 |
+
$mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
|
688 |
+
|
689 |
+
if ($mixins === null) {
|
690 |
+
break; // throw error here??
|
691 |
+
}
|
692 |
+
|
693 |
+
foreach ($mixins as $mixin) {
|
694 |
+
if ($mixin === $block && !$orderedArgs) {
|
695 |
+
continue;
|
696 |
+
}
|
697 |
+
|
698 |
+
$haveScope = false;
|
699 |
+
if (isset($mixin->parent->scope)) {
|
700 |
+
$haveScope = true;
|
701 |
+
$mixinParentEnv = $this->pushEnv();
|
702 |
+
$mixinParentEnv->storeParent = $mixin->parent->scope;
|
703 |
+
}
|
704 |
+
|
705 |
+
$haveArgs = false;
|
706 |
+
if (isset($mixin->args)) {
|
707 |
+
$haveArgs = true;
|
708 |
+
$this->pushEnv();
|
709 |
+
$this->zipSetArgs($mixin->args, $orderedArgs, $keywordArgs);
|
710 |
+
}
|
711 |
+
|
712 |
+
$oldParent = $mixin->parent;
|
713 |
+
if ($mixin != $block) $mixin->parent = $block;
|
714 |
+
|
715 |
+
foreach ($this->sortProps($mixin->props) as $subProp) {
|
716 |
+
if ($suffix !== null &&
|
717 |
+
$subProp[0] == "assign" &&
|
718 |
+
is_string($subProp[1]) &&
|
719 |
+
$subProp[1]{0} != $this->vPrefix)
|
720 |
+
{
|
721 |
+
$subProp[2] = array(
|
722 |
+
'list', ' ',
|
723 |
+
array($subProp[2], array('keyword', $suffix))
|
724 |
+
);
|
725 |
+
}
|
726 |
+
|
727 |
+
$this->compileProp($subProp, $mixin, $out);
|
728 |
+
}
|
729 |
+
|
730 |
+
$mixin->parent = $oldParent;
|
731 |
+
|
732 |
+
if ($haveArgs) $this->popEnv();
|
733 |
+
if ($haveScope) $this->popEnv();
|
734 |
+
}
|
735 |
+
|
736 |
+
break;
|
737 |
+
case 'raw':
|
738 |
+
$out->lines[] = $prop[1];
|
739 |
+
break;
|
740 |
+
case "directive":
|
741 |
+
list(, $name, $value) = $prop;
|
742 |
+
$out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
|
743 |
+
break;
|
744 |
+
case "comment":
|
745 |
+
$out->lines[] = $prop[1];
|
746 |
+
break;
|
747 |
+
case "import";
|
748 |
+
list(, $importPath, $importId) = $prop;
|
749 |
+
$importPath = $this->reduce($importPath);
|
750 |
+
|
751 |
+
if (!isset($this->env->imports)) {
|
752 |
+
$this->env->imports = array();
|
753 |
+
}
|
754 |
+
|
755 |
+
$result = $this->tryImport($importPath, $block, $out);
|
756 |
+
|
757 |
+
$this->env->imports[$importId] = $result === false ?
|
758 |
+
array(false, "@import " . $this->compileValue($importPath).";") :
|
759 |
+
$result;
|
760 |
+
|
761 |
+
break;
|
762 |
+
case "import_mixin":
|
763 |
+
list(,$importId) = $prop;
|
764 |
+
$import = $this->env->imports[$importId];
|
765 |
+
if ($import[0] === false) {
|
766 |
+
if (isset($import[1])) {
|
767 |
+
$out->lines[] = $import[1];
|
768 |
+
}
|
769 |
+
} else {
|
770 |
+
list(, $bottom, $parser, $importDir) = $import;
|
771 |
+
$this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
|
772 |
+
}
|
773 |
+
|
774 |
+
break;
|
775 |
+
default:
|
776 |
+
$this->throwError("unknown op: {$prop[0]}\n");
|
777 |
+
}
|
778 |
+
}
|
779 |
+
|
780 |
+
|
781 |
+
/**
|
782 |
+
* Compiles a primitive value into a CSS property value.
|
783 |
+
*
|
784 |
+
* Values in lessphp are typed by being wrapped in arrays, their format is
|
785 |
+
* typically:
|
786 |
+
*
|
787 |
+
* array(type, contents [, additional_contents]*)
|
788 |
+
*
|
789 |
+
* The input is expected to be reduced. This function will not work on
|
790 |
+
* things like expressions and variables.
|
791 |
+
*/
|
792 |
+
protected function compileValue($value) {
|
793 |
+
switch ($value[0]) {
|
794 |
+
case 'list':
|
795 |
+
// [1] - delimiter
|
796 |
+
// [2] - array of values
|
797 |
+
return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
|
798 |
+
case 'raw_color':
|
799 |
+
if (!empty($this->formatter->compressColors)) {
|
800 |
+
return $this->compileValue($this->coerceColor($value));
|
801 |
+
}
|
802 |
+
return $value[1];
|
803 |
+
case 'keyword':
|
804 |
+
// [1] - the keyword
|
805 |
+
return $value[1];
|
806 |
+
case 'number':
|
807 |
+
list(, $num, $unit) = $value;
|
808 |
+
// [1] - the number
|
809 |
+
// [2] - the unit
|
810 |
+
if ($this->numberPrecision !== null) {
|
811 |
+
$num = round($num, $this->numberPrecision);
|
812 |
+
}
|
813 |
+
return $num . $unit;
|
814 |
+
case 'string':
|
815 |
+
// [1] - contents of string (includes quotes)
|
816 |
+
list(, $delim, $content) = $value;
|
817 |
+
foreach ($content as &$part) {
|
818 |
+
if (is_array($part)) {
|
819 |
+
$part = $this->compileValue($part);
|
820 |
+
}
|
821 |
+
}
|
822 |
+
return $delim . implode($content) . $delim;
|
823 |
+
case 'color':
|
824 |
+
// [1] - red component (either number or a %)
|
825 |
+
// [2] - green component
|
826 |
+
// [3] - blue component
|
827 |
+
// [4] - optional alpha component
|
828 |
+
list(, $r, $g, $b) = $value;
|
829 |
+
$r = round($r);
|
830 |
+
$g = round($g);
|
831 |
+
$b = round($b);
|
832 |
+
|
833 |
+
if (count($value) == 5 && $value[4] != 1) { // rgba
|
834 |
+
return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
|
835 |
+
}
|
836 |
+
|
837 |
+
$h = sprintf("#%02x%02x%02x", $r, $g, $b);
|
838 |
+
|
839 |
+
if (!empty($this->formatter->compressColors)) {
|
840 |
+
// Converting hex color to short notation (e.g. #003399 to #039)
|
841 |
+
if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
|
842 |
+
$h = '#' . $h[1] . $h[3] . $h[5];
|
843 |
+
}
|
844 |
+
}
|
845 |
+
|
846 |
+
return $h;
|
847 |
+
|
848 |
+
case 'function':
|
849 |
+
list(, $name, $args) = $value;
|
850 |
+
return $name.'('.$this->compileValue($args).')';
|
851 |
+
default: // assumed to be unit
|
852 |
+
$this->throwError("unknown value type: $value[0]");
|
853 |
+
}
|
854 |
+
}
|
855 |
+
|
856 |
+
protected function lib_pow($args) {
|
857 |
+
list($base, $exp) = $this->assertArgs($args, 2, "pow");
|
858 |
+
return pow($this->assertNumber($base), $this->assertNumber($exp));
|
859 |
+
}
|
860 |
+
|
861 |
+
protected function lib_pi() {
|
862 |
+
return pi();
|
863 |
+
}
|
864 |
+
|
865 |
+
protected function lib_mod($args) {
|
866 |
+
list($a, $b) = $this->assertArgs($args, 2, "mod");
|
867 |
+
return $this->assertNumber($a) % $this->assertNumber($b);
|
868 |
+
}
|
869 |
+
|
870 |
+
protected function lib_tan($num) {
|
871 |
+
return tan($this->assertNumber($num));
|
872 |
+
}
|
873 |
+
|
874 |
+
protected function lib_sin($num) {
|
875 |
+
return sin($this->assertNumber($num));
|
876 |
+
}
|
877 |
+
|
878 |
+
protected function lib_cos($num) {
|
879 |
+
return cos($this->assertNumber($num));
|
880 |
+
}
|
881 |
+
|
882 |
+
protected function lib_atan($num) {
|
883 |
+
$num = atan($this->assertNumber($num));
|
884 |
+
return array("number", $num, "rad");
|
885 |
+
}
|
886 |
+
|
887 |
+
protected function lib_asin($num) {
|
888 |
+
$num = asin($this->assertNumber($num));
|
889 |
+
return array("number", $num, "rad");
|
890 |
+
}
|
891 |
+
|
892 |
+
protected function lib_acos($num) {
|
893 |
+
$num = acos($this->assertNumber($num));
|
894 |
+
return array("number", $num, "rad");
|
895 |
+
}
|
896 |
+
|
897 |
+
protected function lib_sqrt($num) {
|
898 |
+
return sqrt($this->assertNumber($num));
|
899 |
+
}
|
900 |
+
|
901 |
+
protected function lib_extract($value) {
|
902 |
+
list($list, $idx) = $this->assertArgs($value, 2, "extract");
|
903 |
+
$idx = $this->assertNumber($idx);
|
904 |
+
// 1 indexed
|
905 |
+
if ($list[0] == "list" && isset($list[2][$idx - 1])) {
|
906 |
+
return $list[2][$idx - 1];
|
907 |
+
}
|
908 |
+
}
|
909 |
+
|
910 |
+
protected function lib_isnumber($value) {
|
911 |
+
return $this->toBool($value[0] == "number");
|
912 |
+
}
|
913 |
+
|
914 |
+
protected function lib_isstring($value) {
|
915 |
+
return $this->toBool($value[0] == "string");
|
916 |
+
}
|
917 |
+
|
918 |
+
protected function lib_iscolor($value) {
|
919 |
+
return $this->toBool($this->coerceColor($value));
|
920 |
+
}
|
921 |
+
|
922 |
+
protected function lib_iskeyword($value) {
|
923 |
+
return $this->toBool($value[0] == "keyword");
|
924 |
+
}
|
925 |
+
|
926 |
+
protected function lib_ispixel($value) {
|
927 |
+
return $this->toBool($value[0] == "number" && $value[2] == "px");
|
928 |
+
}
|
929 |
+
|
930 |
+
protected function lib_ispercentage($value) {
|
931 |
+
return $this->toBool($value[0] == "number" && $value[2] == "%");
|
932 |
+
}
|
933 |
+
|
934 |
+
protected function lib_isem($value) {
|
935 |
+
return $this->toBool($value[0] == "number" && $value[2] == "em");
|
936 |
+
}
|
937 |
+
|
938 |
+
protected function lib_isrem($value) {
|
939 |
+
return $this->toBool($value[0] == "number" && $value[2] == "rem");
|
940 |
+
}
|
941 |
+
|
942 |
+
protected function lib_rgbahex($color) {
|
943 |
+
$color = $this->coerceColor($color);
|
944 |
+
if (is_null($color))
|
945 |
+
$this->throwError("color expected for rgbahex");
|
946 |
+
|
947 |
+
return sprintf("#%02x%02x%02x%02x",
|
948 |
+
isset($color[4]) ? $color[4]*255 : 255,
|
949 |
+
$color[1],$color[2], $color[3]);
|
950 |
+
}
|
951 |
+
|
952 |
+
protected function lib_argb($color){
|
953 |
+
return $this->lib_rgbahex($color);
|
954 |
+
}
|
955 |
+
|
956 |
+
// utility func to unquote a string
|
957 |
+
// use func_get_arg to prevent Theme Checker triggering unrelated translation warning.
|
958 |
+
protected function lib_e() {
|
959 |
+
$arg = func_get_arg(0);
|
960 |
+
switch ($arg[0]) {
|
961 |
+
case "list":
|
962 |
+
$items = $arg[2];
|
963 |
+
if (isset($items[0])) {
|
964 |
+
return $this->lib_unquote($items[0]);
|
965 |
+
}
|
966 |
+
return self::$defaultValue;
|
967 |
+
case "string":
|
968 |
+
$arg[1] = "";
|
969 |
+
return $arg;
|
970 |
+
case "keyword":
|
971 |
+
return $arg;
|
972 |
+
default:
|
973 |
+
return array("keyword", $this->compileValue($arg));
|
974 |
+
}
|
975 |
+
}
|
976 |
+
|
977 |
+
// use func_get_arg to prevent Theme Checker triggering unrelated translation warning.
|
978 |
+
protected function lib_unquote($arg) {
|
979 |
+
return $this->lib_e(func_get_arg(0));
|
980 |
+
}
|
981 |
+
|
982 |
+
protected function lib__sprintf($args) {
|
983 |
+
if ($args[0] != "list") return $args;
|
984 |
+
$values = $args[2];
|
985 |
+
$string = array_shift($values);
|
986 |
+
$template = $this->compileValue($this->lib_unquote($string));
|
987 |
+
|
988 |
+
$i = 0;
|
989 |
+
if (preg_match_all('/%[dsa]/', $template, $m)) {
|
990 |
+
foreach ($m[0] as $match) {
|
991 |
+
$val = isset($values[$i]) ?
|
992 |
+
$this->reduce($values[$i]) : array('keyword', '');
|
993 |
+
|
994 |
+
// lessjs compat, renders fully expanded color, not raw color
|
995 |
+
if ($color = $this->coerceColor($val)) {
|
996 |
+
$val = $color;
|
997 |
+
}
|
998 |
+
|
999 |
+
$i++;
|
1000 |
+
$rep = $this->compileValue($this->lib_unquote($val));
|
1001 |
+
$template = preg_replace('/'.self::preg_quote($match).'/',
|
1002 |
+
$rep, $template, 1);
|
1003 |
+
}
|
1004 |
+
}
|
1005 |
+
|
1006 |
+
$d = $string[0] == "string" ? $string[1] : '"';
|
1007 |
+
return array("string", $d, array($template));
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
protected function lib_floor($arg) {
|
1011 |
+
$value = $this->assertNumber($arg);
|
1012 |
+
return array("number", floor($value), $arg[2]);
|
1013 |
+
}
|
1014 |
+
|
1015 |
+
protected function lib_ceil($arg) {
|
1016 |
+
$value = $this->assertNumber($arg);
|
1017 |
+
return array("number", ceil($value), $arg[2]);
|
1018 |
+
}
|
1019 |
+
|
1020 |
+
protected function lib_round($arg) {
|
1021 |
+
$value = $this->assertNumber($arg);
|
1022 |
+
return array("number", round($value), $arg[2]);
|
1023 |
+
}
|
1024 |
+
|
1025 |
+
protected function lib_unit($arg) {
|
1026 |
+
if ($arg[0] == "list") {
|
1027 |
+
list($number, $newUnit) = $arg[2];
|
1028 |
+
return array("number", $this->assertNumber($number),
|
1029 |
+
$this->compileValue($this->lib_unquote($newUnit)));
|
1030 |
+
} else {
|
1031 |
+
return array("number", $this->assertNumber($arg), "");
|
1032 |
+
}
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
/**
|
1036 |
+
* Helper function to get arguments for color manipulation functions.
|
1037 |
+
* takes a list that contains a color like thing and a percentage
|
1038 |
+
*/
|
1039 |
+
protected function colorArgs($args) {
|
1040 |
+
if ($args[0] != 'list' || count($args[2]) < 2) {
|
1041 |
+
return array(array('color', 0, 0, 0), 0);
|
1042 |
+
}
|
1043 |
+
list($color, $delta) = $args[2];
|
1044 |
+
$color = $this->assertColor($color);
|
1045 |
+
$delta = floatval($delta[1]);
|
1046 |
+
|
1047 |
+
return array($color, $delta);
|
1048 |
+
}
|
1049 |
+
|
1050 |
+
protected function lib_darken($args) {
|
1051 |
+
list($color, $delta) = $this->colorArgs($args);
|
1052 |
+
|
1053 |
+
$hsl = $this->toHSL($color);
|
1054 |
+
$hsl[3] = $this->clamp($hsl[3] - $delta, 100);
|
1055 |
+
return $this->toRGB($hsl);
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
protected function lib_lighten($args) {
|
1059 |
+
list($color, $delta) = $this->colorArgs($args);
|
1060 |
+
|
1061 |
+
$hsl = $this->toHSL($color);
|
1062 |
+
$hsl[3] = $this->clamp($hsl[3] + $delta, 100);
|
1063 |
+
return $this->toRGB($hsl);
|
1064 |
+
}
|
1065 |
+
|
1066 |
+
protected function lib_saturate($args) {
|
1067 |
+
list($color, $delta) = $this->colorArgs($args);
|
1068 |
+
|
1069 |
+
$hsl = $this->toHSL($color);
|
1070 |
+
$hsl[2] = $this->clamp($hsl[2] + $delta, 100);
|
1071 |
+
return $this->toRGB($hsl);
|
1072 |
+
}
|
1073 |
+
|
1074 |
+
protected function lib_desaturate($args) {
|
1075 |
+
list($color, $delta) = $this->colorArgs($args);
|
1076 |
+
|
1077 |
+
$hsl = $this->toHSL($color);
|
1078 |
+
$hsl[2] = $this->clamp($hsl[2] - $delta, 100);
|
1079 |
+
return $this->toRGB($hsl);
|
1080 |
+
}
|
1081 |
+
|
1082 |
+
protected function lib_spin($args) {
|
1083 |
+
list($color, $delta) = $this->colorArgs($args);
|
1084 |
+
|
1085 |
+
$hsl = $this->toHSL($color);
|
1086 |
+
|
1087 |
+
$hsl[1] = $hsl[1] + $delta % 360;
|
1088 |
+
if ($hsl[1] < 0) $hsl[1] += 360;
|
1089 |
+
|
1090 |
+
return $this->toRGB($hsl);
|
1091 |
+
}
|
1092 |
+
|
1093 |
+
protected function lib_fadeout($args) {
|
1094 |
+
list($color, $delta) = $this->colorArgs($args);
|
1095 |
+
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100);
|
1096 |
+
return $color;
|
1097 |
+
}
|
1098 |
+
|
1099 |
+
protected function lib_fadein($args) {
|
1100 |
+
list($color, $delta) = $this->colorArgs($args);
|
1101 |
+
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100);
|
1102 |
+
return $color;
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
protected function lib_hue($color) {
|
1106 |
+
$hsl = $this->toHSL($this->assertColor($color));
|
1107 |
+
return round($hsl[1]);
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
protected function lib_saturation($color) {
|
1111 |
+
$hsl = $this->toHSL($this->assertColor($color));
|
1112 |
+
return round($hsl[2]);
|
1113 |
+
}
|
1114 |
+
|
1115 |
+
protected function lib_lightness($color) {
|
1116 |
+
$hsl = $this->toHSL($this->assertColor($color));
|
1117 |
+
return round($hsl[3]);
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
// get the alpha of a color
|
1121 |
+
// defaults to 1 for non-colors or colors without an alpha
|
1122 |
+
protected function lib_alpha($value) {
|
1123 |
+
if (!is_null($color = $this->coerceColor($value))) {
|
1124 |
+
return isset($color[4]) ? $color[4] : 1;
|
1125 |
+
}
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
// set the alpha of the color
|
1129 |
+
protected function lib_fade($args) {
|
1130 |
+
list($color, $alpha) = $this->colorArgs($args);
|
1131 |
+
$color[4] = $this->clamp($alpha / 100.0);
|
1132 |
+
return $color;
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
protected function lib_percentage($arg) {
|
1136 |
+
$num = $this->assertNumber($arg);
|
1137 |
+
return array("number", $num*100, "%");
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
// mixes two colors by weight
|
1141 |
+
// mix(@color1, @color2, [@weight: 50%]);
|
1142 |
+
// http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
|
1143 |
+
protected function lib_mix($args) {
|
1144 |
+
if ($args[0] != "list" || count($args[2]) < 2)
|
1145 |
+
$this->throwError("mix expects (color1, color2, weight)");
|
1146 |
+
|
1147 |
+
list($first, $second) = $args[2];
|
1148 |
+
$first = $this->assertColor($first);
|
1149 |
+
$second = $this->assertColor($second);
|
1150 |
+
|
1151 |
+
$first_a = $this->lib_alpha($first);
|
1152 |
+
$second_a = $this->lib_alpha($second);
|
1153 |
+
|
1154 |
+
if (isset($args[2][2])) {
|
1155 |
+
$weight = $args[2][2][1] / 100.0;
|
1156 |
+
} else {
|
1157 |
+
$weight = 0.5;
|
1158 |
+
}
|
1159 |
+
|
1160 |
+
$w = $weight * 2 - 1;
|
1161 |
+
$a = $first_a - $second_a;
|
1162 |
+
|
1163 |
+
$w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
|
1164 |
+
$w2 = 1.0 - $w1;
|
1165 |
+
|
1166 |
+
$new = array('color',
|
1167 |
+
$w1 * $first[1] + $w2 * $second[1],
|
1168 |
+
$w1 * $first[2] + $w2 * $second[2],
|
1169 |
+
$w1 * $first[3] + $w2 * $second[3],
|
1170 |
+
);
|
1171 |
+
|
1172 |
+
if ($first_a != 1.0 || $second_a != 1.0) {
|
1173 |
+
$new[] = $first_a * $weight + $second_a * ($weight - 1);
|
1174 |
+
}
|
1175 |
+
|
1176 |
+
return $this->fixColor($new);
|
1177 |
+
}
|
1178 |
+
|
1179 |
+
protected function lib_contrast($args) {
|
1180 |
+
if ($args[0] != 'list' || count($args[2]) < 3) {
|
1181 |
+
return array(array('color', 0, 0, 0), 0);
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
list($inputColor, $darkColor, $lightColor) = $args[2];
|
1185 |
+
|
1186 |
+
$inputColor = $this->assertColor($inputColor);
|
1187 |
+
$darkColor = $this->assertColor($darkColor);
|
1188 |
+
$lightColor = $this->assertColor($lightColor);
|
1189 |
+
$hsl = $this->toHSL($inputColor);
|
1190 |
+
|
1191 |
+
if ($hsl[3] > 50) {
|
1192 |
+
return $darkColor;
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
return $lightColor;
|
1196 |
+
}
|
1197 |
+
|
1198 |
+
protected function assertColor($value, $error = "expected color value") {
|
1199 |
+
$color = $this->coerceColor($value);
|
1200 |
+
if (is_null($color)) $this->throwError($error);
|
1201 |
+
return $color;
|
1202 |
+
}
|
1203 |
+
|
1204 |
+
protected function assertNumber($value, $error = "expecting number") {
|
1205 |
+
if ($value[0] == "number") return $value[1];
|
1206 |
+
$this->throwError($error);
|
1207 |
+
}
|
1208 |
+
|
1209 |
+
protected function assertArgs($value, $expectedArgs, $name="") {
|
1210 |
+
if ($expectedArgs == 1) {
|
1211 |
+
return $value;
|
1212 |
+
} else {
|
1213 |
+
if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
|
1214 |
+
$values = $value[2];
|
1215 |
+
$numValues = count($values);
|
1216 |
+
if ($expectedArgs != $numValues) {
|
1217 |
+
if ($name) {
|
1218 |
+
$name = $name . ": ";
|
1219 |
+
}
|
1220 |
+
|
1221 |
+
$this->throwError("${name}expecting $expectedArgs arguments, got $numValues");
|
1222 |
+
}
|
1223 |
+
|
1224 |
+
return $values;
|
1225 |
+
}
|
1226 |
+
}
|
1227 |
+
|
1228 |
+
protected function toHSL($color) {
|
1229 |
+
if ($color[0] == 'hsl') return $color;
|
1230 |
+
|
1231 |
+
$r = $color[1] / 255;
|
1232 |
+
$g = $color[2] / 255;
|
1233 |
+
$b = $color[3] / 255;
|
1234 |
+
|
1235 |
+
$min = min($r, $g, $b);
|
1236 |
+
$max = max($r, $g, $b);
|
1237 |
+
|
1238 |
+
$L = ($min + $max) / 2;
|
1239 |
+
if ($min == $max) {
|
1240 |
+
$S = $H = 0;
|
1241 |
+
} else {
|
1242 |
+
if ($L < 0.5)
|
1243 |
+
$S = ($max - $min)/($max + $min);
|
1244 |
+
else
|
1245 |
+
$S = ($max - $min)/(2.0 - $max - $min);
|
1246 |
+
|
1247 |
+
if ($r == $max) $H = ($g - $b)/($max - $min);
|
1248 |
+
elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
|
1249 |
+
elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
|
1250 |
+
|
1251 |
+
}
|
1252 |
+
|
1253 |
+
$out = array('hsl',
|
1254 |
+
($H < 0 ? $H + 6 : $H)*60,
|
1255 |
+
$S*100,
|
1256 |
+
$L*100,
|
1257 |
+
);
|
1258 |
+
|
1259 |
+
if (count($color) > 4) $out[] = $color[4]; // copy alpha
|
1260 |
+
return $out;
|
1261 |
+
}
|
1262 |
+
|
1263 |
+
protected function toRGB_helper($comp, $temp1, $temp2) {
|
1264 |
+
if ($comp < 0) $comp += 1.0;
|
1265 |
+
elseif ($comp > 1) $comp -= 1.0;
|
1266 |
+
|
1267 |
+
if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
|
1268 |
+
if (2 * $comp < 1) return $temp2;
|
1269 |
+
if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
|
1270 |
+
|
1271 |
+
return $temp1;
|
1272 |
+
}
|
1273 |
+
|
1274 |
+
/**
|
1275 |
+
* Converts a hsl array into a color value in rgb.
|
1276 |
+
* Expects H to be in range of 0 to 360, S and L in 0 to 100
|
1277 |
+
*/
|
1278 |
+
protected function toRGB($color) {
|
1279 |
+
if ($color[0] == 'color') return $color;
|
1280 |
+
|
1281 |
+
$H = $color[1] / 360;
|
1282 |
+
$S = $color[2] / 100;
|
1283 |
+
$L = $color[3] / 100;
|
1284 |
+
|
1285 |
+
if ($S == 0) {
|
1286 |
+
$r = $g = $b = $L;
|
1287 |
+
} else {
|
1288 |
+
$temp2 = $L < 0.5 ?
|
1289 |
+
$L*(1.0 + $S) :
|
1290 |
+
$L + $S - $L * $S;
|
1291 |
+
|
1292 |
+
$temp1 = 2.0 * $L - $temp2;
|
1293 |
+
|
1294 |
+
$r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
|
1295 |
+
$g = $this->toRGB_helper($H, $temp1, $temp2);
|
1296 |
+
$b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
|
1297 |
+
}
|
1298 |
+
|
1299 |
+
// $out = array('color', round($r*255), round($g*255), round($b*255));
|
1300 |
+
$out = array('color', $r*255, $g*255, $b*255);
|
1301 |
+
if (count($color) > 4) $out[] = $color[4]; // copy alpha
|
1302 |
+
return $out;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
protected function clamp($v, $max = 1, $min = 0) {
|
1306 |
+
return min($max, max($min, $v));
|
1307 |
+
}
|
1308 |
+
|
1309 |
+
/**
|
1310 |
+
* Convert the rgb, rgba, hsl color literals of function type
|
1311 |
+
* as returned by the parser into values of color type.
|
1312 |
+
*/
|
1313 |
+
protected function funcToColor($func) {
|
1314 |
+
$fname = $func[1];
|
1315 |
+
if ($func[2][0] != 'list') return false; // need a list of arguments
|
1316 |
+
$rawComponents = $func[2][2];
|
1317 |
+
|
1318 |
+
if ($fname == 'hsl' || $fname == 'hsla') {
|
1319 |
+
$hsl = array('hsl');
|
1320 |
+
$i = 0;
|
1321 |
+
foreach ($rawComponents as $c) {
|
1322 |
+
$val = $this->reduce($c);
|
1323 |
+
$val = isset($val[1]) ? floatval($val[1]) : 0;
|
1324 |
+
|
1325 |
+
if ($i == 0) $clamp = 360;
|
1326 |
+
elseif ($i < 3) $clamp = 100;
|
1327 |
+
else $clamp = 1;
|
1328 |
+
|
1329 |
+
$hsl[] = $this->clamp($val, $clamp);
|
1330 |
+
$i++;
|
1331 |
+
}
|
1332 |
+
|
1333 |
+
while (count($hsl) < 4) $hsl[] = 0;
|
1334 |
+
return $this->toRGB($hsl);
|
1335 |
+
|
1336 |
+
} elseif ($fname == 'rgb' || $fname == 'rgba') {
|
1337 |
+
$components = array();
|
1338 |
+
$i = 1;
|
1339 |
+
foreach ($rawComponents as $c) {
|
1340 |
+
$c = $this->reduce($c);
|
1341 |
+
if ($i < 4) {
|
1342 |
+
if ($c[0] == "number" && $c[2] == "%") {
|
1343 |
+
$components[] = 255 * ($c[1] / 100);
|
1344 |
+
} else {
|
1345 |
+
$components[] = floatval($c[1]);
|
1346 |
+
}
|
1347 |
+
} elseif ($i == 4) {
|
1348 |
+
if ($c[0] == "number" && $c[2] == "%") {
|
1349 |
+
$components[] = 1.0 * ($c[1] / 100);
|
1350 |
+
} else {
|
1351 |
+
$components[] = floatval($c[1]);
|
1352 |
+
}
|
1353 |
+
} else break;
|
1354 |
+
|
1355 |
+
$i++;
|
1356 |
+
}
|
1357 |
+
while (count($components) < 3) $components[] = 0;
|
1358 |
+
array_unshift($components, 'color');
|
1359 |
+
return $this->fixColor($components);
|
1360 |
+
}
|
1361 |
+
|
1362 |
+
return false;
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
protected function reduce($value, $forExpression = false) {
|
1366 |
+
switch ($value[0]) {
|
1367 |
+
case "interpolate":
|
1368 |
+
$reduced = $this->reduce($value[1]);
|
1369 |
+
$var = $this->compileValue($reduced);
|
1370 |
+
$res = $this->reduce(array("variable", $this->vPrefix . $var));
|
1371 |
+
|
1372 |
+
if ($res[0] == "raw_color") {
|
1373 |
+
$res = $this->coerceColor($res);
|
1374 |
+
}
|
1375 |
+
|
1376 |
+
if (empty($value[2])) $res = $this->lib_unquote($res);
|
1377 |
+
|
1378 |
+
return $res;
|
1379 |
+
case "variable":
|
1380 |
+
$key = $value[1];
|
1381 |
+
if (is_array($key)) {
|
1382 |
+
$key = $this->reduce($key);
|
1383 |
+
$key = $this->vPrefix . $this->compileValue($this->lib_unquote($key));
|
1384 |
+
}
|
1385 |
+
|
1386 |
+
$seen =& $this->env->seenNames;
|
1387 |
+
|
1388 |
+
if (!empty($seen[$key])) {
|
1389 |
+
$this->throwError("infinite loop detected: $key");
|
1390 |
+
}
|
1391 |
+
|
1392 |
+
$seen[$key] = true;
|
1393 |
+
$out = $this->reduce($this->get($key, self::$defaultValue));
|
1394 |
+
$seen[$key] = false;
|
1395 |
+
return $out;
|
1396 |
+
case "list":
|
1397 |
+
foreach ($value[2] as &$item) {
|
1398 |
+
$item = $this->reduce($item, $forExpression);
|
1399 |
+
}
|
1400 |
+
return $value;
|
1401 |
+
case "expression":
|
1402 |
+
return $this->evaluate($value);
|
1403 |
+
case "string":
|
1404 |
+
foreach ($value[2] as &$part) {
|
1405 |
+
if (is_array($part)) {
|
1406 |
+
$strip = $part[0] == "variable";
|
1407 |
+
$part = $this->reduce($part);
|
1408 |
+
if ($strip) $part = $this->lib_unquote($part);
|
1409 |
+
}
|
1410 |
+
}
|
1411 |
+
return $value;
|
1412 |
+
case "escape":
|
1413 |
+
list(,$inner) = $value;
|
1414 |
+
return $this->lib_unquote($this->reduce($inner));
|
1415 |
+
case "function":
|
1416 |
+
$color = $this->funcToColor($value);
|
1417 |
+
if ($color) return $color;
|
1418 |
+
|
1419 |
+
list(, $name, $args) = $value;
|
1420 |
+
if ($name == "%") $name = "_sprintf";
|
1421 |
+
$f = isset($this->libFunctions[$name]) ?
|
1422 |
+
$this->libFunctions[$name] : array($this, 'lib_'.$name);
|
1423 |
+
|
1424 |
+
if (is_callable($f)) {
|
1425 |
+
if ($args[0] == 'list')
|
1426 |
+
$args = self::compressList($args[2], $args[1]);
|
1427 |
+
|
1428 |
+
$ret = call_user_func($f, $this->reduce($args, true), $this);
|
1429 |
+
|
1430 |
+
if (is_null($ret)) {
|
1431 |
+
return array("string", "", array(
|
1432 |
+
$name, "(", $args, ")"
|
1433 |
+
));
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
// convert to a typed value if the result is a php primitive
|
1437 |
+
if (is_numeric($ret)) $ret = array('number', $ret, "");
|
1438 |
+
elseif (!is_array($ret)) $ret = array('keyword', $ret);
|
1439 |
+
|
1440 |
+
return $ret;
|
1441 |
+
}
|
1442 |
+
|
1443 |
+
// plain function, reduce args
|
1444 |
+
$value[2] = $this->reduce($value[2]);
|
1445 |
+
return $value;
|
1446 |
+
case "unary":
|
1447 |
+
list(, $op, $exp) = $value;
|
1448 |
+
$exp = $this->reduce($exp);
|
1449 |
+
|
1450 |
+
if ($exp[0] == "number") {
|
1451 |
+
switch ($op) {
|
1452 |
+
case "+":
|
1453 |
+
return $exp;
|
1454 |
+
case "-":
|
1455 |
+
$exp[1] *= -1;
|
1456 |
+
return $exp;
|
1457 |
+
}
|
1458 |
+
}
|
1459 |
+
return array("string", "", array($op, $exp));
|
1460 |
+
}
|
1461 |
+
|
1462 |
+
if ($forExpression) {
|
1463 |
+
switch ($value[0]) {
|
1464 |
+
case "keyword":
|
1465 |
+
if ($color = $this->coerceColor($value)) {
|
1466 |
+
return $color;
|
1467 |
+
}
|
1468 |
+
break;
|
1469 |
+
case "raw_color":
|
1470 |
+
return $this->coerceColor($value);
|
1471 |
+
}
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
return $value;
|
1475 |
+
}
|
1476 |
+
|
1477 |
+
|
1478 |
+
// coerce a value for use in color operation
|
1479 |
+
protected function coerceColor($value) {
|
1480 |
+
switch($value[0]) {
|
1481 |
+
case 'color': return $value;
|
1482 |
+
case 'raw_color':
|
1483 |
+
$c = array("color", 0, 0, 0);
|
1484 |
+
$colorStr = substr($value[1], 1);
|
1485 |
+
$num = hexdec($colorStr);
|
1486 |
+
$width = strlen($colorStr) == 3 ? 16 : 256;
|
1487 |
+
|
1488 |
+
for ($i = 3; $i > 0; $i--) { // 3 2 1
|
1489 |
+
$t = $num % $width;
|
1490 |
+
$num /= $width;
|
1491 |
+
|
1492 |
+
$c[$i] = $t * (256/$width) + $t * floor(16/$width);
|
1493 |
+
}
|
1494 |
+
|
1495 |
+
return $c;
|
1496 |
+
case 'keyword':
|
1497 |
+
$name = $value[1];
|
1498 |
+
if (isset(self::$cssColors[$name])) {
|
1499 |
+
$rgba = explode(',', self::$cssColors[$name]);
|
1500 |
+
|
1501 |
+
if(isset($rgba[3]))
|
1502 |
+
return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
|
1503 |
+
|
1504 |
+
return array('color', $rgba[0], $rgba[1], $rgba[2]);
|
1505 |
+
}
|
1506 |
+
return null;
|
1507 |
+
}
|
1508 |
+
}
|
1509 |
+
|
1510 |
+
// make something string like into a string
|
1511 |
+
protected function coerceString($value) {
|
1512 |
+
switch ($value[0]) {
|
1513 |
+
case "string":
|
1514 |
+
return $value;
|
1515 |
+
case "keyword":
|
1516 |
+
return array("string", "", array($value[1]));
|
1517 |
+
}
|
1518 |
+
return null;
|
1519 |
+
}
|
1520 |
+
|
1521 |
+
// turn list of length 1 into value type
|
1522 |
+
protected function flattenList($value) {
|
1523 |
+
if ($value[0] == "list" && count($value[2]) == 1) {
|
1524 |
+
return $this->flattenList($value[2][0]);
|
1525 |
+
}
|
1526 |
+
return $value;
|
1527 |
+
}
|
1528 |
+
|
1529 |
+
protected function toBool($a) {
|
1530 |
+
if ($a) return self::$TRUE;
|
1531 |
+
else return self::$FALSE;
|
1532 |
+
}
|
1533 |
+
|
1534 |
+
// evaluate an expression
|
1535 |
+
protected function evaluate($exp) {
|
1536 |
+
list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
|
1537 |
+
|
1538 |
+
$left = $this->reduce($left, true);
|
1539 |
+
$right = $this->reduce($right, true);
|
1540 |
+
|
1541 |
+
if ($leftColor = $this->coerceColor($left)) {
|
1542 |
+
$left = $leftColor;
|
1543 |
+
}
|
1544 |
+
|
1545 |
+
if ($rightColor = $this->coerceColor($right)) {
|
1546 |
+
$right = $rightColor;
|
1547 |
+
}
|
1548 |
+
|
1549 |
+
$ltype = $left[0];
|
1550 |
+
$rtype = $right[0];
|
1551 |
+
|
1552 |
+
// operators that work on all types
|
1553 |
+
if ($op == "and") {
|
1554 |
+
return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
|
1555 |
+
}
|
1556 |
+
|
1557 |
+
if ($op == "=") {
|
1558 |
+
return $this->toBool($this->eq($left, $right) );
|
1559 |
+
}
|
1560 |
+
|
1561 |
+
if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
|
1562 |
+
return $str;
|
1563 |
+
}
|
1564 |
+
|
1565 |
+
// type based operators
|
1566 |
+
$fname = "op_${ltype}_${rtype}";
|
1567 |
+
if (is_callable(array($this, $fname))) {
|
1568 |
+
$out = $this->$fname($op, $left, $right);
|
1569 |
+
if (!is_null($out)) return $out;
|
1570 |
+
}
|
1571 |
+
|
1572 |
+
// make the expression look it did before being parsed
|
1573 |
+
$paddedOp = $op;
|
1574 |
+
if ($whiteBefore) $paddedOp = " " . $paddedOp;
|
1575 |
+
if ($whiteAfter) $paddedOp .= " ";
|
1576 |
+
|
1577 |
+
return array("string", "", array($left, $paddedOp, $right));
|
1578 |
+
}
|
1579 |
+
|
1580 |
+
protected function stringConcatenate($left, $right) {
|
1581 |
+
if ($strLeft = $this->coerceString($left)) {
|
1582 |
+
if ($right[0] == "string") {
|
1583 |
+
$right[1] = "";
|
1584 |
+
}
|
1585 |
+
$strLeft[2][] = $right;
|
1586 |
+
return $strLeft;
|
1587 |
+
}
|
1588 |
+
|
1589 |
+
if ($strRight = $this->coerceString($right)) {
|
1590 |
+
array_unshift($strRight[2], $left);
|
1591 |
+
return $strRight;
|
1592 |
+
}
|
1593 |
+
}
|
1594 |
+
|
1595 |
+
|
1596 |
+
// make sure a color's components don't go out of bounds
|
1597 |
+
protected function fixColor($c) {
|
1598 |
+
foreach (range(1, 3) as $i) {
|
1599 |
+
if ($c[$i] < 0) $c[$i] = 0;
|
1600 |
+
if ($c[$i] > 255) $c[$i] = 255;
|
1601 |
+
}
|
1602 |
+
|
1603 |
+
return $c;
|
1604 |
+
}
|
1605 |
+
|
1606 |
+
protected function op_number_color($op, $lft, $rgt) {
|
1607 |
+
if ($op == '+' || $op == '*') {
|
1608 |
+
return $this->op_color_number($op, $rgt, $lft);
|
1609 |
+
}
|
1610 |
+
}
|
1611 |
+
|
1612 |
+
protected function op_color_number($op, $lft, $rgt) {
|
1613 |
+
if ($rgt[0] == '%') $rgt[1] /= 100;
|
1614 |
+
|
1615 |
+
return $this->op_color_color($op, $lft,
|
1616 |
+
array_fill(1, count($lft) - 1, $rgt[1]));
|
1617 |
+
}
|
1618 |
+
|
1619 |
+
protected function op_color_color($op, $left, $right) {
|
1620 |
+
$out = array('color');
|
1621 |
+
$max = count($left) > count($right) ? count($left) : count($right);
|
1622 |
+
foreach (range(1, $max - 1) as $i) {
|
1623 |
+
$lval = isset($left[$i]) ? $left[$i] : 0;
|
1624 |
+
$rval = isset($right[$i]) ? $right[$i] : 0;
|
1625 |
+
switch ($op) {
|
1626 |
+
case '+':
|
1627 |
+
$out[] = $lval + $rval;
|
1628 |
+
break;
|
1629 |
+
case '-':
|
1630 |
+
$out[] = $lval - $rval;
|
1631 |
+
break;
|
1632 |
+
case '*':
|
1633 |
+
$out[] = $lval * $rval;
|
1634 |
+
break;
|
1635 |
+
case '%':
|
1636 |
+
$out[] = $lval % $rval;
|
1637 |
+
break;
|
1638 |
+
case '/':
|
1639 |
+
if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
|
1640 |
+
$out[] = $lval / $rval;
|
1641 |
+
break;
|
1642 |
+
default:
|
1643 |
+
$this->throwError('evaluate error: color op number failed on op '.$op);
|
1644 |
+
}
|
1645 |
+
}
|
1646 |
+
return $this->fixColor($out);
|
1647 |
+
}
|
1648 |
+
|
1649 |
+
function lib_red($color){
|
1650 |
+
$color = $this->coerceColor($color);
|
1651 |
+
if (is_null($color)) {
|
1652 |
+
$this->throwError('color expected for red()');
|
1653 |
+
}
|
1654 |
+
|
1655 |
+
return $color[1];
|
1656 |
+
}
|
1657 |
+
|
1658 |
+
function lib_green($color){
|
1659 |
+
$color = $this->coerceColor($color);
|
1660 |
+
if (is_null($color)) {
|
1661 |
+
$this->throwError('color expected for green()');
|
1662 |
+
}
|
1663 |
+
|
1664 |
+
return $color[2];
|
1665 |
+
}
|
1666 |
+
|
1667 |
+
function lib_blue($color){
|
1668 |
+
$color = $this->coerceColor($color);
|
1669 |
+
if (is_null($color)) {
|
1670 |
+
$this->throwError('color expected for blue()');
|
1671 |
+
}
|
1672 |
+
|
1673 |
+
return $color[3];
|
1674 |
+
}
|
1675 |
+
|
1676 |
+
|
1677 |
+
// operator on two numbers
|
1678 |
+
protected function op_number_number($op, $left, $right) {
|
1679 |
+
$unit = empty($left[2]) ? $right[2] : $left[2];
|
1680 |
+
|
1681 |
+
$value = 0;
|
1682 |
+
switch ($op) {
|
1683 |
+
case '+':
|
1684 |
+
$value = $left[1] + $right[1];
|
1685 |
+
break;
|
1686 |
+
case '*':
|
1687 |
+
$value = $left[1] * $right[1];
|
1688 |
+
break;
|
1689 |
+
case '-':
|
1690 |
+
$value = $left[1] - $right[1];
|
1691 |
+
break;
|
1692 |
+
case '%':
|
1693 |
+
$value = $left[1] % $right[1];
|
1694 |
+
break;
|
1695 |
+
case '/':
|
1696 |
+
if ($right[1] == 0) $this->throwError('parse error: divide by zero');
|
1697 |
+
$value = $left[1] / $right[1];
|
1698 |
+
break;
|
1699 |
+
case '<':
|
1700 |
+
return $this->toBool($left[1] < $right[1]);
|
1701 |
+
case '>':
|
1702 |
+
return $this->toBool($left[1] > $right[1]);
|
1703 |
+
case '>=':
|
1704 |
+
return $this->toBool($left[1] >= $right[1]);
|
1705 |
+
case '=<':
|
1706 |
+
return $this->toBool($left[1] <= $right[1]);
|
1707 |
+
default:
|
1708 |
+
$this->throwError('parse error: unknown number operator: '.$op);
|
1709 |
+
}
|
1710 |
+
|
1711 |
+
return array("number", $value, $unit);
|
1712 |
+
}
|
1713 |
+
|
1714 |
+
|
1715 |
+
/* environment functions */
|
1716 |
+
|
1717 |
+
protected function makeOutputBlock($type, $selectors = null) {
|
1718 |
+
$b = new stdclass;
|
1719 |
+
$b->lines = array();
|
1720 |
+
$b->children = array();
|
1721 |
+
$b->selectors = $selectors;
|
1722 |
+
$b->type = $type;
|
1723 |
+
$b->parent = $this->scope;
|
1724 |
+
return $b;
|
1725 |
+
}
|
1726 |
+
|
1727 |
+
// the state of execution
|
1728 |
+
protected function pushEnv($block = null) {
|
1729 |
+
$e = new stdclass;
|
1730 |
+
$e->parent = $this->env;
|
1731 |
+
$e->store = array();
|
1732 |
+
$e->block = $block;
|
1733 |
+
|
1734 |
+
$this->env = $e;
|
1735 |
+
return $e;
|
1736 |
+
}
|
1737 |
+
|
1738 |
+
// pop something off the stack
|
1739 |
+
protected function popEnv() {
|
1740 |
+
$old = $this->env;
|
1741 |
+
$this->env = $this->env->parent;
|
1742 |
+
return $old;
|
1743 |
+
}
|
1744 |
+
|
1745 |
+
// set something in the current env
|
1746 |
+
protected function set($name, $value) {
|
1747 |
+
$this->env->store[$name] = $value;
|
1748 |
+
}
|
1749 |
+
|
1750 |
+
|
1751 |
+
// get the highest occurrence entry for a name
|
1752 |
+
protected function get($name, $default=null) {
|
1753 |
+
$current = $this->env;
|
1754 |
+
|
1755 |
+
$isArguments = $name == $this->vPrefix . 'arguments';
|
1756 |
+
while ($current) {
|
1757 |
+
if ($isArguments && isset($current->arguments)) {
|
1758 |
+
return array('list', ' ', $current->arguments);
|
1759 |
+
}
|
1760 |
+
|
1761 |
+
if (isset($current->store[$name]))
|
1762 |
+
return $current->store[$name];
|
1763 |
+
else {
|
1764 |
+
$current = isset($current->storeParent) ?
|
1765 |
+
$current->storeParent : $current->parent;
|
1766 |
+
}
|
1767 |
+
}
|
1768 |
+
|
1769 |
+
return $default;
|
1770 |
+
}
|
1771 |
+
|
1772 |
+
// inject array of unparsed strings into environment as variables
|
1773 |
+
protected function injectVariables($args) {
|
1774 |
+
$this->pushEnv();
|
1775 |
+
$parser = new lessc_parser($this, __METHOD__);
|
1776 |
+
foreach ($args as $name => $strValue) {
|
1777 |
+
if ($name{0} != '@') $name = '@'.$name;
|
1778 |
+
$parser->count = 0;
|
1779 |
+
$parser->buffer = (string)$strValue;
|
1780 |
+
if (!$parser->propertyValue($value)) {
|
1781 |
+
throw new Exception("failed to parse passed in variable $name: $strValue");
|
1782 |
+
}
|
1783 |
+
|
1784 |
+
$this->set($name, $value);
|
1785 |
+
}
|
1786 |
+
}
|
1787 |
+
|
1788 |
+
/**
|
1789 |
+
* Initialize any static state, can initialize parser for a file
|
1790 |
+
* $opts isn't used yet
|
1791 |
+
*/
|
1792 |
+
public function __construct($fname = null) {
|
1793 |
+
if ($fname !== null) {
|
1794 |
+
// used for deprecated parse method
|
1795 |
+
$this->_parseFile = $fname;
|
1796 |
+
}
|
1797 |
+
}
|
1798 |
+
|
1799 |
+
public function compile($string, $name = null) {
|
1800 |
+
$locale = setlocale(LC_NUMERIC, 0);
|
1801 |
+
setlocale(LC_NUMERIC, "C");
|
1802 |
+
|
1803 |
+
$this->parser = $this->makeParser($name);
|
1804 |
+
$root = $this->parser->parse($string);
|
1805 |
+
|
1806 |
+
$this->env = null;
|
1807 |
+
$this->scope = null;
|
1808 |
+
|
1809 |
+
$this->formatter = $this->newFormatter();
|
1810 |
+
|
1811 |
+
if (!empty($this->registeredVars)) {
|
1812 |
+
$this->injectVariables($this->registeredVars);
|
1813 |
+
}
|
1814 |
+
|
1815 |
+
$this->sourceParser = $this->parser; // used for error messages
|
1816 |
+
$this->compileBlock($root);
|
1817 |
+
|
1818 |
+
ob_start();
|
1819 |
+
$this->formatter->block($this->scope);
|
1820 |
+
$out = ob_get_clean();
|
1821 |
+
setlocale(LC_NUMERIC, $locale);
|
1822 |
+
return $out;
|
1823 |
+
}
|
1824 |
+
|
1825 |
+
public function compileFile($fname, $outFname = null) {
|
1826 |
+
if (!is_readable($fname)) {
|
1827 |
+
throw new Exception('load error: failed to find '.$fname);
|
1828 |
+
}
|
1829 |
+
|
1830 |
+
$pi = pathinfo($fname);
|
1831 |
+
|
1832 |
+
$oldImport = $this->importDir;
|
1833 |
+
|
1834 |
+
$this->importDir = (array)$this->importDir;
|
1835 |
+
$this->importDir[] = $pi['dirname'].'/';
|
1836 |
+
|
1837 |
+
$this->addParsedFile($fname);
|
1838 |
+
|
1839 |
+
$out = $this->compile($GLOBALS['wp_filesystem']->get_contents($fname), $fname);
|
1840 |
+
|
1841 |
+
$this->importDir = $oldImport;
|
1842 |
+
|
1843 |
+
if ($outFname !== null) {
|
1844 |
+
return $GLOBALS['wp_filesystem']->put_contents($outFname, $out);
|
1845 |
+
}
|
1846 |
+
|
1847 |
+
return $out;
|
1848 |
+
}
|
1849 |
+
|
1850 |
+
// compile only if changed input has changed or output doesn't exist
|
1851 |
+
public function checkedCompile($in, $out) {
|
1852 |
+
if (!is_file($out) || filemtime($in) > filemtime($out)) {
|
1853 |
+
$this->compileFile($in, $out);
|
1854 |
+
return true;
|
1855 |
+
}
|
1856 |
+
return false;
|
1857 |
+
}
|
1858 |
+
|
1859 |
+
/**
|
1860 |
+
* Execute lessphp on a .less file or a lessphp cache structure
|
1861 |
+
*
|
1862 |
+
* The lessphp cache structure contains information about a specific
|
1863 |
+
* less file having been parsed. It can be used as a hint for future
|
1864 |
+
* calls to determine whether or not a rebuild is required.
|
1865 |
+
*
|
1866 |
+
* The cache structure contains two important keys that may be used
|
1867 |
+
* externally:
|
1868 |
+
*
|
1869 |
+
* compiled: The final compiled CSS
|
1870 |
+
* updated: The time (in seconds) the CSS was last compiled
|
1871 |
+
*
|
1872 |
+
* The cache structure is a plain-ol' PHP associative array and can
|
1873 |
+
* be serialized and unserialized without a hitch.
|
1874 |
+
*
|
1875 |
+
* @param mixed $in Input
|
1876 |
+
* @param bool $force Force rebuild?
|
1877 |
+
* @return array lessphp cache structure
|
1878 |
+
*/
|
1879 |
+
public function cachedCompile($in, $force = false) {
|
1880 |
+
// assume no root
|
1881 |
+
$root = null;
|
1882 |
+
|
1883 |
+
if (is_string($in)) {
|
1884 |
+
$root = $in;
|
1885 |
+
} elseif (is_array($in) and isset($in['root'])) {
|
1886 |
+
if ($force or ! isset($in['files'])) {
|
1887 |
+
// If we are forcing a recompile or if for some reason the
|
1888 |
+
// structure does not contain any file information we should
|
1889 |
+
// specify the root to trigger a rebuild.
|
1890 |
+
$root = $in['root'];
|
1891 |
+
} elseif (isset($in['files']) and is_array($in['files'])) {
|
1892 |
+
foreach ($in['files'] as $fname => $ftime ) {
|
1893 |
+
if (!file_exists($fname) or filemtime($fname) > $ftime) {
|
1894 |
+
// One of the files we knew about previously has changed
|
1895 |
+
// so we should look at our incoming root again.
|
1896 |
+
$root = $in['root'];
|
1897 |
+
break;
|
1898 |
+
}
|
1899 |
+
}
|
1900 |
+
}
|
1901 |
+
} else {
|
1902 |
+
// TODO: Throw an exception? We got neither a string nor something
|
1903 |
+
// that looks like a compatible lessphp cache structure.
|
1904 |
+
return null;
|
1905 |
+
}
|
1906 |
+
|
1907 |
+
if ($root !== null) {
|
1908 |
+
// If we have a root value which means we should rebuild.
|
1909 |
+
$out = array();
|
1910 |
+
$out['root'] = $root;
|
1911 |
+
$out['compiled'] = $this->compileFile($root);
|
1912 |
+
$out['files'] = $this->allParsedFiles();
|
1913 |
+
$out['updated'] = time();
|
1914 |
+
return $out;
|
1915 |
+
} else {
|
1916 |
+
// No changes, pass back the structure
|
1917 |
+
// we were given initially.
|
1918 |
+
return $in;
|
1919 |
+
}
|
1920 |
+
|
1921 |
+
}
|
1922 |
+
|
1923 |
+
// parse and compile buffer
|
1924 |
+
// This is deprecated
|
1925 |
+
public function parse($str = null, $initialVariables = null) {
|
1926 |
+
if (is_array($str)) {
|
1927 |
+
$initialVariables = $str;
|
1928 |
+
$str = null;
|
1929 |
+
}
|
1930 |
+
|
1931 |
+
$oldVars = $this->registeredVars;
|
1932 |
+
if ($initialVariables !== null) {
|
1933 |
+
$this->setVariables($initialVariables);
|
1934 |
+
}
|
1935 |
+
|
1936 |
+
if ($str == null) {
|
1937 |
+
if (empty($this->_parseFile)) {
|
1938 |
+
throw new exception("nothing to parse");
|
1939 |
+
}
|
1940 |
+
|
1941 |
+
$out = $this->compileFile($this->_parseFile);
|
1942 |
+
} else {
|
1943 |
+
$out = $this->compile($str);
|
1944 |
+
}
|
1945 |
+
|
1946 |
+
$this->registeredVars = $oldVars;
|
1947 |
+
return $out;
|
1948 |
+
}
|
1949 |
+
|
1950 |
+
protected function makeParser($name) {
|
1951 |
+
$parser = new lessc_parser($this, $name);
|
1952 |
+
$parser->writeComments = $this->preserveComments;
|
1953 |
+
|
1954 |
+
return $parser;
|
1955 |
+
}
|
1956 |
+
|
1957 |
+
public function setFormatter($name) {
|
1958 |
+
$this->formatterName = $name;
|
1959 |
+
}
|
1960 |
+
|
1961 |
+
protected function newFormatter() {
|
1962 |
+
$className = "lessc_formatter_lessjs";
|
1963 |
+
if (!empty($this->formatterName)) {
|
1964 |
+
if (!is_string($this->formatterName))
|
1965 |
+
return $this->formatterName;
|
1966 |
+
$className = "lessc_formatter_$this->formatterName";
|
1967 |
+
}
|
1968 |
+
|
1969 |
+
return new $className;
|
1970 |
+
}
|
1971 |
+
|
1972 |
+
public function setPreserveComments($preserve) {
|
1973 |
+
$this->preserveComments = $preserve;
|
1974 |
+
}
|
1975 |
+
|
1976 |
+
public function registerFunction($name, $func) {
|
1977 |
+
$this->libFunctions[$name] = $func;
|
1978 |
+
}
|
1979 |
+
|
1980 |
+
public function unregisterFunction($name) {
|
1981 |
+
unset($this->libFunctions[$name]);
|
1982 |
+
}
|
1983 |
+
|
1984 |
+
public function setVariables($variables) {
|
1985 |
+
$this->registeredVars = array_merge($this->registeredVars, $variables);
|
1986 |
+
}
|
1987 |
+
|
1988 |
+
public function unsetVariable($name) {
|
1989 |
+
unset($this->registeredVars[$name]);
|
1990 |
+
}
|
1991 |
+
|
1992 |
+
public function setImportDir($dirs) {
|
1993 |
+
$this->importDir = (array)$dirs;
|
1994 |
+
}
|
1995 |
+
|
1996 |
+
public function addImportDir($dir) {
|
1997 |
+
$this->importDir = (array)$this->importDir;
|
1998 |
+
$this->importDir[] = $dir;
|
1999 |
+
}
|
2000 |
+
|
2001 |
+
public function allParsedFiles() {
|
2002 |
+
return $this->allParsedFiles;
|
2003 |
+
}
|
2004 |
+
|
2005 |
+
protected function addParsedFile($file) {
|
2006 |
+
$this->allParsedFiles[realpath($file)] = filemtime($file);
|
2007 |
+
}
|
2008 |
+
|
2009 |
+
/**
|
2010 |
+
* Uses the current value of $this->count to show line and line number
|
2011 |
+
*/
|
2012 |
+
protected function throwError($msg = null) {
|
2013 |
+
if ($this->sourceLoc >= 0) {
|
2014 |
+
$this->sourceParser->throwError($msg, $this->sourceLoc);
|
2015 |
+
}
|
2016 |
+
throw new exception($msg);
|
2017 |
+
}
|
2018 |
+
|
2019 |
+
// compile file $in to file $out if $in is newer than $out
|
2020 |
+
// returns true when it compiles, false otherwise
|
2021 |
+
public static function ccompile($in, $out, $less = null) {
|
2022 |
+
if ($less === null) {
|
2023 |
+
$less = new self;
|
2024 |
+
}
|
2025 |
+
return $less->checkedCompile($in, $out);
|
2026 |
+
}
|
2027 |
+
|
2028 |
+
public static function cexecute($in, $force = false, $less = null) {
|
2029 |
+
if ($less === null) {
|
2030 |
+
$less = new self;
|
2031 |
+
}
|
2032 |
+
return $less->cachedCompile($in, $force);
|
2033 |
+
}
|
2034 |
+
|
2035 |
+
static protected $cssColors = array(
|
2036 |
+
'aliceblue' => '240,248,255',
|
2037 |
+
'antiquewhite' => '250,235,215',
|
2038 |
+
'aqua' => '0,255,255',
|
2039 |
+
'aquamarine' => '127,255,212',
|
2040 |
+
'azure' => '240,255,255',
|
2041 |
+
'beige' => '245,245,220',
|
2042 |
+
'bisque' => '255,228,196',
|
2043 |
+
'black' => '0,0,0',
|
2044 |
+
'blanchedalmond' => '255,235,205',
|
2045 |
+
'blue' => '0,0,255',
|
2046 |
+
'blueviolet' => '138,43,226',
|
2047 |
+
'brown' => '165,42,42',
|
2048 |
+
'burlywood' => '222,184,135',
|
2049 |
+
'cadetblue' => '95,158,160',
|
2050 |
+
'chartreuse' => '127,255,0',
|
2051 |
+
'chocolate' => '210,105,30',
|
2052 |
+
'coral' => '255,127,80',
|
2053 |
+
'cornflowerblue' => '100,149,237',
|
2054 |
+
'cornsilk' => '255,248,220',
|
2055 |
+
'crimson' => '220,20,60',
|
2056 |
+
'cyan' => '0,255,255',
|
2057 |
+
'darkblue' => '0,0,139',
|
2058 |
+
'darkcyan' => '0,139,139',
|
2059 |
+
'darkgoldenrod' => '184,134,11',
|
2060 |
+
'darkgray' => '169,169,169',
|
2061 |
+
'darkgreen' => '0,100,0',
|
2062 |
+
'darkgrey' => '169,169,169',
|
2063 |
+
'darkkhaki' => '189,183,107',
|
2064 |
+
'darkmagenta' => '139,0,139',
|
2065 |
+
'darkolivegreen' => '85,107,47',
|
2066 |
+
'darkorange' => '255,140,0',
|
2067 |
+
'darkorchid' => '153,50,204',
|
2068 |
+
'darkred' => '139,0,0',
|
2069 |
+
'darksalmon' => '233,150,122',
|
2070 |
+
'darkseagreen' => '143,188,143',
|
2071 |
+
'darkslateblue' => '72,61,139',
|
2072 |
+
'darkslategray' => '47,79,79',
|
2073 |
+
'darkslategrey' => '47,79,79',
|
2074 |
+
'darkturquoise' => '0,206,209',
|
2075 |
+
'darkviolet' => '148,0,211',
|
2076 |
+
'deeppink' => '255,20,147',
|
2077 |
+
'deepskyblue' => '0,191,255',
|
2078 |
+
'dimgray' => '105,105,105',
|
2079 |
+
'dimgrey' => '105,105,105',
|
2080 |
+
'dodgerblue' => '30,144,255',
|
2081 |
+
'firebrick' => '178,34,34',
|
2082 |
+
'floralwhite' => '255,250,240',
|
2083 |
+
'forestgreen' => '34,139,34',
|
2084 |
+
'fuchsia' => '255,0,255',
|
2085 |
+
'gainsboro' => '220,220,220',
|
2086 |
+
'ghostwhite' => '248,248,255',
|
2087 |
+
'gold' => '255,215,0',
|
2088 |
+
'goldenrod' => '218,165,32',
|
2089 |
+
'gray' => '128,128,128',
|
2090 |
+
'green' => '0,128,0',
|
2091 |
+
'greenyellow' => '173,255,47',
|
2092 |
+
'grey' => '128,128,128',
|
2093 |
+
'honeydew' => '240,255,240',
|
2094 |
+
'hotpink' => '255,105,180',
|
2095 |
+
'indianred' => '205,92,92',
|
2096 |
+
'indigo' => '75,0,130',
|
2097 |
+
'ivory' => '255,255,240',
|
2098 |
+
'khaki' => '240,230,140',
|
2099 |
+
'lavender' => '230,230,250',
|
2100 |
+
'lavenderblush' => '255,240,245',
|
2101 |
+
'lawngreen' => '124,252,0',
|
2102 |
+
'lemonchiffon' => '255,250,205',
|
2103 |
+
'lightblue' => '173,216,230',
|
2104 |
+
'lightcoral' => '240,128,128',
|
2105 |
+
'lightcyan' => '224,255,255',
|
2106 |
+
'lightgoldenrodyellow' => '250,250,210',
|
2107 |
+
'lightgray' => '211,211,211',
|
2108 |
+
'lightgreen' => '144,238,144',
|
2109 |
+
'lightgrey' => '211,211,211',
|
2110 |
+
'lightpink' => '255,182,193',
|
2111 |
+
'lightsalmon' => '255,160,122',
|
2112 |
+
'lightseagreen' => '32,178,170',
|
2113 |
+
'lightskyblue' => '135,206,250',
|
2114 |
+
'lightslategray' => '119,136,153',
|
2115 |
+
'lightslategrey' => '119,136,153',
|
2116 |
+
'lightsteelblue' => '176,196,222',
|
2117 |
+
'lightyellow' => '255,255,224',
|
2118 |
+
'lime' => '0,255,0',
|
2119 |
+
'limegreen' => '50,205,50',
|
2120 |
+
'linen' => '250,240,230',
|
2121 |
+
'magenta' => '255,0,255',
|
2122 |
+
'maroon' => '128,0,0',
|
2123 |
+
'mediumaquamarine' => '102,205,170',
|
2124 |
+
'mediumblue' => '0,0,205',
|
2125 |
+
'mediumorchid' => '186,85,211',
|
2126 |
+
'mediumpurple' => '147,112,219',
|
2127 |
+
'mediumseagreen' => '60,179,113',
|
2128 |
+
'mediumslateblue' => '123,104,238',
|
2129 |
+
'mediumspringgreen' => '0,250,154',
|
2130 |
+
'mediumturquoise' => '72,209,204',
|
2131 |
+
'mediumvioletred' => '199,21,133',
|
2132 |
+
'midnightblue' => '25,25,112',
|
2133 |
+
'mintcream' => '245,255,250',
|
2134 |
+
'mistyrose' => '255,228,225',
|
2135 |
+
'moccasin' => '255,228,181',
|
2136 |
+
'navajowhite' => '255,222,173',
|
2137 |
+
'navy' => '0,0,128',
|
2138 |
+
'oldlace' => '253,245,230',
|
2139 |
+
'olive' => '128,128,0',
|
2140 |
+
'olivedrab' => '107,142,35',
|
2141 |
+
'orange' => '255,165,0',
|
2142 |
+
'orangered' => '255,69,0',
|
2143 |
+
'orchid' => '218,112,214',
|
2144 |
+
'palegoldenrod' => '238,232,170',
|
2145 |
+
'palegreen' => '152,251,152',
|
2146 |
+
'paleturquoise' => '175,238,238',
|
2147 |
+
'palevioletred' => '219,112,147',
|
2148 |
+
'papayawhip' => '255,239,213',
|
2149 |
+
'peachpuff' => '255,218,185',
|
2150 |
+
'peru' => '205,133,63',
|
2151 |
+
'pink' => '255,192,203',
|
2152 |
+
'plum' => '221,160,221',
|
2153 |
+
'powderblue' => '176,224,230',
|
2154 |
+
'purple' => '128,0,128',
|
2155 |
+
'red' => '255,0,0',
|
2156 |
+
'rosybrown' => '188,143,143',
|
2157 |
+
'royalblue' => '65,105,225',
|
2158 |
+
'saddlebrown' => '139,69,19',
|
2159 |
+
'salmon' => '250,128,114',
|
2160 |
+
'sandybrown' => '244,164,96',
|
2161 |
+
'seagreen' => '46,139,87',
|
2162 |
+
'seashell' => '255,245,238',
|
2163 |
+
'sienna' => '160,82,45',
|
2164 |
+
'silver' => '192,192,192',
|
2165 |
+
'skyblue' => '135,206,235',
|
2166 |
+
'slateblue' => '106,90,205',
|
2167 |
+
'slategray' => '112,128,144',
|
2168 |
+
'slategrey' => '112,128,144',
|
2169 |
+
'snow' => '255,250,250',
|
2170 |
+
'springgreen' => '0,255,127',
|
2171 |
+
'steelblue' => '70,130,180',
|
2172 |
+
'tan' => '210,180,140',
|
2173 |
+
'teal' => '0,128,128',
|
2174 |
+
'thistle' => '216,191,216',
|
2175 |
+
'tomato' => '255,99,71',
|
2176 |
+
'transparent' => '0,0,0,0',
|
2177 |
+
'turquoise' => '64,224,208',
|
2178 |
+
'violet' => '238,130,238',
|
2179 |
+
'wheat' => '245,222,179',
|
2180 |
+
'white' => '255,255,255',
|
2181 |
+
'whitesmoke' => '245,245,245',
|
2182 |
+
'yellow' => '255,255,0',
|
2183 |
+
'yellowgreen' => '154,205,50'
|
2184 |
+
);
|
2185 |
+
}
|
2186 |
+
|
2187 |
+
// responsible for taking a string of LESS code and converting it into a
|
2188 |
+
// syntax tree
|
2189 |
+
/**
|
2190 |
+
* @ignore
|
2191 |
+
*/
|
2192 |
+
class lessc_parser {
|
2193 |
+
static protected $nextBlockId = 0; // used to uniquely identify blocks
|
2194 |
+
|
2195 |
+
static protected $precedence = array(
|
2196 |
+
'=<' => 0,
|
2197 |
+
'>=' => 0,
|
2198 |
+
'=' => 0,
|
2199 |
+
'<' => 0,
|
2200 |
+
'>' => 0,
|
2201 |
+
|
2202 |
+
'+' => 1,
|
2203 |
+
'-' => 1,
|
2204 |
+
'*' => 2,
|
2205 |
+
'/' => 2,
|
2206 |
+
'%' => 2,
|
2207 |
+
);
|
2208 |
+
|
2209 |
+
static protected $whitePattern;
|
2210 |
+
static protected $commentMulti;
|
2211 |
+
|
2212 |
+
static protected $commentSingle = "//";
|
2213 |
+
static protected $commentMultiLeft = "/*";
|
2214 |
+
static protected $commentMultiRight = "*/";
|
2215 |
+
|
2216 |
+
// regex string to match any of the operators
|
2217 |
+
static protected $operatorString;
|
2218 |
+
|
2219 |
+
// these properties will supress division unless it's inside parenthases
|
2220 |
+
static protected $supressDivisionProps =
|
2221 |
+
array('/border-radius$/i', '/^font$/i');
|
2222 |
+
|
2223 |
+
protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport");
|
2224 |
+
protected $lineDirectives = array("charset");
|
2225 |
+
|
2226 |
+
/**
|
2227 |
+
* if we are in parens we can be more liberal with whitespace around
|
2228 |
+
* operators because it must evaluate to a single value and thus is less
|
2229 |
+
* ambiguous.
|
2230 |
+
*
|
2231 |
+
* Consider:
|
2232 |
+
* property1: 10 -5; // is two numbers, 10 and -5
|
2233 |
+
* property2: (10 -5); // should evaluate to 5
|
2234 |
+
*/
|
2235 |
+
protected $inParens = false;
|
2236 |
+
|
2237 |
+
// caches preg escaped literals
|
2238 |
+
static protected $literalCache = array();
|
2239 |
+
|
2240 |
+
public function __construct($lessc, $sourceName = null) {
|
2241 |
+
$this->eatWhiteDefault = true;
|
2242 |
+
// reference to less needed for vPrefix, mPrefix, and parentSelector
|
2243 |
+
$this->lessc = $lessc;
|
2244 |
+
|
2245 |
+
$this->sourceName = $sourceName; // name used for error messages
|
2246 |
+
|
2247 |
+
$this->writeComments = false;
|
2248 |
+
|
2249 |
+
if (!self::$operatorString) {
|
2250 |
+
self::$operatorString =
|
2251 |
+
'('.implode('|', array_map(array('JupiterX_Lessc', 'preg_quote'),
|
2252 |
+
array_keys(self::$precedence))).')';
|
2253 |
+
|
2254 |
+
$commentSingle = JupiterX_Lessc::preg_quote(self::$commentSingle);
|
2255 |
+
$commentMultiLeft = JupiterX_Lessc::preg_quote(self::$commentMultiLeft);
|
2256 |
+
$commentMultiRight = JupiterX_Lessc::preg_quote(self::$commentMultiRight);
|
2257 |
+
|
2258 |
+
self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight;
|
2259 |
+
self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais';
|
2260 |
+
}
|
2261 |
+
}
|
2262 |
+
|
2263 |
+
public function parse($buffer) {
|
2264 |
+
$this->count = 0;
|
2265 |
+
$this->line = 1;
|
2266 |
+
|
2267 |
+
$this->env = null; // block stack
|
2268 |
+
$this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
|
2269 |
+
$this->pushSpecialBlock("root");
|
2270 |
+
$this->eatWhiteDefault = true;
|
2271 |
+
$this->seenComments = array();
|
2272 |
+
|
2273 |
+
// trim whitespace on head
|
2274 |
+
// if (preg_match('/^\s+/', $this->buffer, $m)) {
|
2275 |
+
// $this->line += substr_count($m[0], "\n");
|
2276 |
+
// $this->buffer = ltrim($this->buffer);
|
2277 |
+
// }
|
2278 |
+
$this->whitespace();
|
2279 |
+
|
2280 |
+
// parse the entire file
|
2281 |
+
$lastCount = $this->count;
|
2282 |
+
while (false !== $this->parseChunk());
|
2283 |
+
|
2284 |
+
if ($this->count != strlen($this->buffer))
|
2285 |
+
$this->throwError();
|
2286 |
+
|
2287 |
+
// TODO report where the block was opened
|
2288 |
+
if (!is_null($this->env->parent))
|
2289 |
+
throw new exception('parse error: unclosed block');
|
2290 |
+
|
2291 |
+
return $this->env;
|
2292 |
+
}
|
2293 |
+
|
2294 |
+
/**
|
2295 |
+
* Parse a single chunk off the head of the buffer and append it to the
|
2296 |
+
* current parse environment.
|
2297 |
+
* Returns false when the buffer is empty, or when there is an error.
|
2298 |
+
*
|
2299 |
+
* This function is called repeatedly until the entire document is
|
2300 |
+
* parsed.
|
2301 |
+
*
|
2302 |
+
* This parser is most similar to a recursive descent parser. Single
|
2303 |
+
* functions represent discrete grammatical rules for the language, and
|
2304 |
+
* they are able to capture the text that represents those rules.
|
2305 |
+
*
|
2306 |
+
* Consider the function lessc::keyword(). (all parse functions are
|
2307 |
+
* structured the same)
|
2308 |
+
*
|
2309 |
+
* The function takes a single reference argument. When calling the
|
2310 |
+
* function it will attempt to match a keyword on the head of the buffer.
|
2311 |
+
* If it is successful, it will place the keyword in the referenced
|
2312 |
+
* argument, advance the position in the buffer, and return true. If it
|
2313 |
+
* fails then it won't advance the buffer and it will return false.
|
2314 |
+
*
|
2315 |
+
* All of these parse functions are powered by lessc::match(), which behaves
|
2316 |
+
* the same way, but takes a literal regular expression. Sometimes it is
|
2317 |
+
* more convenient to use match instead of creating a new function.
|
2318 |
+
*
|
2319 |
+
* Because of the format of the functions, to parse an entire string of
|
2320 |
+
* grammatical rules, you can chain them together using &&.
|
2321 |
+
*
|
2322 |
+
* But, if some of the rules in the chain succeed before one fails, then
|
2323 |
+
* the buffer position will be left at an invalid state. In order to
|
2324 |
+
* avoid this, lessc::seek() is used to remember and set buffer positions.
|
2325 |
+
*
|
2326 |
+
* Before parsing a chain, use $s = $this->seek() to remember the current
|
2327 |
+
* position into $s. Then if a chain fails, use $this->seek($s) to
|
2328 |
+
* go back where we started.
|
2329 |
+
*/
|
2330 |
+
protected function parseChunk() {
|
2331 |
+
if (empty($this->buffer)) return false;
|
2332 |
+
$s = $this->seek();
|
2333 |
+
|
2334 |
+
// setting a property
|
2335 |
+
if ($this->keyword($key) && $this->assign() &&
|
2336 |
+
$this->propertyValue($value, $key) && $this->end())
|
2337 |
+
{
|
2338 |
+
$this->append(array('assign', $key, $value), $s);
|
2339 |
+
return true;
|
2340 |
+
} else {
|
2341 |
+
$this->seek($s);
|
2342 |
+
}
|
2343 |
+
|
2344 |
+
|
2345 |
+
// look for special css blocks
|
2346 |
+
if ($this->literal('@', false)) {
|
2347 |
+
$this->count--;
|
2348 |
+
|
2349 |
+
// media
|
2350 |
+
if ($this->literal('@media')) {
|
2351 |
+
if (($this->mediaQueryList($mediaQueries) || true)
|
2352 |
+
&& $this->literal('{'))
|
2353 |
+
{
|
2354 |
+
$media = $this->pushSpecialBlock("media");
|
2355 |
+
$media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
|
2356 |
+
return true;
|
2357 |
+
} else {
|
2358 |
+
$this->seek($s);
|
2359 |
+
return false;
|
2360 |
+
}
|
2361 |
+
}
|
2362 |
+
|
2363 |
+
if ($this->literal("@", false) && $this->keyword($dirName)) {
|
2364 |
+
if ($this->isDirective($dirName, $this->blockDirectives)) {
|
2365 |
+
if (($this->openString("{", $dirValue, null, array(";")) || true) &&
|
2366 |
+
$this->literal("{"))
|
2367 |
+
{
|
2368 |
+
$dir = $this->pushSpecialBlock("directive");
|
2369 |
+
$dir->name = $dirName;
|
2370 |
+
if (isset($dirValue)) $dir->value = $dirValue;
|
2371 |
+
return true;
|
2372 |
+
}
|
2373 |
+
} elseif ($this->isDirective($dirName, $this->lineDirectives)) {
|
2374 |
+
if ($this->propertyValue($dirValue) && $this->end()) {
|
2375 |
+
$this->append(array("directive", $dirName, $dirValue));
|
2376 |
+
return true;
|
2377 |
+
}
|
2378 |
+
}
|
2379 |
+
}
|
2380 |
+
|
2381 |
+
$this->seek($s);
|
2382 |
+
}
|
2383 |
+
|
2384 |
+
// setting a variable
|
2385 |
+
if ($this->variable($var) && $this->assign() &&
|
2386 |
+
$this->propertyValue($value) && $this->end())
|
2387 |
+
{
|
2388 |
+
$this->append(array('assign', $var, $value), $s);
|
2389 |
+
return true;
|
2390 |
+
} else {
|
2391 |
+
$this->seek($s);
|
2392 |
+
}
|
2393 |
+
|
2394 |
+
if ($this->import($importValue)) {
|
2395 |
+
$this->append($importValue, $s);
|
2396 |
+
return true;
|
2397 |
+
}
|
2398 |
+
|
2399 |
+
// opening parametric mixin
|
2400 |
+
if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) &&
|
2401 |
+
($this->guards($guards) || true) &&
|
2402 |
+
$this->literal('{'))
|
2403 |
+
{
|
2404 |
+
$block = $this->pushBlock($this->fixTags(array($tag)));
|
2405 |
+
$block->args = $args;
|
2406 |
+
$block->isVararg = $isVararg;
|
2407 |
+
if (!empty($guards)) $block->guards = $guards;
|
2408 |
+
return true;
|
2409 |
+
} else {
|
2410 |
+
$this->seek($s);
|
2411 |
+
}
|
2412 |
+
|
2413 |
+
// opening a simple block
|
2414 |
+
if ($this->tags($tags) && $this->literal('{')) {
|
2415 |
+
$tags = $this->fixTags($tags);
|
2416 |
+
$this->pushBlock($tags);
|
2417 |
+
return true;
|
2418 |
+
} else {
|
2419 |
+
$this->seek($s);
|
2420 |
+
}
|
2421 |
+
|
2422 |
+
// closing a block
|
2423 |
+
if ($this->literal('}', false)) {
|
2424 |
+
try {
|
2425 |
+
$block = $this->pop();
|
2426 |
+
} catch (exception $e) {
|
2427 |
+
$this->seek($s);
|
2428 |
+
$this->throwError($e->getMessage());
|
2429 |
+
}
|
2430 |
+
|
2431 |
+
$hidden = false;
|
2432 |
+
if (is_null($block->type)) {
|
2433 |
+
$hidden = true;
|
2434 |
+
if (!isset($block->args)) {
|
2435 |
+
foreach ($block->tags as $tag) {
|
2436 |
+
if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) {
|
2437 |
+
$hidden = false;
|
2438 |
+
break;
|
2439 |
+
}
|
2440 |
+
}
|
2441 |
+
}
|
2442 |
+
|
2443 |
+
foreach ($block->tags as $tag) {
|
2444 |
+
if (is_string($tag)) {
|
2445 |
+
$this->env->children[$tag][] = $block;
|
2446 |
+
}
|
2447 |
+
}
|
2448 |
+
}
|
2449 |
+
|
2450 |
+
if (!$hidden) {
|
2451 |
+
$this->append(array('block', $block), $s);
|
2452 |
+
}
|
2453 |
+
|
2454 |
+
// this is done here so comments aren't bundled into he block that
|
2455 |
+
// was just closed
|
2456 |
+
$this->whitespace();
|
2457 |
+
return true;
|
2458 |
+
}
|
2459 |
+
|
2460 |
+
// mixin
|
2461 |
+
if ($this->mixinTags($tags) &&
|
2462 |
+
($this->argumentDef($argv, $isVararg) || true) &&
|
2463 |
+
($this->keyword($suffix) || true) && $this->end())
|
2464 |
+
{
|
2465 |
+
$tags = $this->fixTags($tags);
|
2466 |
+
$this->append(array('mixin', $tags, $argv, $suffix), $s);
|
2467 |
+
return true;
|
2468 |
+
} else {
|
2469 |
+
$this->seek($s);
|
2470 |
+
}
|
2471 |
+
|
2472 |
+
// spare ;
|
2473 |
+
if ($this->literal(';')) return true;
|
2474 |
+
|
2475 |
+
return false; // got nothing, throw error
|
2476 |
+
}
|
2477 |
+
|
2478 |
+
protected function isDirective($dirname, $directives) {
|
2479 |
+
// TODO: cache pattern in parser
|
2480 |
+
$pattern = implode("|",
|
2481 |
+
array_map(array("JupiterX_Lessc", "preg_quote"), $directives));
|
2482 |
+
$pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
|
2483 |
+
|
2484 |
+
return preg_match($pattern, $dirname);
|
2485 |
+
}
|
2486 |
+
|
2487 |
+
protected function fixTags($tags) {
|
2488 |
+
// move @ tags out of variable namespace
|
2489 |
+
foreach ($tags as &$tag) {
|
2490 |
+
if ($tag{0} == $this->lessc->vPrefix)
|
2491 |
+
$tag[0] = $this->lessc->mPrefix;
|
2492 |
+
}
|
2493 |
+
return $tags;
|
2494 |
+
}
|
2495 |
+
|
2496 |
+
// a list of expressions
|
2497 |
+
protected function expressionList(&$exps) {
|
2498 |
+
$values = array();
|
2499 |
+
|
2500 |
+
while ($this->expression($exp)) {
|
2501 |
+
$values[] = $exp;
|
2502 |
+
}
|
2503 |
+
|
2504 |
+
if (count($values) == 0) return false;
|
2505 |
+
|
2506 |
+
$exps = JupiterX_Lessc::compressList($values, ' ');
|
2507 |
+
return true;
|
2508 |
+
}
|
2509 |
+
|
2510 |
+
/**
|
2511 |
+
* Attempt to consume an expression.
|
2512 |
+
* @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
|
2513 |
+
*/
|
2514 |
+
protected function expression(&$out) {
|
2515 |
+
if ($this->value($lhs)) {
|
2516 |
+
$out = $this->expHelper($lhs, 0);
|
2517 |
+
|
2518 |
+
// look for / shorthand
|
2519 |
+
if (!empty($this->env->supressedDivision)) {
|
2520 |
+
unset($this->env->supressedDivision);
|
2521 |
+
$s = $this->seek();
|
2522 |
+
if ($this->literal("/") && $this->value($rhs)) {
|
2523 |
+
$out = array("list", "",
|
2524 |
+
array($out, array("keyword", "/"), $rhs));
|
2525 |
+
} else {
|
2526 |
+
$this->seek($s);
|
2527 |
+
}
|
2528 |
+
}
|
2529 |
+
|
2530 |
+
return true;
|
2531 |
+
}
|
2532 |
+
return false;
|
2533 |
+
}
|
2534 |
+
|
2535 |
+
/**
|
2536 |
+
* recursively parse infix equation with $lhs at precedence $minP
|
2537 |
+
*/
|
2538 |
+
protected function expHelper($lhs, $minP) {
|
2539 |
+
$this->inExp = true;
|
2540 |
+
$ss = $this->seek();
|
2541 |
+
|
2542 |
+
while (true) {
|
2543 |
+
$whiteBefore = isset($this->buffer[$this->count - 1]) &&
|
2544 |
+
ctype_space($this->buffer[$this->count - 1]);
|
2545 |
+
|
2546 |
+
// If there is whitespace before the operator, then we require
|
2547 |
+
// whitespace after the operator for it to be an expression
|
2548 |
+
$needWhite = $whiteBefore && !$this->inParens;
|
2549 |
+
|
2550 |
+
if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
|
2551 |
+
if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
|
2552 |
+
foreach (self::$supressDivisionProps as $pattern) {
|
2553 |
+
if (preg_match($pattern, $this->env->currentProperty)) {
|
2554 |
+
$this->env->supressedDivision = true;
|
2555 |
+
break 2;
|
2556 |
+
}
|
2557 |
+
}
|
2558 |
+
}
|
2559 |
+
|
2560 |
+
|
2561 |
+
$whiteAfter = isset($this->buffer[$this->count - 1]) &&
|
2562 |
+
ctype_space($this->buffer[$this->count - 1]);
|
2563 |
+
|
2564 |
+
if (!$this->value($rhs)) break;
|
2565 |
+
|
2566 |
+
// peek for next operator to see what to do with rhs
|
2567 |
+
if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
|
2568 |
+
$rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
|
2569 |
+
}
|
2570 |
+
|
2571 |
+
$lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
|
2572 |
+
$ss = $this->seek();
|
2573 |
+
|
2574 |
+
continue;
|
2575 |
+
}
|
2576 |
+
|
2577 |
+
break;
|
2578 |
+
}
|
2579 |
+
|
2580 |
+
$this->seek($ss);
|
2581 |
+
|
2582 |
+
return $lhs;
|
2583 |
+
}
|
2584 |
+
|
2585 |
+
// consume a list of values for a property
|
2586 |
+
public function propertyValue(&$value, $keyName = null) {
|
2587 |
+
$values = array();
|
2588 |
+
|
2589 |
+
if ($keyName !== null) $this->env->currentProperty = $keyName;
|
2590 |
+
|
2591 |
+
$s = null;
|
2592 |
+
while ($this->expressionList($v)) {
|
2593 |
+
$values[] = $v;
|
2594 |
+
$s = $this->seek();
|
2595 |
+
if (!$this->literal(',')) break;
|
2596 |
+
}
|
2597 |
+
|
2598 |
+
if ($s) $this->seek($s);
|
2599 |
+
|
2600 |
+
if ($keyName !== null) unset($this->env->currentProperty);
|
2601 |
+
|
2602 |
+
if (count($values) == 0) return false;
|
2603 |
+
|
2604 |
+
$value = JupiterX_Lessc::compressList($values, ', ');
|
2605 |
+
return true;
|
2606 |
+
}
|
2607 |
+
|
2608 |
+
protected function parenValue(&$out) {
|
2609 |
+
$s = $this->seek();
|
2610 |
+
|
2611 |
+
// speed shortcut
|
2612 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
|
2613 |
+
return false;
|
2614 |
+
}
|
2615 |
+
|
2616 |
+
$inParens = $this->inParens;
|
2617 |
+
if ($this->literal("(") &&
|
2618 |
+
($this->inParens = true) && $this->expression($exp) &&
|
2619 |
+
$this->literal(")"))
|
2620 |
+
{
|
2621 |
+
$out = $exp;
|
2622 |
+
$this->inParens = $inParens;
|
2623 |
+
return true;
|
2624 |
+
} else {
|
2625 |
+
$this->inParens = $inParens;
|
2626 |
+
$this->seek($s);
|
2627 |
+
}
|
2628 |
+
|
2629 |
+
return false;
|
2630 |
+
}
|
2631 |
+
|
2632 |
+
// a single value
|
2633 |
+
protected function value(&$value) {
|
2634 |
+
$s = $this->seek();
|
2635 |
+
|
2636 |
+
// speed shortcut
|
2637 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
|
2638 |
+
// negation
|
2639 |
+
if ($this->literal("-", false) &&
|
2640 |
+
(($this->variable($inner) && $inner = array("variable", $inner)) ||
|
2641 |
+
$this->unit($inner) ||
|
2642 |
+
$this->parenValue($inner)))
|
2643 |
+
{
|
2644 |
+
$value = array("unary", "-", $inner);
|
2645 |
+
return true;
|
2646 |
+
} else {
|
2647 |
+
$this->seek($s);
|
2648 |
+
}
|
2649 |
+
}
|
2650 |
+
|
2651 |
+
if ($this->parenValue($value)) return true;
|
2652 |
+
if ($this->unit($value)) return true;
|
2653 |
+
if ($this->color($value)) return true;
|
2654 |
+
if ($this->func($value)) return true;
|
2655 |
+
if ($this->string($value)) return true;
|
2656 |
+
|
2657 |
+
if ($this->keyword($word)) {
|
2658 |
+
$value = array('keyword', $word);
|
2659 |
+
return true;
|
2660 |
+
}
|
2661 |
+
|
2662 |
+
// try a variable
|
2663 |
+
if ($this->variable($var)) {
|
2664 |
+
$value = array('variable', $var);
|
2665 |
+
return true;
|
2666 |
+
}
|
2667 |
+
|
2668 |
+
// unquote string (should this work on any type?
|
2669 |
+
if ($this->literal("~") && $this->string($str)) {
|
2670 |
+
$value = array("escape", $str);
|
2671 |
+
return true;
|
2672 |
+
} else {
|
2673 |
+
$this->seek($s);
|
2674 |
+
}
|
2675 |
+
|
2676 |
+
// css hack: \0
|
2677 |
+
if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
|
2678 |
+
$value = array('keyword', '\\'.$m[1]);
|
2679 |
+
return true;
|
2680 |
+
} else {
|
2681 |
+
$this->seek($s);
|
2682 |
+
}
|
2683 |
+
|
2684 |
+
return false;
|
2685 |
+
}
|
2686 |
+
|
2687 |
+
// an import statement
|
2688 |
+
protected function import(&$out) {
|
2689 |
+
$s = $this->seek();
|
2690 |
+
if (!$this->literal('@import')) return false;
|
2691 |
+
|
2692 |
+
// @import "something.css" media;
|
2693 |
+
// @import url("something.css") media;
|
2694 |
+
// @import url(something.css) media;
|
2695 |
+
|
2696 |
+
if ($this->propertyValue($value)) {
|
2697 |
+
$out = array("import", $value);
|
2698 |
+
return true;
|
2699 |
+
}
|
2700 |
+
}
|
2701 |
+
|
2702 |
+
protected function mediaQueryList(&$out) {
|
2703 |
+
if ($this->genericList($list, "mediaQuery", ",", false)) {
|
2704 |
+
$out = $list[2];
|
2705 |
+
return true;
|
2706 |
+
}
|
2707 |
+
return false;
|
2708 |
+
}
|
2709 |
+
|
2710 |
+
protected function mediaQuery(&$out) {
|
2711 |
+
$s = $this->seek();
|
2712 |
+
|
2713 |
+
$expressions = null;
|
2714 |
+
$parts = array();
|
2715 |
+
|
2716 |
+
if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
|
2717 |
+
$prop = array("mediaType");
|
2718 |
+
if (isset($only)) $prop[] = "only";
|
2719 |
+
if (isset($not)) $prop[] = "not";
|
2720 |
+
$prop[] = $mediaType;
|
2721 |
+
$parts[] = $prop;
|
2722 |
+
} else {
|
2723 |
+
$this->seek($s);
|
2724 |
+
}
|
2725 |
+
|
2726 |
+
|
2727 |
+
if (!empty($mediaType) && !$this->literal("and")) {
|
2728 |
+
// ~
|
2729 |
+
} else {
|
2730 |
+
$this->genericList($expressions, "mediaExpression", "and", false);
|
2731 |
+
if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
|
2732 |
+
}
|
2733 |
+
|
2734 |
+
if (count($parts) == 0) {
|
2735 |
+
$this->seek($s);
|
2736 |
+
return false;
|
2737 |
+
}
|
2738 |
+
|
2739 |
+
$out = $parts;
|
2740 |
+
return true;
|
2741 |
+
}
|
2742 |
+
|
2743 |
+
protected function mediaExpression(&$out) {
|
2744 |
+
$s = $this->seek();
|
2745 |
+
$value = null;
|
2746 |
+
if ($this->literal("(") &&
|
2747 |
+
$this->keyword($feature) &&
|
2748 |
+
($this->literal(":") && $this->expression($value) || true) &&
|
2749 |
+
$this->literal(")"))
|
2750 |
+
{
|
2751 |
+
$out = array("mediaExp", $feature);
|
2752 |
+
if ($value) $out[] = $value;
|
2753 |
+
return true;
|
2754 |
+
} elseif ($this->variable($variable)) {
|
2755 |
+
$out = array('variable', $variable);
|
2756 |
+
return true;
|
2757 |
+
}
|
2758 |
+
|
2759 |
+
$this->seek($s);
|
2760 |
+
return false;
|
2761 |
+
}
|
2762 |
+
|
2763 |
+
// an unbounded string stopped by $end
|
2764 |
+
protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) {
|
2765 |
+
$oldWhite = $this->eatWhiteDefault;
|
2766 |
+
$this->eatWhiteDefault = false;
|
2767 |
+
|
2768 |
+
$stop = array("'", '"', "@{", $end);
|
2769 |
+
$stop = array_map(array("JupiterX_Lessc", "preg_quote"), $stop);
|
2770 |
+
// $stop[] = self::$commentMulti;
|
2771 |
+
|
2772 |
+
if (!is_null($rejectStrs)) {
|
2773 |
+
$stop = array_merge($stop, $rejectStrs);
|
2774 |
+
}
|
2775 |
+
|
2776 |
+
$patt = '(.*?)('.implode("|", $stop).')';
|
2777 |
+
|
2778 |
+
$nestingLevel = 0;
|
2779 |
+
|
2780 |
+
$content = array();
|
2781 |
+
while ($this->match($patt, $m, false)) {
|
2782 |
+
if (!empty($m[1])) {
|
2783 |
+
$content[] = $m[1];
|
2784 |
+
if ($nestingOpen) {
|
2785 |
+
$nestingLevel += substr_count($m[1], $nestingOpen);
|
2786 |
+
}
|
2787 |
+
}
|
2788 |
+
|
2789 |
+
$tok = $m[2];
|
2790 |
+
|
2791 |
+
$this->count-= strlen($tok);
|
2792 |
+
if ($tok == $end) {
|
2793 |
+
if ($nestingLevel == 0) {
|
2794 |
+
break;
|
2795 |
+
} else {
|
2796 |
+
$nestingLevel--;
|
2797 |
+
}
|
2798 |
+
}
|
2799 |
+
|
2800 |
+
if (($tok == "'" || $tok == '"') && $this->string($str)) {
|
2801 |
+
$content[] = $str;
|
2802 |
+
continue;
|
2803 |
+
}
|
2804 |
+
|
2805 |
+
if ($tok == "@{" && $this->interpolation($inter)) {
|
2806 |
+
$content[] = $inter;
|
2807 |
+
continue;
|
2808 |
+
}
|
2809 |
+
|
2810 |
+
if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
|
2811 |
+
break;
|
2812 |
+
}
|
2813 |
+
|
2814 |
+
$content[] = $tok;
|
2815 |
+
$this->count+= strlen($tok);
|
2816 |
+
}
|
2817 |
+
|
2818 |
+
$this->eatWhiteDefault = $oldWhite;
|
2819 |
+
|
2820 |
+
if (count($content) == 0) return false;
|
2821 |
+
|
2822 |
+
// trim the end
|
2823 |
+
if (is_string(end($content))) {
|
2824 |
+
$content[count($content) - 1] = rtrim(end($content));
|
2825 |
+
}
|
2826 |
+
|
2827 |
+
$out = array("string", "", $content);
|
2828 |
+
return true;
|
2829 |
+
}
|
2830 |
+
|
2831 |
+
protected function string(&$out) {
|
2832 |
+
$s = $this->seek();
|
2833 |
+
if ($this->literal('"', false)) {
|
2834 |
+
$delim = '"';
|
2835 |
+
} elseif ($this->literal("'", false)) {
|
2836 |
+
$delim = "'";
|
2837 |
+
} else {
|
2838 |
+
return false;
|
2839 |
+
}
|
2840 |
+
|
2841 |
+
$content = array();
|
2842 |
+
|
2843 |
+
// look for either ending delim , escape, or string interpolation
|
2844 |
+
$patt = '([^\n]*?)(@\{|\\\\|' .
|
2845 |
+
JupiterX_Lessc::preg_quote($delim).')';
|
2846 |
+
|
2847 |
+
$oldWhite = $this->eatWhiteDefault;
|
2848 |
+
$this->eatWhiteDefault = false;
|
2849 |
+
|
2850 |
+
while ($this->match($patt, $m, false)) {
|
2851 |
+
$content[] = $m[1];
|
2852 |
+
if ($m[2] == "@{") {
|
2853 |
+
$this->count -= strlen($m[2]);
|
2854 |
+
if ($this->interpolation($inter, false)) {
|
2855 |
+
$content[] = $inter;
|
2856 |
+
} else {
|
2857 |
+
$this->count += strlen($m[2]);
|
2858 |
+
$content[] = "@{"; // ignore it
|
2859 |
+
}
|
2860 |
+
} elseif ($m[2] == '\\') {
|
2861 |
+
$content[] = $m[2];
|
2862 |
+
if ($this->literal($delim, false)) {
|
2863 |
+
$content[] = $delim;
|
2864 |
+
}
|
2865 |
+
} else {
|
2866 |
+
$this->count -= strlen($delim);
|
2867 |
+
break; // delim
|
2868 |
+
}
|
2869 |
+
}
|
2870 |
+
|
2871 |
+
$this->eatWhiteDefault = $oldWhite;
|
2872 |
+
|
2873 |
+
if ($this->literal($delim)) {
|
2874 |
+
$out = array("string", $delim, $content);
|
2875 |
+
return true;
|
2876 |
+
}
|
2877 |
+
|
2878 |
+
$this->seek($s);
|
2879 |
+
return false;
|
2880 |
+
}
|
2881 |
+
|
2882 |
+
protected function interpolation(&$out) {
|
2883 |
+
$oldWhite = $this->eatWhiteDefault;
|
2884 |
+
$this->eatWhiteDefault = true;
|
2885 |
+
|
2886 |
+
$s = $this->seek();
|
2887 |
+
if ($this->literal("@{") &&
|
2888 |
+
$this->openString("}", $interp, null, array("'", '"', ";")) &&
|
2889 |
+
$this->literal("}", false))
|
2890 |
+
{
|
2891 |
+
$out = array("interpolate", $interp);
|
2892 |
+
$this->eatWhiteDefault = $oldWhite;
|
2893 |
+
if ($this->eatWhiteDefault) $this->whitespace();
|
2894 |
+
return true;
|
2895 |
+
}
|
2896 |
+
|
2897 |
+
$this->eatWhiteDefault = $oldWhite;
|
2898 |
+
$this->seek($s);
|
2899 |
+
return false;
|
2900 |
+
}
|
2901 |
+
|
2902 |
+
protected function unit(&$unit) {
|
2903 |
+
// speed shortcut
|
2904 |
+
if (isset($this->buffer[$this->count])) {
|
2905 |
+
$char = $this->buffer[$this->count];
|
2906 |
+
if (!ctype_digit($char) && $char != ".") return false;
|
2907 |
+
}
|
2908 |
+
|
2909 |
+
if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
|
2910 |
+
$unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
|
2911 |
+
return true;
|
2912 |
+
}
|
2913 |
+
return false;
|
2914 |
+
}
|
2915 |
+
|
2916 |
+
// a # color
|
2917 |
+
protected function color(&$out) {
|
2918 |
+
if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
|
2919 |
+
if (strlen($m[1]) > 7) {
|
2920 |
+
$out = array("string", "", array($m[1]));
|
2921 |
+
} else {
|
2922 |
+
$out = array("raw_color", $m[1]);
|
2923 |
+
}
|
2924 |
+
return true;
|
2925 |
+
}
|
2926 |
+
|
2927 |
+
return false;
|
2928 |
+
}
|
2929 |
+
|
2930 |
+
// consume an argument definition list surrounded by ()
|
2931 |
+
// each argument is a variable name with optional value
|
2932 |
+
// or at the end a ... or a variable named followed by ...
|
2933 |
+
// arguments are separated by , unless a ; is in the list, then ; is the
|
2934 |
+
// delimiter.
|
2935 |
+
protected function argumentDef(&$args, &$isVararg) {
|
2936 |
+
$s = $this->seek();
|
2937 |
+
if (!$this->literal('(')) return false;
|
2938 |
+
|
2939 |
+
$values = array();
|
2940 |
+
$delim = ",";
|
2941 |
+
$method = "expressionList";
|
2942 |
+
|
2943 |
+
$isVararg = false;
|
2944 |
+
while (true) {
|
2945 |
+
if ($this->literal("...")) {
|
2946 |
+
$isVararg = true;
|
2947 |
+
break;
|
2948 |
+
}
|
2949 |
+
|
2950 |
+
if ($this->$method($value)) {
|
2951 |
+
if ($value[0] == "variable") {
|
2952 |
+
$arg = array("arg", $value[1]);
|
2953 |
+
$ss = $this->seek();
|
2954 |
+
|
2955 |
+
if ($this->assign() && $this->$method($rhs)) {
|
2956 |
+
$arg[] = $rhs;
|
2957 |
+
} else {
|
2958 |
+
$this->seek($ss);
|
2959 |
+
if ($this->literal("...")) {
|
2960 |
+
$arg[0] = "rest";
|
2961 |
+
$isVararg = true;
|
2962 |
+
}
|
2963 |
+
}
|
2964 |
+
|
2965 |
+
$values[] = $arg;
|
2966 |
+
if ($isVararg) break;
|
2967 |
+
continue;
|
2968 |
+
} else {
|
2969 |
+
$values[] = array("lit", $value);
|
2970 |
+
}
|
2971 |
+
}
|
2972 |
+
|
2973 |
+
|
2974 |
+
if (!$this->literal($delim)) {
|
2975 |
+
if ($delim == "," && $this->literal(";")) {
|
2976 |
+
// found new delim, convert existing args
|
2977 |
+
$delim = ";";
|
2978 |
+
$method = "propertyValue";
|
2979 |
+
|
2980 |
+
// transform arg list
|
2981 |
+
if (isset($values[1])) { // 2 items
|
2982 |
+
$newList = array();
|
2983 |
+
foreach ($values as $i => $arg) {
|
2984 |
+
switch($arg[0]) {
|
2985 |
+
case "arg":
|
2986 |
+
if ($i) {
|
2987 |
+
$this->throwError("Cannot mix ; and , as delimiter types");
|
2988 |
+
}
|
2989 |
+
$newList[] = $arg[2];
|
2990 |
+
break;
|
2991 |
+
case "lit":
|
2992 |
+
$newList[] = $arg[1];
|
2993 |
+
break;
|
2994 |
+
case "rest":
|
2995 |
+
$this->throwError("Unexpected rest before semicolon");
|
2996 |
+
}
|
2997 |
+
}
|
2998 |
+
|
2999 |
+
$newList = array("list", ", ", $newList);
|
3000 |
+
|
3001 |
+
switch ($values[0][0]) {
|
3002 |
+
case "arg":
|
3003 |
+
$newArg = array("arg", $values[0][1], $newList);
|
3004 |
+
break;
|
3005 |
+
case "lit":
|
3006 |
+
$newArg = array("lit", $newList);
|
3007 |
+
break;
|
3008 |
+
}
|
3009 |
+
|
3010 |
+
} elseif ($values) { // 1 item
|
3011 |
+
$newArg = $values[0];
|
3012 |
+
}
|
3013 |
+
|
3014 |
+
if ($newArg) {
|
3015 |
+
$values = array($newArg);
|
3016 |
+
}
|
3017 |
+
} else {
|
3018 |
+
break;
|
3019 |
+
}
|
3020 |
+
}
|
3021 |
+
}
|
3022 |
+
|
3023 |
+
if (!$this->literal(')')) {
|
3024 |
+
$this->seek($s);
|
3025 |
+
return false;
|
3026 |
+
}
|
3027 |
+
|
3028 |
+
$args = $values;
|
3029 |
+
|
3030 |
+
return true;
|
3031 |
+
}
|
3032 |
+
|
3033 |
+
// consume a list of tags
|
3034 |
+
// this accepts a hanging delimiter
|
3035 |
+
protected function tags(&$tags, $simple = false, $delim = ',') {
|
3036 |
+
$tags = array();
|
3037 |
+
while ($this->tag($tt, $simple)) {
|
3038 |
+
$tags[] = $tt;
|
3039 |
+
if (!$this->literal($delim)) break;
|
3040 |
+
}
|
3041 |
+
if (count($tags) == 0) return false;
|
3042 |
+
|
3043 |
+
return true;
|
3044 |
+
}
|
3045 |
+
|
3046 |
+
// list of tags of specifying mixin path
|
3047 |
+
// optionally separated by > (lazy, accepts extra >)
|
3048 |
+
protected function mixinTags(&$tags) {
|
3049 |
+
$s = $this->seek();
|
3050 |
+
$tags = array();
|
3051 |
+
while ($this->tag($tt, true)) {
|
3052 |
+
$tags[] = $tt;
|
3053 |
+
$this->literal(">");
|
3054 |
+
}
|
3055 |
+
|
3056 |
+
if (count($tags) == 0) return false;
|
3057 |
+
|
3058 |
+
return true;
|
3059 |
+
}
|
3060 |
+
|
3061 |
+
// a bracketed value (contained within in a tag definition)
|
3062 |
+
protected function tagBracket(&$parts, &$hasExpression) {
|
3063 |
+
// speed shortcut
|
3064 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
|
3065 |
+
return false;
|
3066 |
+
}
|
3067 |
+
|
3068 |
+
$s = $this->seek();
|
3069 |
+
|
3070 |
+
$hasInterpolation = false;
|
3071 |
+
|
3072 |
+
if ($this->literal("[", false)) {
|
3073 |
+
$attrParts = array("[");
|
3074 |
+
// keyword, string, operator
|
3075 |
+
while (true) {
|
3076 |
+
if ($this->literal("]", false)) {
|
3077 |
+
$this->count--;
|
3078 |
+
break; // get out early
|
3079 |
+
}
|
3080 |
+
|
3081 |
+
if ($this->match('\s+', $m)) {
|
3082 |
+
$attrParts[] = " ";
|
3083 |
+
continue;
|
3084 |
+
}
|
3085 |
+
if ($this->string($str)) {
|
3086 |
+
// escape parent selector, (yuck)
|
3087 |
+
foreach ($str[2] as &$chunk) {
|
3088 |
+
$chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
|
3089 |
+
}
|
3090 |
+
|
3091 |
+
$attrParts[] = $str;
|
3092 |
+
$hasInterpolation = true;
|
3093 |
+
continue;
|
3094 |
+
}
|
3095 |
+
|
3096 |
+
if ($this->keyword($word)) {
|
3097 |
+
$attrParts[] = $word;
|
3098 |
+
continue;
|
3099 |
+
}
|
3100 |
+
|
3101 |
+
if ($this->interpolation($inter, false)) {
|
3102 |
+
$attrParts[] = $inter;
|
3103 |
+
$hasInterpolation = true;
|
3104 |
+
continue;
|
3105 |
+
}
|
3106 |
+
|
3107 |
+
// operator, handles attr namespace too
|
3108 |
+
if ($this->match('[|-~\$\*\^=]+', $m)) {
|
3109 |
+
$attrParts[] = $m[0];
|
3110 |
+
continue;
|
3111 |
+
}
|
3112 |
+
|
3113 |
+
break;
|
3114 |
+
}
|
3115 |
+
|
3116 |
+
if ($this->literal("]", false)) {
|
3117 |
+
$attrParts[] = "]";
|
3118 |
+
foreach ($attrParts as $part) {
|
3119 |
+
$parts[] = $part;
|
3120 |
+
}
|
3121 |
+
$hasExpression = $hasExpression || $hasInterpolation;
|
3122 |
+
return true;
|
3123 |
+
}
|
3124 |
+
$this->seek($s);
|
3125 |
+
}
|
3126 |
+
|
3127 |
+
$this->seek($s);
|
3128 |
+
return false;
|
3129 |
+
}
|
3130 |
+
|
3131 |
+
// a space separated list of selectors
|
3132 |
+
protected function tag(&$tag, $simple = false) {
|
3133 |
+
if ($simple)
|
3134 |
+
$chars = '^@,:;{}\][>\(\) "\'';
|
3135 |
+
else
|
3136 |
+
$chars = '^@,;{}["\'';
|
3137 |
+
|
3138 |
+
$s = $this->seek();
|
3139 |
+
|
3140 |
+
$hasExpression = false;
|
3141 |
+
$parts = array();
|
3142 |
+
while ($this->tagBracket($parts, $hasExpression));
|
3143 |
+
|
3144 |
+
$oldWhite = $this->eatWhiteDefault;
|
3145 |
+
$this->eatWhiteDefault = false;
|
3146 |
+
|
3147 |
+
while (true) {
|
3148 |
+
if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
|
3149 |
+
$parts[] = $m[1];
|
3150 |
+
if ($simple) break;
|
3151 |
+
|
3152 |
+
while ($this->tagBracket($parts, $hasExpression));
|
3153 |
+
continue;
|
3154 |
+
}
|
3155 |
+
|
3156 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
|
3157 |
+
if ($this->interpolation($interp)) {
|
3158 |
+
$hasExpression = true;
|
3159 |
+
$interp[2] = true; // don't unescape
|
3160 |
+
$parts[] = $interp;
|
3161 |
+
continue;
|
3162 |
+
}
|
3163 |
+
|
3164 |
+
if ($this->literal("@")) {
|
3165 |
+
$parts[] = "@";
|
3166 |
+
continue;
|
3167 |
+
}
|
3168 |
+
}
|
3169 |
+
|
3170 |
+
if ($this->unit($unit)) { // for keyframes
|
3171 |
+
$parts[] = $unit[1];
|
3172 |
+
$parts[] = $unit[2];
|
3173 |
+
continue;
|
3174 |
+
}
|
3175 |
+
|
3176 |
+
break;
|
3177 |
+
}
|
3178 |
+
|
3179 |
+
$this->eatWhiteDefault = $oldWhite;
|
3180 |
+
if (!$parts) {
|
3181 |
+
$this->seek($s);
|
3182 |
+
return false;
|
3183 |
+
}
|
3184 |
+
|
3185 |
+
if ($hasExpression) {
|
3186 |
+
$tag = array("exp", array("string", "", $parts));
|
3187 |
+
} else {
|
3188 |
+
$tag = trim(implode($parts));
|
3189 |
+
}
|
3190 |
+
|
3191 |
+
$this->whitespace();
|
3192 |
+
return true;
|
3193 |
+
}
|
3194 |
+
|
3195 |
+
// a css function
|
3196 |
+
protected function func(&$func) {
|
3197 |
+
$s = $this->seek();
|
3198 |
+
|
3199 |
+
if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
|
3200 |
+
$fname = $m[1];
|
3201 |
+
|
3202 |
+
$sPreArgs = $this->seek();
|
3203 |
+
|
3204 |
+
$args = array();
|
3205 |
+
while (true) {
|
3206 |
+
$ss = $this->seek();
|
3207 |
+
// this ugly nonsense is for ie filter properties
|
3208 |
+
if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
|
3209 |
+
$args[] = array("string", "", array($name, "=", $value));
|
3210 |
+
} else {
|
3211 |
+
$this->seek($ss);
|
3212 |
+
if ($this->expressionList($value)) {
|
3213 |
+
$args[] = $value;
|
3214 |
+
}
|
3215 |
+
}
|
3216 |
+
|
3217 |
+
if (!$this->literal(',')) break;
|
3218 |
+
}
|
3219 |
+
$args = array('list', ',', $args);
|
3220 |
+
|
3221 |
+
if ($this->literal(')')) {
|
3222 |
+
$func = array('function', $fname, $args);
|
3223 |
+
return true;
|
3224 |
+
} elseif ($fname == 'url') {
|
3225 |
+
// couldn't parse and in url? treat as string
|
3226 |
+
$this->seek($sPreArgs);
|
3227 |
+
if ($this->openString(")", $string) && $this->literal(")")) {
|
3228 |
+
$func = array('function', $fname, $string);
|
3229 |
+
return true;
|
3230 |
+
}
|
3231 |
+
}
|
3232 |
+
}
|
3233 |
+
|
3234 |
+
$this->seek($s);
|
3235 |
+
return false;
|
3236 |
+
}
|
3237 |
+
|
3238 |
+
// consume a less variable
|
3239 |
+
protected function variable(&$name) {
|
3240 |
+
$s = $this->seek();
|
3241 |
+
if ($this->literal($this->lessc->vPrefix, false) &&
|
3242 |
+
($this->variable($sub) || $this->keyword($name)))
|
3243 |
+
{
|
3244 |
+
if (!empty($sub)) {
|
3245 |
+
$name = array('variable', $sub);
|
3246 |
+
} else {
|
3247 |
+
$name = $this->lessc->vPrefix.$name;
|
3248 |
+
}
|
3249 |
+
return true;
|
3250 |
+
}
|
3251 |
+
|
3252 |
+
$name = null;
|
3253 |
+
$this->seek($s);
|
3254 |
+
return false;
|
3255 |
+
}
|
3256 |
+
|
3257 |
+
/**
|
3258 |
+
* Consume an assignment operator
|
3259 |
+
* Can optionally take a name that will be set to the current property name
|
3260 |
+
*/
|
3261 |
+
protected function assign($name = null) {
|
3262 |
+
if ($name) $this->currentProperty = $name;
|
3263 |
+
return $this->literal(':') || $this->literal('=');
|
3264 |
+
}
|
3265 |
+
|
3266 |
+
// consume a keyword
|
3267 |
+
protected function keyword(&$word) {
|
3268 |
+
if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
|
3269 |
+
$word = $m[1];
|
3270 |
+
return true;
|
3271 |
+
}
|
3272 |
+
return false;
|
3273 |
+
}
|
3274 |
+
|
3275 |
+
// consume an end of statement delimiter
|
3276 |
+
protected function end() {
|
3277 |
+
if ($this->literal(';')) {
|
3278 |
+
return true;
|
3279 |
+
} elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
|
3280 |
+
// if there is end of file or a closing block next then we don't need a ;
|
3281 |
+
return true;
|
3282 |
+
}
|
3283 |
+
return false;
|
3284 |
+
}
|
3285 |
+
|
3286 |
+
protected function guards(&$guards) {
|
3287 |
+
$s = $this->seek();
|
3288 |
+
|
3289 |
+
if (!$this->literal("when")) {
|
3290 |
+
$this->seek($s);
|
3291 |
+
return false;
|
3292 |
+
}
|
3293 |
+
|
3294 |
+
$guards = array();
|
3295 |
+
|
3296 |
+
while ($this->guardGroup($g)) {
|
3297 |
+
$guards[] = $g;
|
3298 |
+
if (!$this->literal(",")) break;
|
3299 |
+
}
|
3300 |
+
|
3301 |
+
if (count($guards) == 0) {
|
3302 |
+
$guards = null;
|
3303 |
+
$this->seek($s);
|
3304 |
+
return false;
|
3305 |
+
}
|
3306 |
+
|
3307 |
+
return true;
|
3308 |
+
}
|
3309 |
+
|
3310 |
+
// a bunch of guards that are and'd together
|
3311 |
+
// TODO rename to guardGroup
|
3312 |
+
protected function guardGroup(&$guardGroup) {
|
3313 |
+
$s = $this->seek();
|
3314 |
+
$guardGroup = array();
|
3315 |
+
while ($this->guard($guard)) {
|
3316 |
+
$guardGroup[] = $guard;
|
3317 |
+
if (!$this->literal("and")) break;
|
3318 |
+
}
|
3319 |
+
|
3320 |
+
if (count($guardGroup) == 0) {
|
3321 |
+
$guardGroup = null;
|
3322 |
+
$this->seek($s);
|
3323 |
+
return false;
|
3324 |
+
}
|
3325 |
+
|
3326 |
+
return true;
|
3327 |
+
}
|
3328 |
+
|
3329 |
+
protected function guard(&$guard) {
|
3330 |
+
$s = $this->seek();
|
3331 |
+
$negate = $this->literal("not");
|
3332 |
+
|
3333 |
+
if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
|
3334 |
+
$guard = $exp;
|
3335 |
+
if ($negate) $guard = array("negate", $guard);
|
3336 |
+
return true;
|
3337 |
+
}
|
3338 |
+
|
3339 |
+
$this->seek($s);
|
3340 |
+
return false;
|
3341 |
+
}
|
3342 |
+
|
3343 |
+
/* raw parsing functions */
|
3344 |
+
|
3345 |
+
protected function literal($what, $eatWhitespace = null) {
|
3346 |
+
if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
|
3347 |
+
|
3348 |
+
// shortcut on single letter
|
3349 |
+
if (!isset($what[1]) && isset($this->buffer[$this->count])) {
|
3350 |
+
if ($this->buffer[$this->count] == $what) {
|
3351 |
+
if (!$eatWhitespace) {
|
3352 |
+
$this->count++;
|
3353 |
+
return true;
|
3354 |
+
}
|
3355 |
+
// goes below...
|
3356 |
+
} else {
|
3357 |
+
return false;
|
3358 |
+
}
|
3359 |
+
}
|
3360 |
+
|
3361 |
+
if (!isset(self::$literalCache[$what])) {
|
3362 |
+
self::$literalCache[$what] = JupiterX_Lessc::preg_quote($what);
|
3363 |
+
}
|
3364 |
+
|
3365 |
+
return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
|
3366 |
+
}
|
3367 |
+
|
3368 |
+
protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
|
3369 |
+
$s = $this->seek();
|
3370 |
+
$items = array();
|
3371 |
+
while ($this->$parseItem($value)) {
|
3372 |
+
$items[] = $value;
|
3373 |
+
if ($delim) {
|
3374 |
+
if (!$this->literal($delim)) break;
|
3375 |
+
}
|
3376 |
+
}
|
3377 |
+
|
3378 |
+
if (count($items) == 0) {
|
3379 |
+
$this->seek($s);
|
3380 |
+
return false;
|
3381 |
+
}
|
3382 |
+
|
3383 |
+
if ($flatten && count($items) == 1) {
|
3384 |
+
$out = $items[0];
|
3385 |
+
} else {
|
3386 |
+
$out = array("list", $delim, $items);
|
3387 |
+
}
|
3388 |
+
|
3389 |
+
return true;
|
3390 |
+
}
|
3391 |
+
|
3392 |
+
|
3393 |
+
// advance counter to next occurrence of $what
|
3394 |
+
// $until - don't include $what in advance
|
3395 |
+
// $allowNewline, if string, will be used as valid char set
|
3396 |
+
protected function to($what, &$out, $until = false, $allowNewline = false) {
|
3397 |
+
if (is_string($allowNewline)) {
|
3398 |
+
$validChars = $allowNewline;
|
3399 |
+
} else {
|
3400 |
+
$validChars = $allowNewline ? "." : "[^\n]";
|
3401 |
+
}
|
3402 |
+
if (!$this->match('('.$validChars.'*?)'.JupiterX_Lessc::preg_quote($what), $m, !$until)) return false;
|
3403 |
+
if ($until) $this->count -= strlen($what); // give back $what
|
3404 |
+
$out = $m[1];
|
3405 |
+
return true;
|
3406 |
+
}
|
3407 |
+
|
3408 |
+
// try to match something on head of buffer
|
3409 |
+
protected function match($regex, &$out, $eatWhitespace = null) {
|
3410 |
+
if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
|
3411 |
+
|
3412 |
+
$r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
|
3413 |
+
if (preg_match($r, $this->buffer, $out, null, $this->count)) {
|
3414 |
+
$this->count += strlen($out[0]);
|
3415 |
+
if ($eatWhitespace && $this->writeComments) $this->whitespace();
|
3416 |
+
return true;
|
3417 |
+
}
|
3418 |
+
return false;
|
3419 |
+
}
|
3420 |
+
|
3421 |
+
// match some whitespace
|
3422 |
+
protected function whitespace() {
|
3423 |
+
if ($this->writeComments) {
|
3424 |
+
$gotWhite = false;
|
3425 |
+
while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
|
3426 |
+
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
|
3427 |
+
$this->append(array("comment", $m[1]));
|
3428 |
+
$this->commentsSeen[$this->count] = true;
|
3429 |
+
}
|
3430 |
+
$this->count += strlen($m[0]);
|
3431 |
+
$gotWhite = true;
|
3432 |
+
}
|
3433 |
+
return $gotWhite;
|
3434 |
+
} else {
|
3435 |
+
$this->match("", $m);
|
3436 |
+
return strlen($m[0]) > 0;
|
3437 |
+
}
|
3438 |
+
}
|
3439 |
+
|
3440 |
+
// match something without consuming it
|
3441 |
+
protected function peek($regex, &$out = null, $from=null) {
|
3442 |
+
if (is_null($from)) $from = $this->count;
|
3443 |
+
$r = '/'.$regex.'/Ais';
|
3444 |
+
$result = preg_match($r, $this->buffer, $out, null, $from);
|
3445 |
+
|
3446 |
+
return $result;
|
3447 |
+
}
|
3448 |
+
|
3449 |
+
// seek to a spot in the buffer or return where we are on no argument
|
3450 |
+
protected function seek($where = null) {
|
3451 |
+
if ($where === null) return $this->count;
|
3452 |
+
else $this->count = $where;
|
3453 |
+
return true;
|
3454 |
+
}
|
3455 |
+
|
3456 |
+
/* misc functions */
|
3457 |
+
|
3458 |
+
public function throwError($msg = "parse error", $count = null) {
|
3459 |
+
$count = is_null($count) ? $this->count : $count;
|
3460 |
+
|
3461 |
+
$line = $this->line +
|
3462 |
+
substr_count(substr($this->buffer, 0, $count), "\n");
|
3463 |
+
|
3464 |
+
if (!empty($this->sourceName)) {
|
3465 |
+
$loc = "$this->sourceName on line $line";
|
3466 |
+
} else {
|
3467 |
+
$loc = "line: $line";
|
3468 |
+
}
|
3469 |
+
|
3470 |
+
// TODO this depends on $this->count
|
3471 |
+
if ($this->peek("(.*?)(\n|$)", $m, $count)) {
|
3472 |
+
throw new exception("$msg: failed at `$m[1]` $loc");
|
3473 |
+
} else {
|
3474 |
+
throw new exception("$msg: $loc");
|
3475 |
+
}
|
3476 |
+
}
|
3477 |
+
|
3478 |
+
protected function pushBlock($selectors=null, $type=null) {
|
3479 |
+
$b = new stdclass;
|
3480 |
+
$b->parent = $this->env;
|
3481 |
+
|
3482 |
+
$b->type = $type;
|
3483 |
+
$b->id = self::$nextBlockId++;
|
3484 |
+
|
3485 |
+
$b->isVararg = false; // TODO: kill me from here
|
3486 |
+
$b->tags = $selectors;
|
3487 |
+
|
3488 |
+
$b->props = array();
|
3489 |
+
$b->children = array();
|
3490 |
+
|
3491 |
+
$this->env = $b;
|
3492 |
+
return $b;
|
3493 |
+
}
|
3494 |
+
|
3495 |
+
// push a block that doesn't multiply tags
|
3496 |
+
protected function pushSpecialBlock($type) {
|
3497 |
+
return $this->pushBlock(null, $type);
|
3498 |
+
}
|
3499 |
+
|
3500 |
+
// append a property to the current block
|
3501 |
+
protected function append($prop, $pos = null) {
|
3502 |
+
if ($pos !== null) $prop[-1] = $pos;
|
3503 |
+
$this->env->props[] = $prop;
|
3504 |
+
}
|
3505 |
+
|
3506 |
+
// pop something off the stack
|
3507 |
+
protected function pop() {
|
3508 |
+
$old = $this->env;
|
3509 |
+
$this->env = $this->env->parent;
|
3510 |
+
return $old;
|
3511 |
+
}
|
3512 |
+
|
3513 |
+
// remove comments from $text
|
3514 |
+
// todo: make it work for all functions, not just url
|
3515 |
+
protected function removeComments($text) {
|
3516 |
+
$look = array(
|
3517 |
+
'url(', '//', '/*', '"', "'"
|
3518 |
+
);
|
3519 |
+
|
3520 |
+
$out = '';
|
3521 |
+
$min = null;
|
3522 |
+
while (true) {
|
3523 |
+
// find the next item
|
3524 |
+
foreach ($look as $token) {
|
3525 |
+
$pos = strpos($text, $token);
|
3526 |
+
if ($pos !== false) {
|
3527 |
+
if (!isset($min) || $pos < $min[1]) $min = array($token, $pos);
|
3528 |
+
}
|
3529 |
+
}
|
3530 |
+
|
3531 |
+
if (is_null($min)) break;
|
3532 |
+
|
3533 |
+
$count = $min[1];
|
3534 |
+
$skip = 0;
|
3535 |
+
$newlines = 0;
|
3536 |
+
switch ($min[0]) {
|
3537 |
+
case 'url(':
|
3538 |
+
if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
|
3539 |
+
$count += strlen($m[0]) - strlen($min[0]);
|
3540 |
+
break;
|
3541 |
+
case '"':
|
3542 |
+
case "'":
|
3543 |
+
if (preg_match('/'.$min[0].'.*?(?<!\\\\)'.$min[0].'/', $text, $m, 0, $count))
|
3544 |
+
$count += strlen($m[0]) - 1;
|
3545 |
+
break;
|
3546 |
+
case '//':
|
3547 |
+
$skip = strpos($text, "\n", $count);
|
3548 |
+
if ($skip === false) $skip = strlen($text) - $count;
|
3549 |
+
else $skip -= $count;
|
3550 |
+
break;
|
3551 |
+
case '/*':
|
3552 |
+
if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
|
3553 |
+
$skip = strlen($m[0]);
|
3554 |
+
$newlines = substr_count($m[0], "\n");
|
3555 |
+
}
|
3556 |
+
break;
|
3557 |
+
}
|
3558 |
+
|
3559 |
+
if ($skip == 0) $count += strlen($min[0]);
|
3560 |
+
|
3561 |
+
$out .= substr($text, 0, $count).str_repeat("\n", $newlines);
|
3562 |
+
$text = substr($text, $count + $skip);
|
3563 |
+
|
3564 |
+
$min = null;
|
3565 |
+
}
|
3566 |
+
|
3567 |
+
return $out.$text;
|
3568 |
+
}
|
3569 |
+
|
3570 |
+
}
|
3571 |
+
|
3572 |
+
/**
|
3573 |
+
* @ignore
|
3574 |
+
*/
|
3575 |
+
class lessc_formatter_classic {
|
3576 |
+
public $indentChar = " ";
|
3577 |
+
|
3578 |
+
public $break = "\n";
|
3579 |
+
public $open = " {";
|
3580 |
+
public $close = "}";
|
3581 |
+
public $selectorSeparator = ", ";
|
3582 |
+
public $assignSeparator = ":";
|
3583 |
+
|
3584 |
+
public $openSingle = " { ";
|
3585 |
+
public $closeSingle = " }";
|
3586 |
+
|
3587 |
+
public $disableSingle = false;
|
3588 |
+
public $breakSelectors = false;
|
3589 |
+
|
3590 |
+
public $compressColors = false;
|
3591 |
+
|
3592 |
+
public function __construct() {
|
3593 |
+
$this->indentLevel = 0;
|
3594 |
+
}
|
3595 |
+
|
3596 |
+
public function indentStr($n = 0) {
|
3597 |
+
return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
|
3598 |
+
}
|
3599 |
+
|
3600 |
+
public function property($name, $value) {
|
3601 |
+
return $name . $this->assignSeparator . $value . ";";
|
3602 |
+
}
|
3603 |
+
|
3604 |
+
protected function isEmpty($block) {
|
3605 |
+
if (empty($block->lines)) {
|
3606 |
+
foreach ($block->children as $child) {
|
3607 |
+
if (!$this->isEmpty($child)) return false;
|
3608 |
+
}
|
3609 |
+
|
3610 |
+
return true;
|
3611 |
+
}
|
3612 |
+
return false;
|
3613 |
+
}
|
3614 |
+
|
3615 |
+
public function block($block) {
|
3616 |
+
if ($this->isEmpty($block)) return;
|
3617 |
+
|
3618 |
+
$inner = $pre = $this->indentStr();
|
3619 |
+
|
3620 |
+
$isSingle = !$this->disableSingle &&
|
3621 |
+
is_null($block->type) && count($block->lines) == 1;
|
3622 |
+
|
3623 |
+
if (!empty($block->selectors)) {
|
3624 |
+
$this->indentLevel++;
|
3625 |
+
|
3626 |
+
if ($this->breakSelectors) {
|
3627 |
+
$selectorSeparator = $this->selectorSeparator . $this->break . $pre;
|
3628 |
+
} else {
|
3629 |
+
$selectorSeparator = $this->selectorSeparator;
|
3630 |
+
}
|
3631 |
+
|
3632 |
+
echo $pre .
|
3633 |
+
implode($selectorSeparator, $block->selectors);
|
3634 |
+
if ($isSingle) {
|
3635 |
+
echo $this->openSingle;
|
3636 |
+
$inner = "";
|
3637 |
+
} else {
|
3638 |
+
echo $this->open . $this->break;
|
3639 |
+
$inner = $this->indentStr();
|
3640 |
+
}
|
3641 |
+
|
3642 |
+
}
|
3643 |
+
|
3644 |
+
if (!empty($block->lines)) {
|
3645 |
+
$glue = $this->break.$inner;
|
3646 |
+
echo $inner . implode($glue, $block->lines);
|
3647 |
+
if (!$isSingle && !empty($block->children)) {
|
3648 |
+
echo $this->break;
|
3649 |
+
}
|
3650 |
+
}
|
3651 |
+
|
3652 |
+
foreach ($block->children as $child) {
|
3653 |
+
$this->block($child);
|
3654 |
+
}
|
3655 |
+
|
3656 |
+
if (!empty($block->selectors)) {
|
3657 |
+
if (!$isSingle && empty($block->children)) echo $this->break;
|
3658 |
+
|
3659 |
+
if ($isSingle) {
|
3660 |
+
echo $this->closeSingle . $this->break;
|
3661 |
+
} else {
|
3662 |
+
echo $pre . $this->close . $this->break;
|
3663 |
+
}
|
3664 |
+
|
3665 |
+
$this->indentLevel--;
|
3666 |
+
}
|
3667 |
+
}
|
3668 |
+
}
|
3669 |
+
|
3670 |
+
/**
|
3671 |
+
* @ignore
|
3672 |
+
*/
|
3673 |
+
class lessc_formatter_compressed extends lessc_formatter_classic {
|
3674 |
+
public $disableSingle = true;
|
3675 |
+
public $open = "{";
|
3676 |
+
public $selectorSeparator = ",";
|
3677 |
+
public $assignSeparator = ":";
|
3678 |
+
public $break = "";
|
3679 |
+
public $compressColors = true;
|
3680 |
+
|
3681 |
+
public function indentStr($n = 0) {
|
3682 |
+
return "";
|
3683 |
+
}
|
3684 |
+
}
|
3685 |
+
|
3686 |
+
/**
|
3687 |
+
* @ignore
|
3688 |
+
*/
|
3689 |
+
class lessc_formatter_lessjs extends lessc_formatter_classic {
|
3690 |
+
public $disableSingle = true;
|
3691 |
+
public $breakSelectors = true;
|
3692 |
+
public $assignSeparator = ": ";
|
3693 |
+
public $selectorSeparator = ",";
|
3694 |
+
}
|
includes/control-panel/functions.php
CHANGED
@@ -1,158 +1,159 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* The Jupiter Control Panel component.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel
|
6 |
-
*/
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Run on control panel init.
|
10 |
-
*
|
11 |
-
* @since 1.2.0
|
12 |
-
*/
|
13 |
-
add_action( 'jupiterx_control_panel_init', function() {
|
14 |
-
jupiterx_core()->load_files( [
|
15 |
-
'control-panel/includes/class-customizer-option',
|
16 |
-
'control-panel/includes/class-filesystem',
|
17 |
-
'control-panel/includes/class-validator',
|
18 |
-
'control-panel/includes/class-helpers',
|
19 |
-
'control-panel/includes/logic-messages',
|
20 |
-
'control-panel/includes/class-image-sizes',
|
21 |
-
'control-panel/includes/class-settings',
|
22 |
-
'control-panel/includes/class-db-manager',
|
23 |
-
'control-panel/includes/class-install-template',
|
24 |
-
'control-panel/includes/class-install-plugins',
|
25 |
-
'control-panel/includes/class-export-import-content',
|
26 |
-
'control-panel/includes/class-system-status',
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
*
|
33 |
-
*
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
<
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
*
|
46 |
-
*
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
'
|
53 |
-
'
|
54 |
-
'
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
'
|
60 |
-
'
|
61 |
-
'
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
'
|
67 |
-
'
|
68 |
-
'
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
'
|
74 |
-
'
|
75 |
-
'
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
*
|
84 |
-
*
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
<
|
94 |
-
|
95 |
-
<
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
<
|
112 |
-
<
|
113 |
-
|
114 |
-
<
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
<?php
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
<div class="
|
126 |
-
|
127 |
-
|
128 |
-
<?php
|
129 |
-
<?php
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
<?php
|
137 |
-
<?php
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
<?php
|
145 |
-
<?php
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
<?php
|
153 |
-
<?php
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The Jupiter Control Panel component.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Run on control panel init.
|
10 |
+
*
|
11 |
+
* @since 1.2.0
|
12 |
+
*/
|
13 |
+
add_action( 'jupiterx_control_panel_init', function() {
|
14 |
+
jupiterx_core()->load_files( [
|
15 |
+
'control-panel/includes/class-customizer-option',
|
16 |
+
'control-panel/includes/class-filesystem',
|
17 |
+
'control-panel/includes/class-validator',
|
18 |
+
'control-panel/includes/class-helpers',
|
19 |
+
'control-panel/includes/logic-messages',
|
20 |
+
'control-panel/includes/class-image-sizes',
|
21 |
+
'control-panel/includes/class-settings',
|
22 |
+
'control-panel/includes/class-db-manager',
|
23 |
+
'control-panel/includes/class-install-template',
|
24 |
+
'control-panel/includes/class-install-plugins',
|
25 |
+
'control-panel/includes/class-export-import-content',
|
26 |
+
'control-panel/includes/class-system-status',
|
27 |
+
'control-panel/includes/class-db-php-manager',
|
28 |
+
] );
|
29 |
+
} );
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Get started quick guide.
|
33 |
+
*
|
34 |
+
* @since 1.2.0
|
35 |
+
*/
|
36 |
+
add_action( 'jupiterx_control_panel_get_started', function() {
|
37 |
+
?>
|
38 |
+
<h6><?php esc_html_e( 'Get started:', 'jupiterx-core' ); ?></h6>
|
39 |
+
<iframe class="mb-4" width="400" height="225" src="https://www.youtube.com/embed/fnlzOHECEDo?modestbranding=1" frameborder="0" allowfullscreen></iframe>
|
40 |
+
<?php
|
41 |
+
} );
|
42 |
+
|
43 |
+
add_filter( 'jupiterx_control_panel_sections', 'jupiterx_add_control_panel_sections' );
|
44 |
+
/**
|
45 |
+
* Add sections to control panel.
|
46 |
+
*
|
47 |
+
* @since 1.9.0
|
48 |
+
*/
|
49 |
+
function jupiterx_add_control_panel_sections( $sections ) {
|
50 |
+
|
51 |
+
$sections['image_size'] = [
|
52 |
+
'title' => __( 'Image Sizes' , 'jupiterx-core' ),
|
53 |
+
'href' => 'image-sizes',
|
54 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_IMAGE_SIZES' ) && JUPITERX_CONTROL_PANEL_IMAGE_SIZES,
|
55 |
+
'order' => 40,
|
56 |
+
];
|
57 |
+
|
58 |
+
$sections['system_status'] = [
|
59 |
+
'title' => __( 'System Status' , 'jupiterx-core' ),
|
60 |
+
'href' => 'system-status',
|
61 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_SYSTEM_STATUS' ) && JUPITERX_CONTROL_PANEL_SYSTEM_STATUS,
|
62 |
+
'order' => 50,
|
63 |
+
];
|
64 |
+
|
65 |
+
$sections['settings'] = [
|
66 |
+
'title' => __( 'Settings' , 'jupiterx-core' ),
|
67 |
+
'href' => 'settings',
|
68 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_SETTINGS' ) && JUPITERX_CONTROL_PANEL_SETTINGS,
|
69 |
+
'order' => 70,
|
70 |
+
];
|
71 |
+
|
72 |
+
$sections['export_import'] = [
|
73 |
+
'title' => __( 'Export/Import' , 'jupiterx-core' ),
|
74 |
+
'href' => 'export-import',
|
75 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_EXPORT_IMPORT' ) && JUPITERX_CONTROL_PANEL_EXPORT_IMPORT,
|
76 |
+
'order' => 75,
|
77 |
+
];
|
78 |
+
|
79 |
+
return $sections;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Core additional settings.
|
84 |
+
*
|
85 |
+
* @since 1.2.0
|
86 |
+
*/
|
87 |
+
add_action( 'jupiterx_control_panel_after_theme_settings', function() {
|
88 |
+
?>
|
89 |
+
<div class="form-group col-md-6">
|
90 |
+
<label for="jupiterx-cp-settings-svg-support">
|
91 |
+
<?php esc_html_e( 'SVG Support', 'jupiterx-core' ); ?>
|
92 |
+
</label>
|
93 |
+
<input type="hidden" name="jupiterx_svg_support" value="0">
|
94 |
+
<div class="jupiterx-switch">
|
95 |
+
<input type="checkbox" id="jupiterx-cp-settings-svg-support" name="jupiterx_svg_support" value="1" <?php echo esc_attr( ( empty( jupiterx_get_option( 'svg_support' ) ) ) ? '' : 'checked' ); ?>>
|
96 |
+
<label for="jupiterx-cp-settings-svg-support"></label>
|
97 |
+
</div>
|
98 |
+
<small class="form-text text-muted">
|
99 |
+
<?php esc_html_e( 'Enable this option to upload SVG to WordPress Media Library.', 'jupiterx-core' ); ?>
|
100 |
+
</small>
|
101 |
+
</div>
|
102 |
+
<div class="col-md-12">
|
103 |
+
<hr />
|
104 |
+
</div>
|
105 |
+
<div class="form-group col-md-6">
|
106 |
+
<label for="jupiterx-cp-settings-google-analytics-id"><?php esc_html_e( 'Google Analytics ID', 'jupiterx-core' ); ?></label>
|
107 |
+
<?php jupiterx_the_help_link( 'http://help.artbees.net/how-to-s/theme-options/adding-google-analytics-code-into-jupiter-x', esc_html__( 'Adding Google Analytics code into Jupiter X', 'jupiterx-core' ) ); ?>
|
108 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-google-analytics-id" value="<?php echo esc_attr( jupiterx_get_option( 'google_analytics_id' ) ); ?>" name="jupiterx_google_analytics_id" placeholder="UA-45******-*">
|
109 |
+
</div>
|
110 |
+
<div class="form-group col-md-6">
|
111 |
+
<label for="jupiterx-cp-settings-google-analytics-anonymization"><?php esc_html_e( 'IP Anonymization', 'jupiterx-core' ); ?></label>
|
112 |
+
<input type="hidden" name="jupiterx_google_analytics_anonymization" value="0">
|
113 |
+
<div class="jupiterx-switch">
|
114 |
+
<input type="checkbox" id="jupiterx-cp-settings-google-analytics-anonymization" name="jupiterx_google_analytics_anonymization" value="1" <?php echo esc_attr( jupiterx_get_option( 'google_analytics_anonymization', true ) ? 'checked' : '' ); ?>>
|
115 |
+
<label for="jupiterx-cp-settings-google-analytics-anonymization"></label>
|
116 |
+
</div>
|
117 |
+
<small class="form-text text-muted"><?php esc_html_e( 'Enable IP Anonymization for Google Analytics.', 'jupiterx-core' ); ?></small>
|
118 |
+
</div>
|
119 |
+
<div class="form-group col-md-12">
|
120 |
+
<label for="jupiterx-cp-settings-adobe-project-id"><?php esc_html_e( 'Adobe Fonts Project ID', 'jupiterx-core' ); ?></label>
|
121 |
+
<?php jupiterx_the_help_link( 'http://help.artbees.net/how-to-s/typography/using-adobe-fonts-formerly-typekit-in-jupiter-x', esc_html__( 'Using Adobe fonts (formerly Typekit) in Jupiter X', 'jupiterx-core' ) ); ?>
|
122 |
+
<?php jupiterx_pro_badge(); ?>
|
123 |
+
<input <?php echo esc_attr( ( ! jupiterx_is_pro() ) ? 'disabled' : '' ); ?> type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-adobe-project-id" value="<?php echo esc_attr( jupiterx_get_option( 'adobe_fonts_project_id' ) ); ?>" name="jupiterx_adobe_fonts_project_id" placeholder="ezv****">
|
124 |
+
</div>
|
125 |
+
<div class="col-md-12"><hr></div>
|
126 |
+
<div class="form-group col-md-6">
|
127 |
+
<label for="jupiterx-cp-settings-tracking-codes-after-head">
|
128 |
+
<?php /* translators: %s: html */ ?>
|
129 |
+
<?php printf( esc_html__( 'Tracking Codes After %s Tag', 'jupiterx-core' ), '<code><head></code>' ); ?>
|
130 |
+
<?php jupiterx_pro_badge(); ?>
|
131 |
+
</label>
|
132 |
+
<textarea <?php echo esc_attr( ( ! jupiterx_is_pro() ) ? 'disabled' : '' ); ?> class="jupiterx-form-control" rows="7" id="jupiterx-cp-settings-tracking-codes-after-head" name="jupiterx_tracking_codes_after_head" rows="3"><?php echo esc_html( stripslashes( jupiterx_get_option( 'tracking_codes_after_head' ) ) ); ?></textarea>
|
133 |
+
</div>
|
134 |
+
<div class="form-group col-md-6">
|
135 |
+
<label for="jupiterx-cp-settings-tracking-codes-before-head">
|
136 |
+
<?php /* translators: %s: html */ ?>
|
137 |
+
<?php printf( esc_html__( 'Tracking Codes Before %s Tag', 'jupiterx-core' ), '<code></head></code>' ); ?>
|
138 |
+
<?php jupiterx_pro_badge(); ?>
|
139 |
+
</label>
|
140 |
+
<textarea <?php echo esc_attr( ( ! jupiterx_is_pro() ) ? 'disabled' : '' ); ?> class="jupiterx-form-control" rows="7" id="jupiterx-cp-settings-tracking-codes-before-head" name="jupiterx_tracking_codes_before_head" rows="3"><?php echo esc_html( stripslashes( jupiterx_get_option( 'tracking_codes_before_head' ) ) ); ?></textarea>
|
141 |
+
</div>
|
142 |
+
<div class="form-group col-md-6">
|
143 |
+
<label for="jupiterx-cp-settings-tracking-codes-after-body">
|
144 |
+
<?php /* translators: %s: html */ ?>
|
145 |
+
<?php printf( esc_html__( 'Tracking Codes After %s Tag', 'jupiterx-core' ), '<code><body></code>' ); ?>
|
146 |
+
<?php jupiterx_pro_badge(); ?>
|
147 |
+
</label>
|
148 |
+
<textarea <?php echo esc_attr( ( ! jupiterx_is_pro() ) ? 'disabled' : '' ); ?> class="jupiterx-form-control" rows="7" id="jupiterx-cp-settings-tracking-codes-after-body" name="jupiterx_tracking_codes_after_body" rows="3"><?php echo esc_html( stripslashes( jupiterx_get_option( 'tracking_codes_after_body' ) ) ); ?></textarea>
|
149 |
+
</div>
|
150 |
+
<div class="form-group col-md-6">
|
151 |
+
<label for="jupiterx-cp-settings-tracking-codes-before-body">
|
152 |
+
<?php /* translators: %s: html */ ?>
|
153 |
+
<?php printf( esc_html__( 'Tracking Codes Before %s Tag', 'jupiterx-core' ), '<code></body></code>' ); ?>
|
154 |
+
<?php jupiterx_pro_badge(); ?>
|
155 |
+
</label>
|
156 |
+
<textarea <?php echo esc_attr( ( ! jupiterx_is_pro() ) ? 'disabled' : '' ); ?> class="jupiterx-form-control" rows="7" id="jupiterx-cp-settings-tracking-codes-before-body" name="jupiterx_tracking_codes_before_body" rows="3"><?php echo esc_html( stripslashes( jupiterx_get_option( 'tracking_codes_before_body' ) ) ); ?></textarea>
|
157 |
+
</div>
|
158 |
+
<?php
|
159 |
+
} );
|
includes/control-panel/includes/class-browser.php
CHANGED
@@ -1,1193 +1,1193 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Browser detection class
|
4 |
-
*
|
5 |
-
* @author Original Author: Chris Schuld (http://chrisschuld.com/)
|
6 |
-
* @author Modifications for EDD: Chris Christoff
|
7 |
-
* @version 1.9
|
8 |
-
* Usage:
|
9 |
-
* $browser = new Browser();
|
10 |
-
* if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
|
11 |
-
* echo 'You have Firefox version 2 or greater';
|
12 |
-
* }
|
13 |
-
* User agents sampled from: http://www.useragentstring.com/
|
14 |
-
* Based on original work from Gary White (http://apptools.com/phptools/browser/
|
15 |
-
* CHANGELOG:
|
16 |
-
* 2012-12-26 (v1.9c by Chris Christoff):
|
17 |
-
* + Changed vars to publics
|
18 |
-
* 2012-12-23 (v1.9b by Chris Christoff):
|
19 |
-
* + Removed the browser string return and added spacing.
|
20 |
-
* + Also removed return HTML formatting.
|
21 |
-
* 2012-12-23 (v1.9a by Chris Christoff):
|
22 |
-
* + Split user string and add formatting so we can print a nicely
|
23 |
-
* formatted user agent string
|
24 |
-
* 2010-08-20 (v1.9):
|
25 |
-
* + Added MSN Explorer Browser (legacy)
|
26 |
-
* + Added Bing/MSN Robot (Thanks Rob MacDonald)
|
27 |
-
* + Added the Android Platform (PLATFORM_ANDROID)
|
28 |
-
* + Fixed issue with Android 1.6/2.2 (Thanks Tom Hirashima)
|
29 |
-
* 2010-04-27 (v1.8):
|
30 |
-
* + Added iPad Support
|
31 |
-
* 2010-03-07 (v1.7):
|
32 |
-
* + *MAJOR* Rebuild (preg_match and other "slow" routine removal(s))
|
33 |
-
* + Almost allof Gary's original code has been replaced
|
34 |
-
* + Large PHPUNIT testing environment created to validate new releases and additions
|
35 |
-
* + Added FreeBSD Platform
|
36 |
-
* + Added OpenBSD Platform
|
37 |
-
* + Added NetBSD Platform
|
38 |
-
* + Added SunOS Platform
|
39 |
-
* + Added OpenSolaris Platform
|
40 |
-
* + Added support of the Iceweazel Browser
|
41 |
-
* + Added isChromeFrame() call to check if chromeframe is in use
|
42 |
-
* + Moved the Opera check in front of the Firefox check due to legacy Opera User Agents
|
43 |
-
* + Added the __toString() method (Thanks Deano)
|
44 |
-
* 2009-11-15:
|
45 |
-
* + Updated the checkes for Firefox
|
46 |
-
* + Added the NOKIA platform
|
47 |
-
* + Added Checks for the NOKIA brower(s)
|
48 |
-
* 2009-11-08:
|
49 |
-
* + PHP 5.3 Support
|
50 |
-
* + Added support for BlackBerry OS and BlackBerry browser
|
51 |
-
* + Added support for the Opera Mini browser
|
52 |
-
* + Added additional documenation
|
53 |
-
* + Added support for isRobot() and isMobile()
|
54 |
-
* + Added support for Opera version 10
|
55 |
-
* + Added support for deprecated Netscape Navigator version 9
|
56 |
-
* + Added support for IceCat
|
57 |
-
* + Added support for Shiretoko
|
58 |
-
* 2010-04-27 (v1.8):
|
59 |
-
* + Added iPad Support
|
60 |
-
* 2009-08-18:
|
61 |
-
* + Updated to support PHP 5.3 - removed all deprecated function calls
|
62 |
-
* + Updated to remove all double quotes (") -- converted to single quotes (')
|
63 |
-
* 2009-04-27:
|
64 |
-
* + Updated the IE check to remove a typo and bug (thanks John)
|
65 |
-
* 2009-04-22:
|
66 |
-
* + Added detection for GoogleBot
|
67 |
-
* + Added detection for the W3C Validator.
|
68 |
-
* + Added detection for Yahoo! Slurp
|
69 |
-
* 2009-03-14:
|
70 |
-
* + Added detection for iPods.
|
71 |
-
* + Added Platform detection for iPhones
|
72 |
-
* + Added Platform detection for iPods
|
73 |
-
* 2009-02-16: (Rick Hale)
|
74 |
-
* + Added version detection for Android phones.
|
75 |
-
* 2008-12-09:
|
76 |
-
* + Removed unused constant
|
77 |
-
* 2008-11-07:
|
78 |
-
* + Added Google's Chrome to the detection list
|
79 |
-
* + Added isBrowser(string) to the list of functions special thanks to
|
80 |
-
* Daniel 'mavrick' Lang for the function concept (http://mavrick.id.au)
|
81 |
-
* Gary White noted: "Since browser detection is so unreliable, I am
|
82 |
-
* no longer maintaining this script. You are free to use and or
|
83 |
-
* modify/update it as you want, however the author assumes no
|
84 |
-
* responsibility for the accuracy of the detected values."
|
85 |
-
* Anyone experienced with Gary's script might be interested in these notes:
|
86 |
-
* Added class constants
|
87 |
-
* Added detection and version detection for Google's Chrome
|
88 |
-
* Updated the version detection for Amaya
|
89 |
-
* Updated the version detection for Firefox
|
90 |
-
* Updated the version detection for Lynx
|
91 |
-
* Updated the version detection for WebTV
|
92 |
-
* Updated the version detection for NetPositive
|
93 |
-
* Updated the version detection for IE
|
94 |
-
* Updated the version detection for OmniWeb
|
95 |
-
* Updated the version detection for iCab
|
96 |
-
* Updated the version detection for Safari
|
97 |
-
* Updated Safari to remove mobile devices (iPhone)
|
98 |
-
* Added detection for iPhone
|
99 |
-
* Added detection for robots
|
100 |
-
* Added detection for mobile devices
|
101 |
-
* Added detection for BlackBerry
|
102 |
-
* Removed Netscape checks (matches heavily with firefox & mozilla)
|
103 |
-
*/
|
104 |
-
|
105 |
-
|
106 |
-
// Exit if accessed directly
|
107 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
108 |
-
exit;
|
109 |
-
}
|
110 |
-
|
111 |
-
if ( ! class_exists( 'Browser' ) ) {
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Browser detection class
|
115 |
-
*
|
116 |
-
* @author Chris Schuld
|
117 |
-
* @since 1.0
|
118 |
-
*/
|
119 |
-
class Browser {
|
120 |
-
public $_agent = '';
|
121 |
-
public $_browser_name = '';
|
122 |
-
public $_version = '';
|
123 |
-
public $_platform = '';
|
124 |
-
public $_os = '';
|
125 |
-
public $_is_aol = false;
|
126 |
-
public $_is_mobile = false;
|
127 |
-
public $_is_robot = false;
|
128 |
-
public $_aol_version = '';
|
129 |
-
|
130 |
-
public $BROWSER_UNKNOWN = 'unknown';
|
131 |
-
public $VERSION_UNKNOWN = 'unknown';
|
132 |
-
|
133 |
-
public $BROWSER_OPERA = 'Opera'; // Http://www.opera.com/
|
134 |
-
public $BROWSER_OPERA_MINI = 'Opera Mini'; // Http://www.opera.com/mini/
|
135 |
-
public $BROWSER_WEBTV = 'WebTV'; // Http://www.webtv.net/pc/
|
136 |
-
public $BROWSER_IE = 'Internet Explorer'; // Http://www.microsoft.com/ie/
|
137 |
-
public $BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // Http://en.wikipedia.org/wiki/Internet_Explorer_Mobile
|
138 |
-
public $BROWSER_KONQUEROR = 'Konqueror'; // Http://www.konqueror.org/
|
139 |
-
public $BROWSER_ICAB = 'iCab'; // Http://www.icab.de/
|
140 |
-
public $BROWSER_OMNIWEB = 'OmniWeb'; // Http://www.omnigroup.com/applications/omniweb/
|
141 |
-
public $BROWSER_FIREBIRD = 'Firebird'; // Http://www.ibphoenix.com/
|
142 |
-
public $BROWSER_FIREFOX = 'Firefox'; // Http://www.mozilla.com/en-US/firefox/firefox.html
|
143 |
-
public $BROWSER_ICEWEASEL = 'Iceweasel'; // Http://www.geticeweasel.org/
|
144 |
-
public $BROWSER_SHIRETOKO = 'Shiretoko'; // Http://wiki.mozilla.org/Projects/shiretoko
|
145 |
-
public $BROWSER_MOZILLA = 'Mozilla'; // Http://www.mozilla.com/en-US/
|
146 |
-
public $BROWSER_AMAYA = 'Amaya'; // Http://www.w3.org/Amaya/
|
147 |
-
public $BROWSER_LYNX = 'Lynx'; // Http://en.wikipedia.org/wiki/Lynx
|
148 |
-
public $BROWSER_SAFARI = 'Safari'; // Http://apple.com
|
149 |
-
public $BROWSER_IPHONE = 'iPhone'; // Http://apple.com
|
150 |
-
public $BROWSER_IPOD = 'iPod'; // Http://apple.com
|
151 |
-
public $BROWSER_IPAD = 'iPad'; // Http://apple.com
|
152 |
-
public $BROWSER_CHROME = 'Chrome'; // Http://www.google.com/chrome
|
153 |
-
public $BROWSER_ANDROID = 'Android'; // Http://www.android.com/
|
154 |
-
public $BROWSER_GOOGLEBOT = 'GoogleBot'; // Http://en.wikipedia.org/wiki/Googlebot
|
155 |
-
public $BROWSER_SLURP = 'Yahoo! Slurp'; // Http://en.wikipedia.org/wiki/Yahoo!_Slurp
|
156 |
-
public $BROWSER_W3CVALIDATOR = 'W3C Validator'; // Http://validator.w3.org/
|
157 |
-
public $BROWSER_BLACKBERRY = 'BlackBerry'; // Http://www.blackberry.com/
|
158 |
-
public $BROWSER_ICECAT = 'IceCat'; // Http://en.wikipedia.org/wiki/GNU_IceCat
|
159 |
-
public $BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // Http://en.wikipedia.org/wiki/Web_Browser_for_S60
|
160 |
-
public $BROWSER_NOKIA = 'Nokia Browser'; // * all other WAP-based browsers on the Nokia Platform
|
161 |
-
public $BROWSER_MSN = 'MSN Browser'; // Http://explorer.msn.com/
|
162 |
-
public $BROWSER_MSNBOT = 'MSN Bot'; // Http://search.msn.com/msnbot.htm
|
163 |
-
// Http://en.wikipedia.org/wiki/Msnbot (used for Bing as well)
|
164 |
-
public $BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // Http://browser.netscape.com/ (DEPRECATED)
|
165 |
-
public $BROWSER_GALEON = 'Galeon'; // Http://galeon.sourceforge.net/ (DEPRECATED)
|
166 |
-
public $BROWSER_NETPOSITIVE = 'NetPositive'; // Http://en.wikipedia.org/wiki/NetPositive (DEPRECATED)
|
167 |
-
public $BROWSER_PHOENIX = 'Phoenix'; // Http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED)
|
168 |
-
|
169 |
-
public $PLATFORM_UNKNOWN = 'unknown';
|
170 |
-
public $PLATFORM_WINDOWS = 'Windows';
|
171 |
-
public $PLATFORM_WINDOWS_CE = 'Windows CE';
|
172 |
-
public $PLATFORM_APPLE = 'Apple';
|
173 |
-
public $PLATFORM_LINUX = 'Linux';
|
174 |
-
public $PLATFORM_OS2 = 'OS/2';
|
175 |
-
public $PLATFORM_BEOS = 'BeOS';
|
176 |
-
public $PLATFORM_IPHONE = 'iPhone';
|
177 |
-
public $PLATFORM_IPOD = 'iPod';
|
178 |
-
public $PLATFORM_IPAD = 'iPad';
|
179 |
-
public $PLATFORM_BLACKBERRY = 'BlackBerry';
|
180 |
-
public $PLATFORM_NOKIA = 'Nokia';
|
181 |
-
public $PLATFORM_FREEBSD = 'FreeBSD';
|
182 |
-
public $PLATFORM_OPENBSD = 'OpenBSD';
|
183 |
-
public $PLATFORM_NETBSD = 'NetBSD';
|
184 |
-
public $PLATFORM_SUNOS = 'SunOS';
|
185 |
-
public $PLATFORM_OPENSOLARIS = 'OpenSolaris';
|
186 |
-
public $PLATFORM_ANDROID = 'Android';
|
187 |
-
|
188 |
-
public $OPERATING_SYSTEM_UNKNOWN = 'unknown';
|
189 |
-
|
190 |
-
function __construct( $useragent = '' ) {
|
191 |
-
$this->reset();
|
192 |
-
|
193 |
-
if ( $useragent != '' ) {
|
194 |
-
$this->setUserAgent( $useragent );
|
195 |
-
} else {
|
196 |
-
$this->determine();
|
197 |
-
}
|
198 |
-
}
|
199 |
-
|
200 |
-
/**
|
201 |
-
* Reset all properties
|
202 |
-
*/
|
203 |
-
function reset() {
|
204 |
-
$this->_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
205 |
-
$this->_browser_name = $this->BROWSER_UNKNOWN;
|
206 |
-
$this->_version = $this->VERSION_UNKNOWN;
|
207 |
-
$this->_platform = $this->PLATFORM_UNKNOWN;
|
208 |
-
$this->_os = $this->OPERATING_SYSTEM_UNKNOWN;
|
209 |
-
$this->_is_aol = false;
|
210 |
-
$this->_is_mobile = false;
|
211 |
-
$this->_is_robot = false;
|
212 |
-
$this->_aol_version = $this->VERSION_UNKNOWN;
|
213 |
-
}
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Check to see if the specific browser is valid
|
217 |
-
*
|
218 |
-
* @param string $browserName
|
219 |
-
*
|
220 |
-
* @return True if the browser is the specified browser
|
221 |
-
*/
|
222 |
-
function isBrowser( $browserName ) {
|
223 |
-
return ( 0 == strcasecmp( $this->_browser_name, trim( $browserName ) ) );
|
224 |
-
}
|
225 |
-
|
226 |
-
/**
|
227 |
-
* The name of the browser. All return types are from the class contants
|
228 |
-
*
|
229 |
-
* @return string Name of the browser
|
230 |
-
*/
|
231 |
-
function getBrowser() {
|
232 |
-
return $this->_browser_name;
|
233 |
-
}
|
234 |
-
|
235 |
-
/**
|
236 |
-
* Set the name of the browser
|
237 |
-
*
|
238 |
-
* @param $browser The name of the Browser
|
239 |
-
*/
|
240 |
-
function setBrowser( $browser ) {
|
241 |
-
return $this->_browser_name = $browser;
|
242 |
-
}
|
243 |
-
|
244 |
-
/**
|
245 |
-
* The name of the platform. All return types are from the class contants
|
246 |
-
*
|
247 |
-
* @return string Name of the browser
|
248 |
-
*/
|
249 |
-
function getPlatform() {
|
250 |
-
return $this->_platform;
|
251 |
-
}
|
252 |
-
|
253 |
-
/**
|
254 |
-
* Set the name of the platform
|
255 |
-
*
|
256 |
-
* @param $platform The name of the Platform
|
257 |
-
*/
|
258 |
-
function setPlatform( $platform ) {
|
259 |
-
return $this->_platform = $platform;
|
260 |
-
}
|
261 |
-
|
262 |
-
/**
|
263 |
-
* The version of the browser.
|
264 |
-
*
|
265 |
-
* @return string Version of the browser (will only contain alpha-numeric characters and a period)
|
266 |
-
*/
|
267 |
-
function getVersion() {
|
268 |
-
return $this->_version;
|
269 |
-
}
|
270 |
-
|
271 |
-
/**
|
272 |
-
* Set the version of the browser
|
273 |
-
*
|
274 |
-
* @param $version The version of the Browser
|
275 |
-
*/
|
276 |
-
function setVersion( $version ) {
|
277 |
-
$this->_version = preg_replace( '/[^0-9,.,a-z,A-Z-]/', '', $version );
|
278 |
-
}
|
279 |
-
|
280 |
-
/**
|
281 |
-
* The version of AOL.
|
282 |
-
*
|
283 |
-
* @return string Version of AOL (will only contain alpha-numeric characters and a period)
|
284 |
-
*/
|
285 |
-
function getAolVersion() {
|
286 |
-
return $this->_aol_version;
|
287 |
-
}
|
288 |
-
|
289 |
-
/**
|
290 |
-
* Set the version of AOL
|
291 |
-
*
|
292 |
-
* @param $version The version of AOL
|
293 |
-
*/
|
294 |
-
function setAolVersion( $version ) {
|
295 |
-
$this->_aol_version = preg_replace( '/[^0-9,.,a-z,A-Z]/', '', $version );
|
296 |
-
}
|
297 |
-
|
298 |
-
/**
|
299 |
-
* Is the browser from AOL?
|
300 |
-
*
|
301 |
-
* @return boolean True if the browser is from AOL otherwise false
|
302 |
-
*/
|
303 |
-
function isAol() {
|
304 |
-
return $this->_is_aol;
|
305 |
-
}
|
306 |
-
|
307 |
-
/**
|
308 |
-
* Is the browser from a mobile device?
|
309 |
-
*
|
310 |
-
* @return boolean True if the browser is from a mobile device otherwise false
|
311 |
-
*/
|
312 |
-
function isMobile() {
|
313 |
-
return $this->_is_mobile;
|
314 |
-
}
|
315 |
-
|
316 |
-
/**
|
317 |
-
* Is the browser from a robot (ex Slurp,GoogleBot)?
|
318 |
-
*
|
319 |
-
* @return boolean True if the browser is from a robot otherwise false
|
320 |
-
*/
|
321 |
-
function isRobot() {
|
322 |
-
return $this->_is_robot;
|
323 |
-
}
|
324 |
-
|
325 |
-
/**
|
326 |
-
* Set the browser to be from AOL
|
327 |
-
*
|
328 |
-
* @param $isAol
|
329 |
-
*/
|
330 |
-
function setAol( $isAol ) {
|
331 |
-
$this->_is_aol = $isAol;
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Set the Browser to be mobile
|
336 |
-
*
|
337 |
-
* @param boolean $value is the browser a mobile brower or not
|
338 |
-
*/
|
339 |
-
function setMobile( $value = true ) {
|
340 |
-
$this->_is_mobile = $value;
|
341 |
-
}
|
342 |
-
|
343 |
-
/**
|
344 |
-
* Set the Browser to be a robot
|
345 |
-
*
|
346 |
-
* @param boolean $value is the browser a robot or not
|
347 |
-
*/
|
348 |
-
function setRobot( $value = true ) {
|
349 |
-
$this->_is_robot = $value;
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Get the user agent value in use to determine the browser
|
354 |
-
*
|
355 |
-
* @return string The user agent from the HTTP header
|
356 |
-
*/
|
357 |
-
function getUserAgent() {
|
358 |
-
return $this->_agent;
|
359 |
-
}
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
|
363 |
-
*
|
364 |
-
* @param $agent_string The value for the User Agent
|
365 |
-
*/
|
366 |
-
function setUserAgent( $agent_string ) {
|
367 |
-
$this->reset();
|
368 |
-
$this->_agent = $agent_string;
|
369 |
-
$this->determine();
|
370 |
-
}
|
371 |
-
|
372 |
-
/**
|
373 |
-
* Used to determine if the browser is actually "chromeframe"
|
374 |
-
*
|
375 |
-
* @since 1.7
|
376 |
-
* @return boolean True if the browser is using chromeframe
|
377 |
-
*/
|
378 |
-
function isChromeFrame() {
|
379 |
-
return ( strpos( $this->_agent, 'chromeframe' ) !== false );
|
380 |
-
}
|
381 |
-
|
382 |
-
/**
|
383 |
-
* Returns a formatted string with a summary of the details of the browser.
|
384 |
-
*
|
385 |
-
* @return string formatted string with a summary of the browser
|
386 |
-
*/
|
387 |
-
function __toString() {
|
388 |
-
$text1 = $this->getUserAgent(); // Grabs the UA string
|
389 |
-
$UAline1 = substr( $text1, 0, 32 ); // The first line we print should only be the first 32 characters of the UA string
|
390 |
-
$text2 = $this->getUserAgent(); // Now we grab it again and save it to a string
|
391 |
-
$towrapUA = str_replace( $UAline1, '', $text2 ); // The rest of the printoff (other than first line) is equivalent
|
392 |
-
// to the whole string minus the part we printed off. IE
|
393 |
-
// User Agent: thefirst32charactersfromUAline1
|
394 |
-
// the rest of it is now stored in
|
395 |
-
// $text2 to be printed off
|
396 |
-
// But we need to add spaces before each line that is split other than line 1
|
397 |
-
$space = '';
|
398 |
-
for ( $i = 0; $i < 25; $i ++ ) {
|
399 |
-
$space .= ' ';
|
400 |
-
}
|
401 |
-
|
402 |
-
// Now we split the remaining string of UA ($text2) into lines that are prefixed by spaces for formatting
|
403 |
-
$wordwrapped = chunk_split( $towrapUA, 32, "\n $space" );
|
404 |
-
|
405 |
-
return "Platform: {$this->getPlatform()} \n" .
|
406 |
-
"Browser Name: {$this->getBrowser()} \n" .
|
407 |
-
"Browser Version: {$this->getVersion()} \n" .
|
408 |
-
"User Agent String: $UAline1 \n\t\t\t " .
|
409 |
-
"$wordwrapped";
|
410 |
-
}
|
411 |
-
|
412 |
-
/**
|
413 |
-
* Protected routine to calculate and determine what the browser is in use (including platform)
|
414 |
-
*/
|
415 |
-
function determine() {
|
416 |
-
$this->checkPlatform();
|
417 |
-
$this->checkBrowsers();
|
418 |
-
$this->checkForAol();
|
419 |
-
}
|
420 |
-
|
421 |
-
/**
|
422 |
-
* Protected routine to determine the browser type
|
423 |
-
*
|
424 |
-
* @return boolean True if the browser was detected otherwise false
|
425 |
-
*/
|
426 |
-
function checkBrowsers() {
|
427 |
-
return (
|
428 |
-
// Well-known, well-used
|
429 |
-
// Special Notes:
|
430 |
-
// (1) Opera must be checked before FireFox due to the odd
|
431 |
-
// user agents used in some older versions of Opera
|
432 |
-
// (2) WebTV is strapped onto Internet Explorer so we must
|
433 |
-
// check for WebTV before IE
|
434 |
-
// (3) (deprecated) Galeon is based on Firefox and needs to be
|
435 |
-
// tested before Firefox is tested
|
436 |
-
// (4) OmniWeb is based on Safari so OmniWeb check must occur
|
437 |
-
// before Safari
|
438 |
-
// (5) Netscape 9+ is based on Firefox so Netscape checks
|
439 |
-
// before FireFox are necessary
|
440 |
-
$this->checkBrowserWebTv() ||
|
441 |
-
$this->checkBrowserInternetExplorer() ||
|
442 |
-
$this->checkBrowserOpera() ||
|
443 |
-
$this->checkBrowserGaleon() ||
|
444 |
-
$this->checkBrowserNetscapeNavigator9Plus() ||
|
445 |
-
$this->checkBrowserFirefox() ||
|
446 |
-
$this->checkBrowserChrome() ||
|
447 |
-
$this->checkBrowserOmniWeb() ||
|
448 |
-
|
449 |
-
// Common mobile
|
450 |
-
$this->checkBrowserAndroid() ||
|
451 |
-
$this->checkBrowseriPad() ||
|
452 |
-
$this->checkBrowseriPod() ||
|
453 |
-
$this->checkBrowseriPhone() ||
|
454 |
-
$this->checkBrowserBlackBerry() ||
|
455 |
-
$this->checkBrowserNokia() ||
|
456 |
-
|
457 |
-
// Common bots
|
458 |
-
$this->checkBrowserGoogleBot() ||
|
459 |
-
$this->checkBrowserMSNBot() ||
|
460 |
-
$this->checkBrowserSlurp() ||
|
461 |
-
|
462 |
-
// WebKit base check (post mobile and others)
|
463 |
-
$this->checkBrowserSafari() ||
|
464 |
-
|
465 |
-
// Everyone else
|
466 |
-
$this->checkBrowserNetPositive() ||
|
467 |
-
$this->checkBrowserFirebird() ||
|
468 |
-
$this->checkBrowserKonqueror() ||
|
469 |
-
$this->checkBrowserIcab() ||
|
470 |
-
$this->checkBrowserPhoenix() ||
|
471 |
-
$this->checkBrowserAmaya() ||
|
472 |
-
$this->checkBrowserLynx() ||
|
473 |
-
|
474 |
-
$this->checkBrowserShiretoko() ||
|
475 |
-
$this->checkBrowserIceCat() ||
|
476 |
-
$this->checkBrowserW3CValidator() ||
|
477 |
-
$this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
|
478 |
-
);
|
479 |
-
}
|
480 |
-
|
481 |
-
/**
|
482 |
-
* Determine if the user is using a BlackBerry (last updated 1.7)
|
483 |
-
*
|
484 |
-
* @return boolean True if the browser is the BlackBerry browser otherwise false
|
485 |
-
*/
|
486 |
-
function checkBrowserBlackBerry() {
|
487 |
-
if ( stripos( $this->_agent, 'blackberry' ) !== false ) {
|
488 |
-
$aresult = explode( '/', stristr( $this->_agent, 'BlackBerry' ) );
|
489 |
-
$aversion = explode( ' ', $aresult[1] );
|
490 |
-
$this->setVersion( $aversion[0] );
|
491 |
-
$this->_browser_name = $this->BROWSER_BLACKBERRY;
|
492 |
-
$this->setMobile( true );
|
493 |
-
|
494 |
-
return true;
|
495 |
-
}
|
496 |
-
|
497 |
-
return false;
|
498 |
-
}
|
499 |
-
|
500 |
-
/**
|
501 |
-
* Determine if the user is using an AOL User Agent (last updated 1.7)
|
502 |
-
*
|
503 |
-
* @return boolean True if the browser is from AOL otherwise false
|
504 |
-
*/
|
505 |
-
function checkForAol() {
|
506 |
-
$this->setAol( false );
|
507 |
-
$this->setAolVersion( $this->VERSION_UNKNOWN );
|
508 |
-
|
509 |
-
if ( stripos( $this->_agent, 'aol' ) !== false ) {
|
510 |
-
$aversion = explode( ' ', stristr( $this->_agent, 'AOL' ) );
|
511 |
-
$this->setAol( true );
|
512 |
-
$this->setAolVersion( preg_replace( '/[^0-9\.a-z]/i', '', $aversion[1] ) );
|
513 |
-
|
514 |
-
return true;
|
515 |
-
}
|
516 |
-
|
517 |
-
return false;
|
518 |
-
}
|
519 |
-
|
520 |
-
/**
|
521 |
-
* Determine if the browser is the GoogleBot or not (last updated 1.7)
|
522 |
-
*
|
523 |
-
* @return boolean True if the browser is the GoogletBot otherwise false
|
524 |
-
*/
|
525 |
-
function checkBrowserGoogleBot() {
|
526 |
-
if ( stripos( $this->_agent, 'googlebot' ) !== false ) {
|
527 |
-
$aresult = explode( '/', stristr( $this->_agent, 'googlebot' ) );
|
528 |
-
$aversion = explode( ' ', $aresult[1] );
|
529 |
-
$this->setVersion( str_replace( ';', '', $aversion[0] ) );
|
530 |
-
$this->_browser_name = $this->BROWSER_GOOGLEBOT;
|
531 |
-
$this->setRobot( true );
|
532 |
-
|
533 |
-
return true;
|
534 |
-
}
|
535 |
-
|
536 |
-
return false;
|
537 |
-
}
|
538 |
-
|
539 |
-
/**
|
540 |
-
* Determine if the browser is the MSNBot or not (last updated 1.9)
|
541 |
-
*
|
542 |
-
* @return boolean True if the browser is the MSNBot otherwise false
|
543 |
-
*/
|
544 |
-
function checkBrowserMSNBot() {
|
545 |
-
if ( stripos( $this->_agent, 'msnbot' ) !== false ) {
|
546 |
-
$aresult = explode( '/', stristr( $this->_agent, 'msnbot' ) );
|
547 |
-
$aversion = explode( ' ', $aresult[1] );
|
548 |
-
$this->setVersion( str_replace( ';', '', $aversion[0] ) );
|
549 |
-
$this->_browser_name = $this->BROWSER_MSNBOT;
|
550 |
-
$this->setRobot( true );
|
551 |
-
|
552 |
-
return true;
|
553 |
-
}
|
554 |
-
|
555 |
-
return false;
|
556 |
-
}
|
557 |
-
|
558 |
-
/**
|
559 |
-
* Determine if the browser is the W3C Validator or not (last updated 1.7)
|
560 |
-
*
|
561 |
-
* @return boolean True if the browser is the W3C Validator otherwise false
|
562 |
-
*/
|
563 |
-
function checkBrowserW3CValidator() {
|
564 |
-
if ( stripos( $this->_agent, 'W3C-checklink' ) !== false ) {
|
565 |
-
$aresult = explode( '/', stristr( $this->_agent, 'W3C-checklink' ) );
|
566 |
-
$aversion = explode( ' ', $aresult[1] );
|
567 |
-
$this->setVersion( $aversion[0] );
|
568 |
-
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
569 |
-
|
570 |
-
return true;
|
571 |
-
} elseif ( stripos( $this->_agent, 'W3C_Validator' ) !== false ) {
|
572 |
-
// Some of the Validator versions do not delineate w/ a slash - add it back in
|
573 |
-
$ua = str_replace( 'W3C_Validator ', 'W3C_Validator/', $this->_agent );
|
574 |
-
$aresult = explode( '/', stristr( $ua, 'W3C_Validator' ) );
|
575 |
-
$aversion = explode( ' ', $aresult[1] );
|
576 |
-
$this->setVersion( $aversion[0] );
|
577 |
-
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
578 |
-
|
579 |
-
return true;
|
580 |
-
}
|
581 |
-
|
582 |
-
return false;
|
583 |
-
}
|
584 |
-
|
585 |
-
/**
|
586 |
-
* Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
|
587 |
-
*
|
588 |
-
* @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
|
589 |
-
*/
|
590 |
-
function checkBrowserSlurp() {
|
591 |
-
if ( stripos( $this->_agent, 'slurp' ) !== false ) {
|
592 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Slurp' ) );
|
593 |
-
$aversion = explode( ' ', $aresult[1] );
|
594 |
-
$this->setVersion( $aversion[0] );
|
595 |
-
$this->_browser_name = $this->BROWSER_SLURP;
|
596 |
-
$this->setRobot( true );
|
597 |
-
$this->setMobile( false );
|
598 |
-
|
599 |
-
return true;
|
600 |
-
}
|
601 |
-
|
602 |
-
return false;
|
603 |
-
}
|
604 |
-
|
605 |
-
/**
|
606 |
-
* Determine if the browser is Internet Explorer or not (last updated 1.7)
|
607 |
-
*
|
608 |
-
* @return boolean True if the browser is Internet Explorer otherwise false
|
609 |
-
*/
|
610 |
-
function checkBrowserInternetExplorer() {
|
611 |
-
|
612 |
-
// Test for v1 - v1.5 IE
|
613 |
-
if ( stripos( $this->_agent, 'microsoft internet explorer' ) !== false ) {
|
614 |
-
$this->setBrowser( $this->BROWSER_IE );
|
615 |
-
$this->setVersion( '1.0' );
|
616 |
-
$aresult = stristr( $this->_agent, '/' );
|
617 |
-
if ( preg_match( '/308|425|426|474|0b1/i', $aresult ) ) {
|
618 |
-
$this->setVersion( '1.5' );
|
619 |
-
}
|
620 |
-
|
621 |
-
return true;
|
622 |
-
// Test for versions > 1.5
|
623 |
-
} elseif ( stripos( $this->_agent, 'msie' ) !== false && stripos( $this->_agent, 'opera' ) === false ) {
|
624 |
-
// See if the browser is the odd MSN Explorer
|
625 |
-
if ( stripos( $this->_agent, 'msnb' ) !== false ) {
|
626 |
-
$aresult = explode( ' ', stristr( str_replace( ';', '; ', $this->_agent ), 'MSN' ) );
|
627 |
-
$this->setBrowser( $this->BROWSER_MSN );
|
628 |
-
$this->setVersion( str_replace( array( '(', ')', ';' ), '', $aresult[1] ) );
|
629 |
-
|
630 |
-
return true;
|
631 |
-
}
|
632 |
-
$aresult = explode( ' ', stristr( str_replace( ';', '; ', $this->_agent ), 'msie' ) );
|
633 |
-
$this->setBrowser( $this->BROWSER_IE );
|
634 |
-
$this->setVersion( str_replace( array( '(', ')', ';' ), '', $aresult[1] ) );
|
635 |
-
|
636 |
-
return true;
|
637 |
-
// Test for Pocket IE
|
638 |
-
} elseif ( stripos( $this->_agent, 'mspie' ) !== false || stripos( $this->_agent, 'pocket' ) !== false ) {
|
639 |
-
$aresult = explode( ' ', stristr( $this->_agent, 'mspie' ) );
|
640 |
-
$this->setPlatform( $this->PLATFORM_WINDOWS_CE );
|
641 |
-
$this->setBrowser( $this->BROWSER_POCKET_IE );
|
642 |
-
$this->setMobile( true );
|
643 |
-
|
644 |
-
if ( stripos( $this->_agent, 'mspie' ) !== false ) {
|
645 |
-
$this->setVersion( $aresult[1] );
|
646 |
-
} else {
|
647 |
-
$aversion = explode( '/', $this->_agent );
|
648 |
-
$this->setVersion( $aversion[1] );
|
649 |
-
}
|
650 |
-
|
651 |
-
return true;
|
652 |
-
}// End if().
|
653 |
-
|
654 |
-
return false;
|
655 |
-
}
|
656 |
-
|
657 |
-
/**
|
658 |
-
* Determine if the browser is Opera or not (last updated 1.7)
|
659 |
-
*
|
660 |
-
* @return boolean True if the browser is Opera otherwise false
|
661 |
-
*/
|
662 |
-
function checkBrowserOpera() {
|
663 |
-
if ( stripos( $this->_agent, 'opera mini' ) !== false ) {
|
664 |
-
$resultant = stristr( $this->_agent, 'opera mini' );
|
665 |
-
if ( preg_match( '/\//', $resultant ) ) {
|
666 |
-
$aresult = explode( '/', $resultant );
|
667 |
-
$aversion = explode( ' ', $aresult[1] );
|
668 |
-
$this->setVersion( $aversion[0] );
|
669 |
-
} else {
|
670 |
-
$aversion = explode( ' ', stristr( $resultant, 'opera mini' ) );
|
671 |
-
$this->setVersion( $aversion[1] );
|
672 |
-
}
|
673 |
-
$this->_browser_name = $this->BROWSER_OPERA_MINI;
|
674 |
-
$this->setMobile( true );
|
675 |
-
|
676 |
-
return true;
|
677 |
-
} elseif ( stripos( $this->_agent, 'opera' ) !== false ) {
|
678 |
-
$resultant = stristr( $this->_agent, 'opera' );
|
679 |
-
if ( preg_match( '/Version\/(10.*)$/', $resultant, $matches ) ) {
|
680 |
-
$this->setVersion( $matches[1] );
|
681 |
-
} elseif ( preg_match( '/\//', $resultant ) ) {
|
682 |
-
$aresult = explode( '/', str_replace( '(', ' ', $resultant ) );
|
683 |
-
$aversion = explode( ' ', $aresult[1] );
|
684 |
-
$this->setVersion( $aversion[0] );
|
685 |
-
} else {
|
686 |
-
$aversion = explode( ' ', stristr( $resultant, 'opera' ) );
|
687 |
-
$this->setVersion( isset( $aversion[1] ) ? $aversion[1] : '' );
|
688 |
-
}
|
689 |
-
$this->_browser_name = $this->BROWSER_OPERA;
|
690 |
-
|
691 |
-
return true;
|
692 |
-
}
|
693 |
-
|
694 |
-
return false;
|
695 |
-
}
|
696 |
-
|
697 |
-
/**
|
698 |
-
* Determine if the browser is Chrome or not (last updated 1.7)
|
699 |
-
*
|
700 |
-
* @return boolean True if the browser is Chrome otherwise false
|
701 |
-
*/
|
702 |
-
function checkBrowserChrome() {
|
703 |
-
if ( stripos( $this->_agent, 'Chrome' ) !== false ) {
|
704 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Chrome' ) );
|
705 |
-
$aversion = explode( ' ', $aresult[1] );
|
706 |
-
$this->setVersion( $aversion[0] );
|
707 |
-
$this->setBrowser( $this->BROWSER_CHROME );
|
708 |
-
|
709 |
-
return true;
|
710 |
-
}
|
711 |
-
|
712 |
-
return false;
|
713 |
-
}
|
714 |
-
|
715 |
-
|
716 |
-
/**
|
717 |
-
* Determine if the browser is WebTv or not (last updated 1.7)
|
718 |
-
*
|
719 |
-
* @return boolean True if the browser is WebTv otherwise false
|
720 |
-
*/
|
721 |
-
function checkBrowserWebTv() {
|
722 |
-
if ( stripos( $this->_agent, 'webtv' ) !== false ) {
|
723 |
-
$aresult = explode( '/', stristr( $this->_agent, 'webtv' ) );
|
724 |
-
$aversion = explode( ' ', $aresult[1] );
|
725 |
-
$this->setVersion( $aversion[0] );
|
726 |
-
$this->setBrowser( $this->BROWSER_WEBTV );
|
727 |
-
|
728 |
-
return true;
|
729 |
-
}
|
730 |
-
|
731 |
-
return false;
|
732 |
-
}
|
733 |
-
|
734 |
-
/**
|
735 |
-
* Determine if the browser is NetPositive or not (last updated 1.7)
|
736 |
-
*
|
737 |
-
* @return boolean True if the browser is NetPositive otherwise false
|
738 |
-
*/
|
739 |
-
function checkBrowserNetPositive() {
|
740 |
-
if ( stripos( $this->_agent, 'NetPositive' ) !== false ) {
|
741 |
-
$aresult = explode( '/', stristr( $this->_agent, 'NetPositive' ) );
|
742 |
-
$aversion = explode( ' ', $aresult[1] );
|
743 |
-
$this->setVersion( str_replace( array( '(', ')', ';' ), '', $aversion[0] ) );
|
744 |
-
$this->setBrowser( $this->BROWSER_NETPOSITIVE );
|
745 |
-
|
746 |
-
return true;
|
747 |
-
}
|
748 |
-
|
749 |
-
return false;
|
750 |
-
}
|
751 |
-
|
752 |
-
/**
|
753 |
-
* Determine if the browser is Galeon or not (last updated 1.7)
|
754 |
-
*
|
755 |
-
* @return boolean True if the browser is Galeon otherwise false
|
756 |
-
*/
|
757 |
-
function checkBrowserGaleon() {
|
758 |
-
if ( stripos( $this->_agent, 'galeon' ) !== false ) {
|
759 |
-
$aresult = explode( ' ', stristr( $this->_agent, 'galeon' ) );
|
760 |
-
$aversion = explode( '/', $aresult[0] );
|
761 |
-
$this->setVersion( $aversion[1] );
|
762 |
-
$this->setBrowser( $this->BROWSER_GALEON );
|
763 |
-
|
764 |
-
return true;
|
765 |
-
}
|
766 |
-
|
767 |
-
return false;
|
768 |
-
}
|
769 |
-
|
770 |
-
/**
|
771 |
-
* Determine if the browser is Konqueror or not (last updated 1.7)
|
772 |
-
*
|
773 |
-
* @return boolean True if the browser is Konqueror otherwise false
|
774 |
-
*/
|
775 |
-
function checkBrowserKonqueror() {
|
776 |
-
if ( stripos( $this->_agent, 'Konqueror' ) !== false ) {
|
777 |
-
$aresult = explode( ' ', stristr( $this->_agent, 'Konqueror' ) );
|
778 |
-
$aversion = explode( '/', $aresult[0] );
|
779 |
-
$this->setVersion( $aversion[1] );
|
780 |
-
$this->setBrowser( $this->BROWSER_KONQUEROR );
|
781 |
-
|
782 |
-
return true;
|
783 |
-
}
|
784 |
-
|
785 |
-
return false;
|
786 |
-
}
|
787 |
-
|
788 |
-
/**
|
789 |
-
* Determine if the browser is iCab or not (last updated 1.7)
|
790 |
-
*
|
791 |
-
* @return boolean True if the browser is iCab otherwise false
|
792 |
-
*/
|
793 |
-
function checkBrowserIcab() {
|
794 |
-
if ( stripos( $this->_agent, 'icab' ) !== false ) {
|
795 |
-
$aversion = explode( ' ', stristr( str_replace( '/', ' ', $this->_agent ), 'icab' ) );
|
796 |
-
$this->setVersion( $aversion[1] );
|
797 |
-
$this->setBrowser( $this->BROWSER_ICAB );
|
798 |
-
|
799 |
-
return true;
|
800 |
-
}
|
801 |
-
|
802 |
-
return false;
|
803 |
-
}
|
804 |
-
|
805 |
-
/**
|
806 |
-
* Determine if the browser is OmniWeb or not (last updated 1.7)
|
807 |
-
*
|
808 |
-
* @return boolean True if the browser is OmniWeb otherwise false
|
809 |
-
*/
|
810 |
-
function checkBrowserOmniWeb() {
|
811 |
-
if ( stripos( $this->_agent, 'omniweb' ) !== false ) {
|
812 |
-
$aresult = explode( '/', stristr( $this->_agent, 'omniweb' ) );
|
813 |
-
$aversion = explode( ' ', isset( $aresult[1] ) ? $aresult[1] : '' );
|
814 |
-
$this->setVersion( $aversion[0] );
|
815 |
-
$this->setBrowser( $this->BROWSER_OMNIWEB );
|
816 |
-
|
817 |
-
return true;
|
818 |
-
}
|
819 |
-
|
820 |
-
return false;
|
821 |
-
}
|
822 |
-
|
823 |
-
/**
|
824 |
-
* Determine if the browser is Phoenix or not (last updated 1.7)
|
825 |
-
*
|
826 |
-
* @return boolean True if the browser is Phoenix otherwise false
|
827 |
-
*/
|
828 |
-
function checkBrowserPhoenix() {
|
829 |
-
if ( stripos( $this->_agent, 'Phoenix' ) !== false ) {
|
830 |
-
$aversion = explode( '/', stristr( $this->_agent, 'Phoenix' ) );
|
831 |
-
$this->setVersion( $aversion[1] );
|
832 |
-
$this->setBrowser( $this->BROWSER_PHOENIX );
|
833 |
-
|
834 |
-
return true;
|
835 |
-
}
|
836 |
-
|
837 |
-
return false;
|
838 |
-
}
|
839 |
-
|
840 |
-
/**
|
841 |
-
* Determine if the browser is Firebird or not (last updated 1.7)
|
842 |
-
*
|
843 |
-
* @return boolean True if the browser is Firebird otherwise false
|
844 |
-
*/
|
845 |
-
function checkBrowserFirebird() {
|
846 |
-
if ( stripos( $this->_agent, 'Firebird' ) !== false ) {
|
847 |
-
$aversion = explode( '/', stristr( $this->_agent, 'Firebird' ) );
|
848 |
-
$this->setVersion( $aversion[1] );
|
849 |
-
$this->setBrowser( $this->BROWSER_FIREBIRD );
|
850 |
-
|
851 |
-
return true;
|
852 |
-
}
|
853 |
-
|
854 |
-
return false;
|
855 |
-
}
|
856 |
-
|
857 |
-
/**
|
858 |
-
* Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
|
859 |
-
* NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
|
860 |
-
*
|
861 |
-
* @return boolean True if the browser is Netscape Navigator 9+ otherwise false
|
862 |
-
*/
|
863 |
-
function checkBrowserNetscapeNavigator9Plus() {
|
864 |
-
if ( stripos( $this->_agent, 'Firefox' ) !== false && preg_match( '/Navigator\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
865 |
-
$this->setVersion( $matches[1] );
|
866 |
-
$this->setBrowser( $this->BROWSER_NETSCAPE_NAVIGATOR );
|
867 |
-
|
868 |
-
return true;
|
869 |
-
} elseif ( stripos( $this->_agent, 'Firefox' ) === false && preg_match( '/Netscape6?\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
870 |
-
$this->setVersion( $matches[1] );
|
871 |
-
$this->setBrowser( $this->BROWSER_NETSCAPE_NAVIGATOR );
|
872 |
-
|
873 |
-
return true;
|
874 |
-
}
|
875 |
-
|
876 |
-
return false;
|
877 |
-
}
|
878 |
-
|
879 |
-
/**
|
880 |
-
* Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
|
881 |
-
*
|
882 |
-
* @return boolean True if the browser is Shiretoko otherwise false
|
883 |
-
*/
|
884 |
-
function checkBrowserShiretoko() {
|
885 |
-
if ( stripos( $this->_agent, 'Mozilla' ) !== false && preg_match( '/Shiretoko\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
886 |
-
$this->setVersion( $matches[1] );
|
887 |
-
$this->setBrowser( $this->BROWSER_SHIRETOKO );
|
888 |
-
|
889 |
-
return true;
|
890 |
-
}
|
891 |
-
|
892 |
-
return false;
|
893 |
-
}
|
894 |
-
|
895 |
-
/**
|
896 |
-
* Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
|
897 |
-
*
|
898 |
-
* @return boolean True if the browser is Ice Cat otherwise false
|
899 |
-
*/
|
900 |
-
function checkBrowserIceCat() {
|
901 |
-
if ( stripos( $this->_agent, 'Mozilla' ) !== false && preg_match( '/IceCat\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
902 |
-
$this->setVersion( $matches[1] );
|
903 |
-
$this->setBrowser( $this->BROWSER_ICECAT );
|
904 |
-
|
905 |
-
return true;
|
906 |
-
}
|
907 |
-
|
908 |
-
return false;
|
909 |
-
}
|
910 |
-
|
911 |
-
/**
|
912 |
-
* Determine if the browser is Nokia or not (last updated 1.7)
|
913 |
-
*
|
914 |
-
* @return boolean True if the browser is Nokia otherwise false
|
915 |
-
*/
|
916 |
-
function checkBrowserNokia() {
|
917 |
-
if ( preg_match( '/Nokia([^\/]+)\/([^ SP]+)/i', $this->_agent, $matches ) ) {
|
918 |
-
$this->setVersion( $matches[2] );
|
919 |
-
if ( stripos( $this->_agent, 'Series60' ) !== false || strpos( $this->_agent, 'S60' ) !== false ) {
|
920 |
-
$this->setBrowser( $this->BROWSER_NOKIA_S60 );
|
921 |
-
} else {
|
922 |
-
$this->setBrowser( $this->BROWSER_NOKIA );
|
923 |
-
}
|
924 |
-
$this->setMobile( true );
|
925 |
-
|
926 |
-
return true;
|
927 |
-
}
|
928 |
-
|
929 |
-
return false;
|
930 |
-
}
|
931 |
-
|
932 |
-
/**
|
933 |
-
* Determine if the browser is Firefox or not (last updated 1.7)
|
934 |
-
*
|
935 |
-
* @return boolean True if the browser is Firefox otherwise false
|
936 |
-
*/
|
937 |
-
function checkBrowserFirefox() {
|
938 |
-
if ( stripos( $this->_agent, 'safari' ) === false ) {
|
939 |
-
if ( preg_match( '/Firefox[\/ \(]([^ ;\)]+)/i', $this->_agent, $matches ) ) {
|
940 |
-
$this->setVersion( $matches[1] );
|
941 |
-
$this->setBrowser( $this->BROWSER_FIREFOX );
|
942 |
-
|
943 |
-
return true;
|
944 |
-
} elseif ( preg_match( '/Firefox$/i', $this->_agent, $matches ) ) {
|
945 |
-
$this->setVersion( '' );
|
946 |
-
$this->setBrowser( $this->BROWSER_FIREFOX );
|
947 |
-
|
948 |
-
return true;
|
949 |
-
}
|
950 |
-
}
|
951 |
-
|
952 |
-
return false;
|
953 |
-
}
|
954 |
-
|
955 |
-
/**
|
956 |
-
* Determine if the browser is Firefox or not (last updated 1.7)
|
957 |
-
*
|
958 |
-
* @return boolean True if the browser is Firefox otherwise false
|
959 |
-
*/
|
960 |
-
function checkBrowserIceweasel() {
|
961 |
-
if ( stripos( $this->_agent, 'Iceweasel' ) !== false ) {
|
962 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Iceweasel' ) );
|
963 |
-
$aversion = explode( ' ', $aresult[1] );
|
964 |
-
$this->setVersion( $aversion[0] );
|
965 |
-
$this->setBrowser( $this->BROWSER_ICEWEASEL );
|
966 |
-
|
967 |
-
return true;
|
968 |
-
}
|
969 |
-
|
970 |
-
return false;
|
971 |
-
}
|
972 |
-
|
973 |
-
/**
|
974 |
-
* Determine if the browser is Mozilla or not (last updated 1.7)
|
975 |
-
*
|
976 |
-
* @return boolean True if the browser is Mozilla otherwise false
|
977 |
-
*/
|
978 |
-
function checkBrowserMozilla() {
|
979 |
-
if ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/rv:[0-9].[0-9][a-b]?/i', $this->_agent ) && stripos( $this->_agent, 'netscape' ) === false ) {
|
980 |
-
$aversion = explode( ' ', stristr( $this->_agent, 'rv:' ) );
|
981 |
-
preg_match( '/rv:[0-9].[0-9][a-b]?/i', $this->_agent, $aversion );
|
982 |
-
$this->setVersion( str_replace( 'rv:', '', $aversion[0] ) );
|
983 |
-
$this->setBrowser( $this->BROWSER_MOZILLA );
|
984 |
-
|
985 |
-
return true;
|
986 |
-
} elseif ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/rv:[0-9]\.[0-9]/i', $this->_agent ) && stripos( $this->_agent, 'netscape' ) === false ) {
|
987 |
-
$aversion = explode( '', stristr( $this->_agent, 'rv:' ) );
|
988 |
-
$this->setVersion( str_replace( 'rv:', '', $aversion[0] ) );
|
989 |
-
$this->setBrowser( $this->BROWSER_MOZILLA );
|
990 |
-
|
991 |
-
return true;
|
992 |
-
} elseif ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/mozilla\/([^ ]*)/i', $this->_agent, $matches ) && stripos( $this->_agent, 'netscape' ) === false ) {
|
993 |
-
$this->setVersion( $matches[1] );
|
994 |
-
$this->setBrowser( $this->BROWSER_MOZILLA );
|
995 |
-
|
996 |
-
return true;
|
997 |
-
}
|
998 |
-
|
999 |
-
return false;
|
1000 |
-
}
|
1001 |
-
|
1002 |
-
/**
|
1003 |
-
* Determine if the browser is Lynx or not (last updated 1.7)
|
1004 |
-
*
|
1005 |
-
* @return boolean True if the browser is Lynx otherwise false
|
1006 |
-
*/
|
1007 |
-
function checkBrowserLynx() {
|
1008 |
-
if ( stripos( $this->_agent, 'lynx' ) !== false ) {
|
1009 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Lynx' ) );
|
1010 |
-
$aversion = explode( ' ', ( isset( $aresult[1] ) ? $aresult[1] : '' ) );
|
1011 |
-
$this->setVersion( $aversion[0] );
|
1012 |
-
$this->setBrowser( $this->BROWSER_LYNX );
|
1013 |
-
|
1014 |
-
return true;
|
1015 |
-
}
|
1016 |
-
|
1017 |
-
return false;
|
1018 |
-
}
|
1019 |
-
|
1020 |
-
/**
|
1021 |
-
* Determine if the browser is Amaya or not (last updated 1.7)
|
1022 |
-
*
|
1023 |
-
* @return boolean True if the browser is Amaya otherwise false
|
1024 |
-
*/
|
1025 |
-
function checkBrowserAmaya() {
|
1026 |
-
if ( stripos( $this->_agent, 'amaya' ) !== false ) {
|
1027 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Amaya' ) );
|
1028 |
-
$aversion = explode( ' ', $aresult[1] );
|
1029 |
-
$this->setVersion( $aversion[0] );
|
1030 |
-
$this->setBrowser( $this->BROWSER_AMAYA );
|
1031 |
-
|
1032 |
-
return true;
|
1033 |
-
}
|
1034 |
-
|
1035 |
-
return false;
|
1036 |
-
}
|
1037 |
-
|
1038 |
-
/**
|
1039 |
-
* Determine if the browser is Safari or not (last updated 1.7)
|
1040 |
-
*
|
1041 |
-
* @return boolean True if the browser is Safari otherwise false
|
1042 |
-
*/
|
1043 |
-
function checkBrowserSafari() {
|
1044 |
-
if ( stripos( $this->_agent, 'Safari' ) !== false && stripos( $this->_agent, 'iPhone' ) === false && stripos( $this->_agent, 'iPod' ) === false ) {
|
1045 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1046 |
-
if ( isset( $aresult[1] ) ) {
|
1047 |
-
$aversion = explode( ' ', $aresult[1] );
|
1048 |
-
$this->setVersion( $aversion[0] );
|
1049 |
-
} else {
|
1050 |
-
$this->setVersion( $this->VERSION_UNKNOWN );
|
1051 |
-
}
|
1052 |
-
$this->setBrowser( $this->BROWSER_SAFARI );
|
1053 |
-
|
1054 |
-
return true;
|
1055 |
-
}
|
1056 |
-
|
1057 |
-
return false;
|
1058 |
-
}
|
1059 |
-
|
1060 |
-
/**
|
1061 |
-
* Determine if the browser is iPhone or not (last updated 1.7)
|
1062 |
-
*
|
1063 |
-
* @return boolean True if the browser is iPhone otherwise false
|
1064 |
-
*/
|
1065 |
-
function checkBrowseriPhone() {
|
1066 |
-
if ( stripos( $this->_agent, 'iPhone' ) !== false ) {
|
1067 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1068 |
-
if ( isset( $aresult[1] ) ) {
|
1069 |
-
$aversion = explode( ' ', $aresult[1] );
|
1070 |
-
$this->setVersion( $aversion[0] );
|
1071 |
-
} else {
|
1072 |
-
$this->setVersion( $this->VERSION_UNKNOWN );
|
1073 |
-
}
|
1074 |
-
$this->setMobile( true );
|
1075 |
-
$this->setBrowser( $this->BROWSER_IPHONE );
|
1076 |
-
|
1077 |
-
return true;
|
1078 |
-
}
|
1079 |
-
|
1080 |
-
return false;
|
1081 |
-
}
|
1082 |
-
|
1083 |
-
/**
|
1084 |
-
* Determine if the browser is iPod or not (last updated 1.7)
|
1085 |
-
*
|
1086 |
-
* @return boolean True if the browser is iPod otherwise false
|
1087 |
-
*/
|
1088 |
-
function checkBrowseriPad() {
|
1089 |
-
if ( stripos( $this->_agent, 'iPad' ) !== false ) {
|
1090 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1091 |
-
if ( isset( $aresult[1] ) ) {
|
1092 |
-
$aversion = explode( ' ', $aresult[1] );
|
1093 |
-
$this->setVersion( $aversion[0] );
|
1094 |
-
} else {
|
1095 |
-
$this->setVersion( $this->VERSION_UNKNOWN );
|
1096 |
-
}
|
1097 |
-
$this->setMobile( true );
|
1098 |
-
$this->setBrowser( $this->BROWSER_IPAD );
|
1099 |
-
|
1100 |
-
return true;
|
1101 |
-
}
|
1102 |
-
|
1103 |
-
return false;
|
1104 |
-
}
|
1105 |
-
|
1106 |
-
/**
|
1107 |
-
* Determine if the browser is iPod or not (last updated 1.7)
|
1108 |
-
*
|
1109 |
-
* @return boolean True if the browser is iPod otherwise false
|
1110 |
-
*/
|
1111 |
-
function checkBrowseriPod() {
|
1112 |
-
if ( stripos( $this->_agent, 'iPod' ) !== false ) {
|
1113 |
-
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1114 |
-
if ( isset( $aresult[1] ) ) {
|
1115 |
-
$aversion = explode( ' ', $aresult[1] );
|
1116 |
-
$this->setVersion( $aversion[0] );
|
1117 |
-
} else {
|
1118 |
-
$this->setVersion( $this->VERSION_UNKNOWN );
|
1119 |
-
}
|
1120 |
-
$this->setMobile( true );
|
1121 |
-
$this->setBrowser( $this->BROWSER_IPOD );
|
1122 |
-
|
1123 |
-
return true;
|
1124 |
-
}
|
1125 |
-
|
1126 |
-
return false;
|
1127 |
-
}
|
1128 |
-
|
1129 |
-
/**
|
1130 |
-
* Determine if the browser is Android or not (last updated 1.7)
|
1131 |
-
*
|
1132 |
-
* @return boolean True if the browser is Android otherwise false
|
1133 |
-
*/
|
1134 |
-
function checkBrowserAndroid() {
|
1135 |
-
if ( stripos( $this->_agent, 'Android' ) !== false ) {
|
1136 |
-
$aresult = explode( ' ', stristr( $this->_agent, 'Android' ) );
|
1137 |
-
if ( isset( $aresult[1] ) ) {
|
1138 |
-
$aversion = explode( ' ', $aresult[1] );
|
1139 |
-
$this->setVersion( $aversion[0] );
|
1140 |
-
} else {
|
1141 |
-
$this->setVersion( $this->VERSION_UNKNOWN );
|
1142 |
-
}
|
1143 |
-
$this->setMobile( true );
|
1144 |
-
$this->setBrowser( $this->BROWSER_ANDROID );
|
1145 |
-
|
1146 |
-
return true;
|
1147 |
-
}
|
1148 |
-
|
1149 |
-
return false;
|
1150 |
-
}
|
1151 |
-
|
1152 |
-
/**
|
1153 |
-
* Determine the user's platform (last updated 1.7)
|
1154 |
-
*/
|
1155 |
-
function checkPlatform() {
|
1156 |
-
if ( stripos( $this->_agent, 'windows' ) !== false ) {
|
1157 |
-
$this->_platform = $this->PLATFORM_WINDOWS;
|
1158 |
-
} elseif ( stripos( $this->_agent, 'iPad' ) !== false ) {
|
1159 |
-
$this->_platform = $this->PLATFORM_IPAD;
|
1160 |
-
} elseif ( stripos( $this->_agent, 'iPod' ) !== false ) {
|
1161 |
-
$this->_platform = $this->PLATFORM_IPOD;
|
1162 |
-
} elseif ( stripos( $this->_agent, 'iPhone' ) !== false ) {
|
1163 |
-
$this->_platform = $this->PLATFORM_IPHONE;
|
1164 |
-
} elseif ( stripos( $this->_agent, 'mac' ) !== false ) {
|
1165 |
-
$this->_platform = $this->PLATFORM_APPLE;
|
1166 |
-
} elseif ( stripos( $this->_agent, 'android' ) !== false ) {
|
1167 |
-
$this->_platform = $this->PLATFORM_ANDROID;
|
1168 |
-
} elseif ( stripos( $this->_agent, 'linux' ) !== false ) {
|
1169 |
-
$this->_platform = $this->PLATFORM_LINUX;
|
1170 |
-
} elseif ( stripos( $this->_agent, 'Nokia' ) !== false ) {
|
1171 |
-
$this->_platform = $this->PLATFORM_NOKIA;
|
1172 |
-
} elseif ( stripos( $this->_agent, 'BlackBerry' ) !== false ) {
|
1173 |
-
$this->_platform = $this->PLATFORM_BLACKBERRY;
|
1174 |
-
} elseif ( stripos( $this->_agent, 'FreeBSD' ) !== false ) {
|
1175 |
-
$this->_platform = $this->PLATFORM_FREEBSD;
|
1176 |
-
} elseif ( stripos( $this->_agent, 'OpenBSD' ) !== false ) {
|
1177 |
-
$this->_platform = $this->PLATFORM_OPENBSD;
|
1178 |
-
} elseif ( stripos( $this->_agent, 'NetBSD' ) !== false ) {
|
1179 |
-
$this->_platform = $this->PLATFORM_NETBSD;
|
1180 |
-
} elseif ( stripos( $this->_agent, 'OpenSolaris' ) !== false ) {
|
1181 |
-
$this->_platform = $this->PLATFORM_OPENSOLARIS;
|
1182 |
-
} elseif ( stripos( $this->_agent, 'SunOS' ) !== false ) {
|
1183 |
-
$this->_platform = $this->PLATFORM_SUNOS;
|
1184 |
-
} elseif ( stripos( $this->_agent, 'OS\/2' ) !== false ) {
|
1185 |
-
$this->_platform = $this->PLATFORM_OS2;
|
1186 |
-
} elseif ( stripos( $this->_agent, 'BeOS' ) !== false ) {
|
1187 |
-
$this->_platform = $this->PLATFORM_BEOS;
|
1188 |
-
} elseif ( stripos( $this->_agent, 'win' ) !== false ) {
|
1189 |
-
$this->_platform = $this->PLATFORM_WINDOWS;
|
1190 |
-
}
|
1191 |
-
}
|
1192 |
-
}
|
1193 |
-
}// End if().
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Browser detection class
|
4 |
+
*
|
5 |
+
* @author Original Author: Chris Schuld (http://chrisschuld.com/)
|
6 |
+
* @author Modifications for EDD: Chris Christoff
|
7 |
+
* @version 1.9
|
8 |
+
* Usage:
|
9 |
+
* $browser = new Browser();
|
10 |
+
* if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
|
11 |
+
* echo 'You have Firefox version 2 or greater';
|
12 |
+
* }
|
13 |
+
* User agents sampled from: http://www.useragentstring.com/
|
14 |
+
* Based on original work from Gary White (http://apptools.com/phptools/browser/
|
15 |
+
* CHANGELOG:
|
16 |
+
* 2012-12-26 (v1.9c by Chris Christoff):
|
17 |
+
* + Changed vars to publics
|
18 |
+
* 2012-12-23 (v1.9b by Chris Christoff):
|
19 |
+
* + Removed the browser string return and added spacing.
|
20 |
+
* + Also removed return HTML formatting.
|
21 |
+
* 2012-12-23 (v1.9a by Chris Christoff):
|
22 |
+
* + Split user string and add formatting so we can print a nicely
|
23 |
+
* formatted user agent string
|
24 |
+
* 2010-08-20 (v1.9):
|
25 |
+
* + Added MSN Explorer Browser (legacy)
|
26 |
+
* + Added Bing/MSN Robot (Thanks Rob MacDonald)
|
27 |
+
* + Added the Android Platform (PLATFORM_ANDROID)
|
28 |
+
* + Fixed issue with Android 1.6/2.2 (Thanks Tom Hirashima)
|
29 |
+
* 2010-04-27 (v1.8):
|
30 |
+
* + Added iPad Support
|
31 |
+
* 2010-03-07 (v1.7):
|
32 |
+
* + *MAJOR* Rebuild (preg_match and other "slow" routine removal(s))
|
33 |
+
* + Almost allof Gary's original code has been replaced
|
34 |
+
* + Large PHPUNIT testing environment created to validate new releases and additions
|
35 |
+
* + Added FreeBSD Platform
|
36 |
+
* + Added OpenBSD Platform
|
37 |
+
* + Added NetBSD Platform
|
38 |
+
* + Added SunOS Platform
|
39 |
+
* + Added OpenSolaris Platform
|
40 |
+
* + Added support of the Iceweazel Browser
|
41 |
+
* + Added isChromeFrame() call to check if chromeframe is in use
|
42 |
+
* + Moved the Opera check in front of the Firefox check due to legacy Opera User Agents
|
43 |
+
* + Added the __toString() method (Thanks Deano)
|
44 |
+
* 2009-11-15:
|
45 |
+
* + Updated the checkes for Firefox
|
46 |
+
* + Added the NOKIA platform
|
47 |
+
* + Added Checks for the NOKIA brower(s)
|
48 |
+
* 2009-11-08:
|
49 |
+
* + PHP 5.3 Support
|
50 |
+
* + Added support for BlackBerry OS and BlackBerry browser
|
51 |
+
* + Added support for the Opera Mini browser
|
52 |
+
* + Added additional documenation
|
53 |
+
* + Added support for isRobot() and isMobile()
|
54 |
+
* + Added support for Opera version 10
|
55 |
+
* + Added support for deprecated Netscape Navigator version 9
|
56 |
+
* + Added support for IceCat
|
57 |
+
* + Added support for Shiretoko
|
58 |
+
* 2010-04-27 (v1.8):
|
59 |
+
* + Added iPad Support
|
60 |
+
* 2009-08-18:
|
61 |
+
* + Updated to support PHP 5.3 - removed all deprecated function calls
|
62 |
+
* + Updated to remove all double quotes (") -- converted to single quotes (')
|
63 |
+
* 2009-04-27:
|
64 |
+
* + Updated the IE check to remove a typo and bug (thanks John)
|
65 |
+
* 2009-04-22:
|
66 |
+
* + Added detection for GoogleBot
|
67 |
+
* + Added detection for the W3C Validator.
|
68 |
+
* + Added detection for Yahoo! Slurp
|
69 |
+
* 2009-03-14:
|
70 |
+
* + Added detection for iPods.
|
71 |
+
* + Added Platform detection for iPhones
|
72 |
+
* + Added Platform detection for iPods
|
73 |
+
* 2009-02-16: (Rick Hale)
|
74 |
+
* + Added version detection for Android phones.
|
75 |
+
* 2008-12-09:
|
76 |
+
* + Removed unused constant
|
77 |
+
* 2008-11-07:
|
78 |
+
* + Added Google's Chrome to the detection list
|
79 |
+
* + Added isBrowser(string) to the list of functions special thanks to
|
80 |
+
* Daniel 'mavrick' Lang for the function concept (http://mavrick.id.au)
|
81 |
+
* Gary White noted: "Since browser detection is so unreliable, I am
|
82 |
+
* no longer maintaining this script. You are free to use and or
|
83 |
+
* modify/update it as you want, however the author assumes no
|
84 |
+
* responsibility for the accuracy of the detected values."
|
85 |
+
* Anyone experienced with Gary's script might be interested in these notes:
|
86 |
+
* Added class constants
|
87 |
+
* Added detection and version detection for Google's Chrome
|
88 |
+
* Updated the version detection for Amaya
|
89 |
+
* Updated the version detection for Firefox
|
90 |
+
* Updated the version detection for Lynx
|
91 |
+
* Updated the version detection for WebTV
|
92 |
+
* Updated the version detection for NetPositive
|
93 |
+
* Updated the version detection for IE
|
94 |
+
* Updated the version detection for OmniWeb
|
95 |
+
* Updated the version detection for iCab
|
96 |
+
* Updated the version detection for Safari
|
97 |
+
* Updated Safari to remove mobile devices (iPhone)
|
98 |
+
* Added detection for iPhone
|
99 |
+
* Added detection for robots
|
100 |
+
* Added detection for mobile devices
|
101 |
+
* Added detection for BlackBerry
|
102 |
+
* Removed Netscape checks (matches heavily with firefox & mozilla)
|
103 |
+
*/
|
104 |
+
|
105 |
+
|
106 |
+
// Exit if accessed directly
|
107 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
108 |
+
exit;
|
109 |
+
}
|
110 |
+
|
111 |
+
if ( ! class_exists( 'Browser' ) ) {
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Browser detection class
|
115 |
+
*
|
116 |
+
* @author Chris Schuld
|
117 |
+
* @since 1.0
|
118 |
+
*/
|
119 |
+
class Browser {
|
120 |
+
public $_agent = '';
|
121 |
+
public $_browser_name = '';
|
122 |
+
public $_version = '';
|
123 |
+
public $_platform = '';
|
124 |
+
public $_os = '';
|
125 |
+
public $_is_aol = false;
|
126 |
+
public $_is_mobile = false;
|
127 |
+
public $_is_robot = false;
|
128 |
+
public $_aol_version = '';
|
129 |
+
|
130 |
+
public $BROWSER_UNKNOWN = 'unknown';
|
131 |
+
public $VERSION_UNKNOWN = 'unknown';
|
132 |
+
|
133 |
+
public $BROWSER_OPERA = 'Opera'; // Http://www.opera.com/
|
134 |
+
public $BROWSER_OPERA_MINI = 'Opera Mini'; // Http://www.opera.com/mini/
|
135 |
+
public $BROWSER_WEBTV = 'WebTV'; // Http://www.webtv.net/pc/
|
136 |
+
public $BROWSER_IE = 'Internet Explorer'; // Http://www.microsoft.com/ie/
|
137 |
+
public $BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // Http://en.wikipedia.org/wiki/Internet_Explorer_Mobile
|
138 |
+
public $BROWSER_KONQUEROR = 'Konqueror'; // Http://www.konqueror.org/
|
139 |
+
public $BROWSER_ICAB = 'iCab'; // Http://www.icab.de/
|
140 |
+
public $BROWSER_OMNIWEB = 'OmniWeb'; // Http://www.omnigroup.com/applications/omniweb/
|
141 |
+
public $BROWSER_FIREBIRD = 'Firebird'; // Http://www.ibphoenix.com/
|
142 |
+
public $BROWSER_FIREFOX = 'Firefox'; // Http://www.mozilla.com/en-US/firefox/firefox.html
|
143 |
+
public $BROWSER_ICEWEASEL = 'Iceweasel'; // Http://www.geticeweasel.org/
|
144 |
+
public $BROWSER_SHIRETOKO = 'Shiretoko'; // Http://wiki.mozilla.org/Projects/shiretoko
|
145 |
+
public $BROWSER_MOZILLA = 'Mozilla'; // Http://www.mozilla.com/en-US/
|
146 |
+
public $BROWSER_AMAYA = 'Amaya'; // Http://www.w3.org/Amaya/
|
147 |
+
public $BROWSER_LYNX = 'Lynx'; // Http://en.wikipedia.org/wiki/Lynx
|
148 |
+
public $BROWSER_SAFARI = 'Safari'; // Http://apple.com
|
149 |
+
public $BROWSER_IPHONE = 'iPhone'; // Http://apple.com
|
150 |
+
public $BROWSER_IPOD = 'iPod'; // Http://apple.com
|
151 |
+
public $BROWSER_IPAD = 'iPad'; // Http://apple.com
|
152 |
+
public $BROWSER_CHROME = 'Chrome'; // Http://www.google.com/chrome
|
153 |
+
public $BROWSER_ANDROID = 'Android'; // Http://www.android.com/
|
154 |
+
public $BROWSER_GOOGLEBOT = 'GoogleBot'; // Http://en.wikipedia.org/wiki/Googlebot
|
155 |
+
public $BROWSER_SLURP = 'Yahoo! Slurp'; // Http://en.wikipedia.org/wiki/Yahoo!_Slurp
|
156 |
+
public $BROWSER_W3CVALIDATOR = 'W3C Validator'; // Http://validator.w3.org/
|
157 |
+
public $BROWSER_BLACKBERRY = 'BlackBerry'; // Http://www.blackberry.com/
|
158 |
+
public $BROWSER_ICECAT = 'IceCat'; // Http://en.wikipedia.org/wiki/GNU_IceCat
|
159 |
+
public $BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // Http://en.wikipedia.org/wiki/Web_Browser_for_S60
|
160 |
+
public $BROWSER_NOKIA = 'Nokia Browser'; // * all other WAP-based browsers on the Nokia Platform
|
161 |
+
public $BROWSER_MSN = 'MSN Browser'; // Http://explorer.msn.com/
|
162 |
+
public $BROWSER_MSNBOT = 'MSN Bot'; // Http://search.msn.com/msnbot.htm
|
163 |
+
// Http://en.wikipedia.org/wiki/Msnbot (used for Bing as well)
|
164 |
+
public $BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // Http://browser.netscape.com/ (DEPRECATED)
|
165 |
+
public $BROWSER_GALEON = 'Galeon'; // Http://galeon.sourceforge.net/ (DEPRECATED)
|
166 |
+
public $BROWSER_NETPOSITIVE = 'NetPositive'; // Http://en.wikipedia.org/wiki/NetPositive (DEPRECATED)
|
167 |
+
public $BROWSER_PHOENIX = 'Phoenix'; // Http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED)
|
168 |
+
|
169 |
+
public $PLATFORM_UNKNOWN = 'unknown';
|
170 |
+
public $PLATFORM_WINDOWS = 'Windows';
|
171 |
+
public $PLATFORM_WINDOWS_CE = 'Windows CE';
|
172 |
+
public $PLATFORM_APPLE = 'Apple';
|
173 |
+
public $PLATFORM_LINUX = 'Linux';
|
174 |
+
public $PLATFORM_OS2 = 'OS/2';
|
175 |
+
public $PLATFORM_BEOS = 'BeOS';
|
176 |
+
public $PLATFORM_IPHONE = 'iPhone';
|
177 |
+
public $PLATFORM_IPOD = 'iPod';
|
178 |
+
public $PLATFORM_IPAD = 'iPad';
|
179 |
+
public $PLATFORM_BLACKBERRY = 'BlackBerry';
|
180 |
+
public $PLATFORM_NOKIA = 'Nokia';
|
181 |
+
public $PLATFORM_FREEBSD = 'FreeBSD';
|
182 |
+
public $PLATFORM_OPENBSD = 'OpenBSD';
|
183 |
+
public $PLATFORM_NETBSD = 'NetBSD';
|
184 |
+
public $PLATFORM_SUNOS = 'SunOS';
|
185 |
+
public $PLATFORM_OPENSOLARIS = 'OpenSolaris';
|
186 |
+
public $PLATFORM_ANDROID = 'Android';
|
187 |
+
|
188 |
+
public $OPERATING_SYSTEM_UNKNOWN = 'unknown';
|
189 |
+
|
190 |
+
function __construct( $useragent = '' ) {
|
191 |
+
$this->reset();
|
192 |
+
|
193 |
+
if ( $useragent != '' ) {
|
194 |
+
$this->setUserAgent( $useragent );
|
195 |
+
} else {
|
196 |
+
$this->determine();
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Reset all properties
|
202 |
+
*/
|
203 |
+
function reset() {
|
204 |
+
$this->_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
205 |
+
$this->_browser_name = $this->BROWSER_UNKNOWN;
|
206 |
+
$this->_version = $this->VERSION_UNKNOWN;
|
207 |
+
$this->_platform = $this->PLATFORM_UNKNOWN;
|
208 |
+
$this->_os = $this->OPERATING_SYSTEM_UNKNOWN;
|
209 |
+
$this->_is_aol = false;
|
210 |
+
$this->_is_mobile = false;
|
211 |
+
$this->_is_robot = false;
|
212 |
+
$this->_aol_version = $this->VERSION_UNKNOWN;
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Check to see if the specific browser is valid
|
217 |
+
*
|
218 |
+
* @param string $browserName
|
219 |
+
*
|
220 |
+
* @return True if the browser is the specified browser
|
221 |
+
*/
|
222 |
+
function isBrowser( $browserName ) {
|
223 |
+
return ( 0 == strcasecmp( $this->_browser_name, trim( $browserName ) ) );
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* The name of the browser. All return types are from the class contants
|
228 |
+
*
|
229 |
+
* @return string Name of the browser
|
230 |
+
*/
|
231 |
+
function getBrowser() {
|
232 |
+
return $this->_browser_name;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Set the name of the browser
|
237 |
+
*
|
238 |
+
* @param $browser The name of the Browser
|
239 |
+
*/
|
240 |
+
function setBrowser( $browser ) {
|
241 |
+
return $this->_browser_name = $browser;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* The name of the platform. All return types are from the class contants
|
246 |
+
*
|
247 |
+
* @return string Name of the browser
|
248 |
+
*/
|
249 |
+
function getPlatform() {
|
250 |
+
return $this->_platform;
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* Set the name of the platform
|
255 |
+
*
|
256 |
+
* @param $platform The name of the Platform
|
257 |
+
*/
|
258 |
+
function setPlatform( $platform ) {
|
259 |
+
return $this->_platform = $platform;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* The version of the browser.
|
264 |
+
*
|
265 |
+
* @return string Version of the browser (will only contain alpha-numeric characters and a period)
|
266 |
+
*/
|
267 |
+
function getVersion() {
|
268 |
+
return $this->_version;
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Set the version of the browser
|
273 |
+
*
|
274 |
+
* @param $version The version of the Browser
|
275 |
+
*/
|
276 |
+
function setVersion( $version ) {
|
277 |
+
$this->_version = preg_replace( '/[^0-9,.,a-z,A-Z-]/', '', $version );
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* The version of AOL.
|
282 |
+
*
|
283 |
+
* @return string Version of AOL (will only contain alpha-numeric characters and a period)
|
284 |
+
*/
|
285 |
+
function getAolVersion() {
|
286 |
+
return $this->_aol_version;
|
287 |
+
}
|
288 |
+
|
289 |
+
/**
|
290 |
+
* Set the version of AOL
|
291 |
+
*
|
292 |
+
* @param $version The version of AOL
|
293 |
+
*/
|
294 |
+
function setAolVersion( $version ) {
|
295 |
+
$this->_aol_version = preg_replace( '/[^0-9,.,a-z,A-Z]/', '', $version );
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Is the browser from AOL?
|
300 |
+
*
|
301 |
+
* @return boolean True if the browser is from AOL otherwise false
|
302 |
+
*/
|
303 |
+
function isAol() {
|
304 |
+
return $this->_is_aol;
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Is the browser from a mobile device?
|
309 |
+
*
|
310 |
+
* @return boolean True if the browser is from a mobile device otherwise false
|
311 |
+
*/
|
312 |
+
function isMobile() {
|
313 |
+
return $this->_is_mobile;
|
314 |
+
}
|
315 |
+
|
316 |
+
/**
|
317 |
+
* Is the browser from a robot (ex Slurp,GoogleBot)?
|
318 |
+
*
|
319 |
+
* @return boolean True if the browser is from a robot otherwise false
|
320 |
+
*/
|
321 |
+
function isRobot() {
|
322 |
+
return $this->_is_robot;
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* Set the browser to be from AOL
|
327 |
+
*
|
328 |
+
* @param $isAol
|
329 |
+
*/
|
330 |
+
function setAol( $isAol ) {
|
331 |
+
$this->_is_aol = $isAol;
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Set the Browser to be mobile
|
336 |
+
*
|
337 |
+
* @param boolean $value is the browser a mobile brower or not
|
338 |
+
*/
|
339 |
+
function setMobile( $value = true ) {
|
340 |
+
$this->_is_mobile = $value;
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Set the Browser to be a robot
|
345 |
+
*
|
346 |
+
* @param boolean $value is the browser a robot or not
|
347 |
+
*/
|
348 |
+
function setRobot( $value = true ) {
|
349 |
+
$this->_is_robot = $value;
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Get the user agent value in use to determine the browser
|
354 |
+
*
|
355 |
+
* @return string The user agent from the HTTP header
|
356 |
+
*/
|
357 |
+
function getUserAgent() {
|
358 |
+
return $this->_agent;
|
359 |
+
}
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
|
363 |
+
*
|
364 |
+
* @param $agent_string The value for the User Agent
|
365 |
+
*/
|
366 |
+
function setUserAgent( $agent_string ) {
|
367 |
+
$this->reset();
|
368 |
+
$this->_agent = $agent_string;
|
369 |
+
$this->determine();
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Used to determine if the browser is actually "chromeframe"
|
374 |
+
*
|
375 |
+
* @since 1.7
|
376 |
+
* @return boolean True if the browser is using chromeframe
|
377 |
+
*/
|
378 |
+
function isChromeFrame() {
|
379 |
+
return ( strpos( $this->_agent, 'chromeframe' ) !== false );
|
380 |
+
}
|
381 |
+
|
382 |
+
/**
|
383 |
+
* Returns a formatted string with a summary of the details of the browser.
|
384 |
+
*
|
385 |
+
* @return string formatted string with a summary of the browser
|
386 |
+
*/
|
387 |
+
function __toString() {
|
388 |
+
$text1 = $this->getUserAgent(); // Grabs the UA string
|
389 |
+
$UAline1 = substr( $text1, 0, 32 ); // The first line we print should only be the first 32 characters of the UA string
|
390 |
+
$text2 = $this->getUserAgent(); // Now we grab it again and save it to a string
|
391 |
+
$towrapUA = str_replace( $UAline1, '', $text2 ); // The rest of the printoff (other than first line) is equivalent
|
392 |
+
// to the whole string minus the part we printed off. IE
|
393 |
+
// User Agent: thefirst32charactersfromUAline1
|
394 |
+
// the rest of it is now stored in
|
395 |
+
// $text2 to be printed off
|
396 |
+
// But we need to add spaces before each line that is split other than line 1
|
397 |
+
$space = '';
|
398 |
+
for ( $i = 0; $i < 25; $i ++ ) {
|
399 |
+
$space .= ' ';
|
400 |
+
}
|
401 |
+
|
402 |
+
// Now we split the remaining string of UA ($text2) into lines that are prefixed by spaces for formatting
|
403 |
+
$wordwrapped = chunk_split( $towrapUA, 32, "\n $space" );
|
404 |
+
|
405 |
+
return "Platform: {$this->getPlatform()} \n" .
|
406 |
+
"Browser Name: {$this->getBrowser()} \n" .
|
407 |
+
"Browser Version: {$this->getVersion()} \n" .
|
408 |
+
"User Agent String: $UAline1 \n\t\t\t " .
|
409 |
+
"$wordwrapped";
|
410 |
+
}
|
411 |
+
|
412 |
+
/**
|
413 |
+
* Protected routine to calculate and determine what the browser is in use (including platform)
|
414 |
+
*/
|
415 |
+
function determine() {
|
416 |
+
$this->checkPlatform();
|
417 |
+
$this->checkBrowsers();
|
418 |
+
$this->checkForAol();
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Protected routine to determine the browser type
|
423 |
+
*
|
424 |
+
* @return boolean True if the browser was detected otherwise false
|
425 |
+
*/
|
426 |
+
function checkBrowsers() {
|
427 |
+
return (
|
428 |
+
// Well-known, well-used
|
429 |
+
// Special Notes:
|
430 |
+
// (1) Opera must be checked before FireFox due to the odd
|
431 |
+
// user agents used in some older versions of Opera
|
432 |
+
// (2) WebTV is strapped onto Internet Explorer so we must
|
433 |
+
// check for WebTV before IE
|
434 |
+
// (3) (deprecated) Galeon is based on Firefox and needs to be
|
435 |
+
// tested before Firefox is tested
|
436 |
+
// (4) OmniWeb is based on Safari so OmniWeb check must occur
|
437 |
+
// before Safari
|
438 |
+
// (5) Netscape 9+ is based on Firefox so Netscape checks
|
439 |
+
// before FireFox are necessary
|
440 |
+
$this->checkBrowserWebTv() ||
|
441 |
+
$this->checkBrowserInternetExplorer() ||
|
442 |
+
$this->checkBrowserOpera() ||
|
443 |
+
$this->checkBrowserGaleon() ||
|
444 |
+
$this->checkBrowserNetscapeNavigator9Plus() ||
|
445 |
+
$this->checkBrowserFirefox() ||
|
446 |
+
$this->checkBrowserChrome() ||
|
447 |
+
$this->checkBrowserOmniWeb() ||
|
448 |
+
|
449 |
+
// Common mobile
|
450 |
+
$this->checkBrowserAndroid() ||
|
451 |
+
$this->checkBrowseriPad() ||
|
452 |
+
$this->checkBrowseriPod() ||
|
453 |
+
$this->checkBrowseriPhone() ||
|
454 |
+
$this->checkBrowserBlackBerry() ||
|
455 |
+
$this->checkBrowserNokia() ||
|
456 |
+
|
457 |
+
// Common bots
|
458 |
+
$this->checkBrowserGoogleBot() ||
|
459 |
+
$this->checkBrowserMSNBot() ||
|
460 |
+
$this->checkBrowserSlurp() ||
|
461 |
+
|
462 |
+
// WebKit base check (post mobile and others)
|
463 |
+
$this->checkBrowserSafari() ||
|
464 |
+
|
465 |
+
// Everyone else
|
466 |
+
$this->checkBrowserNetPositive() ||
|
467 |
+
$this->checkBrowserFirebird() ||
|
468 |
+
$this->checkBrowserKonqueror() ||
|
469 |
+
$this->checkBrowserIcab() ||
|
470 |
+
$this->checkBrowserPhoenix() ||
|
471 |
+
$this->checkBrowserAmaya() ||
|
472 |
+
$this->checkBrowserLynx() ||
|
473 |
+
|
474 |
+
$this->checkBrowserShiretoko() ||
|
475 |
+
$this->checkBrowserIceCat() ||
|
476 |
+
$this->checkBrowserW3CValidator() ||
|
477 |
+
$this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
|
478 |
+
);
|
479 |
+
}
|
480 |
+
|
481 |
+
/**
|
482 |
+
* Determine if the user is using a BlackBerry (last updated 1.7)
|
483 |
+
*
|
484 |
+
* @return boolean True if the browser is the BlackBerry browser otherwise false
|
485 |
+
*/
|
486 |
+
function checkBrowserBlackBerry() {
|
487 |
+
if ( stripos( $this->_agent, 'blackberry' ) !== false ) {
|
488 |
+
$aresult = explode( '/', stristr( $this->_agent, 'BlackBerry' ) );
|
489 |
+
$aversion = explode( ' ', $aresult[1] );
|
490 |
+
$this->setVersion( $aversion[0] );
|
491 |
+
$this->_browser_name = $this->BROWSER_BLACKBERRY;
|
492 |
+
$this->setMobile( true );
|
493 |
+
|
494 |
+
return true;
|
495 |
+
}
|
496 |
+
|
497 |
+
return false;
|
498 |
+
}
|
499 |
+
|
500 |
+
/**
|
501 |
+
* Determine if the user is using an AOL User Agent (last updated 1.7)
|
502 |
+
*
|
503 |
+
* @return boolean True if the browser is from AOL otherwise false
|
504 |
+
*/
|
505 |
+
function checkForAol() {
|
506 |
+
$this->setAol( false );
|
507 |
+
$this->setAolVersion( $this->VERSION_UNKNOWN );
|
508 |
+
|
509 |
+
if ( stripos( $this->_agent, 'aol' ) !== false ) {
|
510 |
+
$aversion = explode( ' ', stristr( $this->_agent, 'AOL' ) );
|
511 |
+
$this->setAol( true );
|
512 |
+
$this->setAolVersion( preg_replace( '/[^0-9\.a-z]/i', '', $aversion[1] ) );
|
513 |
+
|
514 |
+
return true;
|
515 |
+
}
|
516 |
+
|
517 |
+
return false;
|
518 |
+
}
|
519 |
+
|
520 |
+
/**
|
521 |
+
* Determine if the browser is the GoogleBot or not (last updated 1.7)
|
522 |
+
*
|
523 |
+
* @return boolean True if the browser is the GoogletBot otherwise false
|
524 |
+
*/
|
525 |
+
function checkBrowserGoogleBot() {
|
526 |
+
if ( stripos( $this->_agent, 'googlebot' ) !== false ) {
|
527 |
+
$aresult = explode( '/', stristr( $this->_agent, 'googlebot' ) );
|
528 |
+
$aversion = explode( ' ', $aresult[1] );
|
529 |
+
$this->setVersion( str_replace( ';', '', $aversion[0] ) );
|
530 |
+
$this->_browser_name = $this->BROWSER_GOOGLEBOT;
|
531 |
+
$this->setRobot( true );
|
532 |
+
|
533 |
+
return true;
|
534 |
+
}
|
535 |
+
|
536 |
+
return false;
|
537 |
+
}
|
538 |
+
|
539 |
+
/**
|
540 |
+
* Determine if the browser is the MSNBot or not (last updated 1.9)
|
541 |
+
*
|
542 |
+
* @return boolean True if the browser is the MSNBot otherwise false
|
543 |
+
*/
|
544 |
+
function checkBrowserMSNBot() {
|
545 |
+
if ( stripos( $this->_agent, 'msnbot' ) !== false ) {
|
546 |
+
$aresult = explode( '/', stristr( $this->_agent, 'msnbot' ) );
|
547 |
+
$aversion = explode( ' ', $aresult[1] );
|
548 |
+
$this->setVersion( str_replace( ';', '', $aversion[0] ) );
|
549 |
+
$this->_browser_name = $this->BROWSER_MSNBOT;
|
550 |
+
$this->setRobot( true );
|
551 |
+
|
552 |
+
return true;
|
553 |
+
}
|
554 |
+
|
555 |
+
return false;
|
556 |
+
}
|
557 |
+
|
558 |
+
/**
|
559 |
+
* Determine if the browser is the W3C Validator or not (last updated 1.7)
|
560 |
+
*
|
561 |
+
* @return boolean True if the browser is the W3C Validator otherwise false
|
562 |
+
*/
|
563 |
+
function checkBrowserW3CValidator() {
|
564 |
+
if ( stripos( $this->_agent, 'W3C-checklink' ) !== false ) {
|
565 |
+
$aresult = explode( '/', stristr( $this->_agent, 'W3C-checklink' ) );
|
566 |
+
$aversion = explode( ' ', $aresult[1] );
|
567 |
+
$this->setVersion( $aversion[0] );
|
568 |
+
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
569 |
+
|
570 |
+
return true;
|
571 |
+
} elseif ( stripos( $this->_agent, 'W3C_Validator' ) !== false ) {
|
572 |
+
// Some of the Validator versions do not delineate w/ a slash - add it back in
|
573 |
+
$ua = str_replace( 'W3C_Validator ', 'W3C_Validator/', $this->_agent );
|
574 |
+
$aresult = explode( '/', stristr( $ua, 'W3C_Validator' ) );
|
575 |
+
$aversion = explode( ' ', $aresult[1] );
|
576 |
+
$this->setVersion( $aversion[0] );
|
577 |
+
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
578 |
+
|
579 |
+
return true;
|
580 |
+
}
|
581 |
+
|
582 |
+
return false;
|
583 |
+
}
|
584 |
+
|
585 |
+
/**
|
586 |
+
* Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
|
587 |
+
*
|
588 |
+
* @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
|
589 |
+
*/
|
590 |
+
function checkBrowserSlurp() {
|
591 |
+
if ( stripos( $this->_agent, 'slurp' ) !== false ) {
|
592 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Slurp' ) );
|
593 |
+
$aversion = explode( ' ', $aresult[1] );
|
594 |
+
$this->setVersion( $aversion[0] );
|
595 |
+
$this->_browser_name = $this->BROWSER_SLURP;
|
596 |
+
$this->setRobot( true );
|
597 |
+
$this->setMobile( false );
|
598 |
+
|
599 |
+
return true;
|
600 |
+
}
|
601 |
+
|
602 |
+
return false;
|
603 |
+
}
|
604 |
+
|
605 |
+
/**
|
606 |
+
* Determine if the browser is Internet Explorer or not (last updated 1.7)
|
607 |
+
*
|
608 |
+
* @return boolean True if the browser is Internet Explorer otherwise false
|
609 |
+
*/
|
610 |
+
function checkBrowserInternetExplorer() {
|
611 |
+
|
612 |
+
// Test for v1 - v1.5 IE
|
613 |
+
if ( stripos( $this->_agent, 'microsoft internet explorer' ) !== false ) {
|
614 |
+
$this->setBrowser( $this->BROWSER_IE );
|
615 |
+
$this->setVersion( '1.0' );
|
616 |
+
$aresult = stristr( $this->_agent, '/' );
|
617 |
+
if ( preg_match( '/308|425|426|474|0b1/i', $aresult ) ) {
|
618 |
+
$this->setVersion( '1.5' );
|
619 |
+
}
|
620 |
+
|
621 |
+
return true;
|
622 |
+
// Test for versions > 1.5
|
623 |
+
} elseif ( stripos( $this->_agent, 'msie' ) !== false && stripos( $this->_agent, 'opera' ) === false ) {
|
624 |
+
// See if the browser is the odd MSN Explorer
|
625 |
+
if ( stripos( $this->_agent, 'msnb' ) !== false ) {
|
626 |
+
$aresult = explode( ' ', stristr( str_replace( ';', '; ', $this->_agent ), 'MSN' ) );
|
627 |
+
$this->setBrowser( $this->BROWSER_MSN );
|
628 |
+
$this->setVersion( str_replace( array( '(', ')', ';' ), '', $aresult[1] ) );
|
629 |
+
|
630 |
+
return true;
|
631 |
+
}
|
632 |
+
$aresult = explode( ' ', stristr( str_replace( ';', '; ', $this->_agent ), 'msie' ) );
|
633 |
+
$this->setBrowser( $this->BROWSER_IE );
|
634 |
+
$this->setVersion( str_replace( array( '(', ')', ';' ), '', $aresult[1] ) );
|
635 |
+
|
636 |
+
return true;
|
637 |
+
// Test for Pocket IE
|
638 |
+
} elseif ( stripos( $this->_agent, 'mspie' ) !== false || stripos( $this->_agent, 'pocket' ) !== false ) {
|
639 |
+
$aresult = explode( ' ', stristr( $this->_agent, 'mspie' ) );
|
640 |
+
$this->setPlatform( $this->PLATFORM_WINDOWS_CE );
|
641 |
+
$this->setBrowser( $this->BROWSER_POCKET_IE );
|
642 |
+
$this->setMobile( true );
|
643 |
+
|
644 |
+
if ( stripos( $this->_agent, 'mspie' ) !== false ) {
|
645 |
+
$this->setVersion( $aresult[1] );
|
646 |
+
} else {
|
647 |
+
$aversion = explode( '/', $this->_agent );
|
648 |
+
$this->setVersion( $aversion[1] );
|
649 |
+
}
|
650 |
+
|
651 |
+
return true;
|
652 |
+
}// End if().
|
653 |
+
|
654 |
+
return false;
|
655 |
+
}
|
656 |
+
|
657 |
+
/**
|
658 |
+
* Determine if the browser is Opera or not (last updated 1.7)
|
659 |
+
*
|
660 |
+
* @return boolean True if the browser is Opera otherwise false
|
661 |
+
*/
|
662 |
+
function checkBrowserOpera() {
|
663 |
+
if ( stripos( $this->_agent, 'opera mini' ) !== false ) {
|
664 |
+
$resultant = stristr( $this->_agent, 'opera mini' );
|
665 |
+
if ( preg_match( '/\//', $resultant ) ) {
|
666 |
+
$aresult = explode( '/', $resultant );
|
667 |
+
$aversion = explode( ' ', $aresult[1] );
|
668 |
+
$this->setVersion( $aversion[0] );
|
669 |
+
} else {
|
670 |
+
$aversion = explode( ' ', stristr( $resultant, 'opera mini' ) );
|
671 |
+
$this->setVersion( $aversion[1] );
|
672 |
+
}
|
673 |
+
$this->_browser_name = $this->BROWSER_OPERA_MINI;
|
674 |
+
$this->setMobile( true );
|
675 |
+
|
676 |
+
return true;
|
677 |
+
} elseif ( stripos( $this->_agent, 'opera' ) !== false ) {
|
678 |
+
$resultant = stristr( $this->_agent, 'opera' );
|
679 |
+
if ( preg_match( '/Version\/(10.*)$/', $resultant, $matches ) ) {
|
680 |
+
$this->setVersion( $matches[1] );
|
681 |
+
} elseif ( preg_match( '/\//', $resultant ) ) {
|
682 |
+
$aresult = explode( '/', str_replace( '(', ' ', $resultant ) );
|
683 |
+
$aversion = explode( ' ', $aresult[1] );
|
684 |
+
$this->setVersion( $aversion[0] );
|
685 |
+
} else {
|
686 |
+
$aversion = explode( ' ', stristr( $resultant, 'opera' ) );
|
687 |
+
$this->setVersion( isset( $aversion[1] ) ? $aversion[1] : '' );
|
688 |
+
}
|
689 |
+
$this->_browser_name = $this->BROWSER_OPERA;
|
690 |
+
|
691 |
+
return true;
|
692 |
+
}
|
693 |
+
|
694 |
+
return false;
|
695 |
+
}
|
696 |
+
|
697 |
+
/**
|
698 |
+
* Determine if the browser is Chrome or not (last updated 1.7)
|
699 |
+
*
|
700 |
+
* @return boolean True if the browser is Chrome otherwise false
|
701 |
+
*/
|
702 |
+
function checkBrowserChrome() {
|
703 |
+
if ( stripos( $this->_agent, 'Chrome' ) !== false ) {
|
704 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Chrome' ) );
|
705 |
+
$aversion = explode( ' ', $aresult[1] );
|
706 |
+
$this->setVersion( $aversion[0] );
|
707 |
+
$this->setBrowser( $this->BROWSER_CHROME );
|
708 |
+
|
709 |
+
return true;
|
710 |
+
}
|
711 |
+
|
712 |
+
return false;
|
713 |
+
}
|
714 |
+
|
715 |
+
|
716 |
+
/**
|
717 |
+
* Determine if the browser is WebTv or not (last updated 1.7)
|
718 |
+
*
|
719 |
+
* @return boolean True if the browser is WebTv otherwise false
|
720 |
+
*/
|
721 |
+
function checkBrowserWebTv() {
|
722 |
+
if ( stripos( $this->_agent, 'webtv' ) !== false ) {
|
723 |
+
$aresult = explode( '/', stristr( $this->_agent, 'webtv' ) );
|
724 |
+
$aversion = explode( ' ', $aresult[1] );
|
725 |
+
$this->setVersion( $aversion[0] );
|
726 |
+
$this->setBrowser( $this->BROWSER_WEBTV );
|
727 |
+
|
728 |
+
return true;
|
729 |
+
}
|
730 |
+
|
731 |
+
return false;
|
732 |
+
}
|
733 |
+
|
734 |
+
/**
|
735 |
+
* Determine if the browser is NetPositive or not (last updated 1.7)
|
736 |
+
*
|
737 |
+
* @return boolean True if the browser is NetPositive otherwise false
|
738 |
+
*/
|
739 |
+
function checkBrowserNetPositive() {
|
740 |
+
if ( stripos( $this->_agent, 'NetPositive' ) !== false ) {
|
741 |
+
$aresult = explode( '/', stristr( $this->_agent, 'NetPositive' ) );
|
742 |
+
$aversion = explode( ' ', $aresult[1] );
|
743 |
+
$this->setVersion( str_replace( array( '(', ')', ';' ), '', $aversion[0] ) );
|
744 |
+
$this->setBrowser( $this->BROWSER_NETPOSITIVE );
|
745 |
+
|
746 |
+
return true;
|
747 |
+
}
|
748 |
+
|
749 |
+
return false;
|
750 |
+
}
|
751 |
+
|
752 |
+
/**
|
753 |
+
* Determine if the browser is Galeon or not (last updated 1.7)
|
754 |
+
*
|
755 |
+
* @return boolean True if the browser is Galeon otherwise false
|
756 |
+
*/
|
757 |
+
function checkBrowserGaleon() {
|
758 |
+
if ( stripos( $this->_agent, 'galeon' ) !== false ) {
|
759 |
+
$aresult = explode( ' ', stristr( $this->_agent, 'galeon' ) );
|
760 |
+
$aversion = explode( '/', $aresult[0] );
|
761 |
+
$this->setVersion( $aversion[1] );
|
762 |
+
$this->setBrowser( $this->BROWSER_GALEON );
|
763 |
+
|
764 |
+
return true;
|
765 |
+
}
|
766 |
+
|
767 |
+
return false;
|
768 |
+
}
|
769 |
+
|
770 |
+
/**
|
771 |
+
* Determine if the browser is Konqueror or not (last updated 1.7)
|
772 |
+
*
|
773 |
+
* @return boolean True if the browser is Konqueror otherwise false
|
774 |
+
*/
|
775 |
+
function checkBrowserKonqueror() {
|
776 |
+
if ( stripos( $this->_agent, 'Konqueror' ) !== false ) {
|
777 |
+
$aresult = explode( ' ', stristr( $this->_agent, 'Konqueror' ) );
|
778 |
+
$aversion = explode( '/', $aresult[0] );
|
779 |
+
$this->setVersion( $aversion[1] );
|
780 |
+
$this->setBrowser( $this->BROWSER_KONQUEROR );
|
781 |
+
|
782 |
+
return true;
|
783 |
+
}
|
784 |
+
|
785 |
+
return false;
|
786 |
+
}
|
787 |
+
|
788 |
+
/**
|
789 |
+
* Determine if the browser is iCab or not (last updated 1.7)
|
790 |
+
*
|
791 |
+
* @return boolean True if the browser is iCab otherwise false
|
792 |
+
*/
|
793 |
+
function checkBrowserIcab() {
|
794 |
+
if ( stripos( $this->_agent, 'icab' ) !== false ) {
|
795 |
+
$aversion = explode( ' ', stristr( str_replace( '/', ' ', $this->_agent ), 'icab' ) );
|
796 |
+
$this->setVersion( $aversion[1] );
|
797 |
+
$this->setBrowser( $this->BROWSER_ICAB );
|
798 |
+
|
799 |
+
return true;
|
800 |
+
}
|
801 |
+
|
802 |
+
return false;
|
803 |
+
}
|
804 |
+
|
805 |
+
/**
|
806 |
+
* Determine if the browser is OmniWeb or not (last updated 1.7)
|
807 |
+
*
|
808 |
+
* @return boolean True if the browser is OmniWeb otherwise false
|
809 |
+
*/
|
810 |
+
function checkBrowserOmniWeb() {
|
811 |
+
if ( stripos( $this->_agent, 'omniweb' ) !== false ) {
|
812 |
+
$aresult = explode( '/', stristr( $this->_agent, 'omniweb' ) );
|
813 |
+
$aversion = explode( ' ', isset( $aresult[1] ) ? $aresult[1] : '' );
|
814 |
+
$this->setVersion( $aversion[0] );
|
815 |
+
$this->setBrowser( $this->BROWSER_OMNIWEB );
|
816 |
+
|
817 |
+
return true;
|
818 |
+
}
|
819 |
+
|
820 |
+
return false;
|
821 |
+
}
|
822 |
+
|
823 |
+
/**
|
824 |
+
* Determine if the browser is Phoenix or not (last updated 1.7)
|
825 |
+
*
|
826 |
+
* @return boolean True if the browser is Phoenix otherwise false
|
827 |
+
*/
|
828 |
+
function checkBrowserPhoenix() {
|
829 |
+
if ( stripos( $this->_agent, 'Phoenix' ) !== false ) {
|
830 |
+
$aversion = explode( '/', stristr( $this->_agent, 'Phoenix' ) );
|
831 |
+
$this->setVersion( $aversion[1] );
|
832 |
+
$this->setBrowser( $this->BROWSER_PHOENIX );
|
833 |
+
|
834 |
+
return true;
|
835 |
+
}
|
836 |
+
|
837 |
+
return false;
|
838 |
+
}
|
839 |
+
|
840 |
+
/**
|
841 |
+
* Determine if the browser is Firebird or not (last updated 1.7)
|
842 |
+
*
|
843 |
+
* @return boolean True if the browser is Firebird otherwise false
|
844 |
+
*/
|
845 |
+
function checkBrowserFirebird() {
|
846 |
+
if ( stripos( $this->_agent, 'Firebird' ) !== false ) {
|
847 |
+
$aversion = explode( '/', stristr( $this->_agent, 'Firebird' ) );
|
848 |
+
$this->setVersion( $aversion[1] );
|
849 |
+
$this->setBrowser( $this->BROWSER_FIREBIRD );
|
850 |
+
|
851 |
+
return true;
|
852 |
+
}
|
853 |
+
|
854 |
+
return false;
|
855 |
+
}
|
856 |
+
|
857 |
+
/**
|
858 |
+
* Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
|
859 |
+
* NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
|
860 |
+
*
|
861 |
+
* @return boolean True if the browser is Netscape Navigator 9+ otherwise false
|
862 |
+
*/
|
863 |
+
function checkBrowserNetscapeNavigator9Plus() {
|
864 |
+
if ( stripos( $this->_agent, 'Firefox' ) !== false && preg_match( '/Navigator\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
865 |
+
$this->setVersion( $matches[1] );
|
866 |
+
$this->setBrowser( $this->BROWSER_NETSCAPE_NAVIGATOR );
|
867 |
+
|
868 |
+
return true;
|
869 |
+
} elseif ( stripos( $this->_agent, 'Firefox' ) === false && preg_match( '/Netscape6?\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
870 |
+
$this->setVersion( $matches[1] );
|
871 |
+
$this->setBrowser( $this->BROWSER_NETSCAPE_NAVIGATOR );
|
872 |
+
|
873 |
+
return true;
|
874 |
+
}
|
875 |
+
|
876 |
+
return false;
|
877 |
+
}
|
878 |
+
|
879 |
+
/**
|
880 |
+
* Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
|
881 |
+
*
|
882 |
+
* @return boolean True if the browser is Shiretoko otherwise false
|
883 |
+
*/
|
884 |
+
function checkBrowserShiretoko() {
|
885 |
+
if ( stripos( $this->_agent, 'Mozilla' ) !== false && preg_match( '/Shiretoko\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
886 |
+
$this->setVersion( $matches[1] );
|
887 |
+
$this->setBrowser( $this->BROWSER_SHIRETOKO );
|
888 |
+
|
889 |
+
return true;
|
890 |
+
}
|
891 |
+
|
892 |
+
return false;
|
893 |
+
}
|
894 |
+
|
895 |
+
/**
|
896 |
+
* Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
|
897 |
+
*
|
898 |
+
* @return boolean True if the browser is Ice Cat otherwise false
|
899 |
+
*/
|
900 |
+
function checkBrowserIceCat() {
|
901 |
+
if ( stripos( $this->_agent, 'Mozilla' ) !== false && preg_match( '/IceCat\/([^ ]*)/i', $this->_agent, $matches ) ) {
|
902 |
+
$this->setVersion( $matches[1] );
|
903 |
+
$this->setBrowser( $this->BROWSER_ICECAT );
|
904 |
+
|
905 |
+
return true;
|
906 |
+
}
|
907 |
+
|
908 |
+
return false;
|
909 |
+
}
|
910 |
+
|
911 |
+
/**
|
912 |
+
* Determine if the browser is Nokia or not (last updated 1.7)
|
913 |
+
*
|
914 |
+
* @return boolean True if the browser is Nokia otherwise false
|
915 |
+
*/
|
916 |
+
function checkBrowserNokia() {
|
917 |
+
if ( preg_match( '/Nokia([^\/]+)\/([^ SP]+)/i', $this->_agent, $matches ) ) {
|
918 |
+
$this->setVersion( $matches[2] );
|
919 |
+
if ( stripos( $this->_agent, 'Series60' ) !== false || strpos( $this->_agent, 'S60' ) !== false ) {
|
920 |
+
$this->setBrowser( $this->BROWSER_NOKIA_S60 );
|
921 |
+
} else {
|
922 |
+
$this->setBrowser( $this->BROWSER_NOKIA );
|
923 |
+
}
|
924 |
+
$this->setMobile( true );
|
925 |
+
|
926 |
+
return true;
|
927 |
+
}
|
928 |
+
|
929 |
+
return false;
|
930 |
+
}
|
931 |
+
|
932 |
+
/**
|
933 |
+
* Determine if the browser is Firefox or not (last updated 1.7)
|
934 |
+
*
|
935 |
+
* @return boolean True if the browser is Firefox otherwise false
|
936 |
+
*/
|
937 |
+
function checkBrowserFirefox() {
|
938 |
+
if ( stripos( $this->_agent, 'safari' ) === false ) {
|
939 |
+
if ( preg_match( '/Firefox[\/ \(]([^ ;\)]+)/i', $this->_agent, $matches ) ) {
|
940 |
+
$this->setVersion( $matches[1] );
|
941 |
+
$this->setBrowser( $this->BROWSER_FIREFOX );
|
942 |
+
|
943 |
+
return true;
|
944 |
+
} elseif ( preg_match( '/Firefox$/i', $this->_agent, $matches ) ) {
|
945 |
+
$this->setVersion( '' );
|
946 |
+
$this->setBrowser( $this->BROWSER_FIREFOX );
|
947 |
+
|
948 |
+
return true;
|
949 |
+
}
|
950 |
+
}
|
951 |
+
|
952 |
+
return false;
|
953 |
+
}
|
954 |
+
|
955 |
+
/**
|
956 |
+
* Determine if the browser is Firefox or not (last updated 1.7)
|
957 |
+
*
|
958 |
+
* @return boolean True if the browser is Firefox otherwise false
|
959 |
+
*/
|
960 |
+
function checkBrowserIceweasel() {
|
961 |
+
if ( stripos( $this->_agent, 'Iceweasel' ) !== false ) {
|
962 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Iceweasel' ) );
|
963 |
+
$aversion = explode( ' ', $aresult[1] );
|
964 |
+
$this->setVersion( $aversion[0] );
|
965 |
+
$this->setBrowser( $this->BROWSER_ICEWEASEL );
|
966 |
+
|
967 |
+
return true;
|
968 |
+
}
|
969 |
+
|
970 |
+
return false;
|
971 |
+
}
|
972 |
+
|
973 |
+
/**
|
974 |
+
* Determine if the browser is Mozilla or not (last updated 1.7)
|
975 |
+
*
|
976 |
+
* @return boolean True if the browser is Mozilla otherwise false
|
977 |
+
*/
|
978 |
+
function checkBrowserMozilla() {
|
979 |
+
if ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/rv:[0-9].[0-9][a-b]?/i', $this->_agent ) && stripos( $this->_agent, 'netscape' ) === false ) {
|
980 |
+
$aversion = explode( ' ', stristr( $this->_agent, 'rv:' ) );
|
981 |
+
preg_match( '/rv:[0-9].[0-9][a-b]?/i', $this->_agent, $aversion );
|
982 |
+
$this->setVersion( str_replace( 'rv:', '', $aversion[0] ) );
|
983 |
+
$this->setBrowser( $this->BROWSER_MOZILLA );
|
984 |
+
|
985 |
+
return true;
|
986 |
+
} elseif ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/rv:[0-9]\.[0-9]/i', $this->_agent ) && stripos( $this->_agent, 'netscape' ) === false ) {
|
987 |
+
$aversion = explode( '', stristr( $this->_agent, 'rv:' ) );
|
988 |
+
$this->setVersion( str_replace( 'rv:', '', $aversion[0] ) );
|
989 |
+
$this->setBrowser( $this->BROWSER_MOZILLA );
|
990 |
+
|
991 |
+
return true;
|
992 |
+
} elseif ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/mozilla\/([^ ]*)/i', $this->_agent, $matches ) && stripos( $this->_agent, 'netscape' ) === false ) {
|
993 |
+
$this->setVersion( $matches[1] );
|
994 |
+
$this->setBrowser( $this->BROWSER_MOZILLA );
|
995 |
+
|
996 |
+
return true;
|
997 |
+
}
|
998 |
+
|
999 |
+
return false;
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
/**
|
1003 |
+
* Determine if the browser is Lynx or not (last updated 1.7)
|
1004 |
+
*
|
1005 |
+
* @return boolean True if the browser is Lynx otherwise false
|
1006 |
+
*/
|
1007 |
+
function checkBrowserLynx() {
|
1008 |
+
if ( stripos( $this->_agent, 'lynx' ) !== false ) {
|
1009 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Lynx' ) );
|
1010 |
+
$aversion = explode( ' ', ( isset( $aresult[1] ) ? $aresult[1] : '' ) );
|
1011 |
+
$this->setVersion( $aversion[0] );
|
1012 |
+
$this->setBrowser( $this->BROWSER_LYNX );
|
1013 |
+
|
1014 |
+
return true;
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
return false;
|
1018 |
+
}
|
1019 |
+
|
1020 |
+
/**
|
1021 |
+
* Determine if the browser is Amaya or not (last updated 1.7)
|
1022 |
+
*
|
1023 |
+
* @return boolean True if the browser is Amaya otherwise false
|
1024 |
+
*/
|
1025 |
+
function checkBrowserAmaya() {
|
1026 |
+
if ( stripos( $this->_agent, 'amaya' ) !== false ) {
|
1027 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Amaya' ) );
|
1028 |
+
$aversion = explode( ' ', $aresult[1] );
|
1029 |
+
$this->setVersion( $aversion[0] );
|
1030 |
+
$this->setBrowser( $this->BROWSER_AMAYA );
|
1031 |
+
|
1032 |
+
return true;
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
return false;
|
1036 |
+
}
|
1037 |
+
|
1038 |
+
/**
|
1039 |
+
* Determine if the browser is Safari or not (last updated 1.7)
|
1040 |
+
*
|
1041 |
+
* @return boolean True if the browser is Safari otherwise false
|
1042 |
+
*/
|
1043 |
+
function checkBrowserSafari() {
|
1044 |
+
if ( stripos( $this->_agent, 'Safari' ) !== false && stripos( $this->_agent, 'iPhone' ) === false && stripos( $this->_agent, 'iPod' ) === false ) {
|
1045 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1046 |
+
if ( isset( $aresult[1] ) ) {
|
1047 |
+
$aversion = explode( ' ', $aresult[1] );
|
1048 |
+
$this->setVersion( $aversion[0] );
|
1049 |
+
} else {
|
1050 |
+
$this->setVersion( $this->VERSION_UNKNOWN );
|
1051 |
+
}
|
1052 |
+
$this->setBrowser( $this->BROWSER_SAFARI );
|
1053 |
+
|
1054 |
+
return true;
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
return false;
|
1058 |
+
}
|
1059 |
+
|
1060 |
+
/**
|
1061 |
+
* Determine if the browser is iPhone or not (last updated 1.7)
|
1062 |
+
*
|
1063 |
+
* @return boolean True if the browser is iPhone otherwise false
|
1064 |
+
*/
|
1065 |
+
function checkBrowseriPhone() {
|
1066 |
+
if ( stripos( $this->_agent, 'iPhone' ) !== false ) {
|
1067 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1068 |
+
if ( isset( $aresult[1] ) ) {
|
1069 |
+
$aversion = explode( ' ', $aresult[1] );
|
1070 |
+
$this->setVersion( $aversion[0] );
|
1071 |
+
} else {
|
1072 |
+
$this->setVersion( $this->VERSION_UNKNOWN );
|
1073 |
+
}
|
1074 |
+
$this->setMobile( true );
|
1075 |
+
$this->setBrowser( $this->BROWSER_IPHONE );
|
1076 |
+
|
1077 |
+
return true;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
return false;
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
/**
|
1084 |
+
* Determine if the browser is iPod or not (last updated 1.7)
|
1085 |
+
*
|
1086 |
+
* @return boolean True if the browser is iPod otherwise false
|
1087 |
+
*/
|
1088 |
+
function checkBrowseriPad() {
|
1089 |
+
if ( stripos( $this->_agent, 'iPad' ) !== false ) {
|
1090 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1091 |
+
if ( isset( $aresult[1] ) ) {
|
1092 |
+
$aversion = explode( ' ', $aresult[1] );
|
1093 |
+
$this->setVersion( $aversion[0] );
|
1094 |
+
} else {
|
1095 |
+
$this->setVersion( $this->VERSION_UNKNOWN );
|
1096 |
+
}
|
1097 |
+
$this->setMobile( true );
|
1098 |
+
$this->setBrowser( $this->BROWSER_IPAD );
|
1099 |
+
|
1100 |
+
return true;
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
return false;
|
1104 |
+
}
|
1105 |
+
|
1106 |
+
/**
|
1107 |
+
* Determine if the browser is iPod or not (last updated 1.7)
|
1108 |
+
*
|
1109 |
+
* @return boolean True if the browser is iPod otherwise false
|
1110 |
+
*/
|
1111 |
+
function checkBrowseriPod() {
|
1112 |
+
if ( stripos( $this->_agent, 'iPod' ) !== false ) {
|
1113 |
+
$aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
|
1114 |
+
if ( isset( $aresult[1] ) ) {
|
1115 |
+
$aversion = explode( ' ', $aresult[1] );
|
1116 |
+
$this->setVersion( $aversion[0] );
|
1117 |
+
} else {
|
1118 |
+
$this->setVersion( $this->VERSION_UNKNOWN );
|
1119 |
+
}
|
1120 |
+
$this->setMobile( true );
|
1121 |
+
$this->setBrowser( $this->BROWSER_IPOD );
|
1122 |
+
|
1123 |
+
return true;
|
1124 |
+
}
|
1125 |
+
|
1126 |
+
return false;
|
1127 |
+
}
|
1128 |
+
|
1129 |
+
/**
|
1130 |
+
* Determine if the browser is Android or not (last updated 1.7)
|
1131 |
+
*
|
1132 |
+
* @return boolean True if the browser is Android otherwise false
|
1133 |
+
*/
|
1134 |
+
function checkBrowserAndroid() {
|
1135 |
+
if ( stripos( $this->_agent, 'Android' ) !== false ) {
|
1136 |
+
$aresult = explode( ' ', stristr( $this->_agent, 'Android' ) );
|
1137 |
+
if ( isset( $aresult[1] ) ) {
|
1138 |
+
$aversion = explode( ' ', $aresult[1] );
|
1139 |
+
$this->setVersion( $aversion[0] );
|
1140 |
+
} else {
|
1141 |
+
$this->setVersion( $this->VERSION_UNKNOWN );
|
1142 |
+
}
|
1143 |
+
$this->setMobile( true );
|
1144 |
+
$this->setBrowser( $this->BROWSER_ANDROID );
|
1145 |
+
|
1146 |
+
return true;
|
1147 |
+
}
|
1148 |
+
|
1149 |
+
return false;
|
1150 |
+
}
|
1151 |
+
|
1152 |
+
/**
|
1153 |
+
* Determine the user's platform (last updated 1.7)
|
1154 |
+
*/
|
1155 |
+
function checkPlatform() {
|
1156 |
+
if ( stripos( $this->_agent, 'windows' ) !== false ) {
|
1157 |
+
$this->_platform = $this->PLATFORM_WINDOWS;
|
1158 |
+
} elseif ( stripos( $this->_agent, 'iPad' ) !== false ) {
|
1159 |
+
$this->_platform = $this->PLATFORM_IPAD;
|
1160 |
+
} elseif ( stripos( $this->_agent, 'iPod' ) !== false ) {
|
1161 |
+
$this->_platform = $this->PLATFORM_IPOD;
|
1162 |
+
} elseif ( stripos( $this->_agent, 'iPhone' ) !== false ) {
|
1163 |
+
$this->_platform = $this->PLATFORM_IPHONE;
|
1164 |
+
} elseif ( stripos( $this->_agent, 'mac' ) !== false ) {
|
1165 |
+
$this->_platform = $this->PLATFORM_APPLE;
|
1166 |
+
} elseif ( stripos( $this->_agent, 'android' ) !== false ) {
|
1167 |
+
$this->_platform = $this->PLATFORM_ANDROID;
|
1168 |
+
} elseif ( stripos( $this->_agent, 'linux' ) !== false ) {
|
1169 |
+
$this->_platform = $this->PLATFORM_LINUX;
|
1170 |
+
} elseif ( stripos( $this->_agent, 'Nokia' ) !== false ) {
|
1171 |
+
$this->_platform = $this->PLATFORM_NOKIA;
|
1172 |
+
} elseif ( stripos( $this->_agent, 'BlackBerry' ) !== false ) {
|
1173 |
+
$this->_platform = $this->PLATFORM_BLACKBERRY;
|
1174 |
+
} elseif ( stripos( $this->_agent, 'FreeBSD' ) !== false ) {
|
1175 |
+
$this->_platform = $this->PLATFORM_FREEBSD;
|
1176 |
+
} elseif ( stripos( $this->_agent, 'OpenBSD' ) !== false ) {
|
1177 |
+
$this->_platform = $this->PLATFORM_OPENBSD;
|
1178 |
+
} elseif ( stripos( $this->_agent, 'NetBSD' ) !== false ) {
|
1179 |
+
$this->_platform = $this->PLATFORM_NETBSD;
|
1180 |
+
} elseif ( stripos( $this->_agent, 'OpenSolaris' ) !== false ) {
|
1181 |
+
$this->_platform = $this->PLATFORM_OPENSOLARIS;
|
1182 |
+
} elseif ( stripos( $this->_agent, 'SunOS' ) !== false ) {
|
1183 |
+
$this->_platform = $this->PLATFORM_SUNOS;
|
1184 |
+
} elseif ( stripos( $this->_agent, 'OS\/2' ) !== false ) {
|
1185 |
+
$this->_platform = $this->PLATFORM_OS2;
|
1186 |
+
} elseif ( stripos( $this->_agent, 'BeOS' ) !== false ) {
|
1187 |
+
$this->_platform = $this->PLATFORM_BEOS;
|
1188 |
+
} elseif ( stripos( $this->_agent, 'win' ) !== false ) {
|
1189 |
+
$this->_platform = $this->PLATFORM_WINDOWS;
|
1190 |
+
}
|
1191 |
+
}
|
1192 |
+
}
|
1193 |
+
}// End if().
|
includes/control-panel/includes/class-customizer-option.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* A class that extends WP_Customize_Setting so we can access
|
5 |
-
* the protected updated method when importing options.
|
6 |
-
*
|
7 |
-
* @since 0.3
|
8 |
-
*/
|
9 |
-
|
10 |
-
require_once ABSPATH . 'wp-includes/class-wp-customize-setting.php';
|
11 |
-
|
12 |
-
if ( ! class_exists( 'JupiterX_Customizer_Option' ) ) {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Customizer option class.
|
16 |
-
*
|
17 |
-
* @since 1.9.0
|
18 |
-
*/
|
19 |
-
final class JupiterX_Customizer_Option extends WP_Customize_Setting {
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Import an option value for this setting.
|
23 |
-
*
|
24 |
-
* @since 0.3
|
25 |
-
* @param mixed $value The option value.
|
26 |
-
* @return void
|
27 |
-
*/
|
28 |
-
public function import( $value )
|
29 |
-
{
|
30 |
-
$this->update( $value );
|
31 |
-
}
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A class that extends WP_Customize_Setting so we can access
|
5 |
+
* the protected updated method when importing options.
|
6 |
+
*
|
7 |
+
* @since 0.3
|
8 |
+
*/
|
9 |
+
|
10 |
+
require_once ABSPATH . 'wp-includes/class-wp-customize-setting.php';
|
11 |
+
|
12 |
+
if ( ! class_exists( 'JupiterX_Customizer_Option' ) ) {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Customizer option class.
|
16 |
+
*
|
17 |
+
* @since 1.9.0
|
18 |
+
*/
|
19 |
+
final class JupiterX_Customizer_Option extends WP_Customize_Setting {
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Import an option value for this setting.
|
23 |
+
*
|
24 |
+
* @since 0.3
|
25 |
+
* @param mixed $value The option value.
|
26 |
+
* @return void
|
27 |
+
*/
|
28 |
+
public function import( $value )
|
29 |
+
{
|
30 |
+
$this->update( $value );
|
31 |
+
}
|
32 |
+
}
|
33 |
+
}
|
includes/control-panel/includes/class-db-manager.php
CHANGED
@@ -1,691 +1,691 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Handles database for restoring or creating backups.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel\Database_Manager
|
6 |
-
*
|
7 |
-
* @since 1.9.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Database_Manager' ) ) {
|
11 |
-
/**
|
12 |
-
* Database manager class.
|
13 |
-
*
|
14 |
-
* @since 1.9.0
|
15 |
-
*/
|
16 |
-
class JupiterX_Control_Panel_Database_Manager {
|
17 |
-
|
18 |
-
/**
|
19 |
-
* @var object
|
20 |
-
*/
|
21 |
-
public $errors;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* @var string
|
25 |
-
*/
|
26 |
-
private $basedir;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @var string
|
30 |
-
*/
|
31 |
-
private $backup_dir;
|
32 |
-
|
33 |
-
/**
|
34 |
-
* @var string
|
35 |
-
*/
|
36 |
-
private $dir_prefix;
|
37 |
-
|
38 |
-
/**
|
39 |
-
* @var string
|
40 |
-
*/
|
41 |
-
private $baseurl;
|
42 |
-
|
43 |
-
/**
|
44 |
-
* @var string
|
45 |
-
*/
|
46 |
-
private $backup_url;
|
47 |
-
|
48 |
-
/**
|
49 |
-
* @var object
|
50 |
-
*/
|
51 |
-
private $jupiterx_filesystem;
|
52 |
-
|
53 |
-
/*====================== MAIN SECTION ============================*/
|
54 |
-
/**
|
55 |
-
* The class constructor
|
56 |
-
*
|
57 |
-
* @param $dir_prefix
|
58 |
-
*/
|
59 |
-
public function __construct( $dir_prefix = 'jupiterx_backups' ) {
|
60 |
-
$this->errors = new WP_Error();
|
61 |
-
$this->dir_prefix = $dir_prefix;
|
62 |
-
$this->init();
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Initialize the FS
|
67 |
-
*
|
68 |
-
* @var boolean
|
69 |
-
*/
|
70 |
-
private function init() {
|
71 |
-
|
72 |
-
$wp_upload_dir = wp_upload_dir();
|
73 |
-
|
74 |
-
if ( ! empty( $wp_upload_dir['error'] ) ) {
|
75 |
-
$this->errors->add( 'unable_to_create_upload_directory', $wp_upload_dir['error'] );
|
76 |
-
|
77 |
-
return false;
|
78 |
-
}
|
79 |
-
|
80 |
-
$this->basedir = $wp_upload_dir['basedir'];
|
81 |
-
|
82 |
-
$this->baseurl = $wp_upload_dir['baseurl'];
|
83 |
-
|
84 |
-
$this->jupiterx_filesystem = new JupiterX_Filesystem(
|
85 |
-
[
|
86 |
-
'context' => $this->basedir,
|
87 |
-
]
|
88 |
-
);
|
89 |
-
|
90 |
-
if ( $this->jupiterx_filesystem->get_error_code() ) {
|
91 |
-
$this->errors->add( $this->jupiterx_filesystem->get_error_code(), $this->jupiterx_filesystem->get_error_message() );
|
92 |
-
|
93 |
-
return false;
|
94 |
-
}
|
95 |
-
|
96 |
-
$this->backup_dir = trailingslashit( $this->basedir ) . $this->dir_prefix;
|
97 |
-
|
98 |
-
$this->backup_url = trailingslashit( $this->baseurl ) . $this->dir_prefix;
|
99 |
-
|
100 |
-
// Create index html file
|
101 |
-
if ( ! $this->jupiterx_filesystem->exists( trailingslashit( $this->backup_dir ) . 'index.html' ) ) {
|
102 |
-
$this->jupiterx_filesystem->touch( trailingslashit( $this->backup_dir ) . 'index.html' );
|
103 |
-
}
|
104 |
-
|
105 |
-
if ( ! $this->jupiterx_filesystem->exists( trailingslashit( $this->backup_dir ) . '.htaccess' ) ) {
|
106 |
-
$htaccess_content = '<IfModule mod_rewrite.c>' . "\n" .
|
107 |
-
'RewriteEngine On' . "\n" .
|
108 |
-
'RewriteCond %{REQUEST_FILENAME} ^.*(sql|zip)$' . "\n" .
|
109 |
-
'RewriteRule . - [R=403,L]' . "\n" .
|
110 |
-
'</IfModule>' . "\n";
|
111 |
-
$this->jupiterx_filesystem->put_contents( trailingslashit( $this->backup_dir ) . '.htaccess', $htaccess_content );
|
112 |
-
}
|
113 |
-
|
114 |
-
return true;
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Backup current site database
|
119 |
-
*
|
120 |
-
* @return boolean
|
121 |
-
*/
|
122 |
-
public function backup_db() {
|
123 |
-
// Do not execute if there was as error in initialization
|
124 |
-
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
125 |
-
return false;
|
126 |
-
}
|
127 |
-
|
128 |
-
$file_name = 'dump-' . current_time( 'timestamp' ) . '-' . md5( uniqid() );
|
129 |
-
|
130 |
-
$dump_file_name = $file_name . '.sql';
|
131 |
-
$dump_file_path = $this->get_backup_dir( $dump_file_name );
|
132 |
-
|
133 |
-
$zip_file_name = $file_name . '.zip';
|
134 |
-
$zip_file_path = $this->get_backup_dir( $zip_file_name );
|
135 |
-
|
136 |
-
$dumped = $this->dump_db( $dump_file_path );
|
137 |
-
|
138 |
-
if ( ! $dumped ) {
|
139 |
-
$this->errors->add( 'can_not_create_backup_db_file', __( 'Can not create backup db file.', 'jupiterx-core' ) );
|
140 |
-
|
141 |
-
return false;
|
142 |
-
}
|
143 |
-
|
144 |
-
if ( $this->jupiterx_filesystem->zip(
|
145 |
-
[
|
146 |
-
$dump_file_name => $dump_file_path,
|
147 |
-
], $zip_file_path
|
148 |
-
) ) {
|
149 |
-
$this->jupiterx_filesystem->delete( $dump_file_path );
|
150 |
-
}
|
151 |
-
|
152 |
-
return true;
|
153 |
-
}
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Backup current site media records
|
157 |
-
*
|
158 |
-
* @return boolean
|
159 |
-
*/
|
160 |
-
public function backup_media_records() {
|
161 |
-
// Do not execute if there was as error in initialization
|
162 |
-
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
163 |
-
return false;
|
164 |
-
}
|
165 |
-
|
166 |
-
$file_name = 'media-' . current_time( 'timestamp' ) . '-' . md5( uniqid() );
|
167 |
-
|
168 |
-
$dump_file_name = $file_name . '.sql';
|
169 |
-
$dump_file_path = $this->get_backup_dir( $dump_file_name );
|
170 |
-
|
171 |
-
$dumped = $this->dump_media_records( $dump_file_path );
|
172 |
-
|
173 |
-
if ( ! $dumped ) {
|
174 |
-
$this->errors->add( 'can_not_create_media_records_backup_db_file', __( 'Can not create media records backup file.', 'jupiterx-core' ) );
|
175 |
-
|
176 |
-
return false;
|
177 |
-
}
|
178 |
-
|
179 |
-
return true;
|
180 |
-
}
|
181 |
-
|
182 |
-
/**
|
183 |
-
* Restore current site database
|
184 |
-
*
|
185 |
-
* @return boolean
|
186 |
-
*/
|
187 |
-
public function restore_latest_db() {
|
188 |
-
// Do not execute if there was as error in initialization
|
189 |
-
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
190 |
-
return false;
|
191 |
-
}
|
192 |
-
|
193 |
-
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
194 |
-
|
195 |
-
global $wpdb;
|
196 |
-
|
197 |
-
$wpdb->suppress_errors = false;
|
198 |
-
$wpdb->show_errors = false;
|
199 |
-
|
200 |
-
/* BEGIN: Get the list of backup files and sort them by created date */
|
201 |
-
$list_of_backups = $this->list_of_backups();
|
202 |
-
|
203 |
-
/* BEGIN: Get the lastest backup file by date */
|
204 |
-
$latest_backup_file = end( $list_of_backups );
|
205 |
-
|
206 |
-
$regExp = '/dump-(\d+)-(.*)\.(zip|sql)/';
|
207 |
-
|
208 |
-
if ( preg_match( $regExp, $latest_backup_file['full_path'], $matches ) ) {
|
209 |
-
if ( 'zip' == $matches[3] ) {
|
210 |
-
$unzipfile = $this->jupiterx_filesystem->unzip( $latest_backup_file['full_path'], $this->get_backup_dir() );
|
211 |
-
|
212 |
-
if ( ! $unzipfile ) {
|
213 |
-
$this->errors->add( 'error_unzipping_backup_file', __( 'There was an error unzipping the backup file.', 'jupiterx-core' ) );
|
214 |
-
|
215 |
-
return false;
|
216 |
-
} else if ( is_wp_error( $unzipfile ) ) {
|
217 |
-
$this->errors->add( $unzipfile->get_error_code(), $unzipfile->get_error_message() );
|
218 |
-
|
219 |
-
return false;
|
220 |
-
}
|
221 |
-
|
222 |
-
$database_sql_file = $this->get_backup_dir( basename( $latest_backup_file['full_path'], '.zip' ) . '.sql' );
|
223 |
-
} else {
|
224 |
-
$database_sql_file = $latest_backup_file['full_path'];
|
225 |
-
}
|
226 |
-
} else {
|
227 |
-
$this->errors->add( 'invalid_backup_file_type', __( 'Invalid backup file.', 'jupiterx-core' ) );
|
228 |
-
|
229 |
-
return false;
|
230 |
-
}
|
231 |
-
|
232 |
-
/* Check if sql backup file exists and readable */
|
233 |
-
if ( ! $this->jupiterx_filesystem->exists( $database_sql_file ) || ! $this->jupiterx_filesystem->is_readable( $database_sql_file ) ) {
|
234 |
-
$this->errors->add( 'backup_file_is_not_exists_or_readable', __( 'The backup file is not exists or not readable.', 'jupiterx-core' ) );
|
235 |
-
|
236 |
-
return false;
|
237 |
-
}
|
238 |
-
|
239 |
-
/* Define DB Name and error message */
|
240 |
-
$database_name = DB_NAME;
|
241 |
-
|
242 |
-
/* BEGIN: Create the Database */
|
243 |
-
$sql = "CREATE DATABASE IF NOT EXISTS `$database_name`";
|
244 |
-
$wpdb->query( $sql );
|
245 |
-
|
246 |
-
if ( ! empty( $wpdb->last_error ) ) {
|
247 |
-
$this->errors->add( 'wpdb_last_error', $wpdb->last_error );
|
248 |
-
|
249 |
-
return false;
|
250 |
-
}
|
251 |
-
|
252 |
-
/* BEGIN: Retrieve All Tables from the Database */
|
253 |
-
$tables = $this->get_tables();
|
254 |
-
|
255 |
-
/* BEGIN: Drop All Tables from the Database */
|
256 |
-
foreach ( $tables as $table ) {
|
257 |
-
$wpdb->query( "DROP TABLE IF EXISTS `$database_name`.`$table`" );
|
258 |
-
}
|
259 |
-
|
260 |
-
$sql_query = '';
|
261 |
-
|
262 |
-
$file_contents = explode( "\n", $this->jupiterx_filesystem->get_contents( $database_sql_file ) );
|
263 |
-
|
264 |
-
if ( ! empty( $file_contents ) ) {
|
265 |
-
foreach ( $file_contents as $line ) {
|
266 |
-
// Skip it if it's a comment or empty line
|
267 |
-
if ( empty( $line ) || $line === "\n" || substr( $line, 0, 2 ) == '--' ) {
|
268 |
-
continue;
|
269 |
-
}
|
270 |
-
|
271 |
-
// Contcat the sql query string
|
272 |
-
$sql_query .= $line . "\n";
|
273 |
-
|
274 |
-
// If it has a semicolon at the end, it's the end of the query
|
275 |
-
if ( substr( trim( $line ), -1, 1 ) == ';' ) {
|
276 |
-
if ( strpos( $sql_query, 'CREATE TABLE' ) ) {
|
277 |
-
// Run drop table query
|
278 |
-
$drop_table_legth = strpos( $sql_query, ' (', 0 );
|
279 |
-
$drop_table = substr( $sql_query, 0, $drop_table_legth );
|
280 |
-
$drop_table_if_exists = str_replace( 'CREATE TABLE', 'DROP TABLE IF EXISTS `' . $database_name . '`.', $drop_table );
|
281 |
-
$wpdb->query( $drop_table_if_exists );
|
282 |
-
|
283 |
-
// Run create table query
|
284 |
-
dbDelta( $sql_query );
|
285 |
-
} else {
|
286 |
-
// Run insert record query
|
287 |
-
$wpdb->query( $sql_query );
|
288 |
-
}
|
289 |
-
|
290 |
-
$sql_query = '';
|
291 |
-
}
|
292 |
-
}
|
293 |
-
}
|
294 |
-
|
295 |
-
if ( ! empty( $wpdb->last_error ) ) {
|
296 |
-
$this->errors->add( 'wpdb_last_error', $wpdb->last_error );
|
297 |
-
|
298 |
-
return false;
|
299 |
-
}
|
300 |
-
|
301 |
-
// Delete others backup files.
|
302 |
-
$list_of_backups = $this->list_of_backups();
|
303 |
-
|
304 |
-
if ( ! empty( $list_of_backups ) && is_array( $list_of_backups ) ) {
|
305 |
-
foreach ( $list_of_backups as $list_of_backup ) {
|
306 |
-
$this->jupiterx_filesystem->delete( $list_of_backup['full_path'] );
|
307 |
-
}
|
308 |
-
}
|
309 |
-
|
310 |
-
return true;
|
311 |
-
}
|
312 |
-
|
313 |
-
/**
|
314 |
-
* restore current site media records
|
315 |
-
*
|
316 |
-
* @return boolean
|
317 |
-
*/
|
318 |
-
public function restore_media_records() {
|
319 |
-
// Do not execute if there was as error in initialization
|
320 |
-
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
321 |
-
return false;
|
322 |
-
}
|
323 |
-
|
324 |
-
global $wpdb;
|
325 |
-
|
326 |
-
$wpdb->suppress_errors = false;
|
327 |
-
$wpdb->show_errors = false;
|
328 |
-
|
329 |
-
$list_of_backups = $this->list_of_backups( 'media', 'sql' );
|
330 |
-
|
331 |
-
if ( empty( $list_of_backups ) ) {
|
332 |
-
return true;
|
333 |
-
}
|
334 |
-
|
335 |
-
$latest_backup = end( $list_of_backups );
|
336 |
-
|
337 |
-
if ( ! isset( $latest_backup['full_path'] ) || ! $this->jupiterx_filesystem->exists( $latest_backup['full_path'] ) || ! $this->jupiterx_filesystem->is_readable( $latest_backup['full_path'] ) ) {
|
338 |
-
$this->errors->add( 'media_records_backup_not_exists_or_readable', __( 'Media records backup file is not exists or not readable', 'jupiterx-core' ) );
|
339 |
-
|
340 |
-
return false;
|
341 |
-
}
|
342 |
-
|
343 |
-
$sql_query = '';
|
344 |
-
|
345 |
-
$file_contents = explode( "\n", $this->jupiterx_filesystem->get_contents( $latest_backup['full_path'] ) );
|
346 |
-
|
347 |
-
if ( ! empty( $file_contents ) ) {
|
348 |
-
$max_id = ( $wpdb->get_var( "SELECT MAX(ID) as id FROM $wpdb->posts" ) + 1 );
|
349 |
-
|
350 |
-
foreach ( $file_contents as $line ) {
|
351 |
-
// Skip it if it's empty line
|
352 |
-
if ( empty( $line ) || $line === "\n" ) {
|
353 |
-
continue;
|
354 |
-
}
|
355 |
-
|
356 |
-
// If it has a semicolon at the end, it's the end of the query
|
357 |
-
if ( substr( trim( $line ), -1, 1 ) == ';' ) {
|
358 |
-
// Replace with new POST ID
|
359 |
-
$sql_query = str_replace( [ 'increament_id', 'meta_id' ], [ $max_id, 'NULL' ], $line );
|
360 |
-
|
361 |
-
// Run insert record query
|
362 |
-
$wpdb->query( $sql_query );
|
363 |
-
}
|
364 |
-
|
365 |
-
if ( 0 === strpos( $line, '---END-QUERY---' ) ) {
|
366 |
-
$max_id = ( $wpdb->get_var( "SELECT MAX(ID) as id FROM $wpdb->posts" ) + 1 );
|
367 |
-
}
|
368 |
-
}
|
369 |
-
}
|
370 |
-
|
371 |
-
if ( ! empty( $wpdb->last_error ) ) {
|
372 |
-
$this->errors->add( 'wpdb_last_error', $wpdb->last_error );
|
373 |
-
|
374 |
-
return false;
|
375 |
-
}
|
376 |
-
|
377 |
-
$this->jupiterx_filesystem->delete( $latest_backup['full_path'] );
|
378 |
-
|
379 |
-
return true;
|
380 |
-
}
|
381 |
-
|
382 |
-
|
383 |
-
/**
|
384 |
-
* Get current backups data stored
|
385 |
-
*
|
386 |
-
* @return array
|
387 |
-
*/
|
388 |
-
public function is_restore_db() {
|
389 |
-
/* BEGIN: Get the list of backup files and sort them by created date */
|
390 |
-
$list_of_backups = $this->list_of_backups();
|
391 |
-
|
392 |
-
$result = [
|
393 |
-
'list_of_backups' => $list_of_backups,
|
394 |
-
'latest_backup_file' => end( $list_of_backups ),
|
395 |
-
];
|
396 |
-
|
397 |
-
return $result;
|
398 |
-
}
|
399 |
-
|
400 |
-
/*====================== HELPERS ============================*/
|
401 |
-
|
402 |
-
/**
|
403 |
-
* Get all errors
|
404 |
-
*
|
405 |
-
* @return object
|
406 |
-
*/
|
407 |
-
public function get_errors() {
|
408 |
-
return $this->errors;
|
409 |
-
}
|
410 |
-
|
411 |
-
/**
|
412 |
-
* Get error code
|
413 |
-
*
|
414 |
-
* @return string
|
415 |
-
*/
|
416 |
-
public function get_error_code() {
|
417 |
-
return is_wp_error( $this->errors ) && $this->errors->get_error_code() ? $this->errors->get_error_code() : false;
|
418 |
-
}
|
419 |
-
|
420 |
-
/**
|
421 |
-
* Get error message
|
422 |
-
*
|
423 |
-
* @return string
|
424 |
-
*/
|
425 |
-
public function get_error_message() {
|
426 |
-
return is_wp_error( $this->errors ) && $this->errors->get_error_code() ? $this->errors->get_error_message() : false;
|
427 |
-
}
|
428 |
-
|
429 |
-
/**
|
430 |
-
* Get backup directory
|
431 |
-
*
|
432 |
-
* @param $append
|
433 |
-
* @return string
|
434 |
-
*/
|
435 |
-
public function get_backup_dir( $append = '' ) {
|
436 |
-
if ( ! empty( $append ) ) {
|
437 |
-
return trailingslashit( $this->backup_dir ) . ltrim( $append, '/' );
|
438 |
-
} else {
|
439 |
-
return $this->backup_dir;
|
440 |
-
}
|
441 |
-
}
|
442 |
-
|
443 |
-
/**
|
444 |
-
* Get backup url
|
445 |
-
*
|
446 |
-
* @param $append
|
447 |
-
* @return mixed
|
448 |
-
*/
|
449 |
-
public function get_backup_url( $append = '' ) {
|
450 |
-
if ( ! empty( $append ) ) {
|
451 |
-
return trailingslashit( $this->backup_url ) . ltrim( $append, '/' );
|
452 |
-
} else {
|
453 |
-
return $this->backup_url;
|
454 |
-
}
|
455 |
-
}
|
456 |
-
|
457 |
-
/**
|
458 |
-
* Get list of avalibale backups
|
459 |
-
*
|
460 |
-
* @param $prefix
|
461 |
-
* @param $file_ext
|
462 |
-
* @return array
|
463 |
-
*/
|
464 |
-
public function list_of_backups( $prefix = 'dump', $file_ext = 'zip,sql' ) {
|
465 |
-
$backup_list = [];
|
466 |
-
|
467 |
-
$files = glob( $this->get_backup_dir( $prefix . '-*.{' . $file_ext . '}' ), GLOB_BRACE );
|
468 |
-
|
469 |
-
if ( $files ) {
|
470 |
-
ksort( $files );
|
471 |
-
$file_exts = explode( ',', $file_ext );
|
472 |
-
$regExp = '/' . $prefix . '-(\d+)-(.*)\.(' . implode( '|', $file_exts ) . ')/';
|
473 |
-
foreach ( $files as $file ) {
|
474 |
-
if ( preg_match( $regExp, $file, $matches ) ) {
|
475 |
-
$backup_list[] = [
|
476 |
-
'full_path' => $this->get_backup_dir( $matches[0] ),
|
477 |
-
'full_url' => $this->get_backup_url( $matches[0] ),
|
478 |
-
'name' => $matches[0],
|
479 |
-
'ext' => $matches[3],
|
480 |
-
'created_date' => date( 'Y-m-d H:i:s', $matches[1] ),
|
481 |
-
];
|
482 |
-
}
|
483 |
-
}
|
484 |
-
}
|
485 |
-
|
486 |
-
return $backup_list;
|
487 |
-
}
|
488 |
-
|
489 |
-
/*====================== HELPERS ABOUT DUMPING ============================*/
|
490 |
-
|
491 |
-
/**
|
492 |
-
* Get database tables for current site
|
493 |
-
*
|
494 |
-
* @author Sofyan Sitorus <sofyan@artbees.net>
|
495 |
-
*/
|
496 |
-
public function get_tables() {
|
497 |
-
global $wpdb;
|
498 |
-
$exclude_tables = [
|
499 |
-
$wpdb->base_prefix . 'users',
|
500 |
-
$wpdb->base_prefix . 'usermeta',
|
501 |
-
$wpdb->prefix . 'woocommerce_sessions',
|
502 |
-
$wpdb->prefix . 'woocommerce_attribute_taxonomies',
|
503 |
-
];
|
504 |
-
$multi_site_tables = [
|
505 |
-
$wpdb->base_prefix . 'blogs',
|
506 |
-
$wpdb->base_prefix . 'blog_versions',
|
507 |
-
$wpdb->base_prefix . 'signups',
|
508 |
-
$wpdb->base_prefix . 'site',
|
509 |
-
$wpdb->base_prefix . 'sitemeta',
|
510 |
-
$wpdb->base_prefix . 'sitecategories',
|
511 |
-
$wpdb->base_prefix . 'registration_log',
|
512 |
-
];
|
513 |
-
$current_site_tables = [];
|
514 |
-
$current_blog_id = get_current_blog_id();
|
515 |
-
$tables = $wpdb->get_results( 'SHOW FULL TABLES', ARRAY_N );
|
516 |
-
foreach ( $tables as $table ) {
|
517 |
-
if ( isset( $table[1] ) && 'VIEW' == $table[1] ) {
|
518 |
-
continue;
|
519 |
-
}
|
520 |
-
|
521 |
-
if ( in_array( $table[0], $exclude_tables, true ) ) {
|
522 |
-
continue;
|
523 |
-
}
|
524 |
-
|
525 |
-
if ( is_multisite() ) {
|
526 |
-
if ( in_array( $table[0], $multi_site_tables, true ) ) {
|
527 |
-
continue;
|
528 |
-
}
|
529 |
-
|
530 |
-
if ( is_main_site( $current_blog_id ) ) {
|
531 |
-
$regex = '/^' . $wpdb->prefix . '([0-9])+/i';
|
532 |
-
if ( preg_match( $regex, $table[0] ) ) {
|
533 |
-
continue;
|
534 |
-
}
|
535 |
-
}
|
536 |
-
|
537 |
-
if ( 0 === strpos( $table[0], $wpdb->prefix ) ) {
|
538 |
-
$current_site_tables[] = $table[0];
|
539 |
-
}
|
540 |
-
} else {
|
541 |
-
$current_site_tables[] = $table[0];
|
542 |
-
}
|
543 |
-
}
|
544 |
-
|
545 |
-
return $current_site_tables;
|
546 |
-
}
|
547 |
-
|
548 |
-
/**
|
549 |
-
* Export current site data to local disk
|
550 |
-
*
|
551 |
-
* @param $dump_file_path
|
552 |
-
* @return boolean
|
553 |
-
*/
|
554 |
-
private function dump_db( $dump_file_path ) {
|
555 |
-
global $wpdb;
|
556 |
-
|
557 |
-
$is_success = $this->jupiterx_filesystem->put_contents( $dump_file_path, '', 0777 );
|
558 |
-
|
559 |
-
if ( $is_success ) {
|
560 |
-
/* BEGIN : Prevent saving backup plugin settings in the database dump */
|
561 |
-
$options_backup = get_option( 'wp_db_backup_backups' );
|
562 |
-
$settings_backup = get_option( 'wp_db_backup_options' );
|
563 |
-
delete_option( 'wp_db_backup_backups' );
|
564 |
-
delete_option( 'wp_db_backup_options' );
|
565 |
-
/* END : Prevent saving backup plugin settings in the database dump */
|
566 |
-
|
567 |
-
$tables_exclude = get_option( 'wp_db_exclude_table' );
|
568 |
-
$tables = $this->get_tables();
|
569 |
-
|
570 |
-
if ( $tables ) {
|
571 |
-
$output = '';
|
572 |
-
|
573 |
-
foreach ( $tables as $table ) {
|
574 |
-
if ( empty( $tables_exclude ) || ( ! ( in_array( $table, $tables_exclude, true ) ) ) ) {
|
575 |
-
// Create table SQL syntax
|
576 |
-
$create_table = $wpdb->get_row( 'SHOW CREATE TABLE ' . $table, ARRAY_N );
|
577 |
-
$output .= "\n\n" . $create_table[1] . ";\n\n";
|
578 |
-
|
579 |
-
// Insert records SQL syntax
|
580 |
-
$result = $wpdb->get_results( "SELECT * FROM {$table}", ARRAY_N );
|
581 |
-
$result_count = count( $result );
|
582 |
-
|
583 |
-
if ( $result ) {
|
584 |
-
for ( $i = 0; $i < $result_count; $i++ ) {
|
585 |
-
$row = $result[ $i ];
|
586 |
-
|
587 |
-
$output .= 'INSERT INTO ' . $table . ' VALUES(';
|
588 |
-
|
589 |
-
$row = array_map( [ $wpdb, '_real_escape' ], $row );
|
590 |
-
|
591 |
-
$output .= '"' . implode( '","', $row ) . '"';
|
592 |
-
|
593 |
-
$output .= ");\n";
|
594 |
-
}
|
595 |
-
}
|
596 |
-
|
597 |
-
$output .= "\n";
|
598 |
-
}
|
599 |
-
}
|
600 |
-
|
601 |
-
$this->jupiterx_filesystem->put_contents( $dump_file_path, $output );
|
602 |
-
|
603 |
-
$wpdb->flush();
|
604 |
-
}
|
605 |
-
|
606 |
-
/* BEGIN : Prevent saving backup plugin settings in the database dump */
|
607 |
-
add_option( 'wp_db_backup_backups', $options_backup );
|
608 |
-
add_option( 'wp_db_backup_options', $settings_backup );
|
609 |
-
/* END : Prevent saving backup plugin settings in the database dump */
|
610 |
-
|
611 |
-
return $this->jupiterx_filesystem->chmod( $dump_file_path, 0664 );
|
612 |
-
}
|
613 |
-
|
614 |
-
return $is_success;
|
615 |
-
}
|
616 |
-
|
617 |
-
/**
|
618 |
-
* Export current site media record to local disk
|
619 |
-
*
|
620 |
-
* @param $dump_file_path
|
621 |
-
* @return boolean
|
622 |
-
*/
|
623 |
-
private function dump_media_records( $dump_file_path ) {
|
624 |
-
global $wpdb;
|
625 |
-
|
626 |
-
$result = $wpdb->get_results( "SELECT * FROM $wpdb->posts where post_type='attachment'", ARRAY_N );
|
627 |
-
|
628 |
-
$is_success = $this->jupiterx_filesystem->put_contents( $dump_file_path, '', 0777 );
|
629 |
-
|
630 |
-
if ( $is_success ) {
|
631 |
-
$result = $wpdb->get_results( "SELECT * FROM $wpdb->posts where post_type='attachment'", ARRAY_N );
|
632 |
-
|
633 |
-
// Insert media records SQL syntax
|
634 |
-
if ( $result ) {
|
635 |
-
$result_count = count( $result );
|
636 |
-
|
637 |
-
$output = '';
|
638 |
-
|
639 |
-
for ( $i = 0; $i < $result_count; $i++ ) {
|
640 |
-
$row = $result[ $i ];
|
641 |
-
|
642 |
-
$output .= 'INSERT INTO ' . $wpdb->posts . ' VALUES(';
|
643 |
-
|
644 |
-
$row[0] = 'increament_id';
|
645 |
-
|
646 |
-
$row = array_map( [ $wpdb, '_real_escape' ], $row );
|
647 |
-
|
648 |
-
$output .= '"' . implode( '","', $row ) . '"';
|
649 |
-
|
650 |
-
$output .= ');' . "\n\n";
|
651 |
-
|
652 |
-
$wpdb->flush();
|
653 |
-
|
654 |
-
$postmeta_result = $wpdb->get_results( "SELECT * FROM $wpdb->postmeta where post_id = {$result[$i][0]}", ARRAY_N );
|
655 |
-
|
656 |
-
// Insert media meta records SQL syntax
|
657 |
-
if ( $postmeta_result ) {
|
658 |
-
$postmeta_result_count = count( $postmeta_result );
|
659 |
-
|
660 |
-
for ( $j = 0; $j < $postmeta_result_count; $j++ ) {
|
661 |
-
$postmeta_row = $postmeta_result[ $j ];
|
662 |
-
|
663 |
-
$output .= 'INSERT INTO ' . $wpdb->postmeta . ' VALUES(';
|
664 |
-
|
665 |
-
$postmeta_row[0] = 'meta_id';
|
666 |
-
|
667 |
-
$postmeta_row[1] = 'increament_id';
|
668 |
-
|
669 |
-
$postmeta_row = array_map( [ $wpdb, '_real_escape' ], $postmeta_row );
|
670 |
-
|
671 |
-
$output .= '"' . implode( '","', $postmeta_row ) . '"';
|
672 |
-
|
673 |
-
$output .= ');' . "\n";
|
674 |
-
}
|
675 |
-
|
676 |
-
$output .= "\n\n" . '---END-QUERY---' . "\n\n";
|
677 |
-
}
|
678 |
-
|
679 |
-
$output .= "\n\n\n";
|
680 |
-
}
|
681 |
-
|
682 |
-
$this->jupiterx_filesystem->put_contents( $dump_file_path, $output );
|
683 |
-
}
|
684 |
-
|
685 |
-
return $this->jupiterx_filesystem->chmod( $dump_file_path, 0664 );
|
686 |
-
}
|
687 |
-
|
688 |
-
return $is_success;
|
689 |
-
}
|
690 |
-
}
|
691 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handles database for restoring or creating backups.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel\Database_Manager
|
6 |
+
*
|
7 |
+
* @since 1.9.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Database_Manager' ) ) {
|
11 |
+
/**
|
12 |
+
* Database manager class.
|
13 |
+
*
|
14 |
+
* @since 1.9.0
|
15 |
+
*/
|
16 |
+
class JupiterX_Control_Panel_Database_Manager {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var object
|
20 |
+
*/
|
21 |
+
public $errors;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
private $basedir;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
+
private $backup_dir;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
private $dir_prefix;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @var string
|
40 |
+
*/
|
41 |
+
private $baseurl;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @var string
|
45 |
+
*/
|
46 |
+
private $backup_url;
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @var object
|
50 |
+
*/
|
51 |
+
private $jupiterx_filesystem;
|
52 |
+
|
53 |
+
/*====================== MAIN SECTION ============================*/
|
54 |
+
/**
|
55 |
+
* The class constructor
|
56 |
+
*
|
57 |
+
* @param $dir_prefix
|
58 |
+
*/
|
59 |
+
public function __construct( $dir_prefix = 'jupiterx_backups' ) {
|
60 |
+
$this->errors = new WP_Error();
|
61 |
+
$this->dir_prefix = $dir_prefix;
|
62 |
+
$this->init();
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Initialize the FS
|
67 |
+
*
|
68 |
+
* @var boolean
|
69 |
+
*/
|
70 |
+
private function init() {
|
71 |
+
|
72 |
+
$wp_upload_dir = wp_upload_dir();
|
73 |
+
|
74 |
+
if ( ! empty( $wp_upload_dir['error'] ) ) {
|
75 |
+
$this->errors->add( 'unable_to_create_upload_directory', $wp_upload_dir['error'] );
|
76 |
+
|
77 |
+
return false;
|
78 |
+
}
|
79 |
+
|
80 |
+
$this->basedir = $wp_upload_dir['basedir'];
|
81 |
+
|
82 |
+
$this->baseurl = $wp_upload_dir['baseurl'];
|
83 |
+
|
84 |
+
$this->jupiterx_filesystem = new JupiterX_Filesystem(
|
85 |
+
[
|
86 |
+
'context' => $this->basedir,
|
87 |
+
]
|
88 |
+
);
|
89 |
+
|
90 |
+
if ( $this->jupiterx_filesystem->get_error_code() ) {
|
91 |
+
$this->errors->add( $this->jupiterx_filesystem->get_error_code(), $this->jupiterx_filesystem->get_error_message() );
|
92 |
+
|
93 |
+
return false;
|
94 |
+
}
|
95 |
+
|
96 |
+
$this->backup_dir = trailingslashit( $this->basedir ) . $this->dir_prefix;
|
97 |
+
|
98 |
+
$this->backup_url = trailingslashit( $this->baseurl ) . $this->dir_prefix;
|
99 |
+
|
100 |
+
// Create index html file
|
101 |
+
if ( ! $this->jupiterx_filesystem->exists( trailingslashit( $this->backup_dir ) . 'index.html' ) ) {
|
102 |
+
$this->jupiterx_filesystem->touch( trailingslashit( $this->backup_dir ) . 'index.html' );
|
103 |
+
}
|
104 |
+
|
105 |
+
if ( ! $this->jupiterx_filesystem->exists( trailingslashit( $this->backup_dir ) . '.htaccess' ) ) {
|
106 |
+
$htaccess_content = '<IfModule mod_rewrite.c>' . "\n" .
|
107 |
+
'RewriteEngine On' . "\n" .
|
108 |
+
'RewriteCond %{REQUEST_FILENAME} ^.*(sql|zip)$' . "\n" .
|
109 |
+
'RewriteRule . - [R=403,L]' . "\n" .
|
110 |
+
'</IfModule>' . "\n";
|
111 |
+
$this->jupiterx_filesystem->put_contents( trailingslashit( $this->backup_dir ) . '.htaccess', $htaccess_content );
|
112 |
+
}
|
113 |
+
|
114 |
+
return true;
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Backup current site database
|
119 |
+
*
|
120 |
+
* @return boolean
|
121 |
+
*/
|
122 |
+
public function backup_db() {
|
123 |
+
// Do not execute if there was as error in initialization
|
124 |
+
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
125 |
+
return false;
|
126 |
+
}
|
127 |
+
|
128 |
+
$file_name = 'dump-' . current_time( 'timestamp' ) . '-' . md5( uniqid() );
|
129 |
+
|
130 |
+
$dump_file_name = $file_name . '.sql';
|
131 |
+
$dump_file_path = $this->get_backup_dir( $dump_file_name );
|
132 |
+
|
133 |
+
$zip_file_name = $file_name . '.zip';
|
134 |
+
$zip_file_path = $this->get_backup_dir( $zip_file_name );
|
135 |
+
|
136 |
+
$dumped = $this->dump_db( $dump_file_path );
|
137 |
+
|
138 |
+
if ( ! $dumped ) {
|
139 |
+
$this->errors->add( 'can_not_create_backup_db_file', __( 'Can not create backup db file.', 'jupiterx-core' ) );
|
140 |
+
|
141 |
+
return false;
|
142 |
+
}
|
143 |
+
|
144 |
+
if ( $this->jupiterx_filesystem->zip(
|
145 |
+
[
|
146 |
+
$dump_file_name => $dump_file_path,
|
147 |
+
], $zip_file_path
|
148 |
+
) ) {
|
149 |
+
$this->jupiterx_filesystem->delete( $dump_file_path );
|
150 |
+
}
|
151 |
+
|
152 |
+
return true;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Backup current site media records
|
157 |
+
*
|
158 |
+
* @return boolean
|
159 |
+
*/
|
160 |
+
public function backup_media_records() {
|
161 |
+
// Do not execute if there was as error in initialization
|
162 |
+
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
163 |
+
return false;
|
164 |
+
}
|
165 |
+
|
166 |
+
$file_name = 'media-' . current_time( 'timestamp' ) . '-' . md5( uniqid() );
|
167 |
+
|
168 |
+
$dump_file_name = $file_name . '.sql';
|
169 |
+
$dump_file_path = $this->get_backup_dir( $dump_file_name );
|
170 |
+
|
171 |
+
$dumped = $this->dump_media_records( $dump_file_path );
|
172 |
+
|
173 |
+
if ( ! $dumped ) {
|
174 |
+
$this->errors->add( 'can_not_create_media_records_backup_db_file', __( 'Can not create media records backup file.', 'jupiterx-core' ) );
|
175 |
+
|
176 |
+
return false;
|
177 |
+
}
|
178 |
+
|
179 |
+
return true;
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Restore current site database
|
184 |
+
*
|
185 |
+
* @return boolean
|
186 |
+
*/
|
187 |
+
public function restore_latest_db() {
|
188 |
+
// Do not execute if there was as error in initialization
|
189 |
+
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
190 |
+
return false;
|
191 |
+
}
|
192 |
+
|
193 |
+
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
194 |
+
|
195 |
+
global $wpdb;
|
196 |
+
|
197 |
+
$wpdb->suppress_errors = false;
|
198 |
+
$wpdb->show_errors = false;
|
199 |
+
|
200 |
+
/* BEGIN: Get the list of backup files and sort them by created date */
|
201 |
+
$list_of_backups = $this->list_of_backups();
|
202 |
+
|
203 |
+
/* BEGIN: Get the lastest backup file by date */
|
204 |
+
$latest_backup_file = end( $list_of_backups );
|
205 |
+
|
206 |
+
$regExp = '/dump-(\d+)-(.*)\.(zip|sql)/';
|
207 |
+
|
208 |
+
if ( preg_match( $regExp, $latest_backup_file['full_path'], $matches ) ) {
|
209 |
+
if ( 'zip' == $matches[3] ) {
|
210 |
+
$unzipfile = $this->jupiterx_filesystem->unzip( $latest_backup_file['full_path'], $this->get_backup_dir() );
|
211 |
+
|
212 |
+
if ( ! $unzipfile ) {
|
213 |
+
$this->errors->add( 'error_unzipping_backup_file', __( 'There was an error unzipping the backup file.', 'jupiterx-core' ) );
|
214 |
+
|
215 |
+
return false;
|
216 |
+
} else if ( is_wp_error( $unzipfile ) ) {
|
217 |
+
$this->errors->add( $unzipfile->get_error_code(), $unzipfile->get_error_message() );
|
218 |
+
|
219 |
+
return false;
|
220 |
+
}
|
221 |
+
|
222 |
+
$database_sql_file = $this->get_backup_dir( basename( $latest_backup_file['full_path'], '.zip' ) . '.sql' );
|
223 |
+
} else {
|
224 |
+
$database_sql_file = $latest_backup_file['full_path'];
|
225 |
+
}
|
226 |
+
} else {
|
227 |
+
$this->errors->add( 'invalid_backup_file_type', __( 'Invalid backup file.', 'jupiterx-core' ) );
|
228 |
+
|
229 |
+
return false;
|
230 |
+
}
|
231 |
+
|
232 |
+
/* Check if sql backup file exists and readable */
|
233 |
+
if ( ! $this->jupiterx_filesystem->exists( $database_sql_file ) || ! $this->jupiterx_filesystem->is_readable( $database_sql_file ) ) {
|
234 |
+
$this->errors->add( 'backup_file_is_not_exists_or_readable', __( 'The backup file is not exists or not readable.', 'jupiterx-core' ) );
|
235 |
+
|
236 |
+
return false;
|
237 |
+
}
|
238 |
+
|
239 |
+
/* Define DB Name and error message */
|
240 |
+
$database_name = DB_NAME;
|
241 |
+
|
242 |
+
/* BEGIN: Create the Database */
|
243 |
+
$sql = "CREATE DATABASE IF NOT EXISTS `$database_name`";
|
244 |
+
$wpdb->query( $sql );
|
245 |
+
|
246 |
+
if ( ! empty( $wpdb->last_error ) ) {
|
247 |
+
$this->errors->add( 'wpdb_last_error', $wpdb->last_error );
|
248 |
+
|
249 |
+
return false;
|
250 |
+
}
|
251 |
+
|
252 |
+
/* BEGIN: Retrieve All Tables from the Database */
|
253 |
+
$tables = $this->get_tables();
|
254 |
+
|
255 |
+
/* BEGIN: Drop All Tables from the Database */
|
256 |
+
foreach ( $tables as $table ) {
|
257 |
+
$wpdb->query( "DROP TABLE IF EXISTS `$database_name`.`$table`" );
|
258 |
+
}
|
259 |
+
|
260 |
+
$sql_query = '';
|
261 |
+
|
262 |
+
$file_contents = explode( "\n", $this->jupiterx_filesystem->get_contents( $database_sql_file ) );
|
263 |
+
|
264 |
+
if ( ! empty( $file_contents ) ) {
|
265 |
+
foreach ( $file_contents as $line ) {
|
266 |
+
// Skip it if it's a comment or empty line
|
267 |
+
if ( empty( $line ) || $line === "\n" || substr( $line, 0, 2 ) == '--' ) {
|
268 |
+
continue;
|
269 |
+
}
|
270 |
+
|
271 |
+
// Contcat the sql query string
|
272 |
+
$sql_query .= $line . "\n";
|
273 |
+
|
274 |
+
// If it has a semicolon at the end, it's the end of the query
|
275 |
+
if ( substr( trim( $line ), -1, 1 ) == ';' ) {
|
276 |
+
if ( strpos( $sql_query, 'CREATE TABLE' ) ) {
|
277 |
+
// Run drop table query
|
278 |
+
$drop_table_legth = strpos( $sql_query, ' (', 0 );
|
279 |
+
$drop_table = substr( $sql_query, 0, $drop_table_legth );
|
280 |
+
$drop_table_if_exists = str_replace( 'CREATE TABLE', 'DROP TABLE IF EXISTS `' . $database_name . '`.', $drop_table );
|
281 |
+
$wpdb->query( $drop_table_if_exists );
|
282 |
+
|
283 |
+
// Run create table query
|
284 |
+
dbDelta( $sql_query );
|
285 |
+
} else {
|
286 |
+
// Run insert record query
|
287 |
+
$wpdb->query( $sql_query );
|
288 |
+
}
|
289 |
+
|
290 |
+
$sql_query = '';
|
291 |
+
}
|
292 |
+
}
|
293 |
+
}
|
294 |
+
|
295 |
+
if ( ! empty( $wpdb->last_error ) ) {
|
296 |
+
$this->errors->add( 'wpdb_last_error', $wpdb->last_error );
|
297 |
+
|
298 |
+
return false;
|
299 |
+
}
|
300 |
+
|
301 |
+
// Delete others backup files.
|
302 |
+
$list_of_backups = $this->list_of_backups();
|
303 |
+
|
304 |
+
if ( ! empty( $list_of_backups ) && is_array( $list_of_backups ) ) {
|
305 |
+
foreach ( $list_of_backups as $list_of_backup ) {
|
306 |
+
$this->jupiterx_filesystem->delete( $list_of_backup['full_path'] );
|
307 |
+
}
|
308 |
+
}
|
309 |
+
|
310 |
+
return true;
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* restore current site media records
|
315 |
+
*
|
316 |
+
* @return boolean
|
317 |
+
*/
|
318 |
+
public function restore_media_records() {
|
319 |
+
// Do not execute if there was as error in initialization
|
320 |
+
if ( is_wp_error( $this->errors ) && $this->errors->get_error_code() ) {
|
321 |
+
return false;
|
322 |
+
}
|
323 |
+
|
324 |
+
global $wpdb;
|
325 |
+
|
326 |
+
$wpdb->suppress_errors = false;
|
327 |
+
$wpdb->show_errors = false;
|
328 |
+
|
329 |
+
$list_of_backups = $this->list_of_backups( 'media', 'sql' );
|
330 |
+
|
331 |
+
if ( empty( $list_of_backups ) ) {
|
332 |
+
return true;
|
333 |
+
}
|
334 |
+
|
335 |
+
$latest_backup = end( $list_of_backups );
|
336 |
+
|
337 |
+
if ( ! isset( $latest_backup['full_path'] ) || ! $this->jupiterx_filesystem->exists( $latest_backup['full_path'] ) || ! $this->jupiterx_filesystem->is_readable( $latest_backup['full_path'] ) ) {
|
338 |
+
$this->errors->add( 'media_records_backup_not_exists_or_readable', __( 'Media records backup file is not exists or not readable', 'jupiterx-core' ) );
|
339 |
+
|
340 |
+
return false;
|
341 |
+
}
|
342 |
+
|
343 |
+
$sql_query = '';
|
344 |
+
|
345 |
+
$file_contents = explode( "\n", $this->jupiterx_filesystem->get_contents( $latest_backup['full_path'] ) );
|
346 |
+
|
347 |
+
if ( ! empty( $file_contents ) ) {
|
348 |
+
$max_id = ( $wpdb->get_var( "SELECT MAX(ID) as id FROM $wpdb->posts" ) + 1 );
|
349 |
+
|
350 |
+
foreach ( $file_contents as $line ) {
|
351 |
+
// Skip it if it's empty line
|
352 |
+
if ( empty( $line ) || $line === "\n" ) {
|
353 |
+
continue;
|
354 |
+
}
|
355 |
+
|
356 |
+
// If it has a semicolon at the end, it's the end of the query
|
357 |
+
if ( substr( trim( $line ), -1, 1 ) == ';' ) {
|
358 |
+
// Replace with new POST ID
|
359 |
+
$sql_query = str_replace( [ 'increament_id', 'meta_id' ], [ $max_id, 'NULL' ], $line );
|
360 |
+
|
361 |
+
// Run insert record query
|
362 |
+
$wpdb->query( $sql_query );
|
363 |
+
}
|
364 |
+
|
365 |
+
if ( 0 === strpos( $line, '---END-QUERY---' ) ) {
|
366 |
+
$max_id = ( $wpdb->get_var( "SELECT MAX(ID) as id FROM $wpdb->posts" ) + 1 );
|
367 |
+
}
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
+
if ( ! empty( $wpdb->last_error ) ) {
|
372 |
+
$this->errors->add( 'wpdb_last_error', $wpdb->last_error );
|
373 |
+
|
374 |
+
return false;
|
375 |
+
}
|
376 |
+
|
377 |
+
$this->jupiterx_filesystem->delete( $latest_backup['full_path'] );
|
378 |
+
|
379 |
+
return true;
|
380 |
+
}
|
381 |
+
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Get current backups data stored
|
385 |
+
*
|
386 |
+
* @return array
|
387 |
+
*/
|
388 |
+
public function is_restore_db() {
|
389 |
+
/* BEGIN: Get the list of backup files and sort them by created date */
|
390 |
+
$list_of_backups = $this->list_of_backups();
|
391 |
+
|
392 |
+
$result = [
|
393 |
+
'list_of_backups' => $list_of_backups,
|
394 |
+
'latest_backup_file' => end( $list_of_backups ),
|
395 |
+
];
|
396 |
+
|
397 |
+
return $result;
|
398 |
+
}
|
399 |
+
|
400 |
+
/*====================== HELPERS ============================*/
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Get all errors
|
404 |
+
*
|
405 |
+
* @return object
|
406 |
+
*/
|
407 |
+
public function get_errors() {
|
408 |
+
return $this->errors;
|
409 |
+
}
|
410 |
+
|
411 |
+
/**
|
412 |
+
* Get error code
|
413 |
+
*
|
414 |
+
* @return string
|
415 |
+
*/
|
416 |
+
public function get_error_code() {
|
417 |
+
return is_wp_error( $this->errors ) && $this->errors->get_error_code() ? $this->errors->get_error_code() : false;
|
418 |
+
}
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Get error message
|
422 |
+
*
|
423 |
+
* @return string
|
424 |
+
*/
|
425 |
+
public function get_error_message() {
|
426 |
+
return is_wp_error( $this->errors ) && $this->errors->get_error_code() ? $this->errors->get_error_message() : false;
|
427 |
+
}
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Get backup directory
|
431 |
+
*
|
432 |
+
* @param $append
|
433 |
+
* @return string
|
434 |
+
*/
|
435 |
+
public function get_backup_dir( $append = '' ) {
|
436 |
+
if ( ! empty( $append ) ) {
|
437 |
+
return trailingslashit( $this->backup_dir ) . ltrim( $append, '/' );
|
438 |
+
} else {
|
439 |
+
return $this->backup_dir;
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* Get backup url
|
445 |
+
*
|
446 |
+
* @param $append
|
447 |
+
* @return mixed
|
448 |
+
*/
|
449 |
+
public function get_backup_url( $append = '' ) {
|
450 |
+
if ( ! empty( $append ) ) {
|
451 |
+
return trailingslashit( $this->backup_url ) . ltrim( $append, '/' );
|
452 |
+
} else {
|
453 |
+
return $this->backup_url;
|
454 |
+
}
|
455 |
+
}
|
456 |
+
|
457 |
+
/**
|
458 |
+
* Get list of avalibale backups
|
459 |
+
*
|
460 |
+
* @param $prefix
|
461 |
+
* @param $file_ext
|
462 |
+
* @return array
|
463 |
+
*/
|
464 |
+
public function list_of_backups( $prefix = 'dump', $file_ext = 'zip,sql' ) {
|
465 |
+
$backup_list = [];
|
466 |
+
|
467 |
+
$files = glob( $this->get_backup_dir( $prefix . '-*.{' . $file_ext . '}' ), GLOB_BRACE );
|
468 |
+
|
469 |
+
if ( $files ) {
|
470 |
+
ksort( $files );
|
471 |
+
$file_exts = explode( ',', $file_ext );
|
472 |
+
$regExp = '/' . $prefix . '-(\d+)-(.*)\.(' . implode( '|', $file_exts ) . ')/';
|
473 |
+
foreach ( $files as $file ) {
|
474 |
+
if ( preg_match( $regExp, $file, $matches ) ) {
|
475 |
+
$backup_list[] = [
|
476 |
+
'full_path' => $this->get_backup_dir( $matches[0] ),
|
477 |
+
'full_url' => $this->get_backup_url( $matches[0] ),
|
478 |
+
'name' => $matches[0],
|
479 |
+
'ext' => $matches[3],
|
480 |
+
'created_date' => date( 'Y-m-d H:i:s', $matches[1] ),
|
481 |
+
];
|
482 |
+
}
|
483 |
+
}
|
484 |
+
}
|
485 |
+
|
486 |
+
return $backup_list;
|
487 |
+
}
|
488 |
+
|
489 |
+
/*====================== HELPERS ABOUT DUMPING ============================*/
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Get database tables for current site
|
493 |
+
*
|
494 |
+
* @author Sofyan Sitorus <sofyan@artbees.net>
|
495 |
+
*/
|
496 |
+
public function get_tables() {
|
497 |
+
global $wpdb;
|
498 |
+
$exclude_tables = [
|
499 |
+
$wpdb->base_prefix . 'users',
|
500 |
+
$wpdb->base_prefix . 'usermeta',
|
501 |
+
$wpdb->prefix . 'woocommerce_sessions',
|
502 |
+
$wpdb->prefix . 'woocommerce_attribute_taxonomies',
|
503 |
+
];
|
504 |
+
$multi_site_tables = [
|
505 |
+
$wpdb->base_prefix . 'blogs',
|
506 |
+
$wpdb->base_prefix . 'blog_versions',
|
507 |
+
$wpdb->base_prefix . 'signups',
|
508 |
+
$wpdb->base_prefix . 'site',
|
509 |
+
$wpdb->base_prefix . 'sitemeta',
|
510 |
+
$wpdb->base_prefix . 'sitecategories',
|
511 |
+
$wpdb->base_prefix . 'registration_log',
|
512 |
+
];
|
513 |
+
$current_site_tables = [];
|
514 |
+
$current_blog_id = get_current_blog_id();
|
515 |
+
$tables = $wpdb->get_results( 'SHOW FULL TABLES', ARRAY_N );
|
516 |
+
foreach ( $tables as $table ) {
|
517 |
+
if ( isset( $table[1] ) && 'VIEW' == $table[1] ) {
|
518 |
+
continue;
|
519 |
+
}
|
520 |
+
|
521 |
+
if ( in_array( $table[0], $exclude_tables, true ) ) {
|
522 |
+
continue;
|
523 |
+
}
|
524 |
+
|
525 |
+
if ( is_multisite() ) {
|
526 |
+
if ( in_array( $table[0], $multi_site_tables, true ) ) {
|
527 |
+
continue;
|
528 |
+
}
|
529 |
+
|
530 |
+
if ( is_main_site( $current_blog_id ) ) {
|
531 |
+
$regex = '/^' . $wpdb->prefix . '([0-9])+/i';
|
532 |
+
if ( preg_match( $regex, $table[0] ) ) {
|
533 |
+
continue;
|
534 |
+
}
|
535 |
+
}
|
536 |
+
|
537 |
+
if ( 0 === strpos( $table[0], $wpdb->prefix ) ) {
|
538 |
+
$current_site_tables[] = $table[0];
|
539 |
+
}
|
540 |
+
} else {
|
541 |
+
$current_site_tables[] = $table[0];
|
542 |
+
}
|
543 |
+
}
|
544 |
+
|
545 |
+
return $current_site_tables;
|
546 |
+
}
|
547 |
+
|
548 |
+
/**
|
549 |
+
* Export current site data to local disk
|
550 |
+
*
|
551 |
+
* @param $dump_file_path
|
552 |
+
* @return boolean
|
553 |
+
*/
|
554 |
+
private function dump_db( $dump_file_path ) {
|
555 |
+
global $wpdb;
|
556 |
+
|
557 |
+
$is_success = $this->jupiterx_filesystem->put_contents( $dump_file_path, '', 0777 );
|
558 |
+
|
559 |
+
if ( $is_success ) {
|
560 |
+
/* BEGIN : Prevent saving backup plugin settings in the database dump */
|
561 |
+
$options_backup = get_option( 'wp_db_backup_backups' );
|
562 |
+
$settings_backup = get_option( 'wp_db_backup_options' );
|
563 |
+
delete_option( 'wp_db_backup_backups' );
|
564 |
+
delete_option( 'wp_db_backup_options' );
|
565 |
+
/* END : Prevent saving backup plugin settings in the database dump */
|
566 |
+
|
567 |
+
$tables_exclude = get_option( 'wp_db_exclude_table' );
|
568 |
+
$tables = $this->get_tables();
|
569 |
+
|
570 |
+
if ( $tables ) {
|
571 |
+
$output = '';
|
572 |
+
|
573 |
+
foreach ( $tables as $table ) {
|
574 |
+
if ( empty( $tables_exclude ) || ( ! ( in_array( $table, $tables_exclude, true ) ) ) ) {
|
575 |
+
// Create table SQL syntax
|
576 |
+
$create_table = $wpdb->get_row( 'SHOW CREATE TABLE ' . $table, ARRAY_N );
|
577 |
+
$output .= "\n\n" . $create_table[1] . ";\n\n";
|
578 |
+
|
579 |
+
// Insert records SQL syntax
|
580 |
+
$result = $wpdb->get_results( "SELECT * FROM {$table}", ARRAY_N );
|
581 |
+
$result_count = count( $result );
|
582 |
+
|
583 |
+
if ( $result ) {
|
584 |
+
for ( $i = 0; $i < $result_count; $i++ ) {
|
585 |
+
$row = $result[ $i ];
|
586 |
+
|
587 |
+
$output .= 'INSERT INTO ' . $table . ' VALUES(';
|
588 |
+
|
589 |
+
$row = array_map( [ $wpdb, '_real_escape' ], $row );
|
590 |
+
|
591 |
+
$output .= '"' . implode( '","', $row ) . '"';
|
592 |
+
|
593 |
+
$output .= ");\n";
|
594 |
+
}
|
595 |
+
}
|
596 |
+
|
597 |
+
$output .= "\n";
|
598 |
+
}
|
599 |
+
}
|
600 |
+
|
601 |
+
$this->jupiterx_filesystem->put_contents( $dump_file_path, $output );
|
602 |
+
|
603 |
+
$wpdb->flush();
|
604 |
+
}
|
605 |
+
|
606 |
+
/* BEGIN : Prevent saving backup plugin settings in the database dump */
|
607 |
+
add_option( 'wp_db_backup_backups', $options_backup );
|
608 |
+
add_option( 'wp_db_backup_options', $settings_backup );
|
609 |
+
/* END : Prevent saving backup plugin settings in the database dump */
|
610 |
+
|
611 |
+
return $this->jupiterx_filesystem->chmod( $dump_file_path, 0664 );
|
612 |
+
}
|
613 |
+
|
614 |
+
return $is_success;
|
615 |
+
}
|
616 |
+
|
617 |
+
/**
|
618 |
+
* Export current site media record to local disk
|
619 |
+
*
|
620 |
+
* @param $dump_file_path
|
621 |
+
* @return boolean
|
622 |
+
*/
|
623 |
+
private function dump_media_records( $dump_file_path ) {
|
624 |
+
global $wpdb;
|
625 |
+
|
626 |
+
$result = $wpdb->get_results( "SELECT * FROM $wpdb->posts where post_type='attachment'", ARRAY_N );
|
627 |
+
|
628 |
+
$is_success = $this->jupiterx_filesystem->put_contents( $dump_file_path, '', 0777 );
|
629 |
+
|
630 |
+
if ( $is_success ) {
|
631 |
+
$result = $wpdb->get_results( "SELECT * FROM $wpdb->posts where post_type='attachment'", ARRAY_N );
|
632 |
+
|
633 |
+
// Insert media records SQL syntax
|
634 |
+
if ( $result ) {
|
635 |
+
$result_count = count( $result );
|
636 |
+
|
637 |
+
$output = '';
|
638 |
+
|
639 |
+
for ( $i = 0; $i < $result_count; $i++ ) {
|
640 |
+
$row = $result[ $i ];
|
641 |
+
|
642 |
+
$output .= 'INSERT INTO ' . $wpdb->posts . ' VALUES(';
|
643 |
+
|
644 |
+
$row[0] = 'increament_id';
|
645 |
+
|
646 |
+
$row = array_map( [ $wpdb, '_real_escape' ], $row );
|
647 |
+
|
648 |
+
$output .= '"' . implode( '","', $row ) . '"';
|
649 |
+
|
650 |
+
$output .= ');' . "\n\n";
|
651 |
+
|
652 |
+
$wpdb->flush();
|
653 |
+
|
654 |
+
$postmeta_result = $wpdb->get_results( "SELECT * FROM $wpdb->postmeta where post_id = {$result[$i][0]}", ARRAY_N );
|
655 |
+
|
656 |
+
// Insert media meta records SQL syntax
|
657 |
+
if ( $postmeta_result ) {
|
658 |
+
$postmeta_result_count = count( $postmeta_result );
|
659 |
+
|
660 |
+
for ( $j = 0; $j < $postmeta_result_count; $j++ ) {
|
661 |
+
$postmeta_row = $postmeta_result[ $j ];
|
662 |
+
|
663 |
+
$output .= 'INSERT INTO ' . $wpdb->postmeta . ' VALUES(';
|
664 |
+
|
665 |
+
$postmeta_row[0] = 'meta_id';
|
666 |
+
|
667 |
+
$postmeta_row[1] = 'increament_id';
|
668 |
+
|
669 |
+
$postmeta_row = array_map( [ $wpdb, '_real_escape' ], $postmeta_row );
|
670 |
+
|
671 |
+
$output .= '"' . implode( '","', $postmeta_row ) . '"';
|
672 |
+
|
673 |
+
$output .= ');' . "\n";
|
674 |
+
}
|
675 |
+
|
676 |
+
$output .= "\n\n" . '---END-QUERY---' . "\n\n";
|
677 |
+
}
|
678 |
+
|
679 |
+
$output .= "\n\n\n";
|
680 |
+
}
|
681 |
+
|
682 |
+
$this->jupiterx_filesystem->put_contents( $dump_file_path, $output );
|
683 |
+
}
|
684 |
+
|
685 |
+
return $this->jupiterx_filesystem->chmod( $dump_file_path, 0664 );
|
686 |
+
}
|
687 |
+
|
688 |
+
return $is_success;
|
689 |
+
}
|
690 |
+
}
|
691 |
+
}
|
includes/control-panel/includes/class-db-php-manager.php
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handle database management using PHP.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel\PHP_Database_Manager
|
6 |
+
*
|
7 |
+
* @since 1.11.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* PHP database manager.
|
12 |
+
*
|
13 |
+
* @since 1.11.0
|
14 |
+
*/
|
15 |
+
class JupiterX_Control_Panel_PHP_DB_Manager {
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Set DB max time execution.
|
19 |
+
*/
|
20 |
+
const DB_MAX_TIME = 5000;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Custom table prefix.
|
24 |
+
*/
|
25 |
+
const TABLE_PREFIX = 'jx_';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Construct class.
|
29 |
+
*/
|
30 |
+
public function __constructor() {}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Dump database tables.
|
34 |
+
*
|
35 |
+
* @param string $file File path.
|
36 |
+
*
|
37 |
+
* @return boolean|string Dump success.
|
38 |
+
*/
|
39 |
+
public function dump_tables( $file, $pick_tables = [] ) {
|
40 |
+
try {
|
41 |
+
if ( empty( $pick_tables ) ) {
|
42 |
+
return true;
|
43 |
+
}
|
44 |
+
|
45 |
+
global $wpdb;
|
46 |
+
|
47 |
+
// Set DB wait time out.
|
48 |
+
$wpdb->query( 'SET session wait_timeout = ' . self::DB_MAX_TIME );
|
49 |
+
|
50 |
+
// Attempt to create file.
|
51 |
+
if ( ( $handle = fopen( $file, 'w+' ) ) === false ) {
|
52 |
+
throw new Exception( esc_html__( 'Can\'t open: ', 'jupiterx-core' ) . $file );
|
53 |
+
}
|
54 |
+
|
55 |
+
// Get tables.
|
56 |
+
$tables = $wpdb->get_col( "SHOW FULL TABLES WHERE Table_Type != 'VIEW'" );
|
57 |
+
$pick_tables = count( $pick_tables ) ? $pick_tables : null;
|
58 |
+
$query_limit = 100;
|
59 |
+
|
60 |
+
// Filter tables to dump.
|
61 |
+
if ( is_array( $pick_tables ) ) {
|
62 |
+
foreach ( $tables as $key => $table ) {
|
63 |
+
if ( ! in_array( $tables[ $key ], $pick_tables ) ) {
|
64 |
+
unset( $tables[ $key ] );
|
65 |
+
}
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
// Add file headers.
|
70 |
+
$sql_header = "/* JUPITERX-TABLES (PHP DUMP) MYSQL SCRIPT CREATED ON : " . @date( "Y-m-d H:i:s" ) . " */\n\n";
|
71 |
+
$sql_header .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
|
72 |
+
fwrite( $handle, $sql_header );
|
73 |
+
|
74 |
+
// All tables must be created before inserts due to foreign key constraints.
|
75 |
+
foreach ( $tables as $table ) {
|
76 |
+
$count = 1;
|
77 |
+
$rewrite_table = str_replace( $this->get_table_prefix(), self::TABLE_PREFIX, $table, $count );
|
78 |
+
|
79 |
+
// Drop table.
|
80 |
+
$drop_table_query = 'DROP TABLE IF EXISTS `' . $rewrite_table . '`';
|
81 |
+
fwrite( $handle, "/* DROP TABLE: {$rewrite_table} */\n" );
|
82 |
+
fwrite( $handle, "{$drop_table_query};\n\n" );
|
83 |
+
|
84 |
+
// Create table.
|
85 |
+
$create = $wpdb->get_row( "SHOW CREATE TABLE `{$table}`", ARRAY_N );
|
86 |
+
$create_table_query = str_replace( 'CREATE TABLE `' . $table . '`', 'CREATE TABLE `' . $rewrite_table . '`', $create[1], $count );
|
87 |
+
$create_table_query = trim( preg_replace( '/\s+/', ' ', $create_table_query ) );
|
88 |
+
fwrite( $handle, "/* CREATE TABLE: {$rewrite_table} */\n" );
|
89 |
+
fwrite( $handle, "{$create_table_query};\n\n" );
|
90 |
+
}
|
91 |
+
|
92 |
+
// Create insert in 100 row increments to better handle memory.
|
93 |
+
foreach ( $tables as $table ) {
|
94 |
+
$count = 1;
|
95 |
+
$row_count = $wpdb->get_var( "SELECT Count(*) FROM `{$table}`" );
|
96 |
+
$rewrite_table = str_replace( $this->get_table_prefix(), self::TABLE_PREFIX, $table, $count );
|
97 |
+
|
98 |
+
if ( $row_count > $query_limit ) {
|
99 |
+
$row_count = ceil( $row_count / $query_limit );
|
100 |
+
} else if ( $row_count > 0 ) {
|
101 |
+
$row_count = 1;
|
102 |
+
}
|
103 |
+
|
104 |
+
if ( $row_count >= 1 ) {
|
105 |
+
fwrite( $handle, "/* INSERT TABLE DATA: {$rewrite_table} */\n" );
|
106 |
+
}
|
107 |
+
|
108 |
+
for ( $i = 0; $i < $row_count; $i++ ) {
|
109 |
+
$sql = '';
|
110 |
+
$limit = $i * $query_limit;
|
111 |
+
$query = "SELECT * FROM `{$table}` LIMIT {$limit}, {$query_limit}";
|
112 |
+
$rows = $wpdb->get_results( $query, ARRAY_A );
|
113 |
+
|
114 |
+
if ( '' !== $wpdb->last_error ) {
|
115 |
+
throw new Exception( esc_html__( 'Please contact your database administrator to fix the error. Error: ', 'jupiterx-core' ) . $wpdb->last_error );
|
116 |
+
return;
|
117 |
+
}
|
118 |
+
|
119 |
+
if ( is_array( $rows ) ) {
|
120 |
+
foreach ( $rows as $row ) {
|
121 |
+
$sql .= "INSERT INTO `{$rewrite_table}` VALUES(";
|
122 |
+
$num_values = count( $row );
|
123 |
+
$num_counter = 1;
|
124 |
+
|
125 |
+
foreach ( $row as $value ) {
|
126 |
+
if ( is_null( $value ) || ! isset( $value ) ) {
|
127 |
+
( $num_values == $num_counter ) ? $sql .= 'NULL' : $sql .= 'NULL, ';
|
128 |
+
} else {
|
129 |
+
( $num_values == $num_counter )
|
130 |
+
? $sql .= '"' . $this->esc_sql( $value, true ) . '"'
|
131 |
+
: $sql .= '"' . $this->esc_sql( $value, true ) . '", ';
|
132 |
+
}
|
133 |
+
$num_counter++;
|
134 |
+
}
|
135 |
+
$sql .= ");\n";
|
136 |
+
}
|
137 |
+
fwrite( $handle, $sql );
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
$sql = null;
|
142 |
+
$rows = null;
|
143 |
+
fwrite( $handle, "\n" );
|
144 |
+
}
|
145 |
+
|
146 |
+
$sql_footer = "SET FOREIGN_KEY_CHECKS = 1;\n";
|
147 |
+
fwrite( $handle, $sql_footer );
|
148 |
+
$wpdb->flush();
|
149 |
+
fclose( $handle );
|
150 |
+
return true;
|
151 |
+
} catch ( Exception $e ) {
|
152 |
+
return $e->getMessage();
|
153 |
+
}
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Import to database.
|
158 |
+
*
|
159 |
+
* @return boolean|string Import success.
|
160 |
+
*/
|
161 |
+
public function import_tables( $file ) {
|
162 |
+
try {
|
163 |
+
if ( ! file_exists( $file ) ) {
|
164 |
+
throw new Exception( esc_html__( 'File not exist: ', 'jupiterx-core' ) . $file );
|
165 |
+
}
|
166 |
+
|
167 |
+
// Attempt to read file.
|
168 |
+
if ( ( $handle = fopen( $file, 'r' ) ) === false ) {
|
169 |
+
throw new Exception( esc_html__( 'Can\'t read: ', 'jupiterx-core' ) . $file );
|
170 |
+
}
|
171 |
+
|
172 |
+
global $wpdb;
|
173 |
+
|
174 |
+
while ( ! feof( $handle ) ) {
|
175 |
+
$line = fgets( $handle );
|
176 |
+
|
177 |
+
// Set allowed queries to run.
|
178 |
+
if ( preg_match( '/^\s*(?:SET.?|DROP TABLE.?|CREATE TABLE.?|INSERT INTO.?)\s+/is', $line ) ) {
|
179 |
+
$line = $this->replace_table_prefix( $line );
|
180 |
+
|
181 |
+
$wpdb->query( $line );
|
182 |
+
if ( '' !== $wpdb->last_error ) {
|
183 |
+
error_log( $wpdb->last_error );
|
184 |
+
}
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
$wpdb->flush();
|
189 |
+
fclose( $handle );
|
190 |
+
return true;
|
191 |
+
} catch ( Exception $e ) {
|
192 |
+
return $e->getMessage();
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Get table prefix.
|
198 |
+
*
|
199 |
+
* @return string Table prefix.
|
200 |
+
*/
|
201 |
+
public function get_table_prefix() {
|
202 |
+
global $wpdb;
|
203 |
+
|
204 |
+
return $wpdb->prefix;
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Escape SQL.
|
209 |
+
*
|
210 |
+
* @see https://make.wordpress.org/core/2017/10/31/changed-behaviour-of-esc_sql-in-wordpress-4-8-3
|
211 |
+
*
|
212 |
+
* @param string $data Data.
|
213 |
+
* @param boolean $placeholder_escape Escape placeholder.
|
214 |
+
*
|
215 |
+
* @return string Escaped data.
|
216 |
+
*/
|
217 |
+
private function esc_sql( $data, $placeholder_escape = false ) {
|
218 |
+
global $wpdb;
|
219 |
+
|
220 |
+
if ( $placeholder_escape ) {
|
221 |
+
return $wpdb->remove_placeholder_escape( @esc_sql( $data ) );
|
222 |
+
} else {
|
223 |
+
return @esc_sql( $data );
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Replace SQL line table prefix.
|
229 |
+
*
|
230 |
+
* @param string $line File line.
|
231 |
+
*
|
232 |
+
* @return string Updated line.
|
233 |
+
*/
|
234 |
+
private function replace_table_prefix( $line ) {
|
235 |
+
$count = 1;
|
236 |
+
|
237 |
+
if ( preg_match( '/CREATE TABLE `(.*?)`/', $line, $matches ) ) {
|
238 |
+
$rewrite_table = str_replace( self::TABLE_PREFIX, $this->get_table_prefix(), $matches[1], $count );
|
239 |
+
$line = str_replace( 'CREATE TABLE `' . $matches[1] . '`', 'CREATE TABLE `' . $rewrite_table . '`', $line, $count );
|
240 |
+
} elseif ( preg_match( '/INSERT INTO `(.*?)`/', $line, $matches ) ) {
|
241 |
+
$rewrite_table = str_replace( self::TABLE_PREFIX, $this->get_table_prefix(), $matches[1], $count );
|
242 |
+
$line = str_replace( 'INSERT INTO `' . $matches[1] . '`', 'INSERT INTO `' . $rewrite_table . '`', $line, $count );
|
243 |
+
} else if ( preg_match( '/DROP TABLE IF EXISTS `(.*?)`/', $line, $matches ) ) {
|
244 |
+
$rewrite_table = str_replace( self::TABLE_PREFIX, $this->get_table_prefix(), $matches[1], $count );
|
245 |
+
$line = str_replace( 'DROP TABLE IF EXISTS `' . $matches[1] . '`', 'DROP TABLE IF EXISTS `' . $rewrite_table . '`', $line, $count );
|
246 |
+
}
|
247 |
+
|
248 |
+
return $line;
|
249 |
+
}
|
250 |
+
}
|
includes/control-panel/includes/class-export-import-content.php
CHANGED
@@ -175,6 +175,10 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Export_Import' ) ) {
|
|
175 |
$this->export_settings();
|
176 |
break;
|
177 |
|
|
|
|
|
|
|
|
|
178 |
case 'End':
|
179 |
$this->export_end();
|
180 |
break;
|
@@ -483,6 +487,44 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Export_Import' ) ) {
|
|
483 |
}
|
484 |
}
|
485 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
486 |
/**
|
487 |
* Export customizer mods.
|
488 |
*
|
@@ -1218,6 +1260,44 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Export_Import' ) ) {
|
|
1218 |
|
1219 |
return false;
|
1220 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1221 |
}
|
1222 |
|
1223 |
new JupiterX_Control_Panel_Export_Import();
|
175 |
$this->export_settings();
|
176 |
break;
|
177 |
|
178 |
+
case 'Custom Tables':
|
179 |
+
$this->export_custom_tables();
|
180 |
+
break;
|
181 |
+
|
182 |
case 'End':
|
183 |
$this->export_end();
|
184 |
break;
|
487 |
}
|
488 |
}
|
489 |
|
490 |
+
/**
|
491 |
+
* Export custom tables.
|
492 |
+
*
|
493 |
+
* @since 1.11.0
|
494 |
+
*/
|
495 |
+
private function export_custom_tables() {
|
496 |
+
try {
|
497 |
+
$db_manager = new JupiterX_Control_Panel_PHP_DB_Manager();
|
498 |
+
|
499 |
+
$supported_plugins = $this->get_supported_plugins();
|
500 |
+
|
501 |
+
$supported_tables = array_filter( $this->get_supported_tables(), function( $plugin ) use ( $supported_plugins ) {
|
502 |
+
return in_array( $plugin, $supported_plugins, true );
|
503 |
+
}, ARRAY_FILTER_USE_KEY );
|
504 |
+
|
505 |
+
$tables = [];
|
506 |
+
|
507 |
+
// Prepare table names.
|
508 |
+
foreach ( $supported_tables as $plugin_tables ) {
|
509 |
+
foreach ( $plugin_tables as $table ) {
|
510 |
+
array_push( $tables, $db_manager->get_table_prefix() . $table );
|
511 |
+
}
|
512 |
+
}
|
513 |
+
|
514 |
+
if ( ! empty( $tables ) ) {
|
515 |
+
$dump_tables = $db_manager->dump_tables( $this->folder['export_dir'] . '/tables.sql', $tables );
|
516 |
+
|
517 |
+
if ( $dump_tables !== true ) {
|
518 |
+
throw new Exception( $dump_tables );
|
519 |
+
}
|
520 |
+
}
|
521 |
+
|
522 |
+
return wp_send_json_success( [ 'step' => 'Custom Tables' ] );
|
523 |
+
} catch ( Exception $e ) {
|
524 |
+
return wp_send_json_error( $e->getMessage() );
|
525 |
+
}
|
526 |
+
}
|
527 |
+
|
528 |
/**
|
529 |
* Export customizer mods.
|
530 |
*
|
1260 |
|
1261 |
return false;
|
1262 |
}
|
1263 |
+
|
1264 |
+
/**
|
1265 |
+
* Get supported plugins.
|
1266 |
+
*
|
1267 |
+
* @since 1.11.0
|
1268 |
+
*
|
1269 |
+
* @return array Supported plugins.
|
1270 |
+
*/
|
1271 |
+
private function get_supported_plugins() {
|
1272 |
+
$active_plugins = get_option( 'active_plugins' );
|
1273 |
+
|
1274 |
+
if ( is_multisite() ) {
|
1275 |
+
$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins' ) );
|
1276 |
+
}
|
1277 |
+
|
1278 |
+
$plugins = [];
|
1279 |
+
|
1280 |
+
foreach ( $active_plugins as $plugin ) {
|
1281 |
+
$plugins[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
1282 |
+
}
|
1283 |
+
|
1284 |
+
$supported_plugins = array_intersect( $plugins, $this->supported_plugins );
|
1285 |
+
|
1286 |
+
return $supported_plugins;
|
1287 |
+
}
|
1288 |
+
|
1289 |
+
/**
|
1290 |
+
* Get supported tables to export.
|
1291 |
+
*
|
1292 |
+
* @since 1.11.0
|
1293 |
+
*
|
1294 |
+
* @return array Supported tables.
|
1295 |
+
*/
|
1296 |
+
private function get_supported_tables() {
|
1297 |
+
return [
|
1298 |
+
'jet-engine' => [ 'jet_post_types', 'jet_taxonomies' ],
|
1299 |
+
];
|
1300 |
+
}
|
1301 |
}
|
1302 |
|
1303 |
new JupiterX_Control_Panel_Export_Import();
|
includes/control-panel/includes/class-filesystem.php
CHANGED
@@ -1,613 +1,613 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Class helper as wrapper of built-in WP wp_filesystem object
|
5 |
-
*
|
6 |
-
* @version 1.0.0
|
7 |
-
* @author Sofyan Sitorus <sofyan@artbees.net>
|
8 |
-
*
|
9 |
-
* @since 5.7
|
10 |
-
*/
|
11 |
-
|
12 |
-
require_once ABSPATH . 'wp-admin/includes/file.php';
|
13 |
-
require_once ABSPATH . 'wp-admin/includes/template.php';
|
14 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
15 |
-
|
16 |
-
|
17 |
-
if ( ! class_exists( 'JupiterX_Filesystem' ) ) {
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Filesystem class.
|
21 |
-
*
|
22 |
-
* @since 1.7.0
|
23 |
-
*/
|
24 |
-
class JupiterX_Filesystem {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* @var array
|
28 |
-
*/
|
29 |
-
private $options = [];
|
30 |
-
|
31 |
-
/**
|
32 |
-
* @var array
|
33 |
-
*/
|
34 |
-
public $errors = [];
|
35 |
-
|
36 |
-
/**
|
37 |
-
* @var null
|
38 |
-
*/
|
39 |
-
public $wp_filesystem = null;
|
40 |
-
|
41 |
-
/**
|
42 |
-
* @var array
|
43 |
-
*/
|
44 |
-
private $creds_data = [];
|
45 |
-
|
46 |
-
/**
|
47 |
-
* @var boolean
|
48 |
-
*/
|
49 |
-
private $initialized = false;
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Constructor
|
53 |
-
*
|
54 |
-
* @param (array) $args The arguments for the object options. Default: []
|
55 |
-
* @param (boolean) $init Whether to initialise the object instantly. Default: false.
|
56 |
-
* @param (boolean) $force Whether to force create new instance of $wp_filesystem object. Default: false.
|
57 |
-
*/
|
58 |
-
public function __construct( $args = [], $init = false, $force = false ) {
|
59 |
-
$this->errors = new WP_Error();
|
60 |
-
|
61 |
-
$args = wp_parse_args(
|
62 |
-
(array) $args, [
|
63 |
-
'form_post' => '', // (string) The URL to post the form to. Default: ''.
|
64 |
-
'type' => '', // (string) Chosen type of filesystem. Default: ''.
|
65 |
-
'error' => false, // (boolean) Whether the current request has failed to connect. Default: false.
|
66 |
-
'context' => '', // (string) Full path to the directory that is tested for being writable. Default: WP_CONTENT_DIR.
|
67 |
-
'extra_fields' => null, // (array) Extra POST fields in array key value pair format. Default: null.
|
68 |
-
'allow_relaxed_file_ownership' => false, // (boolean) Whether to allow Group/World writable. Default: false.
|
69 |
-
'override' => true, // (boolean) Whether to override some built-in function with custom function. Default: true.
|
70 |
-
]
|
71 |
-
);
|
72 |
-
|
73 |
-
foreach ( $args as $key => $value ) {
|
74 |
-
$this->setOption( $key, $value );
|
75 |
-
}
|
76 |
-
|
77 |
-
if ( $init ) {
|
78 |
-
$this->init( $force );
|
79 |
-
}
|
80 |
-
}
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Initialize the wp_filesystem object
|
84 |
-
*
|
85 |
-
* @param (boolean) $force Whether to force create new instance of $wp_filesystem object. Default: false.
|
86 |
-
* @return boolean
|
87 |
-
*/
|
88 |
-
public function init( $force = false ) {
|
89 |
-
|
90 |
-
global $wp_filesystem;
|
91 |
-
|
92 |
-
$this->initialized = true;
|
93 |
-
|
94 |
-
if ( ! $force && $wp_filesystem && $wp_filesystem instanceof WP_Filesystem_Base ) {
|
95 |
-
|
96 |
-
$this->wp_filesystem = $wp_filesystem;
|
97 |
-
return true;
|
98 |
-
|
99 |
-
} else {
|
100 |
-
|
101 |
-
$this->creds_data = request_filesystem_credentials(
|
102 |
-
$this->getOption( 'form_post' ),
|
103 |
-
$this->getOption( 'type' ),
|
104 |
-
$this->getOption( 'error' ),
|
105 |
-
$this->getOption( 'context' ),
|
106 |
-
$this->getOption( 'extra_fields' ),
|
107 |
-
$this->getOption( 'allow_relaxed_file_ownership' )
|
108 |
-
);
|
109 |
-
|
110 |
-
if ( ! WP_Filesystem( $this->creds_data, $this->getOption( 'context' ), $this->getOption( 'allow_relaxed_file_ownership' ) ) ) {
|
111 |
-
|
112 |
-
if ( isset( $wp_filesystem->errors ) && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
|
113 |
-
$this->add_error( $wp_filesystem->errors->get_error_code(), $wp_filesystem->errors->get_error_message(), $wp_filesystem->errors->get_error_data() );
|
114 |
-
} else {
|
115 |
-
$this->add_error( 'unable_to_connect_to_filesystem', __( 'Unable to connect to the filesystem. Please confirm your credentials.', 'jupiterx-core' ), $this->creds_data );
|
116 |
-
}
|
117 |
-
|
118 |
-
return false;
|
119 |
-
} else {
|
120 |
-
|
121 |
-
$this->wp_filesystem = $wp_filesystem;
|
122 |
-
|
123 |
-
return true;
|
124 |
-
}
|
125 |
-
}
|
126 |
-
}
|
127 |
-
|
128 |
-
/**
|
129 |
-
* Magic method to call the wp_filesystem method
|
130 |
-
*
|
131 |
-
* @param string $method
|
132 |
-
* @param array $args
|
133 |
-
* @return mixed
|
134 |
-
* @see wp-admin/includes/class-wp-filesystem-base.php for complete methods available
|
135 |
-
*/
|
136 |
-
public function __call( $method, $args ) {
|
137 |
-
|
138 |
-
// Try to initialize the wp_filesystem object
|
139 |
-
if ( ! $this->initialized ) {
|
140 |
-
$this->init();
|
141 |
-
}
|
142 |
-
|
143 |
-
// Stop execution if wp_filesystem objetc is empty
|
144 |
-
if ( ! $this->wp_filesystem || ! $this->wp_filesystem instanceof WP_Filesystem_Base ) {
|
145 |
-
return false;
|
146 |
-
}
|
147 |
-
|
148 |
-
// Do the magic, Abracadabra...!
|
149 |
-
switch ( $method ) {
|
150 |
-
case 'mkdir':
|
151 |
-
case 'put_contents':
|
152 |
-
case 'copy':
|
153 |
-
case 'is_writable':
|
154 |
-
if ( $this->getOption( 'override' ) ) {
|
155 |
-
$result = call_user_func_array( [ $this, $method . '_override' ], $args );
|
156 |
-
} else {
|
157 |
-
$result = call_user_func_array( [ $this->wp_filesystem, $method ], $args );
|
158 |
-
}
|
159 |
-
|
160 |
-
break;
|
161 |
-
|
162 |
-
case 'unzip':
|
163 |
-
$result = call_user_func_array( [ $this, $method . '_custom' ], $args );
|
164 |
-
|
165 |
-
break;
|
166 |
-
|
167 |
-
default:
|
168 |
-
if ( ! is_callable( [ $this->wp_filesystem, $method ] ) ) {
|
169 |
-
$this->add_error( 'invalid_wp_filesystem_method_' . $method, __( 'Invalid method for $wp_filesystem object!', 'jupiterx-core' ) );
|
170 |
-
$result = false;
|
171 |
-
} else {
|
172 |
-
$result = call_user_func_array( [ $this->wp_filesystem, $method ], $args );
|
173 |
-
}
|
174 |
-
|
175 |
-
break;
|
176 |
-
}
|
177 |
-
|
178 |
-
$this->setErrors();
|
179 |
-
|
180 |
-
return $result;
|
181 |
-
}
|
182 |
-
|
183 |
-
/**
|
184 |
-
* Create directory recursively
|
185 |
-
*
|
186 |
-
* @param (string) $path
|
187 |
-
* @param (boolean) $chmod
|
188 |
-
* @param (boolean) $chown
|
189 |
-
* @param (boolean) $chgrp
|
190 |
-
* @return boolean
|
191 |
-
*/
|
192 |
-
private function mkdir_override( $path, $chmod = false, $chown = false, $chgrp = false ) {
|
193 |
-
// Check if $path already exists
|
194 |
-
if ( $this->is_dir( $path ) ) {
|
195 |
-
return true;
|
196 |
-
} else {
|
197 |
-
|
198 |
-
// If file exists has same name with directory, delete it
|
199 |
-
if ( $this->exists( $path ) ) {
|
200 |
-
$this->delete( $path );
|
201 |
-
}
|
202 |
-
|
203 |
-
$path = str_replace( '\\', '/', $path );
|
204 |
-
|
205 |
-
// Split path as folder chunks.
|
206 |
-
$folders = explode( '/', trim( $path, '/' ) );
|
207 |
-
|
208 |
-
$path_prefix = str_replace( implode( '/', $folders ), '', rtrim( $path, '/' ) );
|
209 |
-
|
210 |
-
if ( $folders ) {
|
211 |
-
$new_folders = [];
|
212 |
-
|
213 |
-
// Check directories nested, create new if not exixts.
|
214 |
-
foreach ( $folders as $folder ) {
|
215 |
-
$new_folders[] = trim( $folder, '/' );
|
216 |
-
$new_folder = $path_prefix . implode( '/', $new_folders );
|
217 |
-
|
218 |
-
// Ignore folders outside open_basedir.
|
219 |
-
if ( $this->is_open_basedir_restricted( $new_folder ) ) {
|
220 |
-
continue;
|
221 |
-
}
|
222 |
-
|
223 |
-
// Skip if $new_folder already exists
|
224 |
-
if ( $this->is_dir( $new_folder ) ) {
|
225 |
-
continue;
|
226 |
-
}
|
227 |
-
|
228 |
-
// If file exists has same name with $new_folder, delete it
|
229 |
-
if ( $this->exists( $new_folder ) ) {
|
230 |
-
$this->delete( $new_folder );
|
231 |
-
}
|
232 |
-
|
233 |
-
// Create the $new_folder
|
234 |
-
if ( ! $this->wp_filesystem->mkdir( $new_folder, $chmod, $chown, $chgrp ) ) {
|
235 |
-
$this->add_error( 'can_not_create_directory', sprintf( __( 'Can\'t create directory %s', 'jupiterx-core' ), $new_folder ) );
|
236 |
-
return false;
|
237 |
-
}
|
238 |
-
}
|
239 |
-
}
|
240 |
-
return true;
|
241 |
-
}
|
242 |
-
}
|
243 |
-
|
244 |
-
/**
|
245 |
-
* Write contents to a file
|
246 |
-
*
|
247 |
-
* @param (string) $file
|
248 |
-
* @param (string) $contents
|
249 |
-
* @param (boolean) $mode
|
250 |
-
* @return boolean
|
251 |
-
*/
|
252 |
-
private function put_contents_override( $file, $contents, $mode = false ) {
|
253 |
-
|
254 |
-
if ( $this->is_dir( $file ) ) {
|
255 |
-
$this->add_error( 'directory_exists_has_same_name', sprintf( __( 'A directory exists has same name %s', 'jupiterx-core' ), $new_folder ) );
|
256 |
-
return false;
|
257 |
-
}
|
258 |
-
|
259 |
-
$path = dirname( $file );
|
260 |
-
|
261 |
-
if ( ! $this->is_dir( $path ) ) {
|
262 |
-
$this->mkdir( $path );
|
263 |
-
}
|
264 |
-
|
265 |
-
return $this->wp_filesystem->put_contents( $file, $contents, $mode );
|
266 |
-
}
|
267 |
-
|
268 |
-
/**
|
269 |
-
* Copy file
|
270 |
-
*
|
271 |
-
* @param (string) $source
|
272 |
-
* @param (string) $destination
|
273 |
-
* @param (boolean) $overwrite
|
274 |
-
* @param (boolean) $mode
|
275 |
-
* @return boolean
|
276 |
-
*/
|
277 |
-
private function copy_override( $source, $destination, $overwrite = true, $mode = false ) {
|
278 |
-
if ( ! $overwrite && $this->exists( $destination ) ) {
|
279 |
-
$this->add_error( 'file_already_exists', sprintf( __( 'File already exists %s', 'jupiterx-core' ), $new_folder ) );
|
280 |
-
return false;
|
281 |
-
}
|
282 |
-
|
283 |
-
if ( ! $this->exists( $source ) ) {
|
284 |
-
$this->add_error( 'copy_source_file_not_exists', sprintf( __( 'Copy source file not exists: %s', 'jupiterx-core' ), $source ) );
|
285 |
-
return false;
|
286 |
-
}
|
287 |
-
|
288 |
-
if ( ! $this->is_file( $source ) ) {
|
289 |
-
$this->add_error( 'copy_source_file_not_valid', sprintf( __( 'Copy source file not valid: %s', 'jupiterx-core' ), $source ) );
|
290 |
-
return false;
|
291 |
-
}
|
292 |
-
|
293 |
-
if ( ! $this->is_readable( $source ) ) {
|
294 |
-
$this->add_error( 'copy_source_file_not_readable', sprintf( __( 'Copy source file not readable: %s', 'jupiterx-core' ), $source ) );
|
295 |
-
return false;
|
296 |
-
}
|
297 |
-
|
298 |
-
$content = $this->get_contents( $source );
|
299 |
-
|
300 |
-
if ( false === $content ) {
|
301 |
-
return false;
|
302 |
-
}
|
303 |
-
|
304 |
-
return $this->put_contents( $destination, $content, $mode );
|
305 |
-
}
|
306 |
-
|
307 |
-
/**
|
308 |
-
* Check if file or directory is writable
|
309 |
-
*
|
310 |
-
* @param (string) $file
|
311 |
-
* @return boolean
|
312 |
-
*/
|
313 |
-
private function is_writable_override( $file ) {
|
314 |
-
|
315 |
-
if ( $this->is_dir( $file ) ) {
|
316 |
-
$temp_file = trailingslashit( $file ) . time() . '-' . uniqid() . '.tmp';
|
317 |
-
|
318 |
-
$this->put_contents( $temp_file, '' );
|
319 |
-
|
320 |
-
$is_writable = $this->wp_filesystem->is_writable( $temp_file );
|
321 |
-
|
322 |
-
$this->delete( $temp_file );
|
323 |
-
|
324 |
-
return $is_writable;
|
325 |
-
} else {
|
326 |
-
// Create the file if not exists
|
327 |
-
if ( ! $this->exists( $file ) ) {
|
328 |
-
$this->put_contents( $file, '' );
|
329 |
-
}
|
330 |
-
return $this->wp_filesystem->is_writable( $file );
|
331 |
-
}
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Create zip file of a folder and paste to a destination.
|
336 |
-
*
|
337 |
-
* @since 1.0.3
|
338 |
-
*
|
339 |
-
* @param string $folder Target folder to zip.
|
340 |
-
* @param string $destination Destination to save the zip.
|
341 |
-
* @param string $enclose Enclose all files inside a folder name.
|
342 |
-
*
|
343 |
-
* @return boolean Zipping status.
|
344 |
-
*/
|
345 |
-
public function zip_folder( $folder, $destination, $enclose ) {
|
346 |
-
if ( ! $this->exists( $folder ) ) {
|
347 |
-
return false;
|
348 |
-
}
|
349 |
-
|
350 |
-
$temp_file = tempnam( WP_CONTENT_DIR, 'zip' );
|
351 |
-
|
352 |
-
$zip = new ZipArchive();
|
353 |
-
|
354 |
-
$zip->open( $temp_file );
|
355 |
-
|
356 |
-
$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $folder ) );
|
357 |
-
|
358 |
-
foreach ( $files as $name => $file ) {
|
359 |
-
if ( $file->isDir() ) {
|
360 |
-
continue;
|
361 |
-
}
|
362 |
-
|
363 |
-
$file_path = $file->getRealPath();
|
364 |
-
|
365 |
-
$relative_path = substr( $file_path, strlen( $folder ) + 1 );
|
366 |
-
|
367 |
-
if ( ! empty( $enclose ) ) {
|
368 |
-
$relative_path = $enclose . '/' . $relative_path;
|
369 |
-
}
|
370 |
-
|
371 |
-
$zip->addFile( $file_path, $relative_path );
|
372 |
-
}
|
373 |
-
|
374 |
-
$zip->close();
|
375 |
-
|
376 |
-
// Copy the temp file to directory.
|
377 |
-
$this->copy( $temp_file, $destination );
|
378 |
-
|
379 |
-
// Delete temp file.
|
380 |
-
$this->delete( $temp_file );
|
381 |
-
|
382 |
-
// Check to make sure the file exists.
|
383 |
-
return $this->exists( $destination );
|
384 |
-
}
|
385 |
-
|
386 |
-
/**
|
387 |
-
* Extract zip file.
|
388 |
-
*
|
389 |
-
* @param [type] $source The source zip file.
|
390 |
-
* @param [type] $destination The destination path.
|
391 |
-
* @return [type] [description]
|
392 |
-
*/
|
393 |
-
public function unzip_custom( $source, $destination ) {
|
394 |
-
if ( ! $this->exists( $source ) ) {
|
395 |
-
$this->add_error( 'zip_source_file_not_exists', sprintf( __( 'Zip source file not exists: %s', 'jupiterx-core' ), $source ) );
|
396 |
-
return false;
|
397 |
-
}
|
398 |
-
|
399 |
-
if ( ! $this->is_file( $source ) ) {
|
400 |
-
$this->add_error( 'zip_source_file_not_valid', sprintf( __( 'Zip source file not valid: %s', 'jupiterx-core' ), $source ) );
|
401 |
-
return false;
|
402 |
-
}
|
403 |
-
|
404 |
-
if ( ! $this->is_readable( $source ) ) {
|
405 |
-
$this->add_error( 'zip_source_file_not_readable', sprintf( __( 'Zip source file not readable: %s', 'jupiterx-core' ), $source ) );
|
406 |
-
return false;
|
407 |
-
}
|
408 |
-
|
409 |
-
// Check $destination is valid
|
410 |
-
if ( ! $this->is_dir( $destination ) ) {
|
411 |
-
|
412 |
-
// If file exists has same name with $destination, delete it
|
413 |
-
if ( $this->exists( $destination ) ) {
|
414 |
-
$this->delete( $destination );
|
415 |
-
}
|
416 |
-
|
417 |
-
// Try create new $destination path
|
418 |
-
if ( ! $this->mkdir( $destination ) ) {
|
419 |
-
$this->add_error( 'fail_create_unzip_destination_directory', sprintf( __( 'Failed to create unzip destination directory: %s', 'jupiterx-core' ), $destination ) );
|
420 |
-
return false;
|
421 |
-
}
|
422 |
-
}
|
423 |
-
|
424 |
-
// Check $destination is writable
|
425 |
-
if ( ! $this->is_writable( $destination ) ) {
|
426 |
-
$this->add_error( 'unzip_destination_not_writable', sprintf( __( 'Unzip destination is not writable: %s', 'jupiterx-core' ), $destination ) );
|
427 |
-
return false;
|
428 |
-
}
|
429 |
-
|
430 |
-
global $wp_filesystem;
|
431 |
-
|
432 |
-
$wp_filesystem = $this->wp_filesystem;
|
433 |
-
|
434 |
-
$unzip_file = unzip_file( $source, $destination );
|
435 |
-
|
436 |
-
if ( is_wp_error( $unzip_file ) ) {
|
437 |
-
$this->add_error( $unzip_file->get_error_code(), $unzip_file->get_error_message() );
|
438 |
-
return false;
|
439 |
-
} elseif ( ! $unzip_file ) {
|
440 |
-
$this->add_error( 'failed_unzipping_file', sprintf( __( 'Failed unzipping file: %s', 'jupiterx-core' ), $source ) );
|
441 |
-
return false;
|
442 |
-
}
|
443 |
-
return true;
|
444 |
-
}
|
445 |
-
|
446 |
-
/**
|
447 |
-
* Set options data
|
448 |
-
*
|
449 |
-
* @param (string) $key
|
450 |
-
* @param (string) $value
|
451 |
-
* @return void
|
452 |
-
*/
|
453 |
-
public function setOption( $key, $value ) {
|
454 |
-
switch ( $key ) {
|
455 |
-
case 'context':
|
456 |
-
if ( ! empty( $value ) ) {
|
457 |
-
$value = is_dir( $value ) ? $value : dirname( $value );
|
458 |
-
$value = untrailingslashit( $value );
|
459 |
-
}
|
460 |
-
break;
|
461 |
-
}
|
462 |
-
$this->options[ $key ] = $value;
|
463 |
-
}
|
464 |
-
|
465 |
-
/**
|
466 |
-
* Get options data
|
467 |
-
*
|
468 |
-
* @param (string) $key
|
469 |
-
* @param (null|string) $default
|
470 |
-
* @return mixed
|
471 |
-
*/
|
472 |
-
public function getOption( $key = null, $default = null ) {
|
473 |
-
if ( null === $key ) {
|
474 |
-
return $this->options;
|
475 |
-
} else {
|
476 |
-
return isset( $this->options[ $key ] ) ? $this->options[ $key ] : $default;
|
477 |
-
}
|
478 |
-
}
|
479 |
-
|
480 |
-
/**
|
481 |
-
* Delete options data
|
482 |
-
*
|
483 |
-
* @param (string) $key
|
484 |
-
* @return void
|
485 |
-
*/
|
486 |
-
public function deleteOption( $key ) {
|
487 |
-
unset( $this->options[ $key ] );
|
488 |
-
}
|
489 |
-
|
490 |
-
/**
|
491 |
-
* Set errors data taken from the wp_filesystem errors
|
492 |
-
*
|
493 |
-
* @return void
|
494 |
-
*/
|
495 |
-
private function setErrors() {
|
496 |
-
if ( isset( $this->wp_filesystem->errors ) && is_wp_error( $this->wp_filesystem->errors ) && $this->wp_filesystem->errors->get_error_code() ) {
|
497 |
-
$this->add_error( $this->wp_filesystem->errors->get_error_code(), $this->wp_filesystem->errors->get_error_message() );
|
498 |
-
}
|
499 |
-
}
|
500 |
-
|
501 |
-
/**
|
502 |
-
* Get current connection method
|
503 |
-
*
|
504 |
-
* @return mixed
|
505 |
-
*/
|
506 |
-
public function getConnectionMethod() {
|
507 |
-
return isset( $this->wp_filesystem->method ) ? $this->wp_filesystem->method : false;
|
508 |
-
}
|
509 |
-
|
510 |
-
/**
|
511 |
-
* Get credentials data
|
512 |
-
*
|
513 |
-
* @return mixed
|
514 |
-
*/
|
515 |
-
public function getCredsData() {
|
516 |
-
return $this->creds_data;
|
517 |
-
}
|
518 |
-
|
519 |
-
/**
|
520 |
-
* Get all errors
|
521 |
-
*
|
522 |
-
* @return object Will return the WP_Error object
|
523 |
-
*/
|
524 |
-
public function get_errors() {
|
525 |
-
return $this->errors;
|
526 |
-
}
|
527 |
-
|
528 |
-
/**
|
529 |
-
* Retrieve all error codes
|
530 |
-
*
|
531 |
-
* @return array
|
532 |
-
*/
|
533 |
-
public function get_error_codes() {
|
534 |
-
return $this->errors->get_error_codes();
|
535 |
-
}
|
536 |
-
|
537 |
-
/**
|
538 |
-
* Retrieve first error code available
|
539 |
-
*
|
540 |
-
* @return string, int or Empty if there is no error codes
|
541 |
-
*/
|
542 |
-
public function get_error_code() {
|
543 |
-
return $this->errors->get_error_code();
|
544 |
-
}
|
545 |
-
|
546 |
-
/**
|
547 |
-
* Retrieve all error messages or error messages matching code
|
548 |
-
*
|
549 |
-
* @param (string) $code
|
550 |
-
* @return array
|
551 |
-
*/
|
552 |
-
public function get_error_messages( $code = '' ) {
|
553 |
-
return $this->errors->get_error_messages( $code );
|
554 |
-
}
|
555 |
-
|
556 |
-
/**
|
557 |
-
* Get the first error message available or error message matching code
|
558 |
-
*
|
559 |
-
* @param (string) $code
|
560 |
-
* @return string
|
561 |
-
*/
|
562 |
-
public function get_error_message( $code = '' ) {
|
563 |
-
return $this->errors->get_error_message( $code );
|
564 |
-
}
|
565 |
-
|
566 |
-
/**
|
567 |
-
* Append more error messages to list of error messages.
|
568 |
-
*
|
569 |
-
* @param (string) $code
|
570 |
-
* @param (string) $message
|
571 |
-
* @param (array) $data
|
572 |
-
* @return void
|
573 |
-
*/
|
574 |
-
public function add_error( $code, $message, $data = '' ) {
|
575 |
-
// Log the error
|
576 |
-
if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
|
577 |
-
error_log( 'JupiterX_Filesystem Error Code: ' . $code );
|
578 |
-
error_log( 'JupiterX_Filesystem Error Message: ' . $message );
|
579 |
-
if ( $data && ! is_resource( $data ) ) {
|
580 |
-
error_log( 'JupiterX_Filesystem Error Data: ' . wp_json_encode( $data ) );
|
581 |
-
}
|
582 |
-
}
|
583 |
-
$this->errors->add( $code, $message, $data );
|
584 |
-
}
|
585 |
-
|
586 |
-
/**
|
587 |
-
* Check path is outside open_basedir paths.
|
588 |
-
*
|
589 |
-
* @param string $path
|
590 |
-
* @return boolean
|
591 |
-
*/
|
592 |
-
public function is_open_basedir_restricted( $path ) {
|
593 |
-
$open_basedir_paths = ini_get('open_basedir');
|
594 |
-
|
595 |
-
if ( empty( $open_basedir_paths ) ) {
|
596 |
-
return false;
|
597 |
-
}
|
598 |
-
|
599 |
-
$open_basedir_paths = explode( PATH_SEPARATOR, $open_basedir_paths );
|
600 |
-
|
601 |
-
foreach ( $open_basedir_paths as $open_basedir_path ) {
|
602 |
-
if (
|
603 |
-
strpos( $open_basedir_path, $path ) === 0 &&
|
604 |
-
$open_basedir_path !== $path
|
605 |
-
) {
|
606 |
-
return true;
|
607 |
-
}
|
608 |
-
}
|
609 |
-
|
610 |
-
return false;
|
611 |
-
}
|
612 |
-
}
|
613 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class helper as wrapper of built-in WP wp_filesystem object
|
5 |
+
*
|
6 |
+
* @version 1.0.0
|
7 |
+
* @author Sofyan Sitorus <sofyan@artbees.net>
|
8 |
+
*
|
9 |
+
* @since 5.7
|
10 |
+
*/
|
11 |
+
|
12 |
+
require_once ABSPATH . 'wp-admin/includes/file.php';
|
13 |
+
require_once ABSPATH . 'wp-admin/includes/template.php';
|
14 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
15 |
+
|
16 |
+
|
17 |
+
if ( ! class_exists( 'JupiterX_Filesystem' ) ) {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Filesystem class.
|
21 |
+
*
|
22 |
+
* @since 1.7.0
|
23 |
+
*/
|
24 |
+
class JupiterX_Filesystem {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var array
|
28 |
+
*/
|
29 |
+
private $options = [];
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @var array
|
33 |
+
*/
|
34 |
+
public $errors = [];
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @var null
|
38 |
+
*/
|
39 |
+
public $wp_filesystem = null;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @var array
|
43 |
+
*/
|
44 |
+
private $creds_data = [];
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @var boolean
|
48 |
+
*/
|
49 |
+
private $initialized = false;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Constructor
|
53 |
+
*
|
54 |
+
* @param (array) $args The arguments for the object options. Default: []
|
55 |
+
* @param (boolean) $init Whether to initialise the object instantly. Default: false.
|
56 |
+
* @param (boolean) $force Whether to force create new instance of $wp_filesystem object. Default: false.
|
57 |
+
*/
|
58 |
+
public function __construct( $args = [], $init = false, $force = false ) {
|
59 |
+
$this->errors = new WP_Error();
|
60 |
+
|
61 |
+
$args = wp_parse_args(
|
62 |
+
(array) $args, [
|
63 |
+
'form_post' => '', // (string) The URL to post the form to. Default: ''.
|
64 |
+
'type' => '', // (string) Chosen type of filesystem. Default: ''.
|
65 |
+
'error' => false, // (boolean) Whether the current request has failed to connect. Default: false.
|
66 |
+
'context' => '', // (string) Full path to the directory that is tested for being writable. Default: WP_CONTENT_DIR.
|
67 |
+
'extra_fields' => null, // (array) Extra POST fields in array key value pair format. Default: null.
|
68 |
+
'allow_relaxed_file_ownership' => false, // (boolean) Whether to allow Group/World writable. Default: false.
|
69 |
+
'override' => true, // (boolean) Whether to override some built-in function with custom function. Default: true.
|
70 |
+
]
|
71 |
+
);
|
72 |
+
|
73 |
+
foreach ( $args as $key => $value ) {
|
74 |
+
$this->setOption( $key, $value );
|
75 |
+
}
|
76 |
+
|
77 |
+
if ( $init ) {
|
78 |
+
$this->init( $force );
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Initialize the wp_filesystem object
|
84 |
+
*
|
85 |
+
* @param (boolean) $force Whether to force create new instance of $wp_filesystem object. Default: false.
|
86 |
+
* @return boolean
|
87 |
+
*/
|
88 |
+
public function init( $force = false ) {
|
89 |
+
|
90 |
+
global $wp_filesystem;
|
91 |
+
|
92 |
+
$this->initialized = true;
|
93 |
+
|
94 |
+
if ( ! $force && $wp_filesystem && $wp_filesystem instanceof WP_Filesystem_Base ) {
|
95 |
+
|
96 |
+
$this->wp_filesystem = $wp_filesystem;
|
97 |
+
return true;
|
98 |
+
|
99 |
+
} else {
|
100 |
+
|
101 |
+
$this->creds_data = request_filesystem_credentials(
|
102 |
+
$this->getOption( 'form_post' ),
|
103 |
+
$this->getOption( 'type' ),
|
104 |
+
$this->getOption( 'error' ),
|
105 |
+
$this->getOption( 'context' ),
|
106 |
+
$this->getOption( 'extra_fields' ),
|
107 |
+
$this->getOption( 'allow_relaxed_file_ownership' )
|
108 |
+
);
|
109 |
+
|
110 |
+
if ( ! WP_Filesystem( $this->creds_data, $this->getOption( 'context' ), $this->getOption( 'allow_relaxed_file_ownership' ) ) ) {
|
111 |
+
|
112 |
+
if ( isset( $wp_filesystem->errors ) && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
|
113 |
+
$this->add_error( $wp_filesystem->errors->get_error_code(), $wp_filesystem->errors->get_error_message(), $wp_filesystem->errors->get_error_data() );
|
114 |
+
} else {
|
115 |
+
$this->add_error( 'unable_to_connect_to_filesystem', __( 'Unable to connect to the filesystem. Please confirm your credentials.', 'jupiterx-core' ), $this->creds_data );
|
116 |
+
}
|
117 |
+
|
118 |
+
return false;
|
119 |
+
} else {
|
120 |
+
|
121 |
+
$this->wp_filesystem = $wp_filesystem;
|
122 |
+
|
123 |
+
return true;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Magic method to call the wp_filesystem method
|
130 |
+
*
|
131 |
+
* @param string $method
|
132 |
+
* @param array $args
|
133 |
+
* @return mixed
|
134 |
+
* @see wp-admin/includes/class-wp-filesystem-base.php for complete methods available
|
135 |
+
*/
|
136 |
+
public function __call( $method, $args ) {
|
137 |
+
|
138 |
+
// Try to initialize the wp_filesystem object
|
139 |
+
if ( ! $this->initialized ) {
|
140 |
+
$this->init();
|
141 |
+
}
|
142 |
+
|
143 |
+
// Stop execution if wp_filesystem objetc is empty
|
144 |
+
if ( ! $this->wp_filesystem || ! $this->wp_filesystem instanceof WP_Filesystem_Base ) {
|
145 |
+
return false;
|
146 |
+
}
|
147 |
+
|
148 |
+
// Do the magic, Abracadabra...!
|
149 |
+
switch ( $method ) {
|
150 |
+
case 'mkdir':
|
151 |
+
case 'put_contents':
|
152 |
+
case 'copy':
|
153 |
+
case 'is_writable':
|
154 |
+
if ( $this->getOption( 'override' ) ) {
|
155 |
+
$result = call_user_func_array( [ $this, $method . '_override' ], $args );
|
156 |
+
} else {
|
157 |
+
$result = call_user_func_array( [ $this->wp_filesystem, $method ], $args );
|
158 |
+
}
|
159 |
+
|
160 |
+
break;
|
161 |
+
|
162 |
+
case 'unzip':
|
163 |
+
$result = call_user_func_array( [ $this, $method . '_custom' ], $args );
|
164 |
+
|
165 |
+
break;
|
166 |
+
|
167 |
+
default:
|
168 |
+
if ( ! is_callable( [ $this->wp_filesystem, $method ] ) ) {
|
169 |
+
$this->add_error( 'invalid_wp_filesystem_method_' . $method, __( 'Invalid method for $wp_filesystem object!', 'jupiterx-core' ) );
|
170 |
+
$result = false;
|
171 |
+
} else {
|
172 |
+
$result = call_user_func_array( [ $this->wp_filesystem, $method ], $args );
|
173 |
+
}
|
174 |
+
|
175 |
+
break;
|
176 |
+
}
|
177 |
+
|
178 |
+
$this->setErrors();
|
179 |
+
|
180 |
+
return $result;
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Create directory recursively
|
185 |
+
*
|
186 |
+
* @param (string) $path
|
187 |
+
* @param (boolean) $chmod
|
188 |
+
* @param (boolean) $chown
|
189 |
+
* @param (boolean) $chgrp
|
190 |
+
* @return boolean
|
191 |
+
*/
|
192 |
+
private function mkdir_override( $path, $chmod = false, $chown = false, $chgrp = false ) {
|
193 |
+
// Check if $path already exists
|
194 |
+
if ( $this->is_dir( $path ) ) {
|
195 |
+
return true;
|
196 |
+
} else {
|
197 |
+
|
198 |
+
// If file exists has same name with directory, delete it
|
199 |
+
if ( $this->exists( $path ) ) {
|
200 |
+
$this->delete( $path );
|
201 |
+
}
|
202 |
+
|
203 |
+
$path = str_replace( '\\', '/', $path );
|
204 |
+
|
205 |
+
// Split path as folder chunks.
|
206 |
+
$folders = explode( '/', trim( $path, '/' ) );
|
207 |
+
|
208 |
+
$path_prefix = str_replace( implode( '/', $folders ), '', rtrim( $path, '/' ) );
|
209 |
+
|
210 |
+
if ( $folders ) {
|
211 |
+
$new_folders = [];
|
212 |
+
|
213 |
+
// Check directories nested, create new if not exixts.
|
214 |
+
foreach ( $folders as $folder ) {
|
215 |
+
$new_folders[] = trim( $folder, '/' );
|
216 |
+
$new_folder = $path_prefix . implode( '/', $new_folders );
|
217 |
+
|
218 |
+
// Ignore folders outside open_basedir.
|
219 |
+
if ( $this->is_open_basedir_restricted( $new_folder ) ) {
|
220 |
+
continue;
|
221 |
+
}
|
222 |
+
|
223 |
+
// Skip if $new_folder already exists
|
224 |
+
if ( $this->is_dir( $new_folder ) ) {
|
225 |
+
continue;
|
226 |
+
}
|
227 |
+
|
228 |
+
// If file exists has same name with $new_folder, delete it
|
229 |
+
if ( $this->exists( $new_folder ) ) {
|
230 |
+
$this->delete( $new_folder );
|
231 |
+
}
|
232 |
+
|
233 |
+
// Create the $new_folder
|
234 |
+
if ( ! $this->wp_filesystem->mkdir( $new_folder, $chmod, $chown, $chgrp ) ) {
|
235 |
+
$this->add_error( 'can_not_create_directory', sprintf( __( 'Can\'t create directory %s', 'jupiterx-core' ), $new_folder ) );
|
236 |
+
return false;
|
237 |
+
}
|
238 |
+
}
|
239 |
+
}
|
240 |
+
return true;
|
241 |
+
}
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Write contents to a file
|
246 |
+
*
|
247 |
+
* @param (string) $file
|
248 |
+
* @param (string) $contents
|
249 |
+
* @param (boolean) $mode
|
250 |
+
* @return boolean
|
251 |
+
*/
|
252 |
+
private function put_contents_override( $file, $contents, $mode = false ) {
|
253 |
+
|
254 |
+
if ( $this->is_dir( $file ) ) {
|
255 |
+
$this->add_error( 'directory_exists_has_same_name', sprintf( __( 'A directory exists has same name %s', 'jupiterx-core' ), $new_folder ) );
|
256 |
+
return false;
|
257 |
+
}
|
258 |
+
|
259 |
+
$path = dirname( $file );
|
260 |
+
|
261 |
+
if ( ! $this->is_dir( $path ) ) {
|
262 |
+
$this->mkdir( $path );
|
263 |
+
}
|
264 |
+
|
265 |
+
return $this->wp_filesystem->put_contents( $file, $contents, $mode );
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Copy file
|
270 |
+
*
|
271 |
+
* @param (string) $source
|
272 |
+
* @param (string) $destination
|
273 |
+
* @param (boolean) $overwrite
|
274 |
+
* @param (boolean) $mode
|
275 |
+
* @return boolean
|
276 |
+
*/
|
277 |
+
private function copy_override( $source, $destination, $overwrite = true, $mode = false ) {
|
278 |
+
if ( ! $overwrite && $this->exists( $destination ) ) {
|
279 |
+
$this->add_error( 'file_already_exists', sprintf( __( 'File already exists %s', 'jupiterx-core' ), $new_folder ) );
|
280 |
+
return false;
|
281 |
+
}
|
282 |
+
|
283 |
+
if ( ! $this->exists( $source ) ) {
|
284 |
+
$this->add_error( 'copy_source_file_not_exists', sprintf( __( 'Copy source file not exists: %s', 'jupiterx-core' ), $source ) );
|
285 |
+
return false;
|
286 |
+
}
|
287 |
+
|
288 |
+
if ( ! $this->is_file( $source ) ) {
|
289 |
+
$this->add_error( 'copy_source_file_not_valid', sprintf( __( 'Copy source file not valid: %s', 'jupiterx-core' ), $source ) );
|
290 |
+
return false;
|
291 |
+
}
|
292 |
+
|
293 |
+
if ( ! $this->is_readable( $source ) ) {
|
294 |
+
$this->add_error( 'copy_source_file_not_readable', sprintf( __( 'Copy source file not readable: %s', 'jupiterx-core' ), $source ) );
|
295 |
+
return false;
|
296 |
+
}
|
297 |
+
|
298 |
+
$content = $this->get_contents( $source );
|
299 |
+
|
300 |
+
if ( false === $content ) {
|
301 |
+
return false;
|
302 |
+
}
|
303 |
+
|
304 |
+
return $this->put_contents( $destination, $content, $mode );
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Check if file or directory is writable
|
309 |
+
*
|
310 |
+
* @param (string) $file
|
311 |
+
* @return boolean
|
312 |
+
*/
|
313 |
+
private function is_writable_override( $file ) {
|
314 |
+
|
315 |
+
if ( $this->is_dir( $file ) ) {
|
316 |
+
$temp_file = trailingslashit( $file ) . time() . '-' . uniqid() . '.tmp';
|
317 |
+
|
318 |
+
$this->put_contents( $temp_file, '' );
|
319 |
+
|
320 |
+
$is_writable = $this->wp_filesystem->is_writable( $temp_file );
|
321 |
+
|
322 |
+
$this->delete( $temp_file );
|
323 |
+
|
324 |
+
return $is_writable;
|
325 |
+
} else {
|
326 |
+
// Create the file if not exists
|
327 |
+
if ( ! $this->exists( $file ) ) {
|
328 |
+
$this->put_contents( $file, '' );
|
329 |
+
}
|
330 |
+
return $this->wp_filesystem->is_writable( $file );
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Create zip file of a folder and paste to a destination.
|
336 |
+
*
|
337 |
+
* @since 1.0.3
|
338 |
+
*
|
339 |
+
* @param string $folder Target folder to zip.
|
340 |
+
* @param string $destination Destination to save the zip.
|
341 |
+
* @param string $enclose Enclose all files inside a folder name.
|
342 |
+
*
|
343 |
+
* @return boolean Zipping status.
|
344 |
+
*/
|
345 |
+
public function zip_folder( $folder, $destination, $enclose ) {
|
346 |
+
if ( ! $this->exists( $folder ) ) {
|
347 |
+
return false;
|
348 |
+
}
|
349 |
+
|
350 |
+
$temp_file = tempnam( WP_CONTENT_DIR, 'zip' );
|
351 |
+
|
352 |
+
$zip = new ZipArchive();
|
353 |
+
|
354 |
+
$zip->open( $temp_file );
|
355 |
+
|
356 |
+
$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $folder ) );
|
357 |
+
|
358 |
+
foreach ( $files as $name => $file ) {
|
359 |
+
if ( $file->isDir() ) {
|
360 |
+
continue;
|
361 |
+
}
|
362 |
+
|
363 |
+
$file_path = $file->getRealPath();
|
364 |
+
|
365 |
+
$relative_path = substr( $file_path, strlen( $folder ) + 1 );
|
366 |
+
|
367 |
+
if ( ! empty( $enclose ) ) {
|
368 |
+
$relative_path = $enclose . '/' . $relative_path;
|
369 |
+
}
|
370 |
+
|
371 |
+
$zip->addFile( $file_path, $relative_path );
|
372 |
+
}
|
373 |
+
|
374 |
+
$zip->close();
|
375 |
+
|
376 |
+
// Copy the temp file to directory.
|
377 |
+
$this->copy( $temp_file, $destination );
|
378 |
+
|
379 |
+
// Delete temp file.
|
380 |
+
$this->delete( $temp_file );
|
381 |
+
|
382 |
+
// Check to make sure the file exists.
|
383 |
+
return $this->exists( $destination );
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Extract zip file.
|
388 |
+
*
|
389 |
+
* @param [type] $source The source zip file.
|
390 |
+
* @param [type] $destination The destination path.
|
391 |
+
* @return [type] [description]
|
392 |
+
*/
|
393 |
+
public function unzip_custom( $source, $destination ) {
|
394 |
+
if ( ! $this->exists( $source ) ) {
|
395 |
+
$this->add_error( 'zip_source_file_not_exists', sprintf( __( 'Zip source file not exists: %s', 'jupiterx-core' ), $source ) );
|
396 |
+
return false;
|
397 |
+
}
|
398 |
+
|
399 |
+
if ( ! $this->is_file( $source ) ) {
|
400 |
+
$this->add_error( 'zip_source_file_not_valid', sprintf( __( 'Zip source file not valid: %s', 'jupiterx-core' ), $source ) );
|
401 |
+
return false;
|
402 |
+
}
|
403 |
+
|
404 |
+
if ( ! $this->is_readable( $source ) ) {
|
405 |
+
$this->add_error( 'zip_source_file_not_readable', sprintf( __( 'Zip source file not readable: %s', 'jupiterx-core' ), $source ) );
|
406 |
+
return false;
|
407 |
+
}
|
408 |
+
|
409 |
+
// Check $destination is valid
|
410 |
+
if ( ! $this->is_dir( $destination ) ) {
|
411 |
+
|
412 |
+
// If file exists has same name with $destination, delete it
|
413 |
+
if ( $this->exists( $destination ) ) {
|
414 |
+
$this->delete( $destination );
|
415 |
+
}
|
416 |
+
|
417 |
+
// Try create new $destination path
|
418 |
+
if ( ! $this->mkdir( $destination ) ) {
|
419 |
+
$this->add_error( 'fail_create_unzip_destination_directory', sprintf( __( 'Failed to create unzip destination directory: %s', 'jupiterx-core' ), $destination ) );
|
420 |
+
return false;
|
421 |
+
}
|
422 |
+
}
|
423 |
+
|
424 |
+
// Check $destination is writable
|
425 |
+
if ( ! $this->is_writable( $destination ) ) {
|
426 |
+
$this->add_error( 'unzip_destination_not_writable', sprintf( __( 'Unzip destination is not writable: %s', 'jupiterx-core' ), $destination ) );
|
427 |
+
return false;
|
428 |
+
}
|
429 |
+
|
430 |
+
global $wp_filesystem;
|
431 |
+
|
432 |
+
$wp_filesystem = $this->wp_filesystem;
|
433 |
+
|
434 |
+
$unzip_file = unzip_file( $source, $destination );
|
435 |
+
|
436 |
+
if ( is_wp_error( $unzip_file ) ) {
|
437 |
+
$this->add_error( $unzip_file->get_error_code(), $unzip_file->get_error_message() );
|
438 |
+
return false;
|
439 |
+
} elseif ( ! $unzip_file ) {
|
440 |
+
$this->add_error( 'failed_unzipping_file', sprintf( __( 'Failed unzipping file: %s', 'jupiterx-core' ), $source ) );
|
441 |
+
return false;
|
442 |
+
}
|
443 |
+
return true;
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Set options data
|
448 |
+
*
|
449 |
+
* @param (string) $key
|
450 |
+
* @param (string) $value
|
451 |
+
* @return void
|
452 |
+
*/
|
453 |
+
public function setOption( $key, $value ) {
|
454 |
+
switch ( $key ) {
|
455 |
+
case 'context':
|
456 |
+
if ( ! empty( $value ) ) {
|
457 |
+
$value = is_dir( $value ) ? $value : dirname( $value );
|
458 |
+
$value = untrailingslashit( $value );
|
459 |
+
}
|
460 |
+
break;
|
461 |
+
}
|
462 |
+
$this->options[ $key ] = $value;
|
463 |
+
}
|
464 |
+
|
465 |
+
/**
|
466 |
+
* Get options data
|
467 |
+
*
|
468 |
+
* @param (string) $key
|
469 |
+
* @param (null|string) $default
|
470 |
+
* @return mixed
|
471 |
+
*/
|
472 |
+
public function getOption( $key = null, $default = null ) {
|
473 |
+
if ( null === $key ) {
|
474 |
+
return $this->options;
|
475 |
+
} else {
|
476 |
+
return isset( $this->options[ $key ] ) ? $this->options[ $key ] : $default;
|
477 |
+
}
|
478 |
+
}
|
479 |
+
|
480 |
+
/**
|
481 |
+
* Delete options data
|
482 |
+
*
|
483 |
+
* @param (string) $key
|
484 |
+
* @return void
|
485 |
+
*/
|
486 |
+
public function deleteOption( $key ) {
|
487 |
+
unset( $this->options[ $key ] );
|
488 |
+
}
|
489 |
+
|
490 |
+
/**
|
491 |
+
* Set errors data taken from the wp_filesystem errors
|
492 |
+
*
|
493 |
+
* @return void
|
494 |
+
*/
|
495 |
+
private function setErrors() {
|
496 |
+
if ( isset( $this->wp_filesystem->errors ) && is_wp_error( $this->wp_filesystem->errors ) && $this->wp_filesystem->errors->get_error_code() ) {
|
497 |
+
$this->add_error( $this->wp_filesystem->errors->get_error_code(), $this->wp_filesystem->errors->get_error_message() );
|
498 |
+
}
|
499 |
+
}
|
500 |
+
|
501 |
+
/**
|
502 |
+
* Get current connection method
|
503 |
+
*
|
504 |
+
* @return mixed
|
505 |
+
*/
|
506 |
+
public function getConnectionMethod() {
|
507 |
+
return isset( $this->wp_filesystem->method ) ? $this->wp_filesystem->method : false;
|
508 |
+
}
|
509 |
+
|
510 |
+
/**
|
511 |
+
* Get credentials data
|
512 |
+
*
|
513 |
+
* @return mixed
|
514 |
+
*/
|
515 |
+
public function getCredsData() {
|
516 |
+
return $this->creds_data;
|
517 |
+
}
|
518 |
+
|
519 |
+
/**
|
520 |
+
* Get all errors
|
521 |
+
*
|
522 |
+
* @return object Will return the WP_Error object
|
523 |
+
*/
|
524 |
+
public function get_errors() {
|
525 |
+
return $this->errors;
|
526 |
+
}
|
527 |
+
|
528 |
+
/**
|
529 |
+
* Retrieve all error codes
|
530 |
+
*
|
531 |
+
* @return array
|
532 |
+
*/
|
533 |
+
public function get_error_codes() {
|
534 |
+
return $this->errors->get_error_codes();
|
535 |
+
}
|
536 |
+
|
537 |
+
/**
|
538 |
+
* Retrieve first error code available
|
539 |
+
*
|
540 |
+
* @return string, int or Empty if there is no error codes
|
541 |
+
*/
|
542 |
+
public function get_error_code() {
|
543 |
+
return $this->errors->get_error_code();
|
544 |
+
}
|
545 |
+
|
546 |
+
/**
|
547 |
+
* Retrieve all error messages or error messages matching code
|
548 |
+
*
|
549 |
+
* @param (string) $code
|
550 |
+
* @return array
|
551 |
+
*/
|
552 |
+
public function get_error_messages( $code = '' ) {
|
553 |
+
return $this->errors->get_error_messages( $code );
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Get the first error message available or error message matching code
|
558 |
+
*
|
559 |
+
* @param (string) $code
|
560 |
+
* @return string
|
561 |
+
*/
|
562 |
+
public function get_error_message( $code = '' ) {
|
563 |
+
return $this->errors->get_error_message( $code );
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Append more error messages to list of error messages.
|
568 |
+
*
|
569 |
+
* @param (string) $code
|
570 |
+
* @param (string) $message
|
571 |
+
* @param (array) $data
|
572 |
+
* @return void
|
573 |
+
*/
|
574 |
+
public function add_error( $code, $message, $data = '' ) {
|
575 |
+
// Log the error
|
576 |
+
if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
|
577 |
+
error_log( 'JupiterX_Filesystem Error Code: ' . $code );
|
578 |
+
error_log( 'JupiterX_Filesystem Error Message: ' . $message );
|
579 |
+
if ( $data && ! is_resource( $data ) ) {
|
580 |
+
error_log( 'JupiterX_Filesystem Error Data: ' . wp_json_encode( $data ) );
|
581 |
+
}
|
582 |
+
}
|
583 |
+
$this->errors->add( $code, $message, $data );
|
584 |
+
}
|
585 |
+
|
586 |
+
/**
|
587 |
+
* Check path is outside open_basedir paths.
|
588 |
+
*
|
589 |
+
* @param string $path
|
590 |
+
* @return boolean
|
591 |
+
*/
|
592 |
+
public function is_open_basedir_restricted( $path ) {
|
593 |
+
$open_basedir_paths = ini_get('open_basedir');
|
594 |
+
|
595 |
+
if ( empty( $open_basedir_paths ) ) {
|
596 |
+
return false;
|
597 |
+
}
|
598 |
+
|
599 |
+
$open_basedir_paths = explode( PATH_SEPARATOR, $open_basedir_paths );
|
600 |
+
|
601 |
+
foreach ( $open_basedir_paths as $open_basedir_path ) {
|
602 |
+
if (
|
603 |
+
strpos( $open_basedir_path, $path ) === 0 &&
|
604 |
+
$open_basedir_path !== $path
|
605 |
+
) {
|
606 |
+
return true;
|
607 |
+
}
|
608 |
+
}
|
609 |
+
|
610 |
+
return false;
|
611 |
+
}
|
612 |
+
}
|
613 |
+
}
|
includes/control-panel/includes/class-helpers.php
CHANGED
@@ -1,510 +1,510 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Helpers' ) ) {
|
3 |
-
/**
|
4 |
-
* Helper functions class.
|
5 |
-
*
|
6 |
-
* @since 1.7.0
|
7 |
-
*/
|
8 |
-
class JupiterX_Control_Panel_Helpers {
|
9 |
-
|
10 |
-
/**
|
11 |
-
* Method that is resposible to unzip compress files .
|
12 |
-
* it used native WordPress functions.
|
13 |
-
*
|
14 |
-
* @since 1.0.0
|
15 |
-
* @author Artbees <info@artbees.net>
|
16 |
-
*
|
17 |
-
* @param str $zip_path compress file absolute path.
|
18 |
-
* @param str $dest_path Where should it be uncompressed.
|
19 |
-
*
|
20 |
-
* @return bool will return boolean status of action
|
21 |
-
*/
|
22 |
-
public static function un_zip( $zip_path, $dest_path ) {
|
23 |
-
|
24 |
-
$zip_path = realpath( $zip_path );
|
25 |
-
$dest_path = realpath( $dest_path );
|
26 |
-
|
27 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
28 |
-
array(
|
29 |
-
'context' => $dest_path,
|
30 |
-
)
|
31 |
-
);
|
32 |
-
|
33 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
34 |
-
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
35 |
-
return false;
|
36 |
-
}
|
37 |
-
|
38 |
-
if ( ! $jupiterx_filesystem->exists( $zip_path ) ) {
|
39 |
-
throw new Exception( __( 'Zip file that you are looking for is not exist', 'jupiterx-core' ) );
|
40 |
-
return false;
|
41 |
-
}
|
42 |
-
|
43 |
-
if ( ! $jupiterx_filesystem->exists( $dest_path ) ) {
|
44 |
-
if ( ! $jupiterx_filesystem->mkdir( $dest_path ) ) {
|
45 |
-
throw new Exception( __( 'Unzip destination path not exist', 'jupiterx-core' ) );
|
46 |
-
return false;
|
47 |
-
}
|
48 |
-
}
|
49 |
-
|
50 |
-
if ( ! $jupiterx_filesystem->is_writable( $dest_path ) ) {
|
51 |
-
throw new Exception( __( 'Unzip destination is not writable , Please resolve this issue first.', 'jupiterx-core' ) );
|
52 |
-
return false;
|
53 |
-
}
|
54 |
-
|
55 |
-
$unzipfile = unzip_file( $zip_path, $dest_path );
|
56 |
-
if ( is_wp_error( $unzipfile ) ) {
|
57 |
-
throw new Exception( $unzipfile->get_error_message(), 1 );
|
58 |
-
return false;
|
59 |
-
}
|
60 |
-
return true;
|
61 |
-
}
|
62 |
-
/**
|
63 |
-
* You can create a directory using this helper , it will check the dest directory for if its writable or not then
|
64 |
-
* try to create new one
|
65 |
-
*
|
66 |
-
* @since 1.0.0
|
67 |
-
* @author Artbees <info@artbees.net>
|
68 |
-
*
|
69 |
-
* @param str $path path of directory that need to be created.
|
70 |
-
* @param int $perm permission of new directory , default is : 0775.
|
71 |
-
*
|
72 |
-
* @return bool will return boolean status of action , all message is setted to $this->message()
|
73 |
-
*/
|
74 |
-
public static function check_perm_and_create( $path, $perm = 0775 ) {
|
75 |
-
|
76 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
77 |
-
array(
|
78 |
-
'context' => $path,
|
79 |
-
)
|
80 |
-
);
|
81 |
-
|
82 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
83 |
-
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
84 |
-
return false;
|
85 |
-
}
|
86 |
-
|
87 |
-
if ( $jupiterx_filesystem->exists( $path ) ) {
|
88 |
-
if ( ! $jupiterx_filesystem->is_writable( $path ) ) {
|
89 |
-
throw new Exception( sprintf( __( '%s directory is not writable', 'jupiterx-core' ), $path ) );
|
90 |
-
return false;
|
91 |
-
}
|
92 |
-
return true;
|
93 |
-
} else {
|
94 |
-
if ( ! $jupiterx_filesystem->mkdir( $path, $perm ) ) {
|
95 |
-
throw new Exception( sprintf( __( 'Can\'t create directory %s', 'jupiterx-core' ), $path ) );
|
96 |
-
return false;
|
97 |
-
}
|
98 |
-
return true;
|
99 |
-
}
|
100 |
-
}
|
101 |
-
/**
|
102 |
-
* This method is resposible to download file from url and save it on server.
|
103 |
-
* it will check if curl is available or not and then decide to use curl or file_get_content
|
104 |
-
*
|
105 |
-
* @since 1.0.0
|
106 |
-
* @author Artbees <info@artbees.net>
|
107 |
-
*
|
108 |
-
* @param string $url url of file (http://yahoo.com/test-plugin.zip).
|
109 |
-
* @param string $file_name name of the fire that should be create at destination directory.
|
110 |
-
* @param string $dest_directory absolute path of directory that file save on it.
|
111 |
-
*
|
112 |
-
* @return bool will return action status
|
113 |
-
*/
|
114 |
-
public static function upload_from_url( $url, $file_name, $dest_directory, $remote_args = [] ) {
|
115 |
-
set_time_limit( 0 );
|
116 |
-
|
117 |
-
try {
|
118 |
-
self::check_perm_and_create( $dest_directory );
|
119 |
-
} catch ( Exception $e ) {
|
120 |
-
throw new Exception( sprintf( __( 'Destination directory is not ready for upload . {%s}', 'jupiterx-core' ), $dest_directory ) );
|
121 |
-
return false;
|
122 |
-
}
|
123 |
-
|
124 |
-
|
125 |
-
$response = wp_remote_get( $url, array_merge( [ 'timeout' => 120 ], $remote_args ) );
|
126 |
-
|
127 |
-
if ( is_wp_error( $response ) ) {
|
128 |
-
throw new Exception( $response->get_error_message() );
|
129 |
-
return false;
|
130 |
-
}
|
131 |
-
|
132 |
-
$response_body = wp_remote_retrieve_body( $response );
|
133 |
-
|
134 |
-
if ( is_wp_error( $response_body ) ) {
|
135 |
-
throw new Exception( $response_body->get_error_message() );
|
136 |
-
return false;
|
137 |
-
}
|
138 |
-
|
139 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
140 |
-
array(
|
141 |
-
'context' => $dest_directory,
|
142 |
-
)
|
143 |
-
);
|
144 |
-
|
145 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
146 |
-
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
147 |
-
return false;
|
148 |
-
}
|
149 |
-
|
150 |
-
if ( ! $jupiterx_filesystem->put_contents( $dest_directory . $file_name, $response_body ) ) {
|
151 |
-
throw new Exception( sprintf( __( "Can't write file to {%s}", 'jupiterx-core' ), $dest_directory . $file_name ) );
|
152 |
-
return false;
|
153 |
-
}
|
154 |
-
|
155 |
-
return $dest_directory . $file_name;
|
156 |
-
}
|
157 |
-
|
158 |
-
/**
|
159 |
-
* This method is resposible to delete a directory or file.
|
160 |
-
* if the path is pointing to a directory it will remove all the includes file recursivly and then remove directory at last step
|
161 |
-
* if the path is pointing to a file it will remove it
|
162 |
-
*
|
163 |
-
* @since 1.0.0
|
164 |
-
* @author Artbees <info@artbees.net>
|
165 |
-
*
|
166 |
-
* @param str $dir for example (/var/www/jupiter/wp-content/plugins).
|
167 |
-
*
|
168 |
-
* @return bool true or false
|
169 |
-
*/
|
170 |
-
public static function delete_file_and_dir( $dir ) {
|
171 |
-
|
172 |
-
if ( empty( $dir ) == true || strlen( $dir ) < 2 ) {
|
173 |
-
return false;
|
174 |
-
}
|
175 |
-
|
176 |
-
$dir = realpath( $dir );
|
177 |
-
|
178 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
179 |
-
array(
|
180 |
-
'context' => $dir,
|
181 |
-
)
|
182 |
-
);
|
183 |
-
|
184 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
185 |
-
return false;
|
186 |
-
}
|
187 |
-
|
188 |
-
if ( ! $jupiterx_filesystem->exists( $dir ) ) {
|
189 |
-
return true;
|
190 |
-
}
|
191 |
-
|
192 |
-
if ( $jupiterx_filesystem->is_dir( $dir ) ) {
|
193 |
-
return $jupiterx_filesystem->rmdir( $dir, true );
|
194 |
-
} else {
|
195 |
-
return $jupiterx_filesystem->delete( $dir );
|
196 |
-
}
|
197 |
-
|
198 |
-
}
|
199 |
-
|
200 |
-
|
201 |
-
/**
|
202 |
-
* Prevents cache.
|
203 |
-
* Deletes cache files and transients.
|
204 |
-
*
|
205 |
-
* @since 1.0.0
|
206 |
-
*/
|
207 |
-
|
208 |
-
public static function prevent_cache_plugins() {
|
209 |
-
if ( function_exists( 'w3tc_pgcache_flush' ) ) {
|
210 |
-
w3tc_pgcache_flush();
|
211 |
-
// W3 Total Cache: Page cache flushed.
|
212 |
-
} elseif ( function_exists( 'wp_cache_clear_cache' ) ) {
|
213 |
-
wp_cache_clear_cache();
|
214 |
-
// WP Super Cache: Page cache cleared.
|
215 |
-
} elseif ( function_exists( 'rocket_clean_domain' ) ) {
|
216 |
-
rocket_clean_domain();
|
217 |
-
// WP Rocket: Domain cache purged.
|
218 |
-
}
|
219 |
-
|
220 |
-
if ( ! defined( 'DONOTCACHEPAGE' ) ) {
|
221 |
-
define( 'DONOTCACHEPAGE', true );
|
222 |
-
}
|
223 |
-
|
224 |
-
if ( ! defined( 'DONOTCACHCEOBJECT' ) ) {
|
225 |
-
define( 'DONOTCACHCEOBJECT', true );
|
226 |
-
}
|
227 |
-
|
228 |
-
if ( ! defined( 'DONOTMINIFY' ) ) {
|
229 |
-
define( 'DONOTMINIFY', true );
|
230 |
-
}
|
231 |
-
|
232 |
-
if ( ! defined( 'DONOTCACHEDB' ) ) {
|
233 |
-
define( 'DONOTCACHEDB', true );
|
234 |
-
}
|
235 |
-
|
236 |
-
if ( ! defined( 'DONOTCDN' ) ) {
|
237 |
-
define( 'DONOTCDN', true );
|
238 |
-
}
|
239 |
-
}
|
240 |
-
|
241 |
-
/**
|
242 |
-
* Safely and securely get file from server.
|
243 |
-
* It attempts to read file using WordPress native file read functions
|
244 |
-
* If it fails, we use wp_remote_get. if the site is ssl enabled, we try to convert it http as some servers may fail to get file
|
245 |
-
*
|
246 |
-
* @author Artbees <info@artbees.net>
|
247 |
-
*
|
248 |
-
* @param $file_url string its directory URL.
|
249 |
-
* @param $file_dir string its directory Path.
|
250 |
-
*
|
251 |
-
* @return $wp_file_body string
|
252 |
-
*/
|
253 |
-
public static function getFileBody( $file_uri, $file_dir ) {
|
254 |
-
|
255 |
-
$wp_remote_get_file_body = '';
|
256 |
-
$file_dir = realpath( $file_dir );
|
257 |
-
|
258 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
259 |
-
array(
|
260 |
-
'context' => $file_dir,
|
261 |
-
)
|
262 |
-
);
|
263 |
-
|
264 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
265 |
-
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
266 |
-
return false;
|
267 |
-
}
|
268 |
-
|
269 |
-
$wp_get_file_body = $jupiterx_filesystem->get_contents( $file_dir );
|
270 |
-
if ( false == $wp_get_file_body ) {
|
271 |
-
$wp_remote_get_file = wp_remote_get( $file_uri );
|
272 |
-
|
273 |
-
if ( is_array( $wp_remote_get_file ) && array_key_exists( 'body', $wp_remote_get_file ) ) {
|
274 |
-
$wp_remote_get_file_body = $wp_remote_get_file['body'];
|
275 |
-
|
276 |
-
} elseif ( is_numeric( strpos( $file_uri, 'https://' ) ) ) {
|
277 |
-
|
278 |
-
$file_uri = str_replace( 'https://', 'http://', $file_uri );
|
279 |
-
$wp_remote_get_file = wp_remote_get( $file_uri );
|
280 |
-
|
281 |
-
if ( ! is_array( $wp_remote_get_file ) || ! array_key_exists( 'body', $wp_remote_get_file ) ) {
|
282 |
-
throw new Exception( __( 'SSL connection error. Code: template-assets-get', 'jupiterx-core' ) );
|
283 |
-
return false;
|
284 |
-
}
|
285 |
-
|
286 |
-
$wp_remote_get_file_body = $wp_remote_get_file['body'];
|
287 |
-
}
|
288 |
-
|
289 |
-
$wp_file_body = $wp_remote_get_file_body;
|
290 |
-
|
291 |
-
} else {
|
292 |
-
$wp_file_body = $wp_get_file_body;
|
293 |
-
}
|
294 |
-
return $wp_file_body;
|
295 |
-
}
|
296 |
-
|
297 |
-
/**
|
298 |
-
* Check if the request is done through a localhost.
|
299 |
-
*
|
300 |
-
* @author Artbees <info@artbees.net>
|
301 |
-
*
|
302 |
-
* @return boolean
|
303 |
-
*/
|
304 |
-
public static function is_localhost() {
|
305 |
-
return ('127.0.0.1' == $_SERVER['REMOTE_ADDR'] || 'localhost' == $_SERVER['REMOTE_ADDR'] || '::1' == $_SERVER['REMOTE_ADDR']) ? 1 : 0;
|
306 |
-
}
|
307 |
-
|
308 |
-
/**
|
309 |
-
* Convert alphabetical bit size to numericals
|
310 |
-
*
|
311 |
-
* @author Artbees <info@artbees.net>
|
312 |
-
*
|
313 |
-
* @return number
|
314 |
-
*/
|
315 |
-
public static function let_to_num( $size ) {
|
316 |
-
$l = substr( $size, -1 );
|
317 |
-
$ret = substr( $size, 0, -1 );
|
318 |
-
|
319 |
-
switch ( strtoupper( $l ) ) {
|
320 |
-
case 'P':
|
321 |
-
$ret *= 1024;
|
322 |
-
case 'T':
|
323 |
-
$ret *= 1024;
|
324 |
-
case 'G':
|
325 |
-
$ret *= 1024;
|
326 |
-
case 'M':
|
327 |
-
$ret *= 1024;
|
328 |
-
case 'K':
|
329 |
-
$ret *= 1024;
|
330 |
-
}
|
331 |
-
|
332 |
-
return $ret;
|
333 |
-
}
|
334 |
-
|
335 |
-
/**
|
336 |
-
* Convert boolean value to a string value (e.g. from true to 'true')
|
337 |
-
*
|
338 |
-
* @author Artbees <info@artbees.net>
|
339 |
-
*
|
340 |
-
* @return String
|
341 |
-
*/
|
342 |
-
public static function make_bool_string( $var ) {
|
343 |
-
if ( false == $var || 'false' == $var || 0 == $var || '0' == $var || '' == $var || empty( $var ) ) {
|
344 |
-
return 'false';
|
345 |
-
}
|
346 |
-
return 'true';
|
347 |
-
}
|
348 |
-
|
349 |
-
/**
|
350 |
-
* It will create a compress file from list of files
|
351 |
-
*
|
352 |
-
* @author Artbees <info@artbees.net>
|
353 |
-
*
|
354 |
-
* @param array $files for example : array('preload-images/5.jpg','kwicks/ringo.gif','rod.jpg','reddit.gif');.
|
355 |
-
* @param string $destination name of the file or full address of destination for example : my-archive.zip.
|
356 |
-
* @param boolean $overwrite if destionation exist , should it overwrite the compress file ?.
|
357 |
-
*
|
358 |
-
* @return boolean true if completed and false if something goes wrong
|
359 |
-
*/
|
360 |
-
public static function zip( $files = array(), $destination = '', $overwrite = false ) {
|
361 |
-
|
362 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
363 |
-
array(
|
364 |
-
'context' => $destination,
|
365 |
-
)
|
366 |
-
);
|
367 |
-
|
368 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
369 |
-
return false;
|
370 |
-
}
|
371 |
-
|
372 |
-
// if the zip file already exists and overwrite is false, return false.
|
373 |
-
if ( $jupiterx_filesystem->exists( $destination ) && ! $overwrite ) {
|
374 |
-
return false;
|
375 |
-
}
|
376 |
-
|
377 |
-
$valid_files = array();
|
378 |
-
|
379 |
-
// if files were passed in...
|
380 |
-
if ( is_array( $files ) ) {
|
381 |
-
// cycle through each file.
|
382 |
-
foreach ( $files as $file_name => $file_path ) {
|
383 |
-
// make sure the file exists.
|
384 |
-
if ( $jupiterx_filesystem->exists( $file_path ) ) {
|
385 |
-
$valid_files[ $file_name ] = $file_path;
|
386 |
-
}
|
387 |
-
}
|
388 |
-
}
|
389 |
-
// if we have good files...
|
390 |
-
if ( count( $valid_files ) ) {
|
391 |
-
|
392 |
-
$temp_file = tempnam( sys_get_temp_dir(), 'zip' );
|
393 |
-
|
394 |
-
if ( class_exists( 'ZipArchive', false ) ) {
|
395 |
-
$zip = new ZipArchive();
|
396 |
-
|
397 |
-
// Try open the temp file.
|
398 |
-
$zip->open( $temp_file );
|
399 |
-
|
400 |
-
// add the files to archive.
|
401 |
-
foreach ( $valid_files as $file_name => $file_path ) {
|
402 |
-
$zip->addFile( $file_path, $file_name );
|
403 |
-
}
|
404 |
-
|
405 |
-
// close the zip -- done!
|
406 |
-
$zip->close();
|
407 |
-
|
408 |
-
} else {
|
409 |
-
|
410 |
-
mbstring_binary_safe_encoding();
|
411 |
-
|
412 |
-
require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
|
413 |
-
|
414 |
-
$zip = new PclZip( $temp_file );
|
415 |
-
|
416 |
-
foreach ( $valid_files as $file_name => $file_path ) {
|
417 |
-
$zip->create( $file_path, $file_name );
|
418 |
-
}
|
419 |
-
|
420 |
-
reset_mbstring_encoding();
|
421 |
-
}
|
422 |
-
|
423 |
-
// add the files to archive.
|
424 |
-
foreach ( $valid_files as $file_name => $file_path ) {
|
425 |
-
$zip->addFile( $file_path, $file_name );
|
426 |
-
}
|
427 |
-
|
428 |
-
// debug
|
429 |
-
// echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
|
430 |
-
// close the zip -- done!
|
431 |
-
$zip->close();
|
432 |
-
|
433 |
-
// Copy the temp file to destination.
|
434 |
-
$jupiterx_filesystem->copy( $temp_file, $destination, true, 0644 );
|
435 |
-
|
436 |
-
// Try delete the temp file.
|
437 |
-
$jupiterx_filesystem->delete( $temp_file );
|
438 |
-
|
439 |
-
// check to make sure the file exists.
|
440 |
-
return $jupiterx_filesystem->exists( $destination );
|
441 |
-
|
442 |
-
}
|
443 |
-
return false;
|
444 |
-
}
|
445 |
-
|
446 |
-
public static function search_multdim( $array, $key, $value ) {
|
447 |
-
return (array_search( $value, array_column( $array, $key ) ));
|
448 |
-
}
|
449 |
-
/**
|
450 |
-
* It will check wether wordpress-importer plugin is exist in plugin directory or not.
|
451 |
-
* if exist it will return the WordPress importer file
|
452 |
-
* if not it will use jupiter version
|
453 |
-
*
|
454 |
-
* @author Artbees <info@artbees.net>
|
455 |
-
* @copyright Artbees LTD (c)
|
456 |
-
* @link https://artbees.net
|
457 |
-
* @since Version 5.5
|
458 |
-
*/
|
459 |
-
public static function include_wordpress_importer() {
|
460 |
-
|
461 |
-
if ( ! class_exists( 'WP_Importer' ) ) {
|
462 |
-
defined( 'WP_LOAD_IMPORTERS' ) || define( 'WP_LOAD_IMPORTERS', true );
|
463 |
-
include ABSPATH . '/wp-admin/includes/class-wp-importer.php';
|
464 |
-
}
|
465 |
-
|
466 |
-
if ( ! class_exists( 'JupiterX_WXR_Importer' ) ) {
|
467 |
-
jupiterx_core()->load_files( [
|
468 |
-
'control-panel/includes/importer/class-logger',
|
469 |
-
'control-panel/includes/importer/class-logger-serversentevents',
|
470 |
-
'control-panel/includes/importer/class-wxr-import-info',
|
471 |
-
'control-panel/includes/importer/class-wxr-importer',
|
472 |
-
] );
|
473 |
-
}
|
474 |
-
|
475 |
-
if ( ! class_exists( 'JupiterX_Importer' ) ) {
|
476 |
-
jupiterx_core()->load_files( [
|
477 |
-
'control-panel/includes/importer/class-jupiterx-importer',
|
478 |
-
] );
|
479 |
-
}
|
480 |
-
|
481 |
-
return true;
|
482 |
-
}
|
483 |
-
/**
|
484 |
-
* It will return permission of directory
|
485 |
-
*
|
486 |
-
* @author Artbees <info@artbees.net>
|
487 |
-
*
|
488 |
-
* @param string $path Full path of directory.
|
489 |
-
*
|
490 |
-
* @return int
|
491 |
-
*/
|
492 |
-
public static function get_perm( $path ) {
|
493 |
-
return substr( sprintf( '%o', fileperms( ABSPATH . $path ) ), -4 );
|
494 |
-
}
|
495 |
-
|
496 |
-
/**
|
497 |
-
* Convert Bytes to MegaBytes.
|
498 |
-
*
|
499 |
-
* @access public
|
500 |
-
* @static
|
501 |
-
* @since 1.10.0
|
502 |
-
*
|
503 |
-
* @param [type] $bytes
|
504 |
-
* @return void
|
505 |
-
*/
|
506 |
-
public static function bytes_to_mb( $bytes ) {
|
507 |
-
return round( $bytes / ( 1024 * 1024 ), 2 );
|
508 |
-
}
|
509 |
-
}
|
510 |
-
}
|
1 |
+
<?php
|
2 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Helpers' ) ) {
|
3 |
+
/**
|
4 |
+
* Helper functions class.
|
5 |
+
*
|
6 |
+
* @since 1.7.0
|
7 |
+
*/
|
8 |
+
class JupiterX_Control_Panel_Helpers {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Method that is resposible to unzip compress files .
|
12 |
+
* it used native WordPress functions.
|
13 |
+
*
|
14 |
+
* @since 1.0.0
|
15 |
+
* @author Artbees <info@artbees.net>
|
16 |
+
*
|
17 |
+
* @param str $zip_path compress file absolute path.
|
18 |
+
* @param str $dest_path Where should it be uncompressed.
|
19 |
+
*
|
20 |
+
* @return bool will return boolean status of action
|
21 |
+
*/
|
22 |
+
public static function un_zip( $zip_path, $dest_path ) {
|
23 |
+
|
24 |
+
$zip_path = realpath( $zip_path );
|
25 |
+
$dest_path = realpath( $dest_path );
|
26 |
+
|
27 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
28 |
+
array(
|
29 |
+
'context' => $dest_path,
|
30 |
+
)
|
31 |
+
);
|
32 |
+
|
33 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
34 |
+
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
35 |
+
return false;
|
36 |
+
}
|
37 |
+
|
38 |
+
if ( ! $jupiterx_filesystem->exists( $zip_path ) ) {
|
39 |
+
throw new Exception( __( 'Zip file that you are looking for is not exist', 'jupiterx-core' ) );
|
40 |
+
return false;
|
41 |
+
}
|
42 |
+
|
43 |
+
if ( ! $jupiterx_filesystem->exists( $dest_path ) ) {
|
44 |
+
if ( ! $jupiterx_filesystem->mkdir( $dest_path ) ) {
|
45 |
+
throw new Exception( __( 'Unzip destination path not exist', 'jupiterx-core' ) );
|
46 |
+
return false;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
if ( ! $jupiterx_filesystem->is_writable( $dest_path ) ) {
|
51 |
+
throw new Exception( __( 'Unzip destination is not writable , Please resolve this issue first.', 'jupiterx-core' ) );
|
52 |
+
return false;
|
53 |
+
}
|
54 |
+
|
55 |
+
$unzipfile = unzip_file( $zip_path, $dest_path );
|
56 |
+
if ( is_wp_error( $unzipfile ) ) {
|
57 |
+
throw new Exception( $unzipfile->get_error_message(), 1 );
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
return true;
|
61 |
+
}
|
62 |
+
/**
|
63 |
+
* You can create a directory using this helper , it will check the dest directory for if its writable or not then
|
64 |
+
* try to create new one
|
65 |
+
*
|
66 |
+
* @since 1.0.0
|
67 |
+
* @author Artbees <info@artbees.net>
|
68 |
+
*
|
69 |
+
* @param str $path path of directory that need to be created.
|
70 |
+
* @param int $perm permission of new directory , default is : 0775.
|
71 |
+
*
|
72 |
+
* @return bool will return boolean status of action , all message is setted to $this->message()
|
73 |
+
*/
|
74 |
+
public static function check_perm_and_create( $path, $perm = 0775 ) {
|
75 |
+
|
76 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
77 |
+
array(
|
78 |
+
'context' => $path,
|
79 |
+
)
|
80 |
+
);
|
81 |
+
|
82 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
83 |
+
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
84 |
+
return false;
|
85 |
+
}
|
86 |
+
|
87 |
+
if ( $jupiterx_filesystem->exists( $path ) ) {
|
88 |
+
if ( ! $jupiterx_filesystem->is_writable( $path ) ) {
|
89 |
+
throw new Exception( sprintf( __( '%s directory is not writable', 'jupiterx-core' ), $path ) );
|
90 |
+
return false;
|
91 |
+
}
|
92 |
+
return true;
|
93 |
+
} else {
|
94 |
+
if ( ! $jupiterx_filesystem->mkdir( $path, $perm ) ) {
|
95 |
+
throw new Exception( sprintf( __( 'Can\'t create directory %s', 'jupiterx-core' ), $path ) );
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
/**
|
102 |
+
* This method is resposible to download file from url and save it on server.
|
103 |
+
* it will check if curl is available or not and then decide to use curl or file_get_content
|
104 |
+
*
|
105 |
+
* @since 1.0.0
|
106 |
+
* @author Artbees <info@artbees.net>
|
107 |
+
*
|
108 |
+
* @param string $url url of file (http://yahoo.com/test-plugin.zip).
|
109 |
+
* @param string $file_name name of the fire that should be create at destination directory.
|
110 |
+
* @param string $dest_directory absolute path of directory that file save on it.
|
111 |
+
*
|
112 |
+
* @return bool will return action status
|
113 |
+
*/
|
114 |
+
public static function upload_from_url( $url, $file_name, $dest_directory, $remote_args = [] ) {
|
115 |
+
set_time_limit( 0 );
|
116 |
+
|
117 |
+
try {
|
118 |
+
self::check_perm_and_create( $dest_directory );
|
119 |
+
} catch ( Exception $e ) {
|
120 |
+
throw new Exception( sprintf( __( 'Destination directory is not ready for upload . {%s}', 'jupiterx-core' ), $dest_directory ) );
|
121 |
+
return false;
|
122 |
+
}
|
123 |
+
|
124 |
+
|
125 |
+
$response = wp_remote_get( $url, array_merge( [ 'timeout' => 120 ], $remote_args ) );
|
126 |
+
|
127 |
+
if ( is_wp_error( $response ) ) {
|
128 |
+
throw new Exception( $response->get_error_message() );
|
129 |
+
return false;
|
130 |
+
}
|
131 |
+
|
132 |
+
$response_body = wp_remote_retrieve_body( $response );
|
133 |
+
|
134 |
+
if ( is_wp_error( $response_body ) ) {
|
135 |
+
throw new Exception( $response_body->get_error_message() );
|
136 |
+
return false;
|
137 |
+
}
|
138 |
+
|
139 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
140 |
+
array(
|
141 |
+
'context' => $dest_directory,
|
142 |
+
)
|
143 |
+
);
|
144 |
+
|
145 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
146 |
+
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
147 |
+
return false;
|
148 |
+
}
|
149 |
+
|
150 |
+
if ( ! $jupiterx_filesystem->put_contents( $dest_directory . $file_name, $response_body ) ) {
|
151 |
+
throw new Exception( sprintf( __( "Can't write file to {%s}", 'jupiterx-core' ), $dest_directory . $file_name ) );
|
152 |
+
return false;
|
153 |
+
}
|
154 |
+
|
155 |
+
return $dest_directory . $file_name;
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* This method is resposible to delete a directory or file.
|
160 |
+
* if the path is pointing to a directory it will remove all the includes file recursivly and then remove directory at last step
|
161 |
+
* if the path is pointing to a file it will remove it
|
162 |
+
*
|
163 |
+
* @since 1.0.0
|
164 |
+
* @author Artbees <info@artbees.net>
|
165 |
+
*
|
166 |
+
* @param str $dir for example (/var/www/jupiter/wp-content/plugins).
|
167 |
+
*
|
168 |
+
* @return bool true or false
|
169 |
+
*/
|
170 |
+
public static function delete_file_and_dir( $dir ) {
|
171 |
+
|
172 |
+
if ( empty( $dir ) == true || strlen( $dir ) < 2 ) {
|
173 |
+
return false;
|
174 |
+
}
|
175 |
+
|
176 |
+
$dir = realpath( $dir );
|
177 |
+
|
178 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
179 |
+
array(
|
180 |
+
'context' => $dir,
|
181 |
+
)
|
182 |
+
);
|
183 |
+
|
184 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
185 |
+
return false;
|
186 |
+
}
|
187 |
+
|
188 |
+
if ( ! $jupiterx_filesystem->exists( $dir ) ) {
|
189 |
+
return true;
|
190 |
+
}
|
191 |
+
|
192 |
+
if ( $jupiterx_filesystem->is_dir( $dir ) ) {
|
193 |
+
return $jupiterx_filesystem->rmdir( $dir, true );
|
194 |
+
} else {
|
195 |
+
return $jupiterx_filesystem->delete( $dir );
|
196 |
+
}
|
197 |
+
|
198 |
+
}
|
199 |
+
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Prevents cache.
|
203 |
+
* Deletes cache files and transients.
|
204 |
+
*
|
205 |
+
* @since 1.0.0
|
206 |
+
*/
|
207 |
+
|
208 |
+
public static function prevent_cache_plugins() {
|
209 |
+
if ( function_exists( 'w3tc_pgcache_flush' ) ) {
|
210 |
+
w3tc_pgcache_flush();
|
211 |
+
// W3 Total Cache: Page cache flushed.
|
212 |
+
} elseif ( function_exists( 'wp_cache_clear_cache' ) ) {
|
213 |
+
wp_cache_clear_cache();
|
214 |
+
// WP Super Cache: Page cache cleared.
|
215 |
+
} elseif ( function_exists( 'rocket_clean_domain' ) ) {
|
216 |
+
rocket_clean_domain();
|
217 |
+
// WP Rocket: Domain cache purged.
|
218 |
+
}
|
219 |
+
|
220 |
+
if ( ! defined( 'DONOTCACHEPAGE' ) ) {
|
221 |
+
define( 'DONOTCACHEPAGE', true );
|
222 |
+
}
|
223 |
+
|
224 |
+
if ( ! defined( 'DONOTCACHCEOBJECT' ) ) {
|
225 |
+
define( 'DONOTCACHCEOBJECT', true );
|
226 |
+
}
|
227 |
+
|
228 |
+
if ( ! defined( 'DONOTMINIFY' ) ) {
|
229 |
+
define( 'DONOTMINIFY', true );
|
230 |
+
}
|
231 |
+
|
232 |
+
if ( ! defined( 'DONOTCACHEDB' ) ) {
|
233 |
+
define( 'DONOTCACHEDB', true );
|
234 |
+
}
|
235 |
+
|
236 |
+
if ( ! defined( 'DONOTCDN' ) ) {
|
237 |
+
define( 'DONOTCDN', true );
|
238 |
+
}
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Safely and securely get file from server.
|
243 |
+
* It attempts to read file using WordPress native file read functions
|
244 |
+
* If it fails, we use wp_remote_get. if the site is ssl enabled, we try to convert it http as some servers may fail to get file
|
245 |
+
*
|
246 |
+
* @author Artbees <info@artbees.net>
|
247 |
+
*
|
248 |
+
* @param $file_url string its directory URL.
|
249 |
+
* @param $file_dir string its directory Path.
|
250 |
+
*
|
251 |
+
* @return $wp_file_body string
|
252 |
+
*/
|
253 |
+
public static function getFileBody( $file_uri, $file_dir ) {
|
254 |
+
|
255 |
+
$wp_remote_get_file_body = '';
|
256 |
+
$file_dir = realpath( $file_dir );
|
257 |
+
|
258 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
259 |
+
array(
|
260 |
+
'context' => $file_dir,
|
261 |
+
)
|
262 |
+
);
|
263 |
+
|
264 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
265 |
+
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
266 |
+
return false;
|
267 |
+
}
|
268 |
+
|
269 |
+
$wp_get_file_body = $jupiterx_filesystem->get_contents( $file_dir );
|
270 |
+
if ( false == $wp_get_file_body ) {
|
271 |
+
$wp_remote_get_file = wp_remote_get( $file_uri );
|
272 |
+
|
273 |
+
if ( is_array( $wp_remote_get_file ) && array_key_exists( 'body', $wp_remote_get_file ) ) {
|
274 |
+
$wp_remote_get_file_body = $wp_remote_get_file['body'];
|
275 |
+
|
276 |
+
} elseif ( is_numeric( strpos( $file_uri, 'https://' ) ) ) {
|
277 |
+
|
278 |
+
$file_uri = str_replace( 'https://', 'http://', $file_uri );
|
279 |
+
$wp_remote_get_file = wp_remote_get( $file_uri );
|
280 |
+
|
281 |
+
if ( ! is_array( $wp_remote_get_file ) || ! array_key_exists( 'body', $wp_remote_get_file ) ) {
|
282 |
+
throw new Exception( __( 'SSL connection error. Code: template-assets-get', 'jupiterx-core' ) );
|
283 |
+
return false;
|
284 |
+
}
|
285 |
+
|
286 |
+
$wp_remote_get_file_body = $wp_remote_get_file['body'];
|
287 |
+
}
|
288 |
+
|
289 |
+
$wp_file_body = $wp_remote_get_file_body;
|
290 |
+
|
291 |
+
} else {
|
292 |
+
$wp_file_body = $wp_get_file_body;
|
293 |
+
}
|
294 |
+
return $wp_file_body;
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Check if the request is done through a localhost.
|
299 |
+
*
|
300 |
+
* @author Artbees <info@artbees.net>
|
301 |
+
*
|
302 |
+
* @return boolean
|
303 |
+
*/
|
304 |
+
public static function is_localhost() {
|
305 |
+
return ('127.0.0.1' == $_SERVER['REMOTE_ADDR'] || 'localhost' == $_SERVER['REMOTE_ADDR'] || '::1' == $_SERVER['REMOTE_ADDR']) ? 1 : 0;
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Convert alphabetical bit size to numericals
|
310 |
+
*
|
311 |
+
* @author Artbees <info@artbees.net>
|
312 |
+
*
|
313 |
+
* @return number
|
314 |
+
*/
|
315 |
+
public static function let_to_num( $size ) {
|
316 |
+
$l = substr( $size, -1 );
|
317 |
+
$ret = substr( $size, 0, -1 );
|
318 |
+
|
319 |
+
switch ( strtoupper( $l ) ) {
|
320 |
+
case 'P':
|
321 |
+
$ret *= 1024;
|
322 |
+
case 'T':
|
323 |
+
$ret *= 1024;
|
324 |
+
case 'G':
|
325 |
+
$ret *= 1024;
|
326 |
+
case 'M':
|
327 |
+
$ret *= 1024;
|
328 |
+
case 'K':
|
329 |
+
$ret *= 1024;
|
330 |
+
}
|
331 |
+
|
332 |
+
return $ret;
|
333 |
+
}
|
334 |
+
|
335 |
+
/**
|
336 |
+
* Convert boolean value to a string value (e.g. from true to 'true')
|
337 |
+
*
|
338 |
+
* @author Artbees <info@artbees.net>
|
339 |
+
*
|
340 |
+
* @return String
|
341 |
+
*/
|
342 |
+
public static function make_bool_string( $var ) {
|
343 |
+
if ( false == $var || 'false' == $var || 0 == $var || '0' == $var || '' == $var || empty( $var ) ) {
|
344 |
+
return 'false';
|
345 |
+
}
|
346 |
+
return 'true';
|
347 |
+
}
|
348 |
+
|
349 |
+
/**
|
350 |
+
* It will create a compress file from list of files
|
351 |
+
*
|
352 |
+
* @author Artbees <info@artbees.net>
|
353 |
+
*
|
354 |
+
* @param array $files for example : array('preload-images/5.jpg','kwicks/ringo.gif','rod.jpg','reddit.gif');.
|
355 |
+
* @param string $destination name of the file or full address of destination for example : my-archive.zip.
|
356 |
+
* @param boolean $overwrite if destionation exist , should it overwrite the compress file ?.
|
357 |
+
*
|
358 |
+
* @return boolean true if completed and false if something goes wrong
|
359 |
+
*/
|
360 |
+
public static function zip( $files = array(), $destination = '', $overwrite = false ) {
|
361 |
+
|
362 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
363 |
+
array(
|
364 |
+
'context' => $destination,
|
365 |
+
)
|
366 |
+
);
|
367 |
+
|
368 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
369 |
+
return false;
|
370 |
+
}
|
371 |
+
|
372 |
+
// if the zip file already exists and overwrite is false, return false.
|
373 |
+
if ( $jupiterx_filesystem->exists( $destination ) && ! $overwrite ) {
|
374 |
+
return false;
|
375 |
+
}
|
376 |
+
|
377 |
+
$valid_files = array();
|
378 |
+
|
379 |
+
// if files were passed in...
|
380 |
+
if ( is_array( $files ) ) {
|
381 |
+
// cycle through each file.
|
382 |
+
foreach ( $files as $file_name => $file_path ) {
|
383 |
+
// make sure the file exists.
|
384 |
+
if ( $jupiterx_filesystem->exists( $file_path ) ) {
|
385 |
+
$valid_files[ $file_name ] = $file_path;
|
386 |
+
}
|
387 |
+
}
|
388 |
+
}
|
389 |
+
// if we have good files...
|
390 |
+
if ( count( $valid_files ) ) {
|
391 |
+
|
392 |
+
$temp_file = tempnam( sys_get_temp_dir(), 'zip' );
|
393 |
+
|
394 |
+
if ( class_exists( 'ZipArchive', false ) ) {
|
395 |
+
$zip = new ZipArchive();
|
396 |
+
|
397 |
+
// Try open the temp file.
|
398 |
+
$zip->open( $temp_file );
|
399 |
+
|
400 |
+
// add the files to archive.
|
401 |
+
foreach ( $valid_files as $file_name => $file_path ) {
|
402 |
+
$zip->addFile( $file_path, $file_name );
|
403 |
+
}
|
404 |
+
|
405 |
+
// close the zip -- done!
|
406 |
+
$zip->close();
|
407 |
+
|
408 |
+
} else {
|
409 |
+
|
410 |
+
mbstring_binary_safe_encoding();
|
411 |
+
|
412 |
+
require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
|
413 |
+
|
414 |
+
$zip = new PclZip( $temp_file );
|
415 |
+
|
416 |
+
foreach ( $valid_files as $file_name => $file_path ) {
|
417 |
+
$zip->create( $file_path, $file_name );
|
418 |
+
}
|
419 |
+
|
420 |
+
reset_mbstring_encoding();
|
421 |
+
}
|
422 |
+
|
423 |
+
// add the files to archive.
|
424 |
+
foreach ( $valid_files as $file_name => $file_path ) {
|
425 |
+
$zip->addFile( $file_path, $file_name );
|
426 |
+
}
|
427 |
+
|
428 |
+
// debug
|
429 |
+
// echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
|
430 |
+
// close the zip -- done!
|
431 |
+
$zip->close();
|
432 |
+
|
433 |
+
// Copy the temp file to destination.
|
434 |
+
$jupiterx_filesystem->copy( $temp_file, $destination, true, 0644 );
|
435 |
+
|
436 |
+
// Try delete the temp file.
|
437 |
+
$jupiterx_filesystem->delete( $temp_file );
|
438 |
+
|
439 |
+
// check to make sure the file exists.
|
440 |
+
return $jupiterx_filesystem->exists( $destination );
|
441 |
+
|
442 |
+
}
|
443 |
+
return false;
|
444 |
+
}
|
445 |
+
|
446 |
+
public static function search_multdim( $array, $key, $value ) {
|
447 |
+
return (array_search( $value, array_column( $array, $key ) ));
|
448 |
+
}
|
449 |
+
/**
|
450 |
+
* It will check wether wordpress-importer plugin is exist in plugin directory or not.
|
451 |
+
* if exist it will return the WordPress importer file
|
452 |
+
* if not it will use jupiter version
|
453 |
+
*
|
454 |
+
* @author Artbees <info@artbees.net>
|
455 |
+
* @copyright Artbees LTD (c)
|
456 |
+
* @link https://artbees.net
|
457 |
+
* @since Version 5.5
|
458 |
+
*/
|
459 |
+
public static function include_wordpress_importer() {
|
460 |
+
|
461 |
+
if ( ! class_exists( 'WP_Importer' ) ) {
|
462 |
+
defined( 'WP_LOAD_IMPORTERS' ) || define( 'WP_LOAD_IMPORTERS', true );
|
463 |
+
include ABSPATH . '/wp-admin/includes/class-wp-importer.php';
|
464 |
+
}
|
465 |
+
|
466 |
+
if ( ! class_exists( 'JupiterX_WXR_Importer' ) ) {
|
467 |
+
jupiterx_core()->load_files( [
|
468 |
+
'control-panel/includes/importer/class-logger',
|
469 |
+
'control-panel/includes/importer/class-logger-serversentevents',
|
470 |
+
'control-panel/includes/importer/class-wxr-import-info',
|
471 |
+
'control-panel/includes/importer/class-wxr-importer',
|
472 |
+
] );
|
473 |
+
}
|
474 |
+
|
475 |
+
if ( ! class_exists( 'JupiterX_Importer' ) ) {
|
476 |
+
jupiterx_core()->load_files( [
|
477 |
+
'control-panel/includes/importer/class-jupiterx-importer',
|
478 |
+
] );
|
479 |
+
}
|
480 |
+
|
481 |
+
return true;
|
482 |
+
}
|
483 |
+
/**
|
484 |
+
* It will return permission of directory
|
485 |
+
*
|
486 |
+
* @author Artbees <info@artbees.net>
|
487 |
+
*
|
488 |
+
* @param string $path Full path of directory.
|
489 |
+
*
|
490 |
+
* @return int
|
491 |
+
*/
|
492 |
+
public static function get_perm( $path ) {
|
493 |
+
return substr( sprintf( '%o', fileperms( ABSPATH . $path ) ), -4 );
|
494 |
+
}
|
495 |
+
|
496 |
+
/**
|
497 |
+
* Convert Bytes to MegaBytes.
|
498 |
+
*
|
499 |
+
* @access public
|
500 |
+
* @static
|
501 |
+
* @since 1.10.0
|
502 |
+
*
|
503 |
+
* @param [type] $bytes
|
504 |
+
* @return void
|
505 |
+
*/
|
506 |
+
public static function bytes_to_mb( $bytes ) {
|
507 |
+
return round( $bytes / ( 1024 * 1024 ), 2 );
|
508 |
+
}
|
509 |
+
}
|
510 |
+
}
|
includes/control-panel/includes/class-image-sizes.php
CHANGED
@@ -1,98 +1,152 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class provides the methods to Store and retrieve Image sizes from database.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel\Image_Sizes
|
6 |
-
*
|
7 |
-
* @since 1.2.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
|
11 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Image_Sizes' ) ) {
|
12 |
-
/**
|
13 |
-
* Store and retrieve Image sizes.
|
14 |
-
*
|
15 |
-
* @since 1.2.0
|
16 |
-
*/
|
17 |
-
class JupiterX_Control_Panel_Image_Sizes {
|
18 |
-
|
19 |
-
/**
|
20 |
-
*
|
21 |
-
*
|
22 |
-
*
|
23 |
-
*
|
24 |
-
*
|
25 |
-
*
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
$
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class provides the methods to Store and retrieve Image sizes from database.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel\Image_Sizes
|
6 |
+
*
|
7 |
+
* @since 1.2.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
|
11 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Image_Sizes' ) ) {
|
12 |
+
/**
|
13 |
+
* Store and retrieve Image sizes.
|
14 |
+
*
|
15 |
+
* @since 1.2.0
|
16 |
+
*/
|
17 |
+
class JupiterX_Control_Panel_Image_Sizes {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Array of custom image sizes.
|
21 |
+
*
|
22 |
+
* @since 1.11.0
|
23 |
+
* @access public
|
24 |
+
*
|
25 |
+
* @var array
|
26 |
+
*/
|
27 |
+
protected static $default_options = [
|
28 |
+
[
|
29 |
+
'size_w' => 500,
|
30 |
+
'size_h' => 500,
|
31 |
+
'size_n' => 'Image Size 500x500',
|
32 |
+
'size_c' => 'on',
|
33 |
+
'default' => true,
|
34 |
+
'id' => 1,
|
35 |
+
],
|
36 |
+
];
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Class constructor.
|
40 |
+
*
|
41 |
+
* @since 1.2.0
|
42 |
+
*/
|
43 |
+
public function __construct() {
|
44 |
+
add_filter( 'jupiterx_control_panel_pane_image_sizes', [ $this, 'view' ] );
|
45 |
+
add_action( 'wp_ajax_jupiterx_save_image_sizes', [ $this, 'save_image_size' ] );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Return list of the stored image sizes.
|
50 |
+
*
|
51 |
+
* If empty, it will return default sample size.
|
52 |
+
*
|
53 |
+
* @since 1.2.0
|
54 |
+
*
|
55 |
+
* @return array
|
56 |
+
*/
|
57 |
+
public static function get_available_image_sizes() {
|
58 |
+
$options = get_option( JUPITERX_IMAGE_SIZE_OPTION );
|
59 |
+
|
60 |
+
if ( empty( $options ) ) {
|
61 |
+
$options = [];
|
62 |
+
}
|
63 |
+
|
64 |
+
$existing_default_options = [];
|
65 |
+
|
66 |
+
foreach ( $options as $option ) {
|
67 |
+
if ( ! empty( $option['default'] ) ) {
|
68 |
+
$existing_default_options[] = intval( $option['id'] );
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
$deleted_default_options = get_option( 'jupiterx_image_sizes_deleted' );
|
73 |
+
|
74 |
+
if ( false === $deleted_default_options ) {
|
75 |
+
$deleted_default_options = [];
|
76 |
+
}
|
77 |
+
|
78 |
+
foreach ( self::$default_options as $default_option ) {
|
79 |
+
if (
|
80 |
+
in_array( $default_option['id'], $deleted_default_options, true ) ||
|
81 |
+
in_array( $default_option['id'], $existing_default_options, true )
|
82 |
+
) {
|
83 |
+
continue;
|
84 |
+
}
|
85 |
+
|
86 |
+
array_unshift( $options, $default_option );
|
87 |
+
}
|
88 |
+
|
89 |
+
return $options;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Image sizes HTML directory.
|
94 |
+
*
|
95 |
+
* @since 1.2.0
|
96 |
+
*
|
97 |
+
* @return string
|
98 |
+
*/
|
99 |
+
public function view() {
|
100 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/image-sizes.php';
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Process image sizes data passed via admin-ajax.php and store it in wp_options table.
|
105 |
+
*
|
106 |
+
* @since 1.2.0
|
107 |
+
*/
|
108 |
+
public function save_image_size() {
|
109 |
+
check_ajax_referer( 'ajax-image-sizes-options', 'security' );
|
110 |
+
|
111 |
+
$options = [];
|
112 |
+
|
113 |
+
if ( ! empty( $_POST['options'] ) ) {
|
114 |
+
$options = $_POST['options'];
|
115 |
+
}
|
116 |
+
|
117 |
+
// phpcs:disable
|
118 |
+
$options = array_map( 'sanitize_text_field', $options );
|
119 |
+
// phpcs:enable
|
120 |
+
|
121 |
+
$options_array = [];
|
122 |
+
$default_options = [];
|
123 |
+
|
124 |
+
foreach ( $options as $sizes ) {
|
125 |
+
parse_str( $sizes, $output );
|
126 |
+
|
127 |
+
if ( ! empty( $output['default'] ) ) {
|
128 |
+
$default_options[] = intval( $output['id'] );
|
129 |
+
}
|
130 |
+
|
131 |
+
$options_array[] = $output;
|
132 |
+
}
|
133 |
+
|
134 |
+
$deleted_default_options = [];
|
135 |
+
|
136 |
+
foreach (self::$default_options as $default_option) {
|
137 |
+
if ( in_array( $default_option['id'], $default_options, true ) ) {
|
138 |
+
continue;
|
139 |
+
}
|
140 |
+
|
141 |
+
$deleted_default_options[] = $default_option['id'];
|
142 |
+
}
|
143 |
+
|
144 |
+
update_option( 'jupiterx_image_sizes_deleted', $deleted_default_options );
|
145 |
+
update_option( JUPITERX_IMAGE_SIZE_OPTION, $options_array );
|
146 |
+
|
147 |
+
wp_die( 1 );
|
148 |
+
}
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
new JupiterX_Control_Panel_Image_Sizes();
|
includes/control-panel/includes/class-install-plugins.php
CHANGED
@@ -1,506 +1,492 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class is responsible to manage all jupiters plugin.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel
|
6 |
-
*/
|
7 |
-
|
8 |
-
class JupiterX_Control_Panel_Install_Plugins {
|
9 |
-
|
10 |
-
protected $tgmpa;
|
11 |
-
protected $api_url = 'http://artbees.net/api/v2/';
|
12 |
-
protected $theme_name = 'JupiterX';
|
13 |
-
private static $instance = null;
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Class constructor.
|
17 |
-
*
|
18 |
-
* @since 1.9.0
|
19 |
-
*/
|
20 |
-
public function __construct() {
|
21 |
-
if ( ! class_exists( 'TGM_Plugin_Activation' ) ) {
|
22 |
-
return;
|
23 |
-
}
|
24 |
-
|
25 |
-
$menu_items_access = get_site_option( 'menu_items' );
|
26 |
-
if ( is_multisite() && ! isset( $menu_items_access['plugins'] ) && ! current_user_can( 'manage_network_plugins' ) ) {
|
27 |
-
return;
|
28 |
-
}
|
29 |
-
|
30 |
-
$this->tgmpa = isset( $GLOBALS['tgmpa'] ) ? $GLOBALS['tgmpa'] : TGM_Plugin_Activation::get_instance();
|
31 |
-
|
32 |
-
add_filter( 'jupiterx_control_panel_pane_install_plugins', [ $this, 'view' ] );
|
33 |
-
|
34 |
-
add_action( '
|
35 |
-
|
36 |
-
add_action( '
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
*
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
*
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
$
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
*
|
158 |
-
*
|
159 |
-
*
|
160 |
-
* @
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
'
|
177 |
-
'
|
178 |
-
'
|
179 |
-
'
|
180 |
-
'
|
181 |
-
'
|
182 |
-
'
|
183 |
-
'
|
184 |
-
'
|
185 |
-
'
|
186 |
-
'
|
187 |
-
'
|
188 |
-
'
|
189 |
-
'
|
190 |
-
'
|
191 |
-
'
|
192 |
-
'
|
193 |
-
'
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
$
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
*
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
'
|
229 |
-
|
230 |
-
|
231 |
-
'
|
232 |
-
'
|
233 |
-
'
|
234 |
-
'
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
$plugins =
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
$
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
*
|
262 |
-
*
|
263 |
-
*
|
264 |
-
*
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
$
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
'
|
278 |
-
'
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
'jet-
|
288 |
-
'jet-
|
289 |
-
'jet-
|
290 |
-
'jet-
|
291 |
-
'jet-
|
292 |
-
'jet-
|
293 |
-
'jet-
|
294 |
-
'jet-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
*
|
307 |
-
*
|
308 |
-
*
|
309 |
-
*
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
$
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
$plugins[ $slug ]['
|
346 |
-
}
|
347 |
-
|
348 |
-
if ( $
|
349 |
-
$plugins[ $slug ]['
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
$plugins[ $slug ]['
|
356 |
-
}
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
'
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
->new_version;
|
494 |
-
}
|
495 |
-
|
496 |
-
$conflicts = jupiterx_get_plugin_conflicts( $plugin_data, get_plugins() );
|
497 |
-
|
498 |
-
if ( count( $conflicts['plugins'] ) > 0 || count( $conflicts['themes'] ) > 0 ) {
|
499 |
-
wp_send_json_error( $conflicts );
|
500 |
-
}
|
501 |
-
|
502 |
-
wp_send_json_success();
|
503 |
-
}
|
504 |
-
}
|
505 |
-
|
506 |
-
JupiterX_Control_Panel_Install_Plugins::get_instance();
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class is responsible to manage all jupiters plugin.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel
|
6 |
+
*/
|
7 |
+
|
8 |
+
class JupiterX_Control_Panel_Install_Plugins {
|
9 |
+
|
10 |
+
protected $tgmpa;
|
11 |
+
protected $api_url = 'http://artbees.net/api/v2/';
|
12 |
+
protected $theme_name = 'JupiterX';
|
13 |
+
private static $instance = null;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Class constructor.
|
17 |
+
*
|
18 |
+
* @since 1.9.0
|
19 |
+
*/
|
20 |
+
public function __construct() {
|
21 |
+
if ( ! class_exists( 'TGM_Plugin_Activation' ) ) {
|
22 |
+
return;
|
23 |
+
}
|
24 |
+
|
25 |
+
$menu_items_access = get_site_option( 'menu_items' );
|
26 |
+
if ( is_multisite() && ! isset( $menu_items_access['plugins'] ) && ! current_user_can( 'manage_network_plugins' ) ) {
|
27 |
+
return;
|
28 |
+
}
|
29 |
+
|
30 |
+
$this->tgmpa = isset( $GLOBALS['tgmpa'] ) ? $GLOBALS['tgmpa'] : TGM_Plugin_Activation::get_instance();
|
31 |
+
|
32 |
+
add_filter( 'jupiterx_control_panel_pane_install_plugins', [ $this, 'view' ] );
|
33 |
+
|
34 |
+
add_action( 'wp_ajax_abb_get_plugins', [ $this, 'get_plugins_for_frontend' ] );
|
35 |
+
add_action( 'wp_ajax_abb_deactivate_plugin', [ $this, 'deactivate' ] );
|
36 |
+
add_action( 'wp_ajax_abb_update_plugin_checker', [ $this, 'plugin_conflict_checker' ] );
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Load view from Jupiter X Core plugin.
|
41 |
+
*
|
42 |
+
* @since 1.9.0
|
43 |
+
*/
|
44 |
+
public function view() {
|
45 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/install-plugins.php';
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Get class instance.
|
50 |
+
*
|
51 |
+
* @since 1.9.0
|
52 |
+
*/
|
53 |
+
public static function get_instance() {
|
54 |
+
if ( ! self::$instance ) {
|
55 |
+
self::$instance = new self;
|
56 |
+
}
|
57 |
+
|
58 |
+
return self::$instance;
|
59 |
+
}
|
60 |
+
|
61 |
+
public function is_update_available() {
|
62 |
+
$plugins = $this->get_all_plugins();
|
63 |
+
$plugins = $this->update_plugins_status( $plugins );
|
64 |
+
|
65 |
+
foreach ( $plugins as $plugin => $data ) {
|
66 |
+
if ( $data['update_needed'] ) {
|
67 |
+
return true;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
return false;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Send a json list of plugins and their data and activation limit status for front-end usage.
|
75 |
+
*
|
76 |
+
* @since 1.9.0
|
77 |
+
*/
|
78 |
+
public function get_plugins_for_frontend() {
|
79 |
+
$plugins = $this->get_all_plugins();
|
80 |
+
$plugins = $this->update_plugins_status( $plugins );
|
81 |
+
|
82 |
+
ksort( $plugins );
|
83 |
+
|
84 |
+
$limit = $this->plugins_threshold();
|
85 |
+
|
86 |
+
return wp_send_json( [ 'plugins' => $plugins, 'limit' => $limit ] );
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Get full list of plugins.
|
91 |
+
* 12h cache.
|
92 |
+
*
|
93 |
+
* @since 1.9.0
|
94 |
+
*/
|
95 |
+
public function get_all_plugins() {
|
96 |
+
$plugins = $this->get_free_plugins() + $this->get_pro_plugins();
|
97 |
+
|
98 |
+
return $plugins;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Get list of pro plugins from Artbees API.
|
103 |
+
*
|
104 |
+
* @since 1.9.0
|
105 |
+
*/
|
106 |
+
public function get_pro_plugins() {
|
107 |
+
return $this->get_plugins_from_api( [ 'slug', 'basename', 'version', 'name', 'desc', 'more_link', 'img_url', 'required', 'pro', 'is_callable' ] );
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Filter tgmpa plugins to extract list of free plugins.
|
112 |
+
*
|
113 |
+
* @since 1.9.0
|
114 |
+
*/
|
115 |
+
public function get_free_plugins_raw() {
|
116 |
+
return array_filter(
|
117 |
+
$this->tgmpa->plugins,
|
118 |
+
function( $plugin_info, $plugin ) {
|
119 |
+
return 'repo' === $plugin_info['source'];
|
120 |
+
},
|
121 |
+
ARRAY_FILTER_USE_BOTH
|
122 |
+
);
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Get list of free plugins.
|
127 |
+
* List gets update to add needed info like icon and version from WordPress repo.
|
128 |
+
*
|
129 |
+
* @since 1.9.0
|
130 |
+
*/
|
131 |
+
public function get_free_plugins() {
|
132 |
+
$plugins = $this->get_free_plugins_raw();
|
133 |
+
|
134 |
+
foreach ( $plugins as $plugin => $plugin_info ) {
|
135 |
+
$wp_plugin_info = $this->get_plugin_info_from_wp( $plugin, [ 'icons' => true, 'short_description' => true ] );
|
136 |
+
|
137 |
+
$plugins[ $plugin ]['version'] = $wp_plugin_info->version;
|
138 |
+
$plugins[ $plugin ]['desc'] = $wp_plugin_info->short_description;
|
139 |
+
$plugins[ $plugin ]['img_url'] = isset( $wp_plugin_info->icons['1x'] ) ? $wp_plugin_info->icons['1x'] : $wp_plugin_info->icons['default'];
|
140 |
+
}
|
141 |
+
|
142 |
+
return $plugins;
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Get a list of slugs of free plugins.
|
147 |
+
*
|
148 |
+
* @since 1.9.0
|
149 |
+
*/
|
150 |
+
public function get_free_plugins_slug() {
|
151 |
+
$free_plugins = $this->get_free_plugins();
|
152 |
+
|
153 |
+
return array_column( $plugins, 'slug' );
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Get detail of given plugin from WordPress repo.
|
158 |
+
* Used to get version, icon and plugin description.
|
159 |
+
*
|
160 |
+
* @since 1.9.0
|
161 |
+
*
|
162 |
+
* @param string $plugin_slug Plugin slug from plugin header.
|
163 |
+
* @param array $fields Needed extra information.
|
164 |
+
*/
|
165 |
+
public function get_plugin_info_from_wp( $plugin_slug = '', $fields = [] ) {
|
166 |
+
|
167 |
+
if ( empty( $plugin_slug ) ) {
|
168 |
+
return;
|
169 |
+
}
|
170 |
+
|
171 |
+
if ( ! function_exists( 'plugins_api' ) ) {
|
172 |
+
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
|
173 |
+
}
|
174 |
+
|
175 |
+
$default_fields = [
|
176 |
+
'short_description' => false,
|
177 |
+
'description' => false,
|
178 |
+
'sections' => false,
|
179 |
+
'tested' => false,
|
180 |
+
'requires' => false,
|
181 |
+
'rating' => false,
|
182 |
+
'downloaded' => false,
|
183 |
+
'downloadlink' => false,
|
184 |
+
'last_updated' => false,
|
185 |
+
'added' => false,
|
186 |
+
'tags' => false,
|
187 |
+
'compatibility' => false,
|
188 |
+
'homepage' => false,
|
189 |
+
'versions' => false,
|
190 |
+
'donate_link' => false,
|
191 |
+
'reviews' => false,
|
192 |
+
'banners' => false,
|
193 |
+
'icons' => false,
|
194 |
+
'active_installs' => false,
|
195 |
+
'group' => false,
|
196 |
+
'contributors' => false,
|
197 |
+
];
|
198 |
+
|
199 |
+
$fields = wp_parse_args( $fields, $default_fields );
|
200 |
+
|
201 |
+
$plugin_info = plugins_api(
|
202 |
+
'plugin_information',
|
203 |
+
[
|
204 |
+
'slug' => $plugin_slug,
|
205 |
+
'fields' => $fields,
|
206 |
+
]
|
207 |
+
);
|
208 |
+
|
209 |
+
if ( is_wp_error( $plugin_info ) ) {
|
210 |
+
return [];
|
211 |
+
}
|
212 |
+
|
213 |
+
return $plugin_info;
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Get custom list of plugins from Artbees API.
|
218 |
+
*
|
219 |
+
* @param array $fields Needed information.
|
220 |
+
*/
|
221 |
+
public function get_plugins_from_api( $fields = [] ) {
|
222 |
+
$free_plugins = array_column( $this->get_free_plugins(), 'slug' );
|
223 |
+
|
224 |
+
$response = wp_remote_get(
|
225 |
+
$this->api_url . 'tools/plugin-custom-list',
|
226 |
+
[
|
227 |
+
'sslverify' => false,
|
228 |
+
'headers' =>
|
229 |
+
[
|
230 |
+
'domain' => $_SERVER['SERVER_NAME'],
|
231 |
+
'theme-name' => $this->theme_name,
|
232 |
+
'list-of-attr' => wp_json_encode( $fields ),
|
233 |
+
'from' => 0,
|
234 |
+
'count' => 0,
|
235 |
+
],
|
236 |
+
]
|
237 |
+
);
|
238 |
+
|
239 |
+
$plugins = json_decode( wp_remote_retrieve_body( $response ), true );
|
240 |
+
$plugins = $plugins['data'];
|
241 |
+
|
242 |
+
$plugins = array_filter(
|
243 |
+
$plugins,
|
244 |
+
function( $v, $k ) use ( $free_plugins ) {
|
245 |
+
return ! in_array( $v['slug'], $free_plugins, true );
|
246 |
+
},
|
247 |
+
ARRAY_FILTER_USE_BOTH
|
248 |
+
);
|
249 |
+
|
250 |
+
$corrected_plugins_list = [];
|
251 |
+
|
252 |
+
foreach ( $plugins as $key => $plugin ) {
|
253 |
+
$corrected_plugins_list[ $plugin['slug'] ] = $plugin;
|
254 |
+
}
|
255 |
+
|
256 |
+
return $corrected_plugins_list;
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Check number of activated plugins in two different groups.
|
261 |
+
*
|
262 |
+
* @since 1.9.0
|
263 |
+
*
|
264 |
+
* @return bool $threshold Wether we are meeting threshold or not.
|
265 |
+
*/
|
266 |
+
public function plugins_threshold() {
|
267 |
+
|
268 |
+
$plugins = get_option('active_plugins');
|
269 |
+
$threshold = [];
|
270 |
+
|
271 |
+
if ( count( $plugins ) >= 20 ) {
|
272 |
+
$threshold[] = 'num';
|
273 |
+
}
|
274 |
+
|
275 |
+
$sliders = [
|
276 |
+
'LayerSlider/layerslider.php',
|
277 |
+
'masterslider/masterslider.php',
|
278 |
+
'revslider/revslider.php',
|
279 |
+
];
|
280 |
+
|
281 |
+
if ( count( array_intersect( $plugins, $sliders ) ) >= 1 ) {
|
282 |
+
$threshold[] = 'sliders';
|
283 |
+
}
|
284 |
+
|
285 |
+
$jet_plugins = [
|
286 |
+
'jet-blog/jet-blog.php',
|
287 |
+
'jet-elements/jet-elements.php',
|
288 |
+
'jet-engine/jet-engine.php',
|
289 |
+
'jet-menu/jet-menu.php',
|
290 |
+
'jet-popup/jet-popup.php',
|
291 |
+
'jet-smart-filters/jet-smart-filters.php',
|
292 |
+
'jet-tabs/jet-tabs.php',
|
293 |
+
'jet-tricks/jet-tricks.php',
|
294 |
+
'jet-woo-builder/jet-woo-builder.php',
|
295 |
+
];
|
296 |
+
|
297 |
+
if ( count( array_intersect( $plugins, $jet_plugins ) ) >= 4 ) {
|
298 |
+
$threshold[] = 'jet-plugins';
|
299 |
+
}
|
300 |
+
|
301 |
+
return implode( $threshold, ',' );
|
302 |
+
}
|
303 |
+
|
304 |
+
/**
|
305 |
+
* Update plugin information to add activation, installation and update status to plugin data.
|
306 |
+
* URL used to add activation/installation URL using TGMPA.
|
307 |
+
*
|
308 |
+
* @since 1.9.0
|
309 |
+
*
|
310 |
+
* @param array $plugins List of plugins.
|
311 |
+
*/
|
312 |
+
public function update_plugins_status( $plugins = [] ) {
|
313 |
+
|
314 |
+
foreach ( $plugins as $slug => $plugin ) {
|
315 |
+
|
316 |
+
if ( ! isset( $plugins[ $slug ]['basename'] ) || empty( $plugins[ $slug ]['basename'] ) ) {
|
317 |
+
$plugins[ $slug ]['basename'] = $this->find_plugin_path( $slug );
|
318 |
+
}
|
319 |
+
|
320 |
+
$plugins[ $slug ]['update_needed'] = false;
|
321 |
+
$plugins[ $slug ]['installed'] = false;
|
322 |
+
$plugins[ $slug ]['active'] = false;
|
323 |
+
$plugins[ $slug ]['network_active'] = false;
|
324 |
+
$plugins[ $slug ]['install_disabled'] = false;
|
325 |
+
|
326 |
+
if ( is_plugin_active_for_network( $plugins[ $slug ]['basename'] ) ) {
|
327 |
+
if ( ! current_user_can( 'manage_network_plugins' ) ) {
|
328 |
+
unset( $plugins[ $slug ] );
|
329 |
+
continue;
|
330 |
+
}
|
331 |
+
|
332 |
+
$plugins[ $slug ]['network_active'] = true;
|
333 |
+
}
|
334 |
+
|
335 |
+
if ( $this->tgmpa->is_plugin_active( $slug ) ) {
|
336 |
+
$plugins[ $slug ]['active'] = true;
|
337 |
+
$plugins[ $slug ]['installed'] = true;
|
338 |
+
} elseif ( $this->tgmpa->is_plugin_installed( $slug ) ) {
|
339 |
+
$plugins[ $slug ]['installed'] = true;
|
340 |
+
}
|
341 |
+
|
342 |
+
if ( ! jupiterx_is_pro() && 'true' === $plugins[ $slug ]['pro'] && ! $plugins[ $slug ]['installed'] ) {
|
343 |
+
$plugins[ $slug ]['pro'] = true;
|
344 |
+
} else {
|
345 |
+
unset( $plugins[ $slug ]['pro'] );
|
346 |
+
}
|
347 |
+
|
348 |
+
if ( ! $plugins[ $slug ]['installed'] && ( is_multisite() && ! current_user_can( 'manage_network_plugins' ) ) ) {
|
349 |
+
$plugins[ $slug ]['install_disabled'] = true;
|
350 |
+
}
|
351 |
+
|
352 |
+
if ( ! $plugins[ $slug ]['installed'] && ! $plugins[ $slug ]['install_disabled'] ) {
|
353 |
+
$plugins[ $slug ]['url'] = $this->get_tgmpa_action_url( $slug, 'install' );
|
354 |
+
} else {
|
355 |
+
$plugins[ $slug ]['url'] = $this->get_tgmpa_action_url( $slug, 'activate' );
|
356 |
+
}
|
357 |
+
|
358 |
+
if ( $plugins[ $slug ]['installed'] ) {
|
359 |
+
$plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $this->find_plugin_path( $slug ) );
|
360 |
+
$plugins[ $slug ]['version'] = $plugin_data['Version'];
|
361 |
+
|
362 |
+
if ( $this->tgmpa->does_plugin_have_update( $slug ) ) {
|
363 |
+
$plugins[ $slug ]['update_needed'] = true;
|
364 |
+
$plugins[ $slug ]['update_url'] = $this->get_tgmpa_action_url( $slug, 'update' );
|
365 |
+
}
|
366 |
+
}
|
367 |
+
}
|
368 |
+
|
369 |
+
return $plugins;
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Get plugin basename by plugin slug.
|
374 |
+
* Works only for installed plugins.
|
375 |
+
*
|
376 |
+
* @since 1.9.0
|
377 |
+
*
|
378 |
+
* @param string $plugin_slug
|
379 |
+
*/
|
380 |
+
public function find_plugin_path( $plugin_slug = '' ) {
|
381 |
+
|
382 |
+
$plugins = get_plugins();
|
383 |
+
foreach ( $plugins as $plugin_address => $plugin_data ) {
|
384 |
+
|
385 |
+
// Extract slug from address
|
386 |
+
if ( strlen( $plugin_address ) == basename( $plugin_address ) ) {
|
387 |
+
$slug = strtolower( str_replace( '.php', '', $plugin_address ) );
|
388 |
+
} else {
|
389 |
+
$slug = strtolower( str_replace( '/' . basename( $plugin_address ), '', $plugin_address ) );
|
390 |
+
}
|
391 |
+
// Check if slug exists
|
392 |
+
if ( strtolower( $plugin_slug ) == $slug ) {
|
393 |
+
return $plugin_address;
|
394 |
+
}
|
395 |
+
}
|
396 |
+
|
397 |
+
return false;
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Get installation/activation URL of a plugin using TGMPA.
|
402 |
+
*
|
403 |
+
* @since 1.9.0
|
404 |
+
*
|
405 |
+
* @param string $slug Plugin slug.
|
406 |
+
* @param string $action install/activate
|
407 |
+
*/
|
408 |
+
public function get_tgmpa_action_url( $slug = '', $action = '' ) {
|
409 |
+
if ( ! in_array( $action, [ 'install', 'activate', 'update' ], true ) ) {
|
410 |
+
wp_send_json_error( [ 'message' => esc_html__( 'Action is not valid.', 'jupiterx-core' ) ] );
|
411 |
+
}
|
412 |
+
|
413 |
+
$nonce_url = wp_nonce_url(
|
414 |
+
add_query_arg(
|
415 |
+
[
|
416 |
+
'plugin' => urlencode( $slug ),
|
417 |
+
'tgmpa-' . $action => $action . '-plugin',
|
418 |
+
],
|
419 |
+
admin_url( 'themes.php?page=tgmpa-install-plugins' )
|
420 |
+
),
|
421 |
+
'tgmpa-' . $action,
|
422 |
+
'tgmpa-nonce'
|
423 |
+
);
|
424 |
+
|
425 |
+
return $nonce_url;
|
426 |
+
}
|
427 |
+
|
428 |
+
/**
|
429 |
+
* Deactivate plugin using native WordPress functionalities.
|
430 |
+
*
|
431 |
+
* @since 1.9.0
|
432 |
+
*/
|
433 |
+
public function deactivate() {
|
434 |
+
if ( ! isset( $_POST['slug'] ) ) {
|
435 |
+
wp_send_json_error( [ 'message' => esc_html__( 'Can\'t deactivate plugin', 'jupiterx-core' ) ] );
|
436 |
+
}
|
437 |
+
|
438 |
+
$plugin = $this->find_plugin_path( sanitize_text_field( $_POST['slug'] ) );
|
439 |
+
|
440 |
+
if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
|
441 |
+
wp_send_json_error( esc_html__( 'Sorry, you are not allowed to deactivate this plugin.', 'jupiterx-core' ) );
|
442 |
+
}
|
443 |
+
|
444 |
+
deactivate_plugins( $plugin );
|
445 |
+
|
446 |
+
wp_send_json_success( esc_html__( 'Deactivated Successfully.', 'jupiterx-core' ) );
|
447 |
+
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Check for possible conflicts with Themes & Plugins for a specific plugin.
|
451 |
+
*
|
452 |
+
* @since 1.9.0
|
453 |
+
*
|
454 |
+
* @return void
|
455 |
+
*/
|
456 |
+
public function plugin_conflict_checker() {
|
457 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
458 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
459 |
+
}
|
460 |
+
|
461 |
+
$plugin_data = wp_unslash( $_POST['plugin'] );
|
462 |
+
|
463 |
+
if ( empty( $plugin_data ) ) {
|
464 |
+
wp_json_send_error( __( 'Plugin data is missing', 'jupiterx' ) );
|
465 |
+
}
|
466 |
+
|
467 |
+
if ( 'wp-repo' === $plugin_data['version'] ) {
|
468 |
+
$wp_updated_plugins = get_site_transient('update_plugins');
|
469 |
+
|
470 |
+
if (
|
471 |
+
empty( $wp_updated_plugins ) &&
|
472 |
+
empty( $wp_updated_plugins->response[ $plugin_data['basename'] ] )
|
473 |
+
) {
|
474 |
+
wp_send_json_success();
|
475 |
+
}
|
476 |
+
|
477 |
+
$plugin_data['version'] = $wp_updated_plugins
|
478 |
+
->response[ $plugin_data['basename'] ]
|
479 |
+
->new_version;
|
480 |
+
}
|
481 |
+
|
482 |
+
$conflicts = jupiterx_get_plugin_conflicts( $plugin_data, get_plugins() );
|
483 |
+
|
484 |
+
if ( count( $conflicts['plugins'] ) > 0 || count( $conflicts['themes'] ) > 0 ) {
|
485 |
+
wp_send_json_error( $conflicts );
|
486 |
+
}
|
487 |
+
|
488 |
+
wp_send_json_success();
|
489 |
+
}
|
490 |
+
}
|
491 |
+
|
492 |
+
JupiterX_Control_Panel_Install_Plugins::get_instance();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/control-panel/includes/class-install-template.php
CHANGED
@@ -270,6 +270,9 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Install_Template' ) ) {
|
|
270 |
case 'activate_plugins':
|
271 |
$this->activateRequiredPlugins( $template_name );
|
272 |
break;
|
|
|
|
|
|
|
273 |
case 'theme_content':
|
274 |
$this->importThemeContent( $template_name, $import_media, $partial_import );
|
275 |
break;
|
@@ -674,29 +677,20 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Install_Template' ) ) {
|
|
674 |
public function activateRequiredPlugins( $template_name ) {
|
675 |
|
676 |
$template_settings = $this->getSettingsData( $template_name );
|
677 |
-
$actions = [];
|
678 |
-
$tgmpa_url = $this->tgmpa->get_tgmpa_url();
|
679 |
$template_plugins = $template_settings['options']['jupiterx_support_plugins'];
|
680 |
|
681 |
-
$template_plugins = array_diff( $template_plugins, ['jupiterx-pro', 'advanced-custom-fields-pro'] );
|
682 |
-
|
683 |
$template_plugins[] = 'advanced-custom-fields';
|
684 |
|
685 |
-
$
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
'_wpnonce' => wp_create_nonce( 'bulk-plugins' ),
|
691 |
-
'action' => 'tgmpa-bulk-activate',
|
692 |
-
'action2' => - 1,
|
693 |
-
'message' => esc_html__( 'Activating', 'jupiterx-core' ),
|
694 |
-
];
|
695 |
-
|
696 |
-
$actions['url'] = $tgmpa_url;
|
697 |
-
$actions['status'] = true;
|
698 |
|
699 |
-
wp_send_json(
|
|
|
|
|
700 |
}
|
701 |
|
702 |
|
@@ -1658,7 +1652,7 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Install_Template' ) ) {
|
|
1658 |
public function get_template_psd_link() {
|
1659 |
$template_name = sanitize_text_field( $_POST['template_name'] );
|
1660 |
try {
|
1661 |
-
$response = $this->getTemplateDownloadLink( $template_name, 'download-psd' );
|
1662 |
$this->message(
|
1663 |
'Successfull', true, array(
|
1664 |
'psd_link' => $response,
|
@@ -1778,6 +1772,36 @@ if ( ! class_exists( 'JupiterX_Control_Panel_Install_Template' ) ) {
|
|
1778 |
return true;
|
1779 |
}
|
1780 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1781 |
/**
|
1782 |
* Reusable wrapper method for WP remote getter.
|
1783 |
*
|
270 |
case 'activate_plugins':
|
271 |
$this->activateRequiredPlugins( $template_name );
|
272 |
break;
|
273 |
+
case 'custom_tables':
|
274 |
+
$this->import_custom_tables( $template_name );
|
275 |
+
break;
|
276 |
case 'theme_content':
|
277 |
$this->importThemeContent( $template_name, $import_media, $partial_import );
|
278 |
break;
|
677 |
public function activateRequiredPlugins( $template_name ) {
|
678 |
|
679 |
$template_settings = $this->getSettingsData( $template_name );
|
|
|
|
|
680 |
$template_plugins = $template_settings['options']['jupiterx_support_plugins'];
|
681 |
|
682 |
+
$template_plugins = array_diff( $template_plugins, [ 'jupiterx-pro', 'advanced-custom-fields-pro' ] );
|
|
|
683 |
$template_plugins[] = 'advanced-custom-fields';
|
684 |
|
685 |
+
foreach ( $template_plugins as $slug ) {
|
686 |
+
if ( isset( $this->tgmpa->plugins[ $slug ] ) ) {
|
687 |
+
activate_plugin( $this->tgmpa->plugins[ $slug ]['file_path'] );
|
688 |
+
}
|
689 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
690 |
|
691 |
+
wp_send_json( [
|
692 |
+
'status' => true,
|
693 |
+
] );
|
694 |
}
|
695 |
|
696 |
|
1652 |
public function get_template_psd_link() {
|
1653 |
$template_name = sanitize_text_field( $_POST['template_name'] );
|
1654 |
try {
|
1655 |
+
$response = $this->getTemplateDownloadLink( $template_name . ' jupiterx', 'download-psd' );
|
1656 |
$this->message(
|
1657 |
'Successfull', true, array(
|
1658 |
'psd_link' => $response,
|
1772 |
return true;
|
1773 |
}
|
1774 |
|
1775 |
+
/**
|
1776 |
+
* Import templates's custom tables.
|
1777 |
+
*
|
1778 |
+
* @since 1.11.0
|
1779 |
+
*
|
1780 |
+
* @param string $template_name Template name.
|
1781 |
+
*/
|
1782 |
+
public function import_custom_tables( $template_name ) {
|
1783 |
+
$this->reinitializeData( $template_name );
|
1784 |
+
|
1785 |
+
try {
|
1786 |
+
$template_name = sanitize_title( $template_name );
|
1787 |
+
$import_path = $this->getBasePath() . $template_name;
|
1788 |
+
$file = $import_path . '/tables.sql';
|
1789 |
+
$db_manager = new JupiterX_Control_Panel_PHP_DB_Manager();
|
1790 |
+
|
1791 |
+
if ( file_exists( $file ) ) {
|
1792 |
+
$import_tables = $db_manager->import_tables( $file );
|
1793 |
+
|
1794 |
+
if ( $import_tables !== true ) {
|
1795 |
+
throw new Exception( $import_tables );
|
1796 |
+
}
|
1797 |
+
}
|
1798 |
+
|
1799 |
+
$this->message( 'Custom tables are imported.', true );
|
1800 |
+
} catch ( Exception $e ) {
|
1801 |
+
$this->message( $e->getMessage(), false );
|
1802 |
+
}
|
1803 |
+
}
|
1804 |
+
|
1805 |
/**
|
1806 |
* Reusable wrapper method for WP remote getter.
|
1807 |
*
|
includes/control-panel/includes/class-settings.php
CHANGED
@@ -1,118 +1,118 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Settings API: JupiterX_Control_Panel_Settings base class
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Framework\Control_Panel\Settings
|
6 |
-
*
|
7 |
-
* @since 1.4.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Settings' ) ) {
|
11 |
-
/**
|
12 |
-
* Settings.
|
13 |
-
*
|
14 |
-
* @since 1.4.0
|
15 |
-
*/
|
16 |
-
class JupiterX_Control_Panel_Settings {
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Constructor.
|
20 |
-
*
|
21 |
-
* @since 1.4.0
|
22 |
-
*/
|
23 |
-
public function __construct() {
|
24 |
-
add_filter( 'jupiterx_control_panel_pane_settings', [ $this, 'view' ] );
|
25 |
-
add_action( 'wp_ajax_jupiterx_cp_settings', [ $this, 'ajax_handler' ] );
|
26 |
-
}
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Settings HTML path.
|
30 |
-
*
|
31 |
-
* @since 1.4.0
|
32 |
-
*
|
33 |
-
* @return string
|
34 |
-
*/
|
35 |
-
public function view() {
|
36 |
-
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/settings.php';
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Map the requests to proper methods.
|
41 |
-
*
|
42 |
-
* @since 1.4.0
|
43 |
-
*/
|
44 |
-
public function ajax_handler() {
|
45 |
-
check_ajax_referer( 'jupiterx_control_panel', 'nonce' );
|
46 |
-
|
47 |
-
$type = jupiterx_post( 'type' );
|
48 |
-
|
49 |
-
if ( ! $type ) {
|
50 |
-
wp_send_json_error(
|
51 |
-
__( 'Type param is missing.', 'jupiterx-core' )
|
52 |
-
);
|
53 |
-
}
|
54 |
-
|
55 |
-
if ( 'flush' === $type ) {
|
56 |
-
$this->flush();
|
57 |
-
}
|
58 |
-
|
59 |
-
if ( 'save' === $type ) {
|
60 |
-
$this->save();
|
61 |
-
}
|
62 |
-
|
63 |
-
wp_send_json_error(
|
64 |
-
/* translators: Function request type to initialize. */
|
65 |
-
sprintf( esc_html__( 'Type param (%s) is not valid.', 'jupiterx-core' ), $type )
|
66 |
-
);
|
67 |
-
}
|
68 |
-
|
69 |
-
/**
|
70 |
-
* Flush assets cache.
|
71 |
-
*
|
72 |
-
* @since 1.4.0
|
73 |
-
*/
|
74 |
-
public function flush() {
|
75 |
-
|
76 |
-
jupiterx_core_flush_cache();
|
77 |
-
|
78 |
-
wp_send_json_success( esc_html__( 'Assets flushed successfully.', 'jupiterx-core' ) );
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Save settings.
|
83 |
-
*
|
84 |
-
* @since 1.4.0
|
85 |
-
*/
|
86 |
-
public function save() {
|
87 |
-
$fields = jupiterx_post( 'fields' );
|
88 |
-
|
89 |
-
if ( ! $fields ) {
|
90 |
-
wp_send_json_error( esc_html__( 'Fields param is missing.', 'jupiterx-core' ) );
|
91 |
-
}
|
92 |
-
|
93 |
-
if ( ! jupiterx_is_pro() ) {
|
94 |
-
$pro_fields = [
|
95 |
-
'jupiterx_adobe_fonts_project_id',
|
96 |
-
'jupiterx_tracking_codes_after_head',
|
97 |
-
'jupiterx_tracking_codes_before_head',
|
98 |
-
'jupiterx_tracking_codes_after_body',
|
99 |
-
'jupiterx_tracking_codes_before_body',
|
100 |
-
];
|
101 |
-
|
102 |
-
foreach ( $pro_fields as $name ) {
|
103 |
-
unset( $fields[ $name ] );
|
104 |
-
}
|
105 |
-
}
|
106 |
-
|
107 |
-
foreach ( $fields as $name => $value ) {
|
108 |
-
$name = preg_replace( '/(jupiterx|artbees)_/', '', $name, 1 );
|
109 |
-
jupiterx_update_option( $name, $value );
|
110 |
-
}
|
111 |
-
|
112 |
-
wp_send_json_success( esc_html__( 'Settings saved successfully.', 'jupiterx-core' ) );
|
113 |
-
}
|
114 |
-
|
115 |
-
}
|
116 |
-
|
117 |
-
new JupiterX_Control_Panel_Settings();
|
118 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Settings API: JupiterX_Control_Panel_Settings base class
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Framework\Control_Panel\Settings
|
6 |
+
*
|
7 |
+
* @since 1.4.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Settings' ) ) {
|
11 |
+
/**
|
12 |
+
* Settings.
|
13 |
+
*
|
14 |
+
* @since 1.4.0
|
15 |
+
*/
|
16 |
+
class JupiterX_Control_Panel_Settings {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Constructor.
|
20 |
+
*
|
21 |
+
* @since 1.4.0
|
22 |
+
*/
|
23 |
+
public function __construct() {
|
24 |
+
add_filter( 'jupiterx_control_panel_pane_settings', [ $this, 'view' ] );
|
25 |
+
add_action( 'wp_ajax_jupiterx_cp_settings', [ $this, 'ajax_handler' ] );
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Settings HTML path.
|
30 |
+
*
|
31 |
+
* @since 1.4.0
|
32 |
+
*
|
33 |
+
* @return string
|
34 |
+
*/
|
35 |
+
public function view() {
|
36 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/settings.php';
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Map the requests to proper methods.
|
41 |
+
*
|
42 |
+
* @since 1.4.0
|
43 |
+
*/
|
44 |
+
public function ajax_handler() {
|
45 |
+
check_ajax_referer( 'jupiterx_control_panel', 'nonce' );
|
46 |
+
|
47 |
+
$type = jupiterx_post( 'type' );
|
48 |
+
|
49 |
+
if ( ! $type ) {
|
50 |
+
wp_send_json_error(
|
51 |
+
__( 'Type param is missing.', 'jupiterx-core' )
|
52 |
+
);
|
53 |
+
}
|
54 |
+
|
55 |
+
if ( 'flush' === $type ) {
|
56 |
+
$this->flush();
|
57 |
+
}
|
58 |
+
|
59 |
+
if ( 'save' === $type ) {
|
60 |
+
$this->save();
|
61 |
+
}
|
62 |
+
|
63 |
+
wp_send_json_error(
|
64 |
+
/* translators: Function request type to initialize. */
|
65 |
+
sprintf( esc_html__( 'Type param (%s) is not valid.', 'jupiterx-core' ), $type )
|
66 |
+
);
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Flush assets cache.
|
71 |
+
*
|
72 |
+
* @since 1.4.0
|
73 |
+
*/
|
74 |
+
public function flush() {
|
75 |
+
|
76 |
+
jupiterx_core_flush_cache();
|
77 |
+
|
78 |
+
wp_send_json_success( esc_html__( 'Assets flushed successfully.', 'jupiterx-core' ) );
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Save settings.
|
83 |
+
*
|
84 |
+
* @since 1.4.0
|
85 |
+
*/
|
86 |
+
public function save() {
|
87 |
+
$fields = jupiterx_post( 'fields' );
|
88 |
+
|
89 |
+
if ( ! $fields ) {
|
90 |
+
wp_send_json_error( esc_html__( 'Fields param is missing.', 'jupiterx-core' ) );
|
91 |
+
}
|
92 |
+
|
93 |
+
if ( ! jupiterx_is_pro() ) {
|
94 |
+
$pro_fields = [
|
95 |
+
'jupiterx_adobe_fonts_project_id',
|
96 |
+
'jupiterx_tracking_codes_after_head',
|
97 |
+
'jupiterx_tracking_codes_before_head',
|
98 |
+
'jupiterx_tracking_codes_after_body',
|
99 |
+
'jupiterx_tracking_codes_before_body',
|
100 |
+
];
|
101 |
+
|
102 |
+
foreach ( $pro_fields as $name ) {
|
103 |
+
unset( $fields[ $name ] );
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
foreach ( $fields as $name => $value ) {
|
108 |
+
$name = preg_replace( '/(jupiterx|artbees)_/', '', $name, 1 );
|
109 |
+
jupiterx_update_option( $name, $value );
|
110 |
+
}
|
111 |
+
|
112 |
+
wp_send_json_success( esc_html__( 'Settings saved successfully.', 'jupiterx-core' ) );
|
113 |
+
}
|
114 |
+
|
115 |
+
}
|
116 |
+
|
117 |
+
new JupiterX_Control_Panel_Settings();
|
118 |
+
}
|
includes/control-panel/includes/class-system-status.php
CHANGED
@@ -1,378 +1,378 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class provides the list of system status values
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\Admin
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
/**
|
11 |
-
* Show list of system critical data
|
12 |
-
*
|
13 |
-
* @since 1.0.0
|
14 |
-
* @ignore
|
15 |
-
* @access private
|
16 |
-
*/
|
17 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_System_Status' ) ) {
|
18 |
-
class JupiterX_Control_Panel_System_Status {
|
19 |
-
|
20 |
-
|
21 |
-
/**
|
22 |
-
* JupiterX_Control_Panel_System_Status constructor.
|
23 |
-
*
|
24 |
-
* @since 1.0.0
|
25 |
-
*/
|
26 |
-
public function __construct() {
|
27 |
-
add_filter( 'jupiterx_control_panel_pane_system_status', [ $this, 'view' ] );
|
28 |
-
add_action( 'wp_ajax_jupiterx_cp_system_status', [ $this, 'ajax_handler' ] );
|
29 |
-
add_action( 'wp_ajax_jupiterx_cp_cleanup_mods', [ $this, 'cleanup_mods' ] );
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Load system status.
|
34 |
-
*
|
35 |
-
* @since 1.9.0
|
36 |
-
*
|
37 |
-
* @return string
|
38 |
-
*/
|
39 |
-
public function view() {
|
40 |
-
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/system-status.php';
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Clean up theme mods data and languages specific theme mods.
|
45 |
-
* This will removes all unwanted data (integer keys) from theme mods in multiple requests to avoid timeout.
|
46 |
-
*
|
47 |
-
* @since 1.4.0
|
48 |
-
*
|
49 |
-
* @return void
|
50 |
-
*/
|
51 |
-
public function cleanup_mods() {
|
52 |
-
$theme_slug = get_option( 'stylesheet' );
|
53 |
-
|
54 |
-
if ( ! wp_verify_nonce( $_POST['nonce'], 'jupiterx_mods_cleanup' ) ) {
|
55 |
-
wp_send_json_error( [ 'message' => __( 'Nonce can\'t be verified', 'jupiterx-core' ) ] );
|
56 |
-
}
|
57 |
-
|
58 |
-
$mods = get_option( 'theme_mods_' . $theme_slug );
|
59 |
-
$mods_size = sizeof( $mods );
|
60 |
-
|
61 |
-
$i = 0; // Index.
|
62 |
-
$j = 0; // Numeric keys.
|
63 |
-
foreach ( $mods as $key => $value ) {
|
64 |
-
if ( is_numeric( $key ) ) {
|
65 |
-
unset( $mods[ $key ] );
|
66 |
-
$j++;
|
67 |
-
}
|
68 |
-
|
69 |
-
$i++;
|
70 |
-
// Remove bunch of unwanted data.
|
71 |
-
if ( $j >= 1000 ) {
|
72 |
-
update_option( 'theme_mods_' . $theme_slug, $mods );
|
73 |
-
wp_send_json_success();
|
74 |
-
// If unwanted data length is less than 1000, remove all of them.
|
75 |
-
} elseif ( $i >= $mods_size ) {
|
76 |
-
update_option( 'theme_mods_' . $theme_slug, $mods );
|
77 |
-
}
|
78 |
-
}
|
79 |
-
|
80 |
-
$multilingual = new CoreCustomizerMultilingual();
|
81 |
-
$theme_slug = get_option( 'template' );
|
82 |
-
$option_prefix = str_replace( '-', '_', $theme_slug );
|
83 |
-
$option_name = $option_prefix . $multilingual::get_option_key();
|
84 |
-
$languages = $multilingual::get_languages_list();
|
85 |
-
$k = 0; // Index.
|
86 |
-
$l = 0; // Numeric keys.
|
87 |
-
foreach ( $languages as $language ) {
|
88 |
-
$lang_option_name = $option_name . $language['slug'];
|
89 |
-
$lang_option = get_option( $lang_option_name );
|
90 |
-
$lang_mods = isset( $lang_option['mods'] ) ? $lang_option['mods'] : [];
|
91 |
-
$lang_mode_size = sizeof( $lang_mods );
|
92 |
-
|
93 |
-
foreach ( $lang_mods as $key => $value ) {
|
94 |
-
if ( is_numeric( $key ) ) {
|
95 |
-
unset( $lang_mods[ $key ] );
|
96 |
-
$l++;
|
97 |
-
}
|
98 |
-
|
99 |
-
$k++;
|
100 |
-
// Remove bunch of unwanted data.
|
101 |
-
if ( $l >= 1000 ) {
|
102 |
-
$lang_option['mods'] = $lang_mods;
|
103 |
-
update_option( $lang_option_name, $lang_option );
|
104 |
-
wp_send_json_success();
|
105 |
-
// If unwanted data length is less than 1000, remove all of them.
|
106 |
-
} elseif( $k >= $lang_mode_size ) {
|
107 |
-
$lang_option['mods'] = $lang_mods;
|
108 |
-
update_option( $lang_option_name, $lang_option );
|
109 |
-
wp_send_json_error();
|
110 |
-
}
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
wp_send_json_error();
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Handles AJAX requests.
|
119 |
-
*
|
120 |
-
* @since 1.3.0
|
121 |
-
*/
|
122 |
-
public function ajax_handler() {
|
123 |
-
check_ajax_referer( 'jupiterx_control_panel', 'nonce' );
|
124 |
-
|
125 |
-
$type = jupiterx_post( 'type' );
|
126 |
-
|
127 |
-
if ( ! $type ) {
|
128 |
-
wp_send_json_error( esc_html__( 'Type param is missing.', 'jupiterx-core' ) );
|
129 |
-
}
|
130 |
-
|
131 |
-
$this->$type();
|
132 |
-
|
133 |
-
wp_send_json_error(
|
134 |
-
sprintf( esc_html__( 'Type param (%s) is not valid.', 'jupiterx-core' ), $type )
|
135 |
-
);
|
136 |
-
}
|
137 |
-
|
138 |
-
/**
|
139 |
-
* Checks whether HTTP requests are blocked.
|
140 |
-
*
|
141 |
-
* @see test_http_requests() in Health Check plugin.
|
142 |
-
* @since 1.3.0
|
143 |
-
*/
|
144 |
-
private function http_requests() {
|
145 |
-
$blocked = false;
|
146 |
-
$hosts = [];
|
147 |
-
|
148 |
-
if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) ) {
|
149 |
-
$blocked = true;
|
150 |
-
}
|
151 |
-
|
152 |
-
if ( defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
|
153 |
-
$hosts = explode( ',', WP_ACCESSIBLE_HOSTS );
|
154 |
-
}
|
155 |
-
|
156 |
-
if ( $blocked && 0 === sizeof( $hosts ) ) {
|
157 |
-
wp_send_json_error( esc_html__( 'HTTP requests have been blocked by the WP_HTTP_BLOCK_EXTERNAL constant, with no allowed hosts.', 'jupiterx-core' ) );
|
158 |
-
}
|
159 |
-
|
160 |
-
if ( $blocked && 0 < sizeof( $hosts ) ) {
|
161 |
-
wp_send_json_error(
|
162 |
-
sprintf(
|
163 |
-
esc_html__( 'HTTP requests have been blocked by the WP_HTTP_BLOCK_EXTERNAL constant, with some hosts whitelisted: %s.', 'jupiterx-core' ),
|
164 |
-
implode( ',', $hosts )
|
165 |
-
)
|
166 |
-
);
|
167 |
-
}
|
168 |
-
|
169 |
-
if ( ! $blocked ) {
|
170 |
-
wp_send_json_success();
|
171 |
-
}
|
172 |
-
}
|
173 |
-
|
174 |
-
/**
|
175 |
-
* Checks whether artbees.net is accessible.
|
176 |
-
*
|
177 |
-
* @since 1.3.0
|
178 |
-
*/
|
179 |
-
private function artbees_server() {
|
180 |
-
$response = wp_remote_get( 'https://artbees.net', array(
|
181 |
-
'timeout' => 10,
|
182 |
-
) );
|
183 |
-
|
184 |
-
if ( is_wp_error( $response ) ) {
|
185 |
-
wp_send_json_error( $response->get_error_message() );
|
186 |
-
}
|
187 |
-
|
188 |
-
wp_send_json_success();
|
189 |
-
}
|
190 |
-
|
191 |
-
/**
|
192 |
-
* Create an array of system status
|
193 |
-
*
|
194 |
-
* @since 1.0.0
|
195 |
-
*
|
196 |
-
* @return array
|
197 |
-
*/
|
198 |
-
public static function compile_system_status() {
|
199 |
-
global $wpdb;
|
200 |
-
|
201 |
-
$sysinfo = array();
|
202 |
-
$upload_dir = wp_upload_dir();
|
203 |
-
|
204 |
-
$sysinfo['home_url'] = esc_url( home_url( '/' ) );
|
205 |
-
$sysinfo['site_url'] = esc_url( site_url( '/' ) );
|
206 |
-
|
207 |
-
$sysinfo['wp_content_url'] = WP_CONTENT_URL;
|
208 |
-
$sysinfo['wp_upload_dir'] = $upload_dir['basedir'];
|
209 |
-
$sysinfo['wp_upload_url'] = $upload_dir['baseurl'];
|
210 |
-
$sysinfo['wp_ver'] = get_bloginfo( 'version' );
|
211 |
-
$sysinfo['wp_multisite'] = is_multisite();
|
212 |
-
$sysinfo['permalink_structure'] = get_option( 'permalink_structure' ) ? get_option( 'permalink_structure' ) : 'Default';
|
213 |
-
$sysinfo['front_page_display'] = get_option( 'show_on_front' );
|
214 |
-
if ( 'page' == $sysinfo['front_page_display'] ) {
|
215 |
-
$front_page_id = get_option( 'page_on_front' );
|
216 |
-
$blog_page_id = get_option( 'page_for_posts' );
|
217 |
-
|
218 |
-
$sysinfo['front_page'] = 0 != $front_page_id ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset';
|
219 |
-
$sysinfo['posts_page'] = 0 != $blog_page_id ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset';
|
220 |
-
}
|
221 |
-
|
222 |
-
$sysinfo['wp_mem_limit']['raw'] = JupiterX_Control_Panel_Helpers::let_to_num( WP_MEMORY_LIMIT );
|
223 |
-
$sysinfo['wp_mem_limit']['size'] = size_format( $sysinfo['wp_mem_limit']['raw'] );
|
224 |
-
|
225 |
-
$sysinfo['db_table_prefix'] = 'Length: ' . strlen( $wpdb->prefix ) . ' - Status: ' . (strlen( $wpdb->prefix ) > 16 ? 'ERROR: Too long' : 'Acceptable');
|
226 |
-
|
227 |
-
$sysinfo['wp_debug'] = 'false';
|
228 |
-
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
229 |
-
$sysinfo['wp_debug'] = 'true';
|
230 |
-
}
|
231 |
-
|
232 |
-
$sysinfo['wp_lang'] = get_locale();
|
233 |
-
|
234 |
-
$sysinfo['wp_writable'] = get_home_path();
|
235 |
-
$sysinfo['wp_content_writable'] = WP_CONTENT_DIR;
|
236 |
-
$sysinfo['wp_uploads_writable'] = $sysinfo['wp_upload_dir'];
|
237 |
-
$sysinfo['wp_plugins_writable'] = WP_PLUGIN_DIR;
|
238 |
-
$sysinfo['wp_themes_writable'] = get_theme_root();
|
239 |
-
|
240 |
-
if ( ! class_exists( 'Browser' ) ) {
|
241 |
-
jupiterx_core()->load_files( [
|
242 |
-
'control-panel/includes/class-browser',
|
243 |
-
] );
|
244 |
-
}
|
245 |
-
|
246 |
-
$browser = new Browser();
|
247 |
-
|
248 |
-
$sysinfo['browser'] = array(
|
249 |
-
'agent' => $browser->getUserAgent(),
|
250 |
-
'browser' => $browser->getBrowser(),
|
251 |
-
'version' => $browser->getVersion(),
|
252 |
-
'platform' => $browser->getPlatform(),
|
253 |
-
);
|
254 |
-
|
255 |
-
$sysinfo['server_info'] = esc_html( $_SERVER['SERVER_SOFTWARE'] );
|
256 |
-
$sysinfo['localhost'] = JupiterX_Control_Panel_Helpers::make_bool_string( JupiterX_Control_Panel_Helpers::is_localhost() );
|
257 |
-
$sysinfo['php_ver'] = function_exists( 'phpversion' ) ? esc_html( phpversion() ) : 'phpversion() function does not exist.';
|
258 |
-
$sysinfo['abspath'] = ABSPATH;
|
259 |
-
|
260 |
-
if ( function_exists( 'ini_get' ) ) {
|
261 |
-
$sysinfo['php_mem_limit']['raw'] = JupiterX_Control_Panel_Helpers::let_to_num( ini_get( 'memory_limit' ) );
|
262 |
-
$sysinfo['php_mem_limit']['size'] = size_format( $sysinfo['php_mem_limit']['raw'] );
|
263 |
-
$sysinfo['php_post_max_size'] = size_format( JupiterX_Control_Panel_Helpers::let_to_num( ini_get( 'post_max_size' ) ) );
|
264 |
-
$sysinfo['php_time_limit'] = ini_get( 'max_execution_time' );
|
265 |
-
$sysinfo['php_max_input_var'] = ini_get( 'max_input_vars' );
|
266 |
-
$sysinfo['suhosin_request_max_vars'] = ini_get( 'suhosin.request.max_vars' );
|
267 |
-
$sysinfo['suhosin_post_max_vars'] = ini_get( 'suhosin.post.max_vars' );
|
268 |
-
$sysinfo['php_display_errors'] = JupiterX_Control_Panel_Helpers::make_bool_string( ini_get( 'display_errors' ) );
|
269 |
-
}
|
270 |
-
|
271 |
-
$sysinfo['suhosin_installed'] = extension_loaded( 'suhosin' );
|
272 |
-
$sysinfo['mysql_ver'] = $wpdb->db_version();
|
273 |
-
$sysinfo['max_upload_size'] = size_format( wp_max_upload_size() );
|
274 |
-
|
275 |
-
$sysinfo['def_tz_is_utc'] = 'true';
|
276 |
-
if ( date_default_timezone_get() !== 'UTC' ) {
|
277 |
-
$sysinfo['def_tz_is_utc'] = 'false';
|
278 |
-
}
|
279 |
-
|
280 |
-
$sysinfo['fsockopen_curl'] = 'false';
|
281 |
-
if ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ) {
|
282 |
-
$sysinfo['fsockopen_curl'] = 'true';
|
283 |
-
}
|
284 |
-
|
285 |
-
$sysinfo['soap_client'] = 'false';
|
286 |
-
if ( class_exists( 'SoapClient' ) ) {
|
287 |
-
$sysinfo['soap_client'] = 'true';
|
288 |
-
}
|
289 |
-
|
290 |
-
$sysinfo['dom_document'] = 'false';
|
291 |
-
if ( class_exists( 'DOMDocument' ) ) {
|
292 |
-
$sysinfo['dom_document'] = 'true';
|
293 |
-
}
|
294 |
-
|
295 |
-
$sysinfo['gzip'] = 'false';
|
296 |
-
if ( is_callable( 'gzopen' ) ) {
|
297 |
-
$sysinfo['gzip'] = 'true';
|
298 |
-
}
|
299 |
-
|
300 |
-
$sysinfo['mbstring'] = 'false';
|
301 |
-
|
302 |
-
if ( extension_loaded( 'mbstring' ) && function_exists( 'mb_eregi' ) && function_exists( 'mb_ereg_match' ) ) {
|
303 |
-
$sysinfo['mbstring'] = 'true';
|
304 |
-
}
|
305 |
-
|
306 |
-
$sysinfo['simplexml'] = 'false';
|
307 |
-
|
308 |
-
if ( class_exists( 'SimpleXMLElement' ) && function_exists( 'simplexml_load_string' ) ) {
|
309 |
-
$sysinfo['simplexml'] = 'true';
|
310 |
-
}
|
311 |
-
|
312 |
-
$sysinfo['phpxml'] = 'false';
|
313 |
-
|
314 |
-
if ( function_exists( 'xml_parse' ) ) {
|
315 |
-
$sysinfo['phpxml'] = 'true';
|
316 |
-
}
|
317 |
-
|
318 |
-
$active_plugins = (array) get_option( 'active_plugins', array() );
|
319 |
-
|
320 |
-
if ( is_multisite() ) {
|
321 |
-
$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
|
322 |
-
}
|
323 |
-
|
324 |
-
$sysinfo['plugins'] = array();
|
325 |
-
|
326 |
-
foreach ( $active_plugins as $plugin ) {
|
327 |
-
$plugin_data = @get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
328 |
-
$plugin_name = esc_html( $plugin_data['Name'] );
|
329 |
-
|
330 |
-
$sysinfo['plugins'][ $plugin_name ] = $plugin_data;
|
331 |
-
}
|
332 |
-
|
333 |
-
$active_theme = wp_get_theme();
|
334 |
-
|
335 |
-
$sysinfo['theme']['name'] = $active_theme->Name;
|
336 |
-
$sysinfo['theme']['version'] = $active_theme->Version;
|
337 |
-
$sysinfo['theme']['author_uri'] = $active_theme->{'Author URI'};
|
338 |
-
$sysinfo['theme']['is_child'] = JupiterX_Control_Panel_Helpers::make_bool_string( is_child_theme() );
|
339 |
-
|
340 |
-
if ( is_child_theme() ) {
|
341 |
-
$parent_theme = wp_get_theme( $active_theme->Template );
|
342 |
-
|
343 |
-
$sysinfo['theme']['parent_name'] = $parent_theme->Name;
|
344 |
-
$sysinfo['theme']['parent_version'] = $parent_theme->Version;
|
345 |
-
$sysinfo['theme']['parent_author_uri'] = $parent_theme->{'Author URI'};
|
346 |
-
}
|
347 |
-
|
348 |
-
return $sysinfo;
|
349 |
-
}
|
350 |
-
|
351 |
-
/**
|
352 |
-
* Create an array of system status warnings.
|
353 |
-
*
|
354 |
-
* @since 1.9.0
|
355 |
-
*
|
356 |
-
* @return array
|
357 |
-
*/
|
358 |
-
public static function compile_system_status_warnings() {
|
359 |
-
$helper = JupiterX_Control_Panel_Helpers::class;
|
360 |
-
$sysinfo = self::compile_system_status();
|
361 |
-
$warnings = [];
|
362 |
-
$link = '<a href="https://themes.artbees.net/docs/jupiter-x-server-requirements/" target="_blank">' . __( 'Read More', 'jupiterx-core' ) . '</a>';
|
363 |
-
|
364 |
-
if ( $helper::bytes_to_mb( $sysinfo['wp_mem_limit']['raw'] ) < 256 ) {
|
365 |
-
$warnings['wp_mem_limit']['message'] = __( 'Insufficient memory. You need at least 256MB of memory.', 'jupiterx-core' );
|
366 |
-
$warnings['wp_mem_limit']['message'] .= $link;
|
367 |
-
}
|
368 |
-
|
369 |
-
if ( $helper::bytes_to_mb( $sysinfo['php_mem_limit']['raw'] ) < 256 ) {
|
370 |
-
$warnings['php_mem_limit']['message'] = __( 'Insufficient memory. You need at least 256MB of memory.', 'jupiterx-core' );
|
371 |
-
$warnings['php_mem_limit']['message'] .= $link;
|
372 |
-
}
|
373 |
-
|
374 |
-
return $warnings;
|
375 |
-
}
|
376 |
-
}
|
377 |
-
new JupiterX_Control_Panel_System_Status();
|
378 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class provides the list of system status values
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\Admin
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Show list of system critical data
|
12 |
+
*
|
13 |
+
* @since 1.0.0
|
14 |
+
* @ignore
|
15 |
+
* @access private
|
16 |
+
*/
|
17 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_System_Status' ) ) {
|
18 |
+
class JupiterX_Control_Panel_System_Status {
|
19 |
+
|
20 |
+
|
21 |
+
/**
|
22 |
+
* JupiterX_Control_Panel_System_Status constructor.
|
23 |
+
*
|
24 |
+
* @since 1.0.0
|
25 |
+
*/
|
26 |
+
public function __construct() {
|
27 |
+
add_filter( 'jupiterx_control_panel_pane_system_status', [ $this, 'view' ] );
|
28 |
+
add_action( 'wp_ajax_jupiterx_cp_system_status', [ $this, 'ajax_handler' ] );
|
29 |
+
add_action( 'wp_ajax_jupiterx_cp_cleanup_mods', [ $this, 'cleanup_mods' ] );
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Load system status.
|
34 |
+
*
|
35 |
+
* @since 1.9.0
|
36 |
+
*
|
37 |
+
* @return string
|
38 |
+
*/
|
39 |
+
public function view() {
|
40 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/system-status.php';
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Clean up theme mods data and languages specific theme mods.
|
45 |
+
* This will removes all unwanted data (integer keys) from theme mods in multiple requests to avoid timeout.
|
46 |
+
*
|
47 |
+
* @since 1.4.0
|
48 |
+
*
|
49 |
+
* @return void
|
50 |
+
*/
|
51 |
+
public function cleanup_mods() {
|
52 |
+
$theme_slug = get_option( 'stylesheet' );
|
53 |
+
|
54 |
+
if ( ! wp_verify_nonce( $_POST['nonce'], 'jupiterx_mods_cleanup' ) ) {
|
55 |
+
wp_send_json_error( [ 'message' => __( 'Nonce can\'t be verified', 'jupiterx-core' ) ] );
|
56 |
+
}
|
57 |
+
|
58 |
+
$mods = get_option( 'theme_mods_' . $theme_slug );
|
59 |
+
$mods_size = sizeof( $mods );
|
60 |
+
|
61 |
+
$i = 0; // Index.
|
62 |
+
$j = 0; // Numeric keys.
|
63 |
+
foreach ( $mods as $key => $value ) {
|
64 |
+
if ( is_numeric( $key ) ) {
|
65 |
+
unset( $mods[ $key ] );
|
66 |
+
$j++;
|
67 |
+
}
|
68 |
+
|
69 |
+
$i++;
|
70 |
+
// Remove bunch of unwanted data.
|
71 |
+
if ( $j >= 1000 ) {
|
72 |
+
update_option( 'theme_mods_' . $theme_slug, $mods );
|
73 |
+
wp_send_json_success();
|
74 |
+
// If unwanted data length is less than 1000, remove all of them.
|
75 |
+
} elseif ( $i >= $mods_size ) {
|
76 |
+
update_option( 'theme_mods_' . $theme_slug, $mods );
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
$multilingual = new CoreCustomizerMultilingual();
|
81 |
+
$theme_slug = get_option( 'template' );
|
82 |
+
$option_prefix = str_replace( '-', '_', $theme_slug );
|
83 |
+
$option_name = $option_prefix . $multilingual::get_option_key();
|
84 |
+
$languages = $multilingual::get_languages_list();
|
85 |
+
$k = 0; // Index.
|
86 |
+
$l = 0; // Numeric keys.
|
87 |
+
foreach ( $languages as $language ) {
|
88 |
+
$lang_option_name = $option_name . $language['slug'];
|
89 |
+
$lang_option = get_option( $lang_option_name );
|
90 |
+
$lang_mods = isset( $lang_option['mods'] ) ? $lang_option['mods'] : [];
|
91 |
+
$lang_mode_size = sizeof( $lang_mods );
|
92 |
+
|
93 |
+
foreach ( $lang_mods as $key => $value ) {
|
94 |
+
if ( is_numeric( $key ) ) {
|
95 |
+
unset( $lang_mods[ $key ] );
|
96 |
+
$l++;
|
97 |
+
}
|
98 |
+
|
99 |
+
$k++;
|
100 |
+
// Remove bunch of unwanted data.
|
101 |
+
if ( $l >= 1000 ) {
|
102 |
+
$lang_option['mods'] = $lang_mods;
|
103 |
+
update_option( $lang_option_name, $lang_option );
|
104 |
+
wp_send_json_success();
|
105 |
+
// If unwanted data length is less than 1000, remove all of them.
|
106 |
+
} elseif( $k >= $lang_mode_size ) {
|
107 |
+
$lang_option['mods'] = $lang_mods;
|
108 |
+
update_option( $lang_option_name, $lang_option );
|
109 |
+
wp_send_json_error();
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
wp_send_json_error();
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Handles AJAX requests.
|
119 |
+
*
|
120 |
+
* @since 1.3.0
|
121 |
+
*/
|
122 |
+
public function ajax_handler() {
|
123 |
+
check_ajax_referer( 'jupiterx_control_panel', 'nonce' );
|
124 |
+
|
125 |
+
$type = jupiterx_post( 'type' );
|
126 |
+
|
127 |
+
if ( ! $type ) {
|
128 |
+
wp_send_json_error( esc_html__( 'Type param is missing.', 'jupiterx-core' ) );
|
129 |
+
}
|
130 |
+
|
131 |
+
$this->$type();
|
132 |
+
|
133 |
+
wp_send_json_error(
|
134 |
+
sprintf( esc_html__( 'Type param (%s) is not valid.', 'jupiterx-core' ), $type )
|
135 |
+
);
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Checks whether HTTP requests are blocked.
|
140 |
+
*
|
141 |
+
* @see test_http_requests() in Health Check plugin.
|
142 |
+
* @since 1.3.0
|
143 |
+
*/
|
144 |
+
private function http_requests() {
|
145 |
+
$blocked = false;
|
146 |
+
$hosts = [];
|
147 |
+
|
148 |
+
if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) ) {
|
149 |
+
$blocked = true;
|
150 |
+
}
|
151 |
+
|
152 |
+
if ( defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
|
153 |
+
$hosts = explode( ',', WP_ACCESSIBLE_HOSTS );
|
154 |
+
}
|
155 |
+
|
156 |
+
if ( $blocked && 0 === sizeof( $hosts ) ) {
|
157 |
+
wp_send_json_error( esc_html__( 'HTTP requests have been blocked by the WP_HTTP_BLOCK_EXTERNAL constant, with no allowed hosts.', 'jupiterx-core' ) );
|
158 |
+
}
|
159 |
+
|
160 |
+
if ( $blocked && 0 < sizeof( $hosts ) ) {
|
161 |
+
wp_send_json_error(
|
162 |
+
sprintf(
|
163 |
+
esc_html__( 'HTTP requests have been blocked by the WP_HTTP_BLOCK_EXTERNAL constant, with some hosts whitelisted: %s.', 'jupiterx-core' ),
|
164 |
+
implode( ',', $hosts )
|
165 |
+
)
|
166 |
+
);
|
167 |
+
}
|
168 |
+
|
169 |
+
if ( ! $blocked ) {
|
170 |
+
wp_send_json_success();
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Checks whether artbees.net is accessible.
|
176 |
+
*
|
177 |
+
* @since 1.3.0
|
178 |
+
*/
|
179 |
+
private function artbees_server() {
|
180 |
+
$response = wp_remote_get( 'https://artbees.net', array(
|
181 |
+
'timeout' => 10,
|
182 |
+
) );
|
183 |
+
|
184 |
+
if ( is_wp_error( $response ) ) {
|
185 |
+
wp_send_json_error( $response->get_error_message() );
|
186 |
+
}
|
187 |
+
|
188 |
+
wp_send_json_success();
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Create an array of system status
|
193 |
+
*
|
194 |
+
* @since 1.0.0
|
195 |
+
*
|
196 |
+
* @return array
|
197 |
+
*/
|
198 |
+
public static function compile_system_status() {
|
199 |
+
global $wpdb;
|
200 |
+
|
201 |
+
$sysinfo = array();
|
202 |
+
$upload_dir = wp_upload_dir();
|
203 |
+
|
204 |
+
$sysinfo['home_url'] = esc_url( home_url( '/' ) );
|
205 |
+
$sysinfo['site_url'] = esc_url( site_url( '/' ) );
|
206 |
+
|
207 |
+
$sysinfo['wp_content_url'] = WP_CONTENT_URL;
|
208 |
+
$sysinfo['wp_upload_dir'] = $upload_dir['basedir'];
|
209 |
+
$sysinfo['wp_upload_url'] = $upload_dir['baseurl'];
|
210 |
+
$sysinfo['wp_ver'] = get_bloginfo( 'version' );
|
211 |
+
$sysinfo['wp_multisite'] = is_multisite();
|
212 |
+
$sysinfo['permalink_structure'] = get_option( 'permalink_structure' ) ? get_option( 'permalink_structure' ) : 'Default';
|
213 |
+
$sysinfo['front_page_display'] = get_option( 'show_on_front' );
|
214 |
+
if ( 'page' == $sysinfo['front_page_display'] ) {
|
215 |
+
$front_page_id = get_option( 'page_on_front' );
|
216 |
+
$blog_page_id = get_option( 'page_for_posts' );
|
217 |
+
|
218 |
+
$sysinfo['front_page'] = 0 != $front_page_id ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset';
|
219 |
+
$sysinfo['posts_page'] = 0 != $blog_page_id ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset';
|
220 |
+
}
|
221 |
+
|
222 |
+
$sysinfo['wp_mem_limit']['raw'] = JupiterX_Control_Panel_Helpers::let_to_num( WP_MEMORY_LIMIT );
|
223 |
+
$sysinfo['wp_mem_limit']['size'] = size_format( $sysinfo['wp_mem_limit']['raw'] );
|
224 |
+
|
225 |
+
$sysinfo['db_table_prefix'] = 'Length: ' . strlen( $wpdb->prefix ) . ' - Status: ' . (strlen( $wpdb->prefix ) > 16 ? 'ERROR: Too long' : 'Acceptable');
|
226 |
+
|
227 |
+
$sysinfo['wp_debug'] = 'false';
|
228 |
+
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
229 |
+
$sysinfo['wp_debug'] = 'true';
|
230 |
+
}
|
231 |
+
|
232 |
+
$sysinfo['wp_lang'] = get_locale();
|
233 |
+
|
234 |
+
$sysinfo['wp_writable'] = get_home_path();
|
235 |
+
$sysinfo['wp_content_writable'] = WP_CONTENT_DIR;
|
236 |
+
$sysinfo['wp_uploads_writable'] = $sysinfo['wp_upload_dir'];
|
237 |
+
$sysinfo['wp_plugins_writable'] = WP_PLUGIN_DIR;
|
238 |
+
$sysinfo['wp_themes_writable'] = get_theme_root();
|
239 |
+
|
240 |
+
if ( ! class_exists( 'Browser' ) ) {
|
241 |
+
jupiterx_core()->load_files( [
|
242 |
+
'control-panel/includes/class-browser',
|
243 |
+
] );
|
244 |
+
}
|
245 |
+
|
246 |
+
$browser = new Browser();
|
247 |
+
|
248 |
+
$sysinfo['browser'] = array(
|
249 |
+
'agent' => $browser->getUserAgent(),
|
250 |
+
'browser' => $browser->getBrowser(),
|
251 |
+
'version' => $browser->getVersion(),
|
252 |
+
'platform' => $browser->getPlatform(),
|
253 |
+
);
|
254 |
+
|
255 |
+
$sysinfo['server_info'] = esc_html( $_SERVER['SERVER_SOFTWARE'] );
|
256 |
+
$sysinfo['localhost'] = JupiterX_Control_Panel_Helpers::make_bool_string( JupiterX_Control_Panel_Helpers::is_localhost() );
|
257 |
+
$sysinfo['php_ver'] = function_exists( 'phpversion' ) ? esc_html( phpversion() ) : 'phpversion() function does not exist.';
|
258 |
+
$sysinfo['abspath'] = ABSPATH;
|
259 |
+
|
260 |
+
if ( function_exists( 'ini_get' ) ) {
|
261 |
+
$sysinfo['php_mem_limit']['raw'] = JupiterX_Control_Panel_Helpers::let_to_num( ini_get( 'memory_limit' ) );
|
262 |
+
$sysinfo['php_mem_limit']['size'] = size_format( $sysinfo['php_mem_limit']['raw'] );
|
263 |
+
$sysinfo['php_post_max_size'] = size_format( JupiterX_Control_Panel_Helpers::let_to_num( ini_get( 'post_max_size' ) ) );
|
264 |
+
$sysinfo['php_time_limit'] = ini_get( 'max_execution_time' );
|
265 |
+
$sysinfo['php_max_input_var'] = ini_get( 'max_input_vars' );
|
266 |
+
$sysinfo['suhosin_request_max_vars'] = ini_get( 'suhosin.request.max_vars' );
|
267 |
+
$sysinfo['suhosin_post_max_vars'] = ini_get( 'suhosin.post.max_vars' );
|
268 |
+
$sysinfo['php_display_errors'] = JupiterX_Control_Panel_Helpers::make_bool_string( ini_get( 'display_errors' ) );
|
269 |
+
}
|
270 |
+
|
271 |
+
$sysinfo['suhosin_installed'] = extension_loaded( 'suhosin' );
|
272 |
+
$sysinfo['mysql_ver'] = $wpdb->db_version();
|
273 |
+
$sysinfo['max_upload_size'] = size_format( wp_max_upload_size() );
|
274 |
+
|
275 |
+
$sysinfo['def_tz_is_utc'] = 'true';
|
276 |
+
if ( date_default_timezone_get() !== 'UTC' ) {
|
277 |
+
$sysinfo['def_tz_is_utc'] = 'false';
|
278 |
+
}
|
279 |
+
|
280 |
+
$sysinfo['fsockopen_curl'] = 'false';
|
281 |
+
if ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ) {
|
282 |
+
$sysinfo['fsockopen_curl'] = 'true';
|
283 |
+
}
|
284 |
+
|
285 |
+
$sysinfo['soap_client'] = 'false';
|
286 |
+
if ( class_exists( 'SoapClient' ) ) {
|
287 |
+
$sysinfo['soap_client'] = 'true';
|
288 |
+
}
|
289 |
+
|
290 |
+
$sysinfo['dom_document'] = 'false';
|
291 |
+
if ( class_exists( 'DOMDocument' ) ) {
|
292 |
+
$sysinfo['dom_document'] = 'true';
|
293 |
+
}
|
294 |
+
|
295 |
+
$sysinfo['gzip'] = 'false';
|
296 |
+
if ( is_callable( 'gzopen' ) ) {
|
297 |
+
$sysinfo['gzip'] = 'true';
|
298 |
+
}
|
299 |
+
|
300 |
+
$sysinfo['mbstring'] = 'false';
|
301 |
+
|
302 |
+
if ( extension_loaded( 'mbstring' ) && function_exists( 'mb_eregi' ) && function_exists( 'mb_ereg_match' ) ) {
|
303 |
+
$sysinfo['mbstring'] = 'true';
|
304 |
+
}
|
305 |
+
|
306 |
+
$sysinfo['simplexml'] = 'false';
|
307 |
+
|
308 |
+
if ( class_exists( 'SimpleXMLElement' ) && function_exists( 'simplexml_load_string' ) ) {
|
309 |
+
$sysinfo['simplexml'] = 'true';
|
310 |
+
}
|
311 |
+
|
312 |
+
$sysinfo['phpxml'] = 'false';
|
313 |
+
|
314 |
+
if ( function_exists( 'xml_parse' ) ) {
|
315 |
+
$sysinfo['phpxml'] = 'true';
|
316 |
+
}
|
317 |
+
|
318 |
+
$active_plugins = (array) get_option( 'active_plugins', array() );
|
319 |
+
|
320 |
+
if ( is_multisite() ) {
|
321 |
+
$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
|
322 |
+
}
|
323 |
+
|
324 |
+
$sysinfo['plugins'] = array();
|
325 |
+
|
326 |
+
foreach ( $active_plugins as $plugin ) {
|
327 |
+
$plugin_data = @get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
328 |
+
$plugin_name = esc_html( $plugin_data['Name'] );
|
329 |
+
|
330 |
+
$sysinfo['plugins'][ $plugin_name ] = $plugin_data;
|
331 |
+
}
|
332 |
+
|
333 |
+
$active_theme = wp_get_theme();
|
334 |
+
|
335 |
+
$sysinfo['theme']['name'] = $active_theme->Name;
|
336 |
+
$sysinfo['theme']['version'] = $active_theme->Version;
|
337 |
+
$sysinfo['theme']['author_uri'] = $active_theme->{'Author URI'};
|
338 |
+
$sysinfo['theme']['is_child'] = JupiterX_Control_Panel_Helpers::make_bool_string( is_child_theme() );
|
339 |
+
|
340 |
+
if ( is_child_theme() ) {
|
341 |
+
$parent_theme = wp_get_theme( $active_theme->Template );
|
342 |
+
|
343 |
+
$sysinfo['theme']['parent_name'] = $parent_theme->Name;
|
344 |
+
$sysinfo['theme']['parent_version'] = $parent_theme->Version;
|
345 |
+
$sysinfo['theme']['parent_author_uri'] = $parent_theme->{'Author URI'};
|
346 |
+
}
|
347 |
+
|
348 |
+
return $sysinfo;
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Create an array of system status warnings.
|
353 |
+
*
|
354 |
+
* @since 1.9.0
|
355 |
+
*
|
356 |
+
* @return array
|
357 |
+
*/
|
358 |
+
public static function compile_system_status_warnings() {
|
359 |
+
$helper = JupiterX_Control_Panel_Helpers::class;
|
360 |
+
$sysinfo = self::compile_system_status();
|
361 |
+
$warnings = [];
|
362 |
+
$link = '<a href="https://themes.artbees.net/docs/jupiter-x-server-requirements/" target="_blank">' . __( 'Read More', 'jupiterx-core' ) . '</a>';
|
363 |
+
|
364 |
+
if ( $helper::bytes_to_mb( $sysinfo['wp_mem_limit']['raw'] ) < 256 ) {
|
365 |
+
$warnings['wp_mem_limit']['message'] = __( 'Insufficient memory. You need at least 256MB of memory.', 'jupiterx-core' );
|
366 |
+
$warnings['wp_mem_limit']['message'] .= $link;
|
367 |
+
}
|
368 |
+
|
369 |
+
if ( $helper::bytes_to_mb( $sysinfo['php_mem_limit']['raw'] ) < 256 ) {
|
370 |
+
$warnings['php_mem_limit']['message'] = __( 'Insufficient memory. You need at least 256MB of memory.', 'jupiterx-core' );
|
371 |
+
$warnings['php_mem_limit']['message'] .= $link;
|
372 |
+
}
|
373 |
+
|
374 |
+
return $warnings;
|
375 |
+
}
|
376 |
+
}
|
377 |
+
new JupiterX_Control_Panel_System_Status();
|
378 |
+
}
|
includes/control-panel/includes/class-validator.php
CHANGED
@@ -1,166 +1,166 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Validator' ) ) {
|
3 |
-
/**
|
4 |
-
* Control panel validator class.
|
5 |
-
*
|
6 |
-
* @since 1.9.0
|
7 |
-
*/
|
8 |
-
class JupiterX_Control_Panel_Validator {
|
9 |
-
|
10 |
-
private $value;
|
11 |
-
public function setValue( $value = '' ) {
|
12 |
-
$this->value = $value;
|
13 |
-
return $this;
|
14 |
-
}
|
15 |
-
public function getValue() {
|
16 |
-
return $this->value;
|
17 |
-
}
|
18 |
-
|
19 |
-
private $field_name;
|
20 |
-
public function setFieldName( $field_name = '' ) {
|
21 |
-
$this->field_name = $field_name;
|
22 |
-
return $this;
|
23 |
-
}
|
24 |
-
public function getFieldName() {
|
25 |
-
return $this->field_name;
|
26 |
-
}
|
27 |
-
|
28 |
-
private $message;
|
29 |
-
public function setMessage( $message, $append = true, $param = '' ) {
|
30 |
-
$message = str_replace( '{param}', $param, str_replace( '{field_name}', $this->getFieldName(), $message ) );
|
31 |
-
if ( $append == true ) {
|
32 |
-
$this->message .= $message;
|
33 |
-
} else {
|
34 |
-
$this->message = $message;
|
35 |
-
}
|
36 |
-
return $this;
|
37 |
-
}
|
38 |
-
public function getMessage() {
|
39 |
-
return $this->message;
|
40 |
-
}
|
41 |
-
public function clearMessage() {
|
42 |
-
$this->message = '';
|
43 |
-
return $this;
|
44 |
-
}
|
45 |
-
public function checkErrorExistence() {
|
46 |
-
if ( $this->message == '' ) {
|
47 |
-
return false;
|
48 |
-
} else {
|
49 |
-
return true;
|
50 |
-
}
|
51 |
-
}
|
52 |
-
public function run( $config ) {
|
53 |
-
$this->clearMessage();
|
54 |
-
|
55 |
-
$field_name = $this->getFieldName();
|
56 |
-
if ( empty( $field_name ) == true || $field_name == '' ) {
|
57 |
-
$this->setMessage( 'You must pass a field name for executing validation', false );
|
58 |
-
return false;
|
59 |
-
}
|
60 |
-
|
61 |
-
preg_match_all( '/(.*?):\s?(.*?)(,|$)/', $config, $validators );
|
62 |
-
$validators = array_combine( array_map( 'trim', $validators[1] ), $validators[2] );
|
63 |
-
|
64 |
-
if ( is_array( $validators ) === false || count( $validators ) == 0 ) {
|
65 |
-
$this->setMessage( 'You must pass an string of validations' );
|
66 |
-
return false;
|
67 |
-
}
|
68 |
-
|
69 |
-
if ( array_key_exists( 'required', $validators ) ) {
|
70 |
-
$this->requiredCheck();
|
71 |
-
}
|
72 |
-
|
73 |
-
if ( array_key_exists( 'string', $validators ) ) {
|
74 |
-
$this->stringCheck();
|
75 |
-
}
|
76 |
-
|
77 |
-
if ( array_key_exists( 'int', $validators ) ) {
|
78 |
-
$this->intCheck();
|
79 |
-
}
|
80 |
-
|
81 |
-
if ( array_key_exists( 'min_len', $validators ) ) {
|
82 |
-
$this->minLenCheck( $validators['min_len'] );
|
83 |
-
}
|
84 |
-
|
85 |
-
if ( array_key_exists( 'max_len', $validators ) ) {
|
86 |
-
$this->maxLenCheck( $validators['max_len'] );
|
87 |
-
}
|
88 |
-
|
89 |
-
if ( array_key_exists( 'exact_len', $validators ) ) {
|
90 |
-
$this->exactLenCheck( $validators['exact_len'] );
|
91 |
-
}
|
92 |
-
|
93 |
-
if ( array_key_exists( 'array', $validators ) ) {
|
94 |
-
$this->arrayCheck();
|
95 |
-
}
|
96 |
-
|
97 |
-
if ( $this->checkErrorExistence() ) {
|
98 |
-
return false;
|
99 |
-
} else {
|
100 |
-
return true;
|
101 |
-
}
|
102 |
-
}
|
103 |
-
|
104 |
-
private function requiredCheck() {
|
105 |
-
$value = $this->getValue();
|
106 |
-
if ( empty( $value ) == true || $value == '' ) {
|
107 |
-
$this->setMessage( 'The {field_name} field is required.' );
|
108 |
-
return false;
|
109 |
-
}
|
110 |
-
return true;
|
111 |
-
}
|
112 |
-
|
113 |
-
private function arrayCheck() {
|
114 |
-
$value = $this->getValue();
|
115 |
-
if ( is_array( $value ) === false || count( $value ) < 1 ) {
|
116 |
-
$this->setMessage( 'The {field_name} field must be an array with at least one element.' );
|
117 |
-
return false;
|
118 |
-
}
|
119 |
-
return true;
|
120 |
-
}
|
121 |
-
|
122 |
-
private function stringCheck() {
|
123 |
-
$value = $this->getValue();
|
124 |
-
if ( is_string( $value ) === false ) {
|
125 |
-
$this->setMessage( 'The {field_name} field must have an string value.' );
|
126 |
-
return false;
|
127 |
-
}
|
128 |
-
return true;
|
129 |
-
}
|
130 |
-
|
131 |
-
private function intCheck() {
|
132 |
-
$value = $this->getValue();
|
133 |
-
if ( is_int( $value ) == false ) {
|
134 |
-
$this->setMessage( 'The {field_name} field must contain an integer.' );
|
135 |
-
return false;
|
136 |
-
}
|
137 |
-
return true;
|
138 |
-
}
|
139 |
-
|
140 |
-
private function minLenCheck( $min_len ) {
|
141 |
-
$value = $this->getValue();
|
142 |
-
if ( strlen( $value ) < $min_len ) {
|
143 |
-
$this->setMessage( 'The {field_name} field must be at least {param} characters in length.', true, $min_len );
|
144 |
-
return false;
|
145 |
-
}
|
146 |
-
return true;
|
147 |
-
}
|
148 |
-
private function maxLenCheck( $max_len ) {
|
149 |
-
$value = $this->getValue();
|
150 |
-
if ( strlen( $value ) > $max_len ) {
|
151 |
-
$this->setMessage( 'The {field_name} field cannot exceed {param} characters in length.', true, $max_len );
|
152 |
-
return false;
|
153 |
-
}
|
154 |
-
return true;
|
155 |
-
}
|
156 |
-
|
157 |
-
private function exactLenCheck( $exact_len ) {
|
158 |
-
$value = $this->getValue();
|
159 |
-
if ( strlen( $value ) != $exact_len ) {
|
160 |
-
$this->setMessage( 'The {field_name} field must be exactly {param} characters in length.', true, $exact_len );
|
161 |
-
return false;
|
162 |
-
}
|
163 |
-
return true;
|
164 |
-
}
|
165 |
-
}
|
166 |
-
}
|
1 |
+
<?php
|
2 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Validator' ) ) {
|
3 |
+
/**
|
4 |
+
* Control panel validator class.
|
5 |
+
*
|
6 |
+
* @since 1.9.0
|
7 |
+
*/
|
8 |
+
class JupiterX_Control_Panel_Validator {
|
9 |
+
|
10 |
+
private $value;
|
11 |
+
public function setValue( $value = '' ) {
|
12 |
+
$this->value = $value;
|
13 |
+
return $this;
|
14 |
+
}
|
15 |
+
public function getValue() {
|
16 |
+
return $this->value;
|
17 |
+
}
|
18 |
+
|
19 |
+
private $field_name;
|
20 |
+
public function setFieldName( $field_name = '' ) {
|
21 |
+
$this->field_name = $field_name;
|
22 |
+
return $this;
|
23 |
+
}
|
24 |
+
public function getFieldName() {
|
25 |
+
return $this->field_name;
|
26 |
+
}
|
27 |
+
|
28 |
+
private $message;
|
29 |
+
public function setMessage( $message, $append = true, $param = '' ) {
|
30 |
+
$message = str_replace( '{param}', $param, str_replace( '{field_name}', $this->getFieldName(), $message ) );
|
31 |
+
if ( $append == true ) {
|
32 |
+
$this->message .= $message;
|
33 |
+
} else {
|
34 |
+
$this->message = $message;
|
35 |
+
}
|
36 |
+
return $this;
|
37 |
+
}
|
38 |
+
public function getMessage() {
|
39 |
+
return $this->message;
|
40 |
+
}
|
41 |
+
public function clearMessage() {
|
42 |
+
$this->message = '';
|
43 |
+
return $this;
|
44 |
+
}
|
45 |
+
public function checkErrorExistence() {
|
46 |
+
if ( $this->message == '' ) {
|
47 |
+
return false;
|
48 |
+
} else {
|
49 |
+
return true;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
public function run( $config ) {
|
53 |
+
$this->clearMessage();
|
54 |
+
|
55 |
+
$field_name = $this->getFieldName();
|
56 |
+
if ( empty( $field_name ) == true || $field_name == '' ) {
|
57 |
+
$this->setMessage( 'You must pass a field name for executing validation', false );
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
preg_match_all( '/(.*?):\s?(.*?)(,|$)/', $config, $validators );
|
62 |
+
$validators = array_combine( array_map( 'trim', $validators[1] ), $validators[2] );
|
63 |
+
|
64 |
+
if ( is_array( $validators ) === false || count( $validators ) == 0 ) {
|
65 |
+
$this->setMessage( 'You must pass an string of validations' );
|
66 |
+
return false;
|
67 |
+
}
|
68 |
+
|
69 |
+
if ( array_key_exists( 'required', $validators ) ) {
|
70 |
+
$this->requiredCheck();
|
71 |
+
}
|
72 |
+
|
73 |
+
if ( array_key_exists( 'string', $validators ) ) {
|
74 |
+
$this->stringCheck();
|
75 |
+
}
|
76 |
+
|
77 |
+
if ( array_key_exists( 'int', $validators ) ) {
|
78 |
+
$this->intCheck();
|
79 |
+
}
|
80 |
+
|
81 |
+
if ( array_key_exists( 'min_len', $validators ) ) {
|
82 |
+
$this->minLenCheck( $validators['min_len'] );
|
83 |
+
}
|
84 |
+
|
85 |
+
if ( array_key_exists( 'max_len', $validators ) ) {
|
86 |
+
$this->maxLenCheck( $validators['max_len'] );
|
87 |
+
}
|
88 |
+
|
89 |
+
if ( array_key_exists( 'exact_len', $validators ) ) {
|
90 |
+
$this->exactLenCheck( $validators['exact_len'] );
|
91 |
+
}
|
92 |
+
|
93 |
+
if ( array_key_exists( 'array', $validators ) ) {
|
94 |
+
$this->arrayCheck();
|
95 |
+
}
|
96 |
+
|
97 |
+
if ( $this->checkErrorExistence() ) {
|
98 |
+
return false;
|
99 |
+
} else {
|
100 |
+
return true;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
private function requiredCheck() {
|
105 |
+
$value = $this->getValue();
|
106 |
+
if ( empty( $value ) == true || $value == '' ) {
|
107 |
+
$this->setMessage( 'The {field_name} field is required.' );
|
108 |
+
return false;
|
109 |
+
}
|
110 |
+
return true;
|
111 |
+
}
|
112 |
+
|
113 |
+
private function arrayCheck() {
|
114 |
+
$value = $this->getValue();
|
115 |
+
if ( is_array( $value ) === false || count( $value ) < 1 ) {
|
116 |
+
$this->setMessage( 'The {field_name} field must be an array with at least one element.' );
|
117 |
+
return false;
|
118 |
+
}
|
119 |
+
return true;
|
120 |
+
}
|
121 |
+
|
122 |
+
private function stringCheck() {
|
123 |
+
$value = $this->getValue();
|
124 |
+
if ( is_string( $value ) === false ) {
|
125 |
+
$this->setMessage( 'The {field_name} field must have an string value.' );
|
126 |
+
return false;
|
127 |
+
}
|
128 |
+
return true;
|
129 |
+
}
|
130 |
+
|
131 |
+
private function intCheck() {
|
132 |
+
$value = $this->getValue();
|
133 |
+
if ( is_int( $value ) == false ) {
|
134 |
+
$this->setMessage( 'The {field_name} field must contain an integer.' );
|
135 |
+
return false;
|
136 |
+
}
|
137 |
+
return true;
|
138 |
+
}
|
139 |
+
|
140 |
+
private function minLenCheck( $min_len ) {
|
141 |
+
$value = $this->getValue();
|
142 |
+
if ( strlen( $value ) < $min_len ) {
|
143 |
+
$this->setMessage( 'The {field_name} field must be at least {param} characters in length.', true, $min_len );
|
144 |
+
return false;
|
145 |
+
}
|
146 |
+
return true;
|
147 |
+
}
|
148 |
+
private function maxLenCheck( $max_len ) {
|
149 |
+
$value = $this->getValue();
|
150 |
+
if ( strlen( $value ) > $max_len ) {
|
151 |
+
$this->setMessage( 'The {field_name} field cannot exceed {param} characters in length.', true, $max_len );
|
152 |
+
return false;
|
153 |
+
}
|
154 |
+
return true;
|
155 |
+
}
|
156 |
+
|
157 |
+
private function exactLenCheck( $exact_len ) {
|
158 |
+
$value = $this->getValue();
|
159 |
+
if ( strlen( $value ) != $exact_len ) {
|
160 |
+
$this->setMessage( 'The {field_name} field must be exactly {param} characters in length.', true, $exact_len );
|
161 |
+
return false;
|
162 |
+
}
|
163 |
+
return true;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
includes/control-panel/includes/importer/class-jupiterx-importer.php
CHANGED
@@ -1,155 +1,155 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class extends JupiterX_WXR_Importer.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\Control_Panel\Importer
|
6 |
-
*
|
7 |
-
* @since 1.1.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
/**
|
11 |
-
* JupiterX Importer.
|
12 |
-
*
|
13 |
-
* @since 1.1.0
|
14 |
-
* @package JupiterX\Framework\Control_Panel\Importer
|
15 |
-
*/
|
16 |
-
class JupiterX_Importer extends JupiterX_WXR_Importer {
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Term meta.
|
20 |
-
*
|
21 |
-
* @var array
|
22 |
-
*/
|
23 |
-
protected $jupiterx_meta = [];
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Import pages only.
|
27 |
-
*
|
28 |
-
* @var boolean
|
29 |
-
*/
|
30 |
-
protected $partial_import;
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Constructor.
|
34 |
-
*
|
35 |
-
* @param array $options The JupiterX_WXR_Importer options.
|
36 |
-
*/
|
37 |
-
public function __construct( $options = [], $partial_import = false ) {
|
38 |
-
parent::__construct( $options, $partial_import );
|
39 |
-
|
40 |
-
add_action( 'wp_import_insert_term', [ $this, 'jupiterx_process_term_meta' ] );
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Parse term node.
|
45 |
-
*
|
46 |
-
* It's a copy from the parent class. There's no way to access `$node` variable through
|
47 |
-
* actions so it's necessary to override it.
|
48 |
-
*
|
49 |
-
* The addition is `_jupiterx_parse_term_meta_node` method call.
|
50 |
-
*
|
51 |
-
* @since 1.1.0
|
52 |
-
*/
|
53 |
-
protected function parse_term_node( $node, $type = 'term' ) {
|
54 |
-
$data = array();
|
55 |
-
$meta = array();
|
56 |
-
|
57 |
-
$tag_name = array(
|
58 |
-
'id' => 'wp:term_id',
|
59 |
-
'taxonomy' => 'wp:term_taxonomy',
|
60 |
-
'slug' => 'wp:term_slug',
|
61 |
-
'parent' => 'wp:term_parent',
|
62 |
-
'name' => 'wp:term_name',
|
63 |
-
'description' => 'wp:term_description',
|
64 |
-
);
|
65 |
-
$taxonomy = null;
|
66 |
-
|
67 |
-
// Special casing!
|
68 |
-
switch ( $type ) {
|
69 |
-
case 'category':
|
70 |
-
$tag_name['slug'] = 'wp:category_nicename';
|
71 |
-
$tag_name['parent'] = 'wp:category_parent';
|
72 |
-
$tag_name['name'] = 'wp:cat_name';
|
73 |
-
$tag_name['description'] = 'wp:category_description';
|
74 |
-
$tag_name['taxonomy'] = null;
|
75 |
-
|
76 |
-
$data['taxonomy'] = 'category';
|
77 |
-
break;
|
78 |
-
|
79 |
-
case 'tag':
|
80 |
-
$tag_name['slug'] = 'wp:tag_slug';
|
81 |
-
$tag_name['parent'] = null;
|
82 |
-
$tag_name['name'] = 'wp:tag_name';
|
83 |
-
$tag_name['description'] = 'wp:tag_description';
|
84 |
-
$tag_name['taxonomy'] = null;
|
85 |
-
|
86 |
-
$data['taxonomy'] = 'post_tag';
|
87 |
-
break;
|
88 |
-
}
|
89 |
-
|
90 |
-
foreach ( $node->childNodes as $child ) {
|
91 |
-
// We only care about child elements
|
92 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
93 |
-
continue;
|
94 |
-
}
|
95 |
-
|
96 |
-
$key = array_search( $child->tagName, $tag_name );
|
97 |
-
if ( $key ) {
|
98 |
-
$data[ $key ] = $child->textContent;
|
99 |
-
}
|
100 |
-
}
|
101 |
-
|
102 |
-
$this->_jupiterx_parse_term_meta_node( $node->childNodes );
|
103 |
-
|
104 |
-
if ( empty( $data['taxonomy'] ) ) {
|
105 |
-
return null;
|
106 |
-
}
|
107 |
-
|
108 |
-
// Compatibility with WXR 1.0
|
109 |
-
if ( $data['taxonomy'] === 'tag' ) {
|
110 |
-
$data['taxonomy'] = 'post_tag';
|
111 |
-
}
|
112 |
-
|
113 |
-
return compact( 'data', 'meta' );
|
114 |
-
}
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Parse term meta node.
|
118 |
-
*
|
119 |
-
* @since 1.1.0
|
120 |
-
*/
|
121 |
-
private function _jupiterx_parse_term_meta_node( $childNodes ) {
|
122 |
-
$this->jupiterx_meta = [];
|
123 |
-
|
124 |
-
foreach ( $childNodes as $child ) {
|
125 |
-
|
126 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
127 |
-
continue;
|
128 |
-
}
|
129 |
-
|
130 |
-
if ( 'wp:termmeta' !== $child->tagName ) {
|
131 |
-
continue;
|
132 |
-
}
|
133 |
-
|
134 |
-
$meta_node = $this->parse_meta_node( $child );
|
135 |
-
|
136 |
-
$this->jupiterx_meta[ $meta_node['key'] ] = $meta_node['value'];
|
137 |
-
}
|
138 |
-
}
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Process term meta.
|
142 |
-
*
|
143 |
-
* @since 1.1.0
|
144 |
-
*/
|
145 |
-
public function jupiterx_process_term_meta( $term_id ) {
|
146 |
-
|
147 |
-
if ( empty( $this->jupiterx_meta ) ) {
|
148 |
-
return;
|
149 |
-
}
|
150 |
-
|
151 |
-
foreach( $this->jupiterx_meta as $term_key => $term_val ) {
|
152 |
-
update_term_meta( $term_id, $term_key, $term_val );
|
153 |
-
}
|
154 |
-
}
|
155 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class extends JupiterX_WXR_Importer.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\Control_Panel\Importer
|
6 |
+
*
|
7 |
+
* @since 1.1.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* JupiterX Importer.
|
12 |
+
*
|
13 |
+
* @since 1.1.0
|
14 |
+
* @package JupiterX\Framework\Control_Panel\Importer
|
15 |
+
*/
|
16 |
+
class JupiterX_Importer extends JupiterX_WXR_Importer {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Term meta.
|
20 |
+
*
|
21 |
+
* @var array
|
22 |
+
*/
|
23 |
+
protected $jupiterx_meta = [];
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Import pages only.
|
27 |
+
*
|
28 |
+
* @var boolean
|
29 |
+
*/
|
30 |
+
protected $partial_import;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Constructor.
|
34 |
+
*
|
35 |
+
* @param array $options The JupiterX_WXR_Importer options.
|
36 |
+
*/
|
37 |
+
public function __construct( $options = [], $partial_import = false ) {
|
38 |
+
parent::__construct( $options, $partial_import );
|
39 |
+
|
40 |
+
add_action( 'wp_import_insert_term', [ $this, 'jupiterx_process_term_meta' ] );
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Parse term node.
|
45 |
+
*
|
46 |
+
* It's a copy from the parent class. There's no way to access `$node` variable through
|
47 |
+
* actions so it's necessary to override it.
|
48 |
+
*
|
49 |
+
* The addition is `_jupiterx_parse_term_meta_node` method call.
|
50 |
+
*
|
51 |
+
* @since 1.1.0
|
52 |
+
*/
|
53 |
+
protected function parse_term_node( $node, $type = 'term' ) {
|
54 |
+
$data = array();
|
55 |
+
$meta = array();
|
56 |
+
|
57 |
+
$tag_name = array(
|
58 |
+
'id' => 'wp:term_id',
|
59 |
+
'taxonomy' => 'wp:term_taxonomy',
|
60 |
+
'slug' => 'wp:term_slug',
|
61 |
+
'parent' => 'wp:term_parent',
|
62 |
+
'name' => 'wp:term_name',
|
63 |
+
'description' => 'wp:term_description',
|
64 |
+
);
|
65 |
+
$taxonomy = null;
|
66 |
+
|
67 |
+
// Special casing!
|
68 |
+
switch ( $type ) {
|
69 |
+
case 'category':
|
70 |
+
$tag_name['slug'] = 'wp:category_nicename';
|
71 |
+
$tag_name['parent'] = 'wp:category_parent';
|
72 |
+
$tag_name['name'] = 'wp:cat_name';
|
73 |
+
$tag_name['description'] = 'wp:category_description';
|
74 |
+
$tag_name['taxonomy'] = null;
|
75 |
+
|
76 |
+
$data['taxonomy'] = 'category';
|
77 |
+
break;
|
78 |
+
|
79 |
+
case 'tag':
|
80 |
+
$tag_name['slug'] = 'wp:tag_slug';
|
81 |
+
$tag_name['parent'] = null;
|
82 |
+
$tag_name['name'] = 'wp:tag_name';
|
83 |
+
$tag_name['description'] = 'wp:tag_description';
|
84 |
+
$tag_name['taxonomy'] = null;
|
85 |
+
|
86 |
+
$data['taxonomy'] = 'post_tag';
|
87 |
+
break;
|
88 |
+
}
|
89 |
+
|
90 |
+
foreach ( $node->childNodes as $child ) {
|
91 |
+
// We only care about child elements
|
92 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
93 |
+
continue;
|
94 |
+
}
|
95 |
+
|
96 |
+
$key = array_search( $child->tagName, $tag_name );
|
97 |
+
if ( $key ) {
|
98 |
+
$data[ $key ] = $child->textContent;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
|
102 |
+
$this->_jupiterx_parse_term_meta_node( $node->childNodes );
|
103 |
+
|
104 |
+
if ( empty( $data['taxonomy'] ) ) {
|
105 |
+
return null;
|
106 |
+
}
|
107 |
+
|
108 |
+
// Compatibility with WXR 1.0
|
109 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
110 |
+
$data['taxonomy'] = 'post_tag';
|
111 |
+
}
|
112 |
+
|
113 |
+
return compact( 'data', 'meta' );
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Parse term meta node.
|
118 |
+
*
|
119 |
+
* @since 1.1.0
|
120 |
+
*/
|
121 |
+
private function _jupiterx_parse_term_meta_node( $childNodes ) {
|
122 |
+
$this->jupiterx_meta = [];
|
123 |
+
|
124 |
+
foreach ( $childNodes as $child ) {
|
125 |
+
|
126 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
127 |
+
continue;
|
128 |
+
}
|
129 |
+
|
130 |
+
if ( 'wp:termmeta' !== $child->tagName ) {
|
131 |
+
continue;
|
132 |
+
}
|
133 |
+
|
134 |
+
$meta_node = $this->parse_meta_node( $child );
|
135 |
+
|
136 |
+
$this->jupiterx_meta[ $meta_node['key'] ] = $meta_node['value'];
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Process term meta.
|
142 |
+
*
|
143 |
+
* @since 1.1.0
|
144 |
+
*/
|
145 |
+
public function jupiterx_process_term_meta( $term_id ) {
|
146 |
+
|
147 |
+
if ( empty( $this->jupiterx_meta ) ) {
|
148 |
+
return;
|
149 |
+
}
|
150 |
+
|
151 |
+
foreach( $this->jupiterx_meta as $term_key => $term_val ) {
|
152 |
+
update_term_meta( $term_id, $term_key, $term_val );
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
includes/control-panel/includes/importer/class-logger-serversentevents.php
CHANGED
@@ -1,57 +1,57 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* WP Importer Logger Server Sent Event class.
|
4 |
-
*
|
5 |
-
* For use to save the server log of importing process in Jupiter.
|
6 |
-
*
|
7 |
-
* @package Jupiter
|
8 |
-
* @subpackage Template Import
|
9 |
-
* @since 6.0.3
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Store server log while importing process.
|
14 |
-
*
|
15 |
-
* @since 6.0.3
|
16 |
-
*
|
17 |
-
* @see https://github.com/humanmade/WordPress-Importer/blob/master/class-logger-serversentevents.php
|
18 |
-
*
|
19 |
-
* @codingStandardsIgnoreFile
|
20 |
-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
21 |
-
*/
|
22 |
-
class JupiterX_Importer_Logger_ServerSentEvents extends JupiterX_Importer_Logger {
|
23 |
-
/**
|
24 |
-
* Logs with an arbitrary level.
|
25 |
-
*
|
26 |
-
* @param mixed $level
|
27 |
-
* @param string $message
|
28 |
-
* @param array $context
|
29 |
-
* @return null
|
30 |
-
*/
|
31 |
-
public function log( $level, $message, array $context = array() ) {
|
32 |
-
$data = compact( 'level', 'message' );
|
33 |
-
|
34 |
-
switch ( $level ) {
|
35 |
-
case 'emergency':
|
36 |
-
case 'alert':
|
37 |
-
case 'critical':
|
38 |
-
case 'error':
|
39 |
-
case 'warning':
|
40 |
-
case 'notice':
|
41 |
-
case 'info':
|
42 |
-
echo "event: log\n";
|
43 |
-
echo 'data: ' . wp_json_encode( $data ) . "\n\n";
|
44 |
-
flush();
|
45 |
-
break;
|
46 |
-
|
47 |
-
case 'debug':
|
48 |
-
if ( defined( 'IMPORT_DEBUG' ) && IMPORT_DEBUG ) {
|
49 |
-
echo "event: log\n";
|
50 |
-
echo 'data: ' . wp_json_encode( $data ) . "\n\n";
|
51 |
-
flush();
|
52 |
-
break;
|
53 |
-
}
|
54 |
-
break;
|
55 |
-
}
|
56 |
-
}
|
57 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WP Importer Logger Server Sent Event class.
|
4 |
+
*
|
5 |
+
* For use to save the server log of importing process in Jupiter.
|
6 |
+
*
|
7 |
+
* @package Jupiter
|
8 |
+
* @subpackage Template Import
|
9 |
+
* @since 6.0.3
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Store server log while importing process.
|
14 |
+
*
|
15 |
+
* @since 6.0.3
|
16 |
+
*
|
17 |
+
* @see https://github.com/humanmade/WordPress-Importer/blob/master/class-logger-serversentevents.php
|
18 |
+
*
|
19 |
+
* @codingStandardsIgnoreFile
|
20 |
+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
21 |
+
*/
|
22 |
+
class JupiterX_Importer_Logger_ServerSentEvents extends JupiterX_Importer_Logger {
|
23 |
+
/**
|
24 |
+
* Logs with an arbitrary level.
|
25 |
+
*
|
26 |
+
* @param mixed $level
|
27 |
+
* @param string $message
|
28 |
+
* @param array $context
|
29 |
+
* @return null
|
30 |
+
*/
|
31 |
+
public function log( $level, $message, array $context = array() ) {
|
32 |
+
$data = compact( 'level', 'message' );
|
33 |
+
|
34 |
+
switch ( $level ) {
|
35 |
+
case 'emergency':
|
36 |
+
case 'alert':
|
37 |
+
case 'critical':
|
38 |
+
case 'error':
|
39 |
+
case 'warning':
|
40 |
+
case 'notice':
|
41 |
+
case 'info':
|
42 |
+
echo "event: log\n";
|
43 |
+
echo 'data: ' . wp_json_encode( $data ) . "\n\n";
|
44 |
+
flush();
|
45 |
+
break;
|
46 |
+
|
47 |
+
case 'debug':
|
48 |
+
if ( defined( 'IMPORT_DEBUG' ) && IMPORT_DEBUG ) {
|
49 |
+
echo "event: log\n";
|
50 |
+
echo 'data: ' . wp_json_encode( $data ) . "\n\n";
|
51 |
+
flush();
|
52 |
+
break;
|
53 |
+
}
|
54 |
+
break;
|
55 |
+
}
|
56 |
+
}
|
57 |
+
}
|
includes/control-panel/includes/importer/class-logger.php
CHANGED
@@ -1,138 +1,138 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Describes a logger instance
|
5 |
-
*
|
6 |
-
* Based on PSR-3: http://www.php-fig.org/psr/psr-3/
|
7 |
-
*
|
8 |
-
* The message MUST be a string or object implementing __toString().
|
9 |
-
*
|
10 |
-
* The message MAY contain placeholders in the form: {foo} where foo
|
11 |
-
* will be replaced by the context data in key "foo".
|
12 |
-
*
|
13 |
-
* The context array can contain arbitrary data, the only assumption that
|
14 |
-
* can be made by implementors is that if an Exception instance is given
|
15 |
-
* to produce a stack trace, it MUST be in a key named "exception".
|
16 |
-
*
|
17 |
-
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
|
18 |
-
* for the full interface specification.
|
19 |
-
*
|
20 |
-
* @codingStandardsIgnoreFile
|
21 |
-
*/
|
22 |
-
class JupiterX_Importer_Logger {
|
23 |
-
/**
|
24 |
-
* System is unusable.
|
25 |
-
*
|
26 |
-
* @param string $message
|
27 |
-
* @param array $context
|
28 |
-
* @return null
|
29 |
-
*/
|
30 |
-
public function emergency( $message, array $context = array() ) {
|
31 |
-
return $this->log( 'emergency', $message, $context );
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Action must be taken immediately.
|
36 |
-
*
|
37 |
-
* Example: Entire website down, database unavailable, etc. This should
|
38 |
-
* trigger the SMS alerts and wake you up.
|
39 |
-
*
|
40 |
-
* @param string $message
|
41 |
-
* @param array $context
|
42 |
-
* @return null
|
43 |
-
*/
|
44 |
-
public function alert( $message, array $context = array() ) {
|
45 |
-
return $this->log( 'alert', $message, $context );
|
46 |
-
}
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Critical conditions.
|
50 |
-
*
|
51 |
-
* Example: Application component unavailable, unexpected exception.
|
52 |
-
*
|
53 |
-
* @param string $message
|
54 |
-
* @param array $context
|
55 |
-
* @return null
|
56 |
-
*/
|
57 |
-
public function critical( $message, array $context = array() ) {
|
58 |
-
return $this->log( 'critical', $message, $context );
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Runtime errors that do not require immediate action but should typically
|
63 |
-
* be logged and monitored.
|
64 |
-
*
|
65 |
-
* @param string $message
|
66 |
-
* @param array $context
|
67 |
-
* @return null
|
68 |
-
*/
|
69 |
-
public function error( $message, array $context = array()) {
|
70 |
-
return $this->log( 'error', $message, $context );
|
71 |
-
}
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Exceptional occurrences that are not errors.
|
75 |
-
*
|
76 |
-
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
77 |
-
* that are not necessarily wrong.
|
78 |
-
*
|
79 |
-
* @param string $message
|
80 |
-
* @param array $context
|
81 |
-
* @return null
|
82 |
-
*/
|
83 |
-
public function warning( $message, array $context = array() ) {
|
84 |
-
return $this->log( 'warning', $message, $context );
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Normal but significant events.
|
89 |
-
*
|
90 |
-
* @param string $message
|
91 |
-
* @param array $context
|
92 |
-
* @return null
|
93 |
-
*/
|
94 |
-
public function notice( $message, array $context = array() ) {
|
95 |
-
return $this->log( 'notice', $message, $context );
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* Interesting events.
|
100 |
-
*
|
101 |
-
* Example: User logs in, SQL logs.
|
102 |
-
*
|
103 |
-
* @param string $message
|
104 |
-
* @param array $context
|
105 |
-
* @return null
|
106 |
-
*/
|
107 |
-
public function info( $message, array $context = array() ) {
|
108 |
-
return $this->log( 'info', $message, $context );
|
109 |
-
}
|
110 |
-
|
111 |
-
/**
|
112 |
-
* Detailed debug information.
|
113 |
-
*
|
114 |
-
* @param string $message
|
115 |
-
* @param array $context
|
116 |
-
* @return null
|
117 |
-
*/
|
118 |
-
public function debug( $message, array $context = array() ) {
|
119 |
-
return $this->log( 'debug', $message, $context );
|
120 |
-
}
|
121 |
-
|
122 |
-
/**
|
123 |
-
* Logs with an arbitrary level.
|
124 |
-
*
|
125 |
-
* @param mixed $level
|
126 |
-
* @param string $message
|
127 |
-
* @param array $context
|
128 |
-
* @return null
|
129 |
-
*/
|
130 |
-
public function log( $level, $message, array $context = array() ) {
|
131 |
-
$this->messages[] = array(
|
132 |
-
'timestamp' => time(),
|
133 |
-
'level' => $level,
|
134 |
-
'message' => $message,
|
135 |
-
'context' => $context,
|
136 |
-
);
|
137 |
-
}
|
138 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Describes a logger instance
|
5 |
+
*
|
6 |
+
* Based on PSR-3: http://www.php-fig.org/psr/psr-3/
|
7 |
+
*
|
8 |
+
* The message MUST be a string or object implementing __toString().
|
9 |
+
*
|
10 |
+
* The message MAY contain placeholders in the form: {foo} where foo
|
11 |
+
* will be replaced by the context data in key "foo".
|
12 |
+
*
|
13 |
+
* The context array can contain arbitrary data, the only assumption that
|
14 |
+
* can be made by implementors is that if an Exception instance is given
|
15 |
+
* to produce a stack trace, it MUST be in a key named "exception".
|
16 |
+
*
|
17 |
+
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
|
18 |
+
* for the full interface specification.
|
19 |
+
*
|
20 |
+
* @codingStandardsIgnoreFile
|
21 |
+
*/
|
22 |
+
class JupiterX_Importer_Logger {
|
23 |
+
/**
|
24 |
+
* System is unusable.
|
25 |
+
*
|
26 |
+
* @param string $message
|
27 |
+
* @param array $context
|
28 |
+
* @return null
|
29 |
+
*/
|
30 |
+
public function emergency( $message, array $context = array() ) {
|
31 |
+
return $this->log( 'emergency', $message, $context );
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Action must be taken immediately.
|
36 |
+
*
|
37 |
+
* Example: Entire website down, database unavailable, etc. This should
|
38 |
+
* trigger the SMS alerts and wake you up.
|
39 |
+
*
|
40 |
+
* @param string $message
|
41 |
+
* @param array $context
|
42 |
+
* @return null
|
43 |
+
*/
|
44 |
+
public function alert( $message, array $context = array() ) {
|
45 |
+
return $this->log( 'alert', $message, $context );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Critical conditions.
|
50 |
+
*
|
51 |
+
* Example: Application component unavailable, unexpected exception.
|
52 |
+
*
|
53 |
+
* @param string $message
|
54 |
+
* @param array $context
|
55 |
+
* @return null
|
56 |
+
*/
|
57 |
+
public function critical( $message, array $context = array() ) {
|
58 |
+
return $this->log( 'critical', $message, $context );
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Runtime errors that do not require immediate action but should typically
|
63 |
+
* be logged and monitored.
|
64 |
+
*
|
65 |
+
* @param string $message
|
66 |
+
* @param array $context
|
67 |
+
* @return null
|
68 |
+
*/
|
69 |
+
public function error( $message, array $context = array()) {
|
70 |
+
return $this->log( 'error', $message, $context );
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Exceptional occurrences that are not errors.
|
75 |
+
*
|
76 |
+
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
77 |
+
* that are not necessarily wrong.
|
78 |
+
*
|
79 |
+
* @param string $message
|
80 |
+
* @param array $context
|
81 |
+
* @return null
|
82 |
+
*/
|
83 |
+
public function warning( $message, array $context = array() ) {
|
84 |
+
return $this->log( 'warning', $message, $context );
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Normal but significant events.
|
89 |
+
*
|
90 |
+
* @param string $message
|
91 |
+
* @param array $context
|
92 |
+
* @return null
|
93 |
+
*/
|
94 |
+
public function notice( $message, array $context = array() ) {
|
95 |
+
return $this->log( 'notice', $message, $context );
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Interesting events.
|
100 |
+
*
|
101 |
+
* Example: User logs in, SQL logs.
|
102 |
+
*
|
103 |
+
* @param string $message
|
104 |
+
* @param array $context
|
105 |
+
* @return null
|
106 |
+
*/
|
107 |
+
public function info( $message, array $context = array() ) {
|
108 |
+
return $this->log( 'info', $message, $context );
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Detailed debug information.
|
113 |
+
*
|
114 |
+
* @param string $message
|
115 |
+
* @param array $context
|
116 |
+
* @return null
|
117 |
+
*/
|
118 |
+
public function debug( $message, array $context = array() ) {
|
119 |
+
return $this->log( 'debug', $message, $context );
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Logs with an arbitrary level.
|
124 |
+
*
|
125 |
+
* @param mixed $level
|
126 |
+
* @param string $message
|
127 |
+
* @param array $context
|
128 |
+
* @return null
|
129 |
+
*/
|
130 |
+
public function log( $level, $message, array $context = array() ) {
|
131 |
+
$this->messages[] = array(
|
132 |
+
'timestamp' => time(),
|
133 |
+
'level' => $level,
|
134 |
+
'message' => $message,
|
135 |
+
'context' => $context,
|
136 |
+
);
|
137 |
+
}
|
138 |
+
}
|
includes/control-panel/includes/importer/class-wxr-import-info.php
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* WXR Import Info class.
|
4 |
-
*
|
5 |
-
* As an abstraction of importing site info.
|
6 |
-
*
|
7 |
-
* @package Jupiter
|
8 |
-
* @subpackage Template Import
|
9 |
-
* @since 6.0.3
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Initialize base variable of importing info.
|
14 |
-
*
|
15 |
-
* @since 6.0.3
|
16 |
-
*
|
17 |
-
* @see https://github.com/humanmade/WordPress-Importer/blob/master/class-wxr-import-info.php
|
18 |
-
*
|
19 |
-
* @codingStandardsIgnoreFile
|
20 |
-
*/
|
21 |
-
class JupiterX_WXR_Import_Info {
|
22 |
-
public $home;
|
23 |
-
public $siteurl;
|
24 |
-
|
25 |
-
public $title;
|
26 |
-
|
27 |
-
public $users = array();
|
28 |
-
public $post_count = 0;
|
29 |
-
public $media_count = 0;
|
30 |
-
public $comment_count = 0;
|
31 |
-
public $term_count = 0;
|
32 |
-
|
33 |
-
public $generator = '';
|
34 |
-
public $version;
|
35 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WXR Import Info class.
|
4 |
+
*
|
5 |
+
* As an abstraction of importing site info.
|
6 |
+
*
|
7 |
+
* @package Jupiter
|
8 |
+
* @subpackage Template Import
|
9 |
+
* @since 6.0.3
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Initialize base variable of importing info.
|
14 |
+
*
|
15 |
+
* @since 6.0.3
|
16 |
+
*
|
17 |
+
* @see https://github.com/humanmade/WordPress-Importer/blob/master/class-wxr-import-info.php
|
18 |
+
*
|
19 |
+
* @codingStandardsIgnoreFile
|
20 |
+
*/
|
21 |
+
class JupiterX_WXR_Import_Info {
|
22 |
+
public $home;
|
23 |
+
public $siteurl;
|
24 |
+
|
25 |
+
public $title;
|
26 |
+
|
27 |
+
public $users = array();
|
28 |
+
public $post_count = 0;
|
29 |
+
public $media_count = 0;
|
30 |
+
public $comment_count = 0;
|
31 |
+
public $term_count = 0;
|
32 |
+
|
33 |
+
public $generator = '';
|
34 |
+
public $version;
|
35 |
+
}
|
includes/control-panel/includes/importer/class-wxr-importer.php
CHANGED
@@ -1,2076 +1,2076 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* WXR Importer class.
|
4 |
-
*
|
5 |
-
* Main class of WordPress Importer v2 to handle import process.
|
6 |
-
*
|
7 |
-
* @package Jupiter
|
8 |
-
* @subpackage Template Import
|
9 |
-
* @since 6.0.3
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* The main class of WordPress Importer v2.
|
14 |
-
*
|
15 |
-
* @since 6.0.3
|
16 |
-
*
|
17 |
-
* @see https://github.com/humanmade/WordPress-Importer/blob/master/class-wxr-importer.php
|
18 |
-
*
|
19 |
-
* @codingStandardsIgnoreFile
|
20 |
-
* @SuppressWarnings(PHPMD)
|
21 |
-
* - Temporary suppress warning. Worry if we change the content of the class or change how
|
22 |
-
* the logical conditions work, it will cause some issues.
|
23 |
-
*/
|
24 |
-
class JupiterX_WXR_Importer extends WP_Importer {
|
25 |
-
/**
|
26 |
-
* Maximum supported WXR version
|
27 |
-
*/
|
28 |
-
const MAX_WXR_VERSION = 1.2;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Regular expression for checking if a post references an attachment
|
32 |
-
*
|
33 |
-
* Note: This is a quick, weak check just to exclude text-only posts. More
|
34 |
-
* vigorous checking is done later to verify.
|
35 |
-
*/
|
36 |
-
const REGEX_HAS_ATTACHMENT_REFS = '!
|
37 |
-
(
|
38 |
-
# Match anything with an image or attachment class
|
39 |
-
class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
|
40 |
-
|
|
41 |
-
# Match anything that looks like an upload URL
|
42 |
-
src=[\'"][^\'"]*(
|
43 |
-
[0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
|
44 |
-
|
|
45 |
-
content/uploads[^\'"]+
|
46 |
-
)[\'"]
|
47 |
-
)!ix';
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Version of WXR we're importing.
|
51 |
-
*
|
52 |
-
* Defaults to 1.0 for compatibility. Typically overridden by a
|
53 |
-
* `<wp:wxr_version>` tag at the start of the file.
|
54 |
-
*
|
55 |
-
* @var string
|
56 |
-
*/
|
57 |
-
protected $version = '1.0';
|
58 |
-
|
59 |
-
// information to import from WXR file
|
60 |
-
protected $categories = array();
|
61 |
-
protected $tags = array();
|
62 |
-
protected $base_url = '';
|
63 |
-
|
64 |
-
// TODO: REMOVE THESE
|
65 |
-
protected $processed_terms = array();
|
66 |
-
protected $processed_posts = array();
|
67 |
-
protected $processed_menu_items = array();
|
68 |
-
protected $menu_item_orphans = array();
|
69 |
-
protected $missing_menu_items = array();
|
70 |
-
|
71 |
-
// NEW STYLE
|
72 |
-
protected $mapping = array();
|
73 |
-
protected $requires_remapping = array();
|
74 |
-
protected $exists = array();
|
75 |
-
protected $user_slug_override = array();
|
76 |
-
|
77 |
-
protected $url_remap = array();
|
78 |
-
protected $featured_images = array();
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Logger instance.
|
82 |
-
*
|
83 |
-
* @var JupiterX_Importer_Logger
|
84 |
-
*/
|
85 |
-
protected $logger;
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Import pages only.
|
89 |
-
*
|
90 |
-
* @var boolean
|
91 |
-
*/
|
92 |
-
protected $partial_import;
|
93 |
-
|
94 |
-
/**
|
95 |
-
* Constructor
|
96 |
-
*
|
97 |
-
* @param array $options {
|
98 |
-
* @var bool $prefill_existing_posts Should we prefill `post_exists` calls? (True prefills and uses more memory, false checks once per imported post and takes longer. Default is true.)
|
99 |
-
* @var bool $prefill_existing_comments Should we prefill `comment_exists` calls? (True prefills and uses more memory, false checks once per imported comment and takes longer. Default is true.)
|
100 |
-
* @var bool $prefill_existing_terms Should we prefill `term_exists` calls? (True prefills and uses more memory, false checks once per imported term and takes longer. Default is true.)
|
101 |
-
* @var bool $update_attachment_guids Should attachment GUIDs be updated to the new URL? (True updates the GUID, which keeps compatibility with v1, false doesn't update, and allows deduplication and reimporting. Default is false.)
|
102 |
-
* @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
|
103 |
-
* @var bool $aggressive_url_search Should we search/replace for URLs aggressively? (True searches all posts' content for old URLs and replaces, false checks for `<img class="wp-image-*">` only. Default is false.)
|
104 |
-
* @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
|
105 |
-
* }
|
106 |
-
*/
|
107 |
-
public function __construct( $options = array(), $partial_import = false ) {
|
108 |
-
$this->partial_import = $partial_import;
|
109 |
-
|
110 |
-
// Initialize some important variables
|
111 |
-
$empty_types = array(
|
112 |
-
'post' => array(),
|
113 |
-
'comment' => array(),
|
114 |
-
'term' => array(),
|
115 |
-
'user' => array(),
|
116 |
-
);
|
117 |
-
|
118 |
-
$this->mapping = $empty_types;
|
119 |
-
$this->mapping['user_slug'] = array();
|
120 |
-
$this->mapping['term_id'] = array();
|
121 |
-
$this->requires_remapping = $empty_types;
|
122 |
-
$this->exists = $empty_types;
|
123 |
-
|
124 |
-
$this->options = wp_parse_args( $options, array(
|
125 |
-
'prefill_existing_posts' => true,
|
126 |
-
'prefill_existing_comments' => true,
|
127 |
-
'prefill_existing_terms' => true,
|
128 |
-
'update_attachment_guids' => false,
|
129 |
-
'fetch_attachments' => false,
|
130 |
-
'aggressive_url_search' => false,
|
131 |
-
'default_author' => null,
|
132 |
-
) );
|
133 |
-
}
|
134 |
-
|
135 |
-
public function set_logger( $logger ) {
|
136 |
-
$this->logger = $logger;
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Get a stream reader for the file.
|
141 |
-
*
|
142 |
-
* @param string $file Path to the XML file.
|
143 |
-
* @return XMLReader|WP_Error Reader instance on success, error otherwise.
|
144 |
-
*/
|
145 |
-
protected function get_reader( $file ) {
|
146 |
-
// Avoid loading external entities for security
|
147 |
-
$old_value = null;
|
148 |
-
if ( function_exists( 'libxml_disable_entity_loader' ) ) {
|
149 |
-
// $old_value = libxml_disable_entity_loader( true );
|
150 |
-
}
|
151 |
-
|
152 |
-
$reader = new XMLReader();
|
153 |
-
$status = $reader->open( $file );
|
154 |
-
|
155 |
-
if ( ! is_null( $old_value ) ) {
|
156 |
-
// libxml_disable_entity_loader( $old_value );
|
157 |
-
}
|
158 |
-
|
159 |
-
if ( ! $status ) {
|
160 |
-
return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'jupiterx-core' ) );
|
161 |
-
}
|
162 |
-
|
163 |
-
return $reader;
|
164 |
-
}
|
165 |
-
|
166 |
-
/**
|
167 |
-
* The main controller for the actual import stage.
|
168 |
-
*
|
169 |
-
* @param string $file Path to the WXR file for importing
|
170 |
-
*/
|
171 |
-
public function get_preliminary_information( $file ) {
|
172 |
-
// Let's run the actual importer now, woot
|
173 |
-
$reader = $this->get_reader( $file );
|
174 |
-
if ( is_wp_error( $reader ) ) {
|
175 |
-
return $reader;
|
176 |
-
}
|
177 |
-
|
178 |
-
// Set the version to compatibility mode first
|
179 |
-
$this->version = '1.0';
|
180 |
-
|
181 |
-
// Start parsing!
|
182 |
-
$data = new JupiterX_WXR_Import_Info();
|
183 |
-
while ( $reader->read() ) {
|
184 |
-
// Only deal with element opens
|
185 |
-
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
186 |
-
continue;
|
187 |
-
}
|
188 |
-
|
189 |
-
switch ( $reader->name ) {
|
190 |
-
case 'wp:wxr_version':
|
191 |
-
// Upgrade to the correct version
|
192 |
-
$this->version = $reader->readString();
|
193 |
-
|
194 |
-
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
195 |
-
$this->logger->warning( sprintf(
|
196 |
-
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'jupiterx-core' ),
|
197 |
-
$this->version,
|
198 |
-
self::MAX_WXR_VERSION
|
199 |
-
) );
|
200 |
-
}
|
201 |
-
|
202 |
-
// Handled everything in this node, move on to the next
|
203 |
-
$reader->next();
|
204 |
-
break;
|
205 |
-
|
206 |
-
case 'generator':
|
207 |
-
$data->generator = $reader->readString();
|
208 |
-
$reader->next();
|
209 |
-
break;
|
210 |
-
|
211 |
-
case 'title':
|
212 |
-
$data->title = $reader->readString();
|
213 |
-
$reader->next();
|
214 |
-
break;
|
215 |
-
|
216 |
-
case 'wp:base_site_url':
|
217 |
-
$data->siteurl = $reader->readString();
|
218 |
-
$reader->next();
|
219 |
-
break;
|
220 |
-
|
221 |
-
case 'wp:base_blog_url':
|
222 |
-
$data->home = $reader->readString();
|
223 |
-
$reader->next();
|
224 |
-
break;
|
225 |
-
|
226 |
-
case 'item':
|
227 |
-
$node = $reader->expand();
|
228 |
-
$parsed = $this->parse_post_node( $node );
|
229 |
-
if ( is_wp_error( $parsed ) ) {
|
230 |
-
$this->log_error( $parsed );
|
231 |
-
|
232 |
-
// Skip the rest of this post
|
233 |
-
$reader->next();
|
234 |
-
break;
|
235 |
-
}
|
236 |
-
|
237 |
-
if ( $parsed['data']['post_type'] === 'attachment' ) {
|
238 |
-
$data->media_count++;
|
239 |
-
} else {
|
240 |
-
$data->post_count++;
|
241 |
-
}
|
242 |
-
$data->comment_count += count( $parsed['comments'] );
|
243 |
-
|
244 |
-
// Handled everything in this node, move on to the next
|
245 |
-
$reader->next();
|
246 |
-
break;
|
247 |
-
|
248 |
-
case 'wp:category':
|
249 |
-
case 'wp:tag':
|
250 |
-
case 'wp:term':
|
251 |
-
$data->term_count++;
|
252 |
-
|
253 |
-
// Handled everything in this node, move on to the next
|
254 |
-
$reader->next();
|
255 |
-
break;
|
256 |
-
}
|
257 |
-
}
|
258 |
-
|
259 |
-
$data->version = $this->version;
|
260 |
-
|
261 |
-
return $data;
|
262 |
-
}
|
263 |
-
|
264 |
-
/**
|
265 |
-
* The main controller for the actual import stage.
|
266 |
-
*
|
267 |
-
* @param string $file Path to the WXR file for importing
|
268 |
-
*/
|
269 |
-
public function import( $file ) {
|
270 |
-
add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
|
271 |
-
add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
|
272 |
-
|
273 |
-
$result = $this->import_start( $file );
|
274 |
-
if ( is_wp_error( $result ) ) {
|
275 |
-
return $result;
|
276 |
-
}
|
277 |
-
|
278 |
-
// Let's run the actual importer now, woot
|
279 |
-
$reader = $this->get_reader( $file );
|
280 |
-
if ( is_wp_error( $reader ) ) {
|
281 |
-
return $reader;
|
282 |
-
}
|
283 |
-
|
284 |
-
// Set the version to compatibility mode first
|
285 |
-
$this->version = '1.0';
|
286 |
-
|
287 |
-
// Reset other variables
|
288 |
-
$this->base_url = '';
|
289 |
-
|
290 |
-
// Start parsing!
|
291 |
-
while ( $reader->read() ) {
|
292 |
-
// Only deal with element opens
|
293 |
-
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
294 |
-
continue;
|
295 |
-
}
|
296 |
-
|
297 |
-
if ( $reader->name !== 'item' && $this->partial_import ) {
|
298 |
-
continue;
|
299 |
-
}
|
300 |
-
|
301 |
-
switch ( $reader->name ) {
|
302 |
-
case 'wp:wxr_version':
|
303 |
-
// Upgrade to the correct version
|
304 |
-
$this->version = $reader->readString();
|
305 |
-
|
306 |
-
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
307 |
-
$this->logger->warning( sprintf(
|
308 |
-
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'jupiterx-core' ),
|
309 |
-
$this->version,
|
310 |
-
self::MAX_WXR_VERSION
|
311 |
-
) );
|
312 |
-
}
|
313 |
-
|
314 |
-
// Handled everything in this node, move on to the next
|
315 |
-
$reader->next();
|
316 |
-
break;
|
317 |
-
|
318 |
-
case 'wp:base_site_url':
|
319 |
-
$this->base_url = $reader->readString();
|
320 |
-
|
321 |
-
// Handled everything in this node, move on to the next
|
322 |
-
$reader->next();
|
323 |
-
break;
|
324 |
-
|
325 |
-
case 'item':
|
326 |
-
$node = $reader->expand();
|
327 |
-
$parsed = $this->parse_post_node( $node );
|
328 |
-
if ( is_wp_error( $parsed ) ) {
|
329 |
-
$this->log_error( $parsed );
|
330 |
-
|
331 |
-
// Skip the rest of this post
|
332 |
-
$reader->next();
|
333 |
-
break;
|
334 |
-
}
|
335 |
-
|
336 |
-
if (
|
337 |
-
in_array( $parsed['data']['post_type'], [ 'nav_menu_item' ], true ) &&
|
338 |
-
$this->partial_import
|
339 |
-
) {
|
340 |
-
break;
|
341 |
-
}
|
342 |
-
|
343 |
-
$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
|
344 |
-
|
345 |
-
// Handled everything in this node, move on to the next
|
346 |
-
$reader->next();
|
347 |
-
break;
|
348 |
-
|
349 |
-
case 'wp:category':
|
350 |
-
$node = $reader->expand();
|
351 |
-
|
352 |
-
$parsed = $this->parse_term_node( $node, 'category' );
|
353 |
-
if ( is_wp_error( $parsed ) ) {
|
354 |
-
$this->log_error( $parsed );
|
355 |
-
|
356 |
-
// Skip the rest of this post
|
357 |
-
$reader->next();
|
358 |
-
break;
|
359 |
-
}
|
360 |
-
|
361 |
-
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
362 |
-
|
363 |
-
// Handled everything in this node, move on to the next
|
364 |
-
$reader->next();
|
365 |
-
break;
|
366 |
-
|
367 |
-
case 'wp:tag':
|
368 |
-
$node = $reader->expand();
|
369 |
-
|
370 |
-
$parsed = $this->parse_term_node( $node, 'tag' );
|
371 |
-
if ( is_wp_error( $parsed ) ) {
|
372 |
-
$this->log_error( $parsed );
|
373 |
-
|
374 |
-
// Skip the rest of this post
|
375 |
-
$reader->next();
|
376 |
-
break;
|
377 |
-
}
|
378 |
-
|
379 |
-
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
380 |
-
|
381 |
-
// Handled everything in this node, move on to the next
|
382 |
-
$reader->next();
|
383 |
-
break;
|
384 |
-
|
385 |
-
case 'wp:term':
|
386 |
-
$node = $reader->expand();
|
387 |
-
|
388 |
-
$parsed = $this->parse_term_node( $node );
|
389 |
-
if ( is_wp_error( $parsed ) ) {
|
390 |
-
$this->log_error( $parsed );
|
391 |
-
|
392 |
-
// Skip the rest of this post
|
393 |
-
$reader->next();
|
394 |
-
break;
|
395 |
-
}
|
396 |
-
|
397 |
-
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
398 |
-
|
399 |
-
// Handled everything in this node, move on to the next
|
400 |
-
$reader->next();
|
401 |
-
break;
|
402 |
-
|
403 |
-
default:
|
404 |
-
// Skip this node, probably handled by something already
|
405 |
-
break;
|
406 |
-
}
|
407 |
-
}
|
408 |
-
|
409 |
-
// Now that we've done the main processing, do any required
|
410 |
-
// post-processing and remapping.
|
411 |
-
$this->post_process();
|
412 |
-
|
413 |
-
if ( $this->options['aggressive_url_search'] ) {
|
414 |
-
$this->replace_attachment_urls_in_content();
|
415 |
-
}
|
416 |
-
// $this->remap_featured_images();
|
417 |
-
|
418 |
-
$this->import_end();
|
419 |
-
}
|
420 |
-
|
421 |
-
/**
|
422 |
-
* Log an error instance to the logger.
|
423 |
-
*
|
424 |
-
* @param WP_Error $error Error instance to log.
|
425 |
-
*/
|
426 |
-
protected function log_error( WP_Error $error ) {
|
427 |
-
$this->logger->warning( $error->get_error_message() );
|
428 |
-
|
429 |
-
// Log the data as debug info too
|
430 |
-
$data = $error->get_error_data();
|
431 |
-
if ( ! empty( $data ) ) {
|
432 |
-
$this->logger->debug( var_export( $data, true ) );
|
433 |
-
}
|
434 |
-
}
|
435 |
-
|
436 |
-
/**
|
437 |
-
* Parses the WXR file and prepares us for the task of processing parsed data
|
438 |
-
*
|
439 |
-
* @param string $file Path to the WXR file for importing
|
440 |
-
*/
|
441 |
-
protected function import_start( $file ) {
|
442 |
-
if ( ! is_file( $file ) ) {
|
443 |
-
return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'jupiterx-core' ) );
|
444 |
-
}
|
445 |
-
|
446 |
-
// Suspend bunches of stuff in WP core
|
447 |
-
wp_defer_term_counting( true );
|
448 |
-
wp_defer_comment_counting( true );
|
449 |
-
wp_suspend_cache_invalidation( true );
|
450 |
-
|
451 |
-
// Prefill exists calls if told to
|
452 |
-
if ( $this->options['prefill_existing_posts'] ) {
|
453 |
-
$this->prefill_existing_posts();
|
454 |
-
}
|
455 |
-
if ( $this->options['prefill_existing_comments'] ) {
|
456 |
-
$this->prefill_existing_comments();
|
457 |
-
}
|
458 |
-
if ( $this->options['prefill_existing_terms'] ) {
|
459 |
-
$this->prefill_existing_terms();
|
460 |
-
}
|
461 |
-
|
462 |
-
/**
|
463 |
-
* Begin the import.
|
464 |
-
*
|
465 |
-
* Fires before the import process has begun. If you need to suspend
|
466 |
-
* caching or heavy processing on hooks, do so here.
|
467 |
-
*/
|
468 |
-
do_action( 'import_start' );
|
469 |
-
}
|
470 |
-
|
471 |
-
/**
|
472 |
-
* Performs post-import cleanup of files and the cache
|
473 |
-
*/
|
474 |
-
protected function import_end() {
|
475 |
-
// Re-enable stuff in core
|
476 |
-
wp_suspend_cache_invalidation( false );
|
477 |
-
wp_cache_flush();
|
478 |
-
foreach ( get_taxonomies() as $tax ) {
|
479 |
-
delete_option( "{$tax}_children" );
|
480 |
-
_get_term_hierarchy( $tax );
|
481 |
-
}
|
482 |
-
|
483 |
-
wp_defer_term_counting( false );
|
484 |
-
wp_defer_comment_counting( false );
|
485 |
-
|
486 |
-
/**
|
487 |
-
* Complete the import.
|
488 |
-
*
|
489 |
-
* Fires after the import process has finished. If you need to update
|
490 |
-
* your cache or re-enable processing, do so here.
|
491 |
-
*/
|
492 |
-
do_action( 'import_end' );
|
493 |
-
}
|
494 |
-
|
495 |
-
/**
|
496 |
-
* Set the user mapping.
|
497 |
-
*
|
498 |
-
* @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
|
499 |
-
*/
|
500 |
-
public function set_user_mapping( $mapping ) {
|
501 |
-
foreach ( $mapping as $map ) {
|
502 |
-
if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
|
503 |
-
$this->logger->warning( __( 'Invalid author mapping', 'jupiterx-core' ) );
|
504 |
-
$this->logger->debug( var_export( $map, true ) );
|
505 |
-
continue;
|
506 |
-
}
|
507 |
-
|
508 |
-
$old_slug = $map['old_slug'];
|
509 |
-
$old_id = $map['old_id'];
|
510 |
-
$new_id = $map['new_id'];
|
511 |
-
|
512 |
-
$this->mapping['user'][ $old_id ] = $new_id;
|
513 |
-
$this->mapping['user_slug'][ $old_slug ] = $new_id;
|
514 |
-
}
|
515 |
-
}
|
516 |
-
|
517 |
-
/**
|
518 |
-
* Set the user slug overrides.
|
519 |
-
*
|
520 |
-
* Allows overriding the slug in the import with a custom/renamed version.
|
521 |
-
*
|
522 |
-
* @param string[] $overrides Map of old slug to new slug.
|
523 |
-
*/
|
524 |
-
public function set_user_slug_overrides( $overrides ) {
|
525 |
-
foreach ( $overrides as $original => $renamed ) {
|
526 |
-
$this->user_slug_override[ $original ] = $renamed;
|
527 |
-
}
|
528 |
-
}
|
529 |
-
|
530 |
-
/**
|
531 |
-
* Parse a post node into post data.
|
532 |
-
*
|
533 |
-
* @param DOMElement $node Parent node of post data (typically `item`).
|
534 |
-
* @return array|WP_Error Post data array on success, error otherwise.
|
535 |
-
*/
|
536 |
-
protected function parse_post_node( $node ) {
|
537 |
-
$data = array();
|
538 |
-
$meta = array();
|
539 |
-
$comments = array();
|
540 |
-
$terms = array();
|
541 |
-
|
542 |
-
foreach ( $node->childNodes as $child ) {
|
543 |
-
// We only care about child elements
|
544 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
545 |
-
continue;
|
546 |
-
}
|
547 |
-
|
548 |
-
switch ( $child->tagName ) {
|
549 |
-
case 'wp:post_type':
|
550 |
-
$data['post_type'] = $child->textContent;
|
551 |
-
break;
|
552 |
-
|
553 |
-
case 'title':
|
554 |
-
$data['post_title'] = $child->textContent;
|
555 |
-
break;
|
556 |
-
|
557 |
-
case 'guid':
|
558 |
-
$data['guid'] = $child->textContent;
|
559 |
-
break;
|
560 |
-
|
561 |
-
case 'dc:creator':
|
562 |
-
$data['post_author'] = $child->textContent;
|
563 |
-
break;
|
564 |
-
|
565 |
-
case 'content:encoded':
|
566 |
-
$data['post_content'] = $child->textContent;
|
567 |
-
break;
|
568 |
-
|
569 |
-
case 'excerpt:encoded':
|
570 |
-
$data['post_excerpt'] = $child->textContent;
|
571 |
-
break;
|
572 |
-
|
573 |
-
case 'wp:post_id':
|
574 |
-
$data['post_id'] = $child->textContent;
|
575 |
-
break;
|
576 |
-
|
577 |
-
case 'wp:post_date':
|
578 |
-
$data['post_date'] = $child->textContent;
|
579 |
-
break;
|
580 |
-
|
581 |
-
case 'wp:post_date_gmt':
|
582 |
-
$data['post_date_gmt'] = $child->textContent;
|
583 |
-
break;
|
584 |
-
|
585 |
-
case 'wp:comment_status':
|
586 |
-
$data['comment_status'] = $child->textContent;
|
587 |
-
break;
|
588 |
-
|
589 |
-
case 'wp:ping_status':
|
590 |
-
$data['ping_status'] = $child->textContent;
|
591 |
-
break;
|
592 |
-
|
593 |
-
case 'wp:post_name':
|
594 |
-
$data['post_name'] = $child->textContent;
|
595 |
-
break;
|
596 |
-
|
597 |
-
case 'wp:status':
|
598 |
-
$data['post_status'] = $child->textContent;
|
599 |
-
|
600 |
-
if ( $data['post_status'] === 'auto-draft' ) {
|
601 |
-
// Bail now
|
602 |
-
return new WP_Error(
|
603 |
-
'wxr_importer.post.cannot_import_draft',
|
604 |
-
__( 'Cannot import auto-draft posts', 'jupiterx-core' ),
|
605 |
-
$data
|
606 |
-
);
|
607 |
-
}
|
608 |
-
break;
|
609 |
-
|
610 |
-
case 'wp:post_parent':
|
611 |
-
$data['post_parent'] = $child->textContent;
|
612 |
-
break;
|
613 |
-
|
614 |
-
case 'wp:menu_order':
|
615 |
-
$data['menu_order'] = $child->textContent;
|
616 |
-
break;
|
617 |
-
|
618 |
-
case 'wp:post_password':
|
619 |
-
$data['post_password'] = $child->textContent;
|
620 |
-
break;
|
621 |
-
|
622 |
-
case 'wp:is_sticky':
|
623 |
-
$data['is_sticky'] = $child->textContent;
|
624 |
-
break;
|
625 |
-
|
626 |
-
case 'wp:attachment_url':
|
627 |
-
$data['attachment_url'] = $child->textContent;
|
628 |
-
break;
|
629 |
-
|
630 |
-
case 'wp:postmeta':
|
631 |
-
$meta_item = $this->parse_meta_node( $child );
|
632 |
-
if ( ! empty( $meta_item ) ) {
|
633 |
-
$meta[] = $meta_item;
|
634 |
-
}
|
635 |
-
break;
|
636 |
-
|
637 |
-
case 'wp:comment':
|
638 |
-
$comment_item = $this->parse_comment_node( $child );
|
639 |
-
if ( ! empty( $comment_item ) ) {
|
640 |
-
$comments[] = $comment_item;
|
641 |
-
}
|
642 |
-
break;
|
643 |
-
|
644 |
-
case 'category':
|
645 |
-
$term_item = $this->parse_category_node( $child );
|
646 |
-
if ( ! empty( $term_item ) ) {
|
647 |
-
$terms[] = $term_item;
|
648 |
-
}
|
649 |
-
break;
|
650 |
-
}
|
651 |
-
}
|
652 |
-
|
653 |
-
return compact( 'data', 'meta', 'comments', 'terms' );
|
654 |
-
}
|
655 |
-
|
656 |
-
/**
|
657 |
-
* Create new posts based on import information
|
658 |
-
*
|
659 |
-
* Posts marked as having a parent which doesn't exist will become top level items.
|
660 |
-
* Doesn't create a new post if: the post type doesn't exist, the given post ID
|
661 |
-
* is already noted as imported or a post with the same title and date already exists.
|
662 |
-
* Note that new/updated terms, comments and meta are imported for the last of the above.
|
663 |
-
*/
|
664 |
-
protected function process_post( $data, $meta, $comments, $terms ) {
|
665 |
-
/**
|
666 |
-
* Pre-process post data.
|
667 |
-
*
|
668 |
-
* @param array $data Post data. (Return empty to skip.)
|
669 |
-
* @param array $meta Meta data.
|
670 |
-
* @param array $comments Comments on the post.
|
671 |
-
* @param array $terms Terms on the post.
|
672 |
-
*/
|
673 |
-
$data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
|
674 |
-
if ( empty( $data ) ) {
|
675 |
-
return false;
|
676 |
-
}
|
677 |
-
|
678 |
-
$original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
|
679 |
-
$parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
|
680 |
-
$author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
|
681 |
-
|
682 |
-
// Have we already processed this?
|
683 |
-
if ( isset( $this->mapping['post'][ $original_id ] ) ) {
|
684 |
-
return;
|
685 |
-
}
|
686 |
-
|
687 |
-
$post_type_object = get_post_type_object( $data['post_type'] );
|
688 |
-
|
689 |
-
// Is this type even valid?
|
690 |
-
if ( ! $post_type_object ) {
|
691 |
-
$this->logger->warning( sprintf(
|
692 |
-
__( 'Failed to import "%s": Invalid post type %s', 'jupiterx-core' ),
|
693 |
-
$data['post_title'],
|
694 |
-
$data['post_type']
|
695 |
-
) );
|
696 |
-
return false;
|
697 |
-
}
|
698 |
-
|
699 |
-
$post_exists = $this->post_exists( $data ) && ! $this->partial_import; // allow post duplication on partial import
|
700 |
-
if ( $post_exists ) {
|
701 |
-
$this->logger->info( sprintf(
|
702 |
-
__( '%s "%s" already exists.', 'jupiterx-core' ),
|
703 |
-
$post_type_object->labels->singular_name,
|
704 |
-
$data['post_title']
|
705 |
-
) );
|
706 |
-
|
707 |
-
/**
|
708 |
-
* Post processing already imported.
|
709 |
-
*
|
710 |
-
* @param array $data Raw data imported for the post.
|
711 |
-
*/
|
712 |
-
do_action( 'wxr_importer.process_already_imported.post', $data );
|
713 |
-
|
714 |
-
// Even though this post already exists, new comments might need importing
|
715 |
-
$this->process_comments( $comments, $original_id, $data, $post_exists );
|
716 |
-
|
717 |
-
return false;
|
718 |
-
}
|
719 |
-
|
720 |
-
// Map the parent post, or mark it as one we need to fix
|
721 |
-
$requires_remapping = false;
|
722 |
-
if ( $parent_id ) {
|
723 |
-
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
724 |
-
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
725 |
-
} else {
|
726 |
-
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
727 |
-
$requires_remapping = true;
|
728 |
-
|
729 |
-
$data['post_parent'] = 0;
|
730 |
-
}
|
731 |
-
}
|
732 |
-
|
733 |
-
// Map the author, or mark it as one we need to fix
|
734 |
-
$author = sanitize_user( $data['post_author'], true );
|
735 |
-
if ( empty( $author ) ) {
|
736 |
-
// Missing or invalid author, use default if available.
|
737 |
-
$data['post_author'] = $this->options['default_author'];
|
738 |
-
} elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
|
739 |
-
$data['post_author'] = $this->mapping['user_slug'][ $author ];
|
740 |
-
} else {
|
741 |
-
$meta[] = array( 'key' => '_wxr_import_user_slug', 'value' => $author );
|
742 |
-
$requires_remapping = true;
|
743 |
-
|
744 |
-
$data['post_author'] = (int) get_current_user_id();
|
745 |
-
}
|
746 |
-
|
747 |
-
// Does the post look like it contains attachment images?
|
748 |
-
if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
|
749 |
-
$meta[] = array( 'key' => '_wxr_import_has_attachment_refs', 'value' => true );
|
750 |
-
$requires_remapping = true;
|
751 |
-
}
|
752 |
-
|
753 |
-
// Whitelist to just the keys we allow
|
754 |
-
$postdata = array(
|
755 |
-
'import_id' => $data['post_id'],
|
756 |
-
);
|
757 |
-
$allowed = array(
|
758 |
-
'post_author' => true,
|
759 |
-
'post_date' => true,
|
760 |
-
'post_date_gmt' => true,
|
761 |
-
'post_content' => true,
|
762 |
-
'post_excerpt' => true,
|
763 |
-
'post_title' => true,
|
764 |
-
'post_status' => true,
|
765 |
-
'post_name' => true,
|
766 |
-
'comment_status' => true,
|
767 |
-
'ping_status' => true,
|
768 |
-
'guid' => true,
|
769 |
-
'post_parent' => true,
|
770 |
-
'menu_order' => true,
|
771 |
-
'post_type' => true,
|
772 |
-
'post_password' => true,
|
773 |
-
);
|
774 |
-
foreach ( $data as $key => $value ) {
|
775 |
-
if ( ! isset( $allowed[ $key ] ) ) {
|
776 |
-
continue;
|
777 |
-
}
|
778 |
-
|
779 |
-
$postdata[ $key ] = $data[ $key ];
|
780 |
-
}
|
781 |
-
|
782 |
-
$postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
|
783 |
-
|
784 |
-
if ( 'attachment' === $postdata['post_type'] ) {
|
785 |
-
if ( ! $this->options['fetch_attachments'] ) {
|
786 |
-
$this->logger->notice( sprintf(
|
787 |
-
__( 'Skipping attachment "%s", fetching attachments disabled', 'jupiterx-core' ),
|
788 |
-
$data['post_title']
|
789 |
-
) );
|
790 |
-
/**
|
791 |
-
* Post processing skipped.
|
792 |
-
*
|
793 |
-
* @param array $data Raw data imported for the post.
|
794 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
795 |
-
*/
|
796 |
-
do_action( 'wxr_importer.process_skipped.post', $data, $meta );
|
797 |
-
return false;
|
798 |
-
}
|
799 |
-
$remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
|
800 |
-
$post_id = $this->process_attachment( $postdata, $meta, $remote_url );
|
801 |
-
} else {
|
802 |
-
$post_id = wp_insert_post( $postdata, true );
|
803 |
-
do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
|
804 |
-
}
|
805 |
-
|
806 |
-
if ( is_wp_error( $post_id ) ) {
|
807 |
-
$this->logger->error( sprintf(
|
808 |
-
__( 'Failed to import "%s" (%s)', 'jupiterx-core' ),
|
809 |
-
$data['post_title'],
|
810 |
-
$post_type_object->labels->singular_name
|
811 |
-
) );
|
812 |
-
$this->logger->debug( $post_id->get_error_message() );
|
813 |
-
|
814 |
-
/**
|
815 |
-
* Post processing failed.
|
816 |
-
*
|
817 |
-
* @param WP_Error $post_id Error object.
|
818 |
-
* @param array $data Raw data imported for the post.
|
819 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
820 |
-
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
821 |
-
* @param array $terms Raw term data, already processed.
|
822 |
-
*/
|
823 |
-
do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
|
824 |
-
return false;
|
825 |
-
}
|
826 |
-
|
827 |
-
// Ensure stickiness is handled correctly too
|
828 |
-
if ( $data['is_sticky'] === '1' ) {
|
829 |
-
stick_post( $post_id );
|
830 |
-
}
|
831 |
-
|
832 |
-
// map pre-import ID to local ID
|
833 |
-
$this->mapping['post'][ $original_id ] = (int) $post_id;
|
834 |
-
if ( $requires_remapping ) {
|
835 |
-
$this->requires_remapping['post'][ $post_id ] = true;
|
836 |
-
}
|
837 |
-
$this->mark_post_exists( $data, $post_id );
|
838 |
-
|
839 |
-
$this->logger->info( sprintf(
|
840 |
-
__( 'Imported "%s" (%s)', 'jupiterx-core' ),
|
841 |
-
$data['post_title'],
|
842 |
-
$post_type_object->labels->singular_name
|
843 |
-
) );
|
844 |
-
$this->logger->debug( sprintf(
|
845 |
-
__( 'Post %d remapped to %d', 'jupiterx-core' ),
|
846 |
-
$original_id,
|
847 |
-
$post_id
|
848 |
-
) );
|
849 |
-
|
850 |
-
// Handle the terms too
|
851 |
-
$terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
|
852 |
-
|
853 |
-
if ( ! empty( $terms ) ) {
|
854 |
-
$term_ids = array();
|
855 |
-
foreach ( $terms as $term ) {
|
856 |
-
$taxonomy = $term['taxonomy'];
|
857 |
-
$key = sha1( $taxonomy . ':' . $term['slug'] );
|
858 |
-
|
859 |
-
if ( isset( $this->mapping['term'][ $key ] ) ) {
|
860 |
-
$term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
|
861 |
-
} else {
|
862 |
-
$meta[] = array( 'key' => '_wxr_import_term', 'value' => $term );
|
863 |
-
$requires_remapping = true;
|
864 |
-
}
|
865 |
-
}
|
866 |
-
|
867 |
-
foreach ( $term_ids as $tax => $ids ) {
|
868 |
-
$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
|
869 |
-
do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
|
870 |
-
}
|
871 |
-
}
|
872 |
-
|
873 |
-
$this->process_comments( $comments, $post_id, $data );
|
874 |
-
$this->process_post_meta( $meta, $post_id, $data );
|
875 |
-
|
876 |
-
if ( 'nav_menu_item' === $data['post_type'] ) {
|
877 |
-
$this->process_menu_item_meta( $post_id, $data, $meta );
|
878 |
-
}
|
879 |
-
|
880 |
-
/**
|
881 |
-
* Post processing completed.
|
882 |
-
*
|
883 |
-
* @param int $post_id New post ID.
|
884 |
-
* @param array $data Raw data imported for the post.
|
885 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
886 |
-
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
887 |
-
* @param array $terms Raw term data, already processed.
|
888 |
-
*/
|
889 |
-
do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
|
890 |
-
}
|
891 |
-
|
892 |
-
/**
|
893 |
-
* Attempt to create a new menu item from import data
|
894 |
-
*
|
895 |
-
* Fails for draft, orphaned menu items and those without an associated nav_menu
|
896 |
-
* or an invalid nav_menu term. If the post type or term object which the menu item
|
897 |
-
* represents doesn't exist then the menu item will not be imported (waits until the
|
898 |
-
* end of the import to retry again before discarding).
|
899 |
-
*
|
900 |
-
* @param array $item Menu item details from WXR file
|
901 |
-
*/
|
902 |
-
protected function process_menu_item_meta( $post_id, $data, $meta ) {
|
903 |
-
|
904 |
-
$item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
905 |
-
$original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
|
906 |
-
$object_id = null;
|
907 |
-
|
908 |
-
$this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
|
909 |
-
|
910 |
-
$requires_remapping = false;
|
911 |
-
switch ( $item_type ) {
|
912 |
-
case 'taxonomy':
|
913 |
-
if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
|
914 |
-
$object_id = $this->mapping['term_id'][ $original_object_id ];
|
915 |
-
} else {
|
916 |
-
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
917 |
-
$requires_remapping = true;
|
918 |
-
}
|
919 |
-
break;
|
920 |
-
|
921 |
-
case 'post_type':
|
922 |
-
if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
|
923 |
-
$object_id = $this->mapping['post'][ $original_object_id ];
|
924 |
-
} else {
|
925 |
-
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
926 |
-
$requires_remapping = true;
|
927 |
-
}
|
928 |
-
break;
|
929 |
-
|
930 |
-
case 'custom':
|
931 |
-
// Custom refers to itself, wonderfully easy.
|
932 |
-
$object_id = $post_id;
|
933 |
-
break;
|
934 |
-
|
935 |
-
default:
|
936 |
-
// associated object is missing or not imported yet, we'll retry later
|
937 |
-
$this->missing_menu_items[] = $item;
|
938 |
-
$this->logger->debug( 'Unknown menu item type' );
|
939 |
-
break;
|
940 |
-
}
|
941 |
-
|
942 |
-
if ( $requires_remapping ) {
|
943 |
-
$this->requires_remapping['post'][ $post_id ] = true;
|
944 |
-
}
|
945 |
-
|
946 |
-
if ( empty( $object_id ) ) {
|
947 |
-
// Nothing needed here.
|
948 |
-
return;
|
949 |
-
}
|
950 |
-
|
951 |
-
$this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
|
952 |
-
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
|
953 |
-
}
|
954 |
-
|
955 |
-
/**
|
956 |
-
* If fetching attachments is enabled then attempt to create a new attachment
|
957 |
-
*
|
958 |
-
* @param array $post Attachment post details from WXR
|
959 |
-
* @param string $url URL to fetch attachment from
|
960 |
-
* @return int|WP_Error Post ID on success, WP_Error otherwise
|
961 |
-
*/
|
962 |
-
protected function process_attachment( $post, $meta, $remote_url ) {
|
963 |
-
// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
|
964 |
-
// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
|
965 |
-
$post['upload_date'] = $post['post_date'];
|
966 |
-
foreach ( $meta as $meta_item ) {
|
967 |
-
if ( $meta_item['key'] !== '_wp_attached_file' ) {
|
968 |
-
continue;
|
969 |
-
}
|
970 |
-
|
971 |
-
if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
|
972 |
-
$post['upload_date'] = $matches[0];
|
973 |
-
}
|
974 |
-
break;
|
975 |
-
}
|
976 |
-
|
977 |
-
// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
|
978 |
-
if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
|
979 |
-
$remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
|
980 |
-
}
|
981 |
-
|
982 |
-
$upload = $this->fetch_remote_file( $remote_url, $post );
|
983 |
-
if ( is_wp_error( $upload ) ) {
|
984 |
-
return $upload;
|
985 |
-
}
|
986 |
-
|
987 |
-
$info = wp_check_filetype( $upload['file'] );
|
988 |
-
if ( ! $info ) {
|
989 |
-
return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'jupiterx-core' ) );
|
990 |
-
}
|
991 |
-
|
992 |
-
$post['post_mime_type'] = $info['type'];
|
993 |
-
|
994 |
-
// WP really likes using the GUID for display. Allow updating it.
|
995 |
-
// See https://core.trac.wordpress.org/ticket/33386
|
996 |
-
if ( $this->options['update_attachment_guids'] ) {
|
997 |
-
$post['guid'] = $upload['url'];
|
998 |
-
}
|
999 |
-
|
1000 |
-
// as per wp-admin/includes/upload.php
|
1001 |
-
$post_id = wp_insert_attachment( $post, $upload['file'] );
|
1002 |
-
if ( is_wp_error( $post_id ) ) {
|
1003 |
-
return $post_id;
|
1004 |
-
}
|
1005 |
-
|
1006 |
-
$attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
|
1007 |
-
wp_update_attachment_metadata( $post_id, $attachment_metadata );
|
1008 |
-
|
1009 |
-
// Map this image URL later if we need to
|
1010 |
-
$this->url_remap[ $remote_url ] = $upload['url'];
|
1011 |
-
|
1012 |
-
// If we have a HTTPS URL, ensure the HTTP URL gets replaced too
|
1013 |
-
if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
|
1014 |
-
$insecure_url = 'http' . substr( $remote_url, 5 );
|
1015 |
-
$this->url_remap[ $insecure_url ] = $upload['url'];
|
1016 |
-
}
|
1017 |
-
|
1018 |
-
if ( $this->options['aggressive_url_search'] ) {
|
1019 |
-
// remap resized image URLs, works by stripping the extension and remapping the URL stub.
|
1020 |
-
/*if ( preg_match( '!^image/!', $info['type'] ) ) {
|
1021 |
-
$parts = pathinfo( $remote_url );
|
1022 |
-
$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
|
1023 |
-
|
1024 |
-
$parts_new = pathinfo( $upload['url'] );
|
1025 |
-
$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
|
1026 |
-
|
1027 |
-
$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
|
1028 |
-
}*/
|
1029 |
-
}
|
1030 |
-
|
1031 |
-
return $post_id;
|
1032 |
-
}
|
1033 |
-
|
1034 |
-
/**
|
1035 |
-
* Parse a meta node into meta data.
|
1036 |
-
*
|
1037 |
-
* @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
|
1038 |
-
* @return array|null Meta data array on success, or null on error.
|
1039 |
-
*/
|
1040 |
-
protected function parse_meta_node( $node ) {
|
1041 |
-
foreach ( $node->childNodes as $child ) {
|
1042 |
-
// We only care about child elements
|
1043 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1044 |
-
continue;
|
1045 |
-
}
|
1046 |
-
|
1047 |
-
switch ( $child->tagName ) {
|
1048 |
-
case 'wp:meta_key':
|
1049 |
-
$key = $child->textContent;
|
1050 |
-
break;
|
1051 |
-
|
1052 |
-
case 'wp:meta_value':
|
1053 |
-
$value = $child->textContent;
|
1054 |
-
break;
|
1055 |
-
}
|
1056 |
-
}
|
1057 |
-
|
1058 |
-
if ( empty( $key ) ) {
|
1059 |
-
return null;
|
1060 |
-
}
|
1061 |
-
|
1062 |
-
return compact( 'key', 'value' );
|
1063 |
-
}
|
1064 |
-
|
1065 |
-
/**
|
1066 |
-
* Process and import post meta items.
|
1067 |
-
*
|
1068 |
-
* @param array $meta List of meta data arrays
|
1069 |
-
* @param int $post_id Post to associate with
|
1070 |
-
* @param array $post Post data
|
1071 |
-
* @return int|WP_Error Number of meta items imported on success, error otherwise.
|
1072 |
-
*/
|
1073 |
-
protected function process_post_meta( $meta, $post_id, $post ) {
|
1074 |
-
if ( empty( $meta ) ) {
|
1075 |
-
return true;
|
1076 |
-
}
|
1077 |
-
|
1078 |
-
foreach ( $meta as $meta_item ) {
|
1079 |
-
/**
|
1080 |
-
* Pre-process post meta data.
|
1081 |
-
*
|
1082 |
-
* @param array $meta_item Meta data. (Return empty to skip.)
|
1083 |
-
* @param int $post_id Post the meta is attached to.
|
1084 |
-
*/
|
1085 |
-
$meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
|
1086 |
-
if ( empty( $meta_item ) ) {
|
1087 |
-
return false;
|
1088 |
-
}
|
1089 |
-
|
1090 |
-
$key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
|
1091 |
-
$value = false;
|
1092 |
-
|
1093 |
-
if ( '_edit_last' === $key ) {
|
1094 |
-
$value = intval( $meta_item['value'] );
|
1095 |
-
if ( ! isset( $this->mapping['user'][ $value ] ) ) {
|
1096 |
-
// Skip!
|
1097 |
-
continue;
|
1098 |
-
}
|
1099 |
-
|
1100 |
-
$value = $this->mapping['user'][ $value ];
|
1101 |
-
}
|
1102 |
-
|
1103 |
-
if ( $key ) {
|
1104 |
-
// export gets meta straight from the DB so could have a serialized string
|
1105 |
-
if ( ! $value ) {
|
1106 |
-
$value = maybe_unserialize( $meta_item['value'] );
|
1107 |
-
}
|
1108 |
-
|
1109 |
-
add_post_meta( $post_id, $key, $value );
|
1110 |
-
do_action( 'import_post_meta', $post_id, $key, $value );
|
1111 |
-
|
1112 |
-
// if the post has a featured image, take note of this in case of remap
|
1113 |
-
if ( '_thumbnail_id' === $key ) {
|
1114 |
-
$this->featured_images[ $post_id ] = (int) $value;
|
1115 |
-
}
|
1116 |
-
}
|
1117 |
-
}
|
1118 |
-
|
1119 |
-
return true;
|
1120 |
-
}
|
1121 |
-
|
1122 |
-
/**
|
1123 |
-
* Parse a comment node into comment data.
|
1124 |
-
*
|
1125 |
-
* @param DOMElement $node Parent node of comment data (typically `wp:comment`).
|
1126 |
-
* @return array Comment data array.
|
1127 |
-
*/
|
1128 |
-
protected function parse_comment_node( $node ) {
|
1129 |
-
$data = array(
|
1130 |
-
'commentmeta' => array(),
|
1131 |
-
);
|
1132 |
-
|
1133 |
-
foreach ( $node->childNodes as $child ) {
|
1134 |
-
// We only care about child elements
|
1135 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1136 |
-
continue;
|
1137 |
-
}
|
1138 |
-
|
1139 |
-
switch ( $child->tagName ) {
|
1140 |
-
case 'wp:comment_id':
|
1141 |
-
$data['comment_id'] = $child->textContent;
|
1142 |
-
break;
|
1143 |
-
case 'wp:comment_author':
|
1144 |
-
$data['comment_author'] = $child->textContent;
|
1145 |
-
break;
|
1146 |
-
|
1147 |
-
case 'wp:comment_author_email':
|
1148 |
-
$data['comment_author_email'] = $child->textContent;
|
1149 |
-
break;
|
1150 |
-
|
1151 |
-
case 'wp:comment_author_IP':
|
1152 |
-
$data['comment_author_IP'] = $child->textContent;
|
1153 |
-
break;
|
1154 |
-
|
1155 |
-
case 'wp:comment_author_url':
|
1156 |
-
$data['comment_author_url'] = $child->textContent;
|
1157 |
-
break;
|
1158 |
-
|
1159 |
-
case 'wp:comment_user_id':
|
1160 |
-
$data['comment_user_id'] = $child->textContent;
|
1161 |
-
break;
|
1162 |
-
|
1163 |
-
case 'wp:comment_date':
|
1164 |
-
$data['comment_date'] = $child->textContent;
|
1165 |
-
break;
|
1166 |
-
|
1167 |
-
case 'wp:comment_date_gmt':
|
1168 |
-
$data['comment_date_gmt'] = $child->textContent;
|
1169 |
-
break;
|
1170 |
-
|
1171 |
-
case 'wp:comment_content':
|
1172 |
-
$data['comment_content'] = $child->textContent;
|
1173 |
-
break;
|
1174 |
-
|
1175 |
-
case 'wp:comment_approved':
|
1176 |
-
$data['comment_approved'] = $child->textContent;
|
1177 |
-
break;
|
1178 |
-
|
1179 |
-
case 'wp:comment_type':
|
1180 |
-
$data['comment_type'] = $child->textContent;
|
1181 |
-
break;
|
1182 |
-
|
1183 |
-
case 'wp:comment_parent':
|
1184 |
-
$data['comment_parent'] = $child->textContent;
|
1185 |
-
break;
|
1186 |
-
|
1187 |
-
case 'wp:commentmeta':
|
1188 |
-
$meta_item = $this->parse_meta_node( $child );
|
1189 |
-
if ( ! empty( $meta_item ) ) {
|
1190 |
-
$data['commentmeta'][] = $meta_item;
|
1191 |
-
}
|
1192 |
-
break;
|
1193 |
-
}
|
1194 |
-
}
|
1195 |
-
|
1196 |
-
return $data;
|
1197 |
-
}
|
1198 |
-
|
1199 |
-
/**
|
1200 |
-
* Process and import comment data.
|
1201 |
-
*
|
1202 |
-
* @param array $comments List of comment data arrays.
|
1203 |
-
* @param int $post_id Post to associate with.
|
1204 |
-
* @param array $post Post data.
|
1205 |
-
* @return int|WP_Error Number of comments imported on success, error otherwise.
|
1206 |
-
*/
|
1207 |
-
protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
|
1208 |
-
|
1209 |
-
$comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
|
1210 |
-
if ( empty( $comments ) ) {
|
1211 |
-
return 0;
|
1212 |
-
}
|
1213 |
-
|
1214 |
-
$num_comments = 0;
|
1215 |
-
|
1216 |
-
// Sort by ID to avoid excessive remapping later
|
1217 |
-
usort( $comments, array( $this, 'sort_comments_by_id' ) );
|
1218 |
-
|
1219 |
-
foreach ( $comments as $key => $comment ) {
|
1220 |
-
/**
|
1221 |
-
* Pre-process comment data
|
1222 |
-
*
|
1223 |
-
* @param array $comment Comment data. (Return empty to skip.)
|
1224 |
-
* @param int $post_id Post the comment is attached to.
|
1225 |
-
*/
|
1226 |
-
$comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
|
1227 |
-
if ( empty( $comment ) ) {
|
1228 |
-
return false;
|
1229 |
-
}
|
1230 |
-
|
1231 |
-
$original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
|
1232 |
-
$parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
|
1233 |
-
$author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
|
1234 |
-
|
1235 |
-
// if this is a new post we can skip the comment_exists() check
|
1236 |
-
// TODO: Check comment_exists for performance
|
1237 |
-
if ( $post_exists ) {
|
1238 |
-
$existing = $this->comment_exists( $comment );
|
1239 |
-
if ( $existing ) {
|
1240 |
-
|
1241 |
-
/**
|
1242 |
-
* Comment processing already imported.
|
1243 |
-
*
|
1244 |
-
* @param array $comment Raw data imported for the comment.
|
1245 |
-
*/
|
1246 |
-
do_action( 'wxr_importer.process_already_imported.comment', $comment );
|
1247 |
-
|
1248 |
-
$this->mapping['comment'][ $original_id ] = $existing;
|
1249 |
-
continue;
|
1250 |
-
}
|
1251 |
-
}
|
1252 |
-
|
1253 |
-
// Remove meta from the main array
|
1254 |
-
$meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
|
1255 |
-
unset( $comment['commentmeta'] );
|
1256 |
-
|
1257 |
-
// Map the parent comment, or mark it as one we need to fix
|
1258 |
-
$requires_remapping = false;
|
1259 |
-
if ( $parent_id ) {
|
1260 |
-
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1261 |
-
$comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1262 |
-
} else {
|
1263 |
-
// Prepare for remapping later
|
1264 |
-
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1265 |
-
$requires_remapping = true;
|
1266 |
-
|
1267 |
-
// Wipe the parent for now
|
1268 |
-
$comment['comment_parent'] = 0;
|
1269 |
-
}
|
1270 |
-
}
|
1271 |
-
|
1272 |
-
// Map the author, or mark it as one we need to fix
|
1273 |
-
if ( $author_id ) {
|
1274 |
-
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1275 |
-
$comment['user_id'] = $this->mapping['user'][ $author_id ];
|
1276 |
-
} else {
|
1277 |
-
// Prepare for remapping later
|
1278 |
-
$meta[] = array( 'key' => '_wxr_import_user', 'value' => $author_id );
|
1279 |
-
$requires_remapping = true;
|
1280 |
-
|
1281 |
-
// Wipe the user for now
|
1282 |
-
$comment['user_id'] = 0;
|
1283 |
-
}
|
1284 |
-
}
|
1285 |
-
|
1286 |
-
// Run standard core filters
|
1287 |
-
$comment['comment_post_ID'] = $post_id;
|
1288 |
-
$comment = wp_filter_comment( $comment );
|
1289 |
-
|
1290 |
-
// wp_insert_comment expects slashed data
|
1291 |
-
$comment_id = wp_insert_comment( wp_slash( $comment ) );
|
1292 |
-
$this->mapping['comment'][ $original_id ] = $comment_id;
|
1293 |
-
if ( $requires_remapping ) {
|
1294 |
-
$this->requires_remapping['comment'][ $comment_id ] = true;
|
1295 |
-
}
|
1296 |
-
$this->mark_comment_exists( $comment, $comment_id );
|
1297 |
-
|
1298 |
-
/**
|
1299 |
-
* Comment has been imported.
|
1300 |
-
*
|
1301 |
-
* @param int $comment_id New comment ID
|
1302 |
-
* @param array $comment Comment inserted (`comment_id` item refers to the original ID)
|
1303 |
-
* @param int $post_id Post parent of the comment
|
1304 |
-
* @param array $post Post data
|
1305 |
-
*/
|
1306 |
-
do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
|
1307 |
-
|
1308 |
-
// Process the meta items
|
1309 |
-
foreach ( $meta as $meta_item ) {
|
1310 |
-
$value = maybe_unserialize( $meta_item['value'] );
|
1311 |
-
add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
|
1312 |
-
}
|
1313 |
-
|
1314 |
-
/**
|
1315 |
-
* Post processing completed.
|
1316 |
-
*
|
1317 |
-
* @param int $post_id New post ID.
|
1318 |
-
* @param array $comment Raw data imported for the comment.
|
1319 |
-
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
1320 |
-
* @param array $post_id Parent post ID.
|
1321 |
-
*/
|
1322 |
-
do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
|
1323 |
-
|
1324 |
-
$num_comments++;
|
1325 |
-
}
|
1326 |
-
|
1327 |
-
return $num_comments;
|
1328 |
-
}
|
1329 |
-
|
1330 |
-
protected function parse_category_node( $node ) {
|
1331 |
-
$data = array(
|
1332 |
-
// Default taxonomy to "category", since this is a `<category>` tag
|
1333 |
-
'taxonomy' => 'category',
|
1334 |
-
);
|
1335 |
-
$meta = array();
|
1336 |
-
|
1337 |
-
if ( $node->hasAttribute( 'domain' ) ) {
|
1338 |
-
$data['taxonomy'] = $node->getAttribute( 'domain' );
|
1339 |
-
}
|
1340 |
-
if ( $node->hasAttribute( 'nicename' ) ) {
|
1341 |
-
$data['slug'] = $node->getAttribute( 'nicename' );
|
1342 |
-
}
|
1343 |
-
|
1344 |
-
$data['name'] = $node->textContent;
|
1345 |
-
|
1346 |
-
if ( empty( $data['slug'] ) ) {
|
1347 |
-
return null;
|
1348 |
-
}
|
1349 |
-
|
1350 |
-
// Just for extra compatibility
|
1351 |
-
if ( $data['taxonomy'] === 'tag' ) {
|
1352 |
-
$data['taxonomy'] = 'post_tag';
|
1353 |
-
}
|
1354 |
-
|
1355 |
-
return $data;
|
1356 |
-
}
|
1357 |
-
|
1358 |
-
/**
|
1359 |
-
* Callback for `usort` to sort comments by ID
|
1360 |
-
*
|
1361 |
-
* @param array $a Comment data for the first comment
|
1362 |
-
* @param array $b Comment data for the second comment
|
1363 |
-
* @return int
|
1364 |
-
*/
|
1365 |
-
public static function sort_comments_by_id( $a, $b ) {
|
1366 |
-
if ( empty( $a['comment_id'] ) ) {
|
1367 |
-
return 1;
|
1368 |
-
}
|
1369 |
-
|
1370 |
-
if ( empty( $b['comment_id'] ) ) {
|
1371 |
-
return -1;
|
1372 |
-
}
|
1373 |
-
|
1374 |
-
return $a['comment_id'] - $b['comment_id'];
|
1375 |
-
}
|
1376 |
-
|
1377 |
-
protected function parse_term_node( $node, $type = 'term' ) {
|
1378 |
-
$data = array();
|
1379 |
-
$meta = array();
|
1380 |
-
|
1381 |
-
$tag_name = array(
|
1382 |
-
'id' => 'wp:term_id',
|
1383 |
-
'taxonomy' => 'wp:term_taxonomy',
|
1384 |
-
'slug' => 'wp:term_slug',
|
1385 |
-
'parent' => 'wp:term_parent',
|
1386 |
-
'name' => 'wp:term_name',
|
1387 |
-
'description' => 'wp:term_description',
|
1388 |
-
);
|
1389 |
-
$taxonomy = null;
|
1390 |
-
|
1391 |
-
// Special casing!
|
1392 |
-
switch ( $type ) {
|
1393 |
-
case 'category':
|
1394 |
-
$tag_name['slug'] = 'wp:category_nicename';
|
1395 |
-
$tag_name['parent'] = 'wp:category_parent';
|
1396 |
-
$tag_name['name'] = 'wp:cat_name';
|
1397 |
-
$tag_name['description'] = 'wp:category_description';
|
1398 |
-
$tag_name['taxonomy'] = null;
|
1399 |
-
|
1400 |
-
$data['taxonomy'] = 'category';
|
1401 |
-
break;
|
1402 |
-
|
1403 |
-
case 'tag':
|
1404 |
-
$tag_name['slug'] = 'wp:tag_slug';
|
1405 |
-
$tag_name['parent'] = null;
|
1406 |
-
$tag_name['name'] = 'wp:tag_name';
|
1407 |
-
$tag_name['description'] = 'wp:tag_description';
|
1408 |
-
$tag_name['taxonomy'] = null;
|
1409 |
-
|
1410 |
-
$data['taxonomy'] = 'post_tag';
|
1411 |
-
break;
|
1412 |
-
}
|
1413 |
-
|
1414 |
-
foreach ( $node->childNodes as $child ) {
|
1415 |
-
// We only care about child elements
|
1416 |
-
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1417 |
-
continue;
|
1418 |
-
}
|
1419 |
-
|
1420 |
-
$key = array_search( $child->tagName, $tag_name );
|
1421 |
-
if ( $key ) {
|
1422 |
-
$data[ $key ] = $child->textContent;
|
1423 |
-
}
|
1424 |
-
}
|
1425 |
-
|
1426 |
-
if ( empty( $data['taxonomy'] ) ) {
|
1427 |
-
return null;
|
1428 |
-
}
|
1429 |
-
|
1430 |
-
// Compatibility with WXR 1.0
|
1431 |
-
if ( $data['taxonomy'] === 'tag' ) {
|
1432 |
-
$data['taxonomy'] = 'post_tag';
|
1433 |
-
}
|
1434 |
-
|
1435 |
-
return compact( 'data', 'meta' );
|
1436 |
-
}
|
1437 |
-
|
1438 |
-
protected function process_term( $data, $meta ) {
|
1439 |
-
/**
|
1440 |
-
* Pre-process term data.
|
1441 |
-
*
|
1442 |
-
* @param array $data Term data. (Return empty to skip.)
|
1443 |
-
* @param array $meta Meta data.
|
1444 |
-
*/
|
1445 |
-
$data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
|
1446 |
-
if ( empty( $data ) ) {
|
1447 |
-
return false;
|
1448 |
-
}
|
1449 |
-
|
1450 |
-
$original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
|
1451 |
-
$parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
|
1452 |
-
|
1453 |
-
$mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
1454 |
-
$existing = $this->term_exists( $data );
|
1455 |
-
if ( $existing ) {
|
1456 |
-
|
1457 |
-
/**
|
1458 |
-
* Term processing already imported.
|
1459 |
-
*
|
1460 |
-
* @param array $data Raw data imported for the term.
|
1461 |
-
*/
|
1462 |
-
do_action( 'wxr_importer.process_already_imported.term', $data );
|
1463 |
-
|
1464 |
-
$this->mapping['term'][ $mapping_key ] = $existing;
|
1465 |
-
$this->mapping['term_id'][ $original_id ] = $existing;
|
1466 |
-
return false;
|
1467 |
-
}
|
1468 |
-
|
1469 |
-
// WP really likes to repeat itself in export files
|
1470 |
-
if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
|
1471 |
-
return false;
|
1472 |
-
}
|
1473 |
-
|
1474 |
-
$termdata = array();
|
1475 |
-
$allowed = array(
|
1476 |
-
'slug' => true,
|
1477 |
-
'description' => true,
|
1478 |
-
);
|
1479 |
-
|
1480 |
-
// Map the parent comment, or mark it as one we need to fix
|
1481 |
-
// TODO: add parent mapping and remapping
|
1482 |
-
/*$requires_remapping = false;
|
1483 |
-
if ( $parent_id ) {
|
1484 |
-
if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
|
1485 |
-
$data['parent'] = $this->mapping['term'][ $parent_id ];
|
1486 |
-
} else {
|
1487 |
-
// Prepare for remapping later
|
1488 |
-
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1489 |
-
$requires_remapping = true;
|
1490 |
-
|
1491 |
-
// Wipe the parent for now
|
1492 |
-
$data['parent'] = 0;
|
1493 |
-
}
|
1494 |
-
}*/
|
1495 |
-
|
1496 |
-
foreach ( $data as $key => $value ) {
|
1497 |
-
if ( ! isset( $allowed[ $key ] ) ) {
|
1498 |
-
continue;
|
1499 |
-
}
|
1500 |
-
|
1501 |
-
$termdata[ $key ] = $data[ $key ];
|
1502 |
-
}
|
1503 |
-
|
1504 |
-
$result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
|
1505 |
-
if ( is_wp_error( $result ) ) {
|
1506 |
-
$this->logger->warning( sprintf(
|
1507 |
-
__( 'Failed to import %s %s', 'jupiterx-core' ),
|
1508 |
-
$data['taxonomy'],
|
1509 |
-
$data['name']
|
1510 |
-
) );
|
1511 |
-
$this->logger->debug( $result->get_error_message() );
|
1512 |
-
do_action( 'wp_import_insert_term_failed', $result, $data );
|
1513 |
-
|
1514 |
-
/**
|
1515 |
-
* Term processing failed.
|
1516 |
-
*
|
1517 |
-
* @param WP_Error $result Error object.
|
1518 |
-
* @param array $data Raw data imported for the term.
|
1519 |
-
* @param array $meta Meta data supplied for the term.
|
1520 |
-
*/
|
1521 |
-
do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
|
1522 |
-
return false;
|
1523 |
-
}
|
1524 |
-
|
1525 |
-
$term_id = $result['term_id'];
|
1526 |
-
|
1527 |
-
$this->mapping['term'][ $mapping_key ] = $term_id;
|
1528 |
-
$this->mapping['term_id'][ $original_id ] = $term_id;
|
1529 |
-
|
1530 |
-
$this->logger->info( sprintf(
|
1531 |
-
__( 'Imported "%s" (%s)', 'jupiterx-core' ),
|
1532 |
-
$data['name'],
|
1533 |
-
$data['taxonomy']
|
1534 |
-
) );
|
1535 |
-
$this->logger->debug( sprintf(
|
1536 |
-
__( 'Term %d remapped to %d', 'jupiterx-core' ),
|
1537 |
-
$original_id,
|
1538 |
-
$term_id
|
1539 |
-
) );
|
1540 |
-
|
1541 |
-
do_action( 'wp_import_insert_term', $term_id, $data );
|
1542 |
-
|
1543 |
-
/**
|
1544 |
-
* Term processing completed.
|
1545 |
-
*
|
1546 |
-
* @param int $term_id New term ID.
|
1547 |
-
* @param array $data Raw data imported for the term.
|
1548 |
-
*/
|
1549 |
-
do_action( 'wxr_importer.processed.term', $term_id, $data );
|
1550 |
-
}
|
1551 |
-
|
1552 |
-
/**
|
1553 |
-
* Attempt to download a remote file attachment
|
1554 |
-
*
|
1555 |
-
* @param string $url URL of item to fetch
|
1556 |
-
* @param array $post Attachment details
|
1557 |
-
* @return array|WP_Error Local file location details on success, WP_Error otherwise
|
1558 |
-
*/
|
1559 |
-
protected function fetch_remote_file( $url, $post ) {
|
1560 |
-
// extract the file name and extension from the url
|
1561 |
-
$file_name = basename( $url );
|
1562 |
-
|
1563 |
-
// get placeholder file in the upload dir with a unique, sanitized filename
|
1564 |
-
$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
|
1565 |
-
if ( $upload['error'] ) {
|
1566 |
-
return new WP_Error( 'upload_dir_error', $upload['error'] );
|
1567 |
-
}
|
1568 |
-
|
1569 |
-
// fetch the remote url and write it to the placeholder file
|
1570 |
-
$response = wp_remote_get( $url, array(
|
1571 |
-
'stream' => true,
|
1572 |
-
'filename' => $upload['file'],
|
1573 |
-
) );
|
1574 |
-
|
1575 |
-
// request failed
|
1576 |
-
if ( is_wp_error( $response ) ) {
|
1577 |
-
unlink( $upload['file'] );
|
1578 |
-
return $response;
|
1579 |
-
}
|
1580 |
-
|
1581 |
-
$code = (int) wp_remote_retrieve_response_code( $response );
|
1582 |
-
|
1583 |
-
// make sure the fetch was successful
|
1584 |
-
if ( $code !== 200 ) {
|
1585 |
-
unlink( $upload['file'] );
|
1586 |
-
return new WP_Error(
|
1587 |
-
'import_file_error',
|
1588 |
-
sprintf(
|
1589 |
-
__( 'Remote server returned %1$d %2$s for %3$s', 'jupiterx-core' ),
|
1590 |
-
$code,
|
1591 |
-
get_status_header_desc( $code ),
|
1592 |
-
$url
|
1593 |
-
)
|
1594 |
-
);
|
1595 |
-
}
|
1596 |
-
|
1597 |
-
$filesize = filesize( $upload['file'] );
|
1598 |
-
$headers = wp_remote_retrieve_headers( $response );
|
1599 |
-
|
1600 |
-
if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
|
1601 |
-
unlink( $upload['file'] );
|
1602 |
-
return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'jupiterx-core' ) );
|
1603 |
-
}
|
1604 |
-
|
1605 |
-
if ( 0 === $filesize ) {
|
1606 |
-
unlink( $upload['file'] );
|
1607 |
-
return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'jupiterx-core' ) );
|
1608 |
-
}
|
1609 |
-
|
1610 |
-
$max_size = (int) $this->max_attachment_size();
|
1611 |
-
if ( ! empty( $max_size ) && $filesize > $max_size ) {
|
1612 |
-
unlink( $upload['file'] );
|
1613 |
-
$message = sprintf( __( 'Remote file is too large, limit is %s', 'jupiterx-core' ), size_format( $max_size ) );
|
1614 |
-
return new WP_Error( 'import_file_error', $message );
|
1615 |
-
}
|
1616 |
-
|
1617 |
-
return $upload;
|
1618 |
-
}
|
1619 |
-
|
1620 |
-
protected function post_process() {
|
1621 |
-
// Time to tackle any left-over bits
|
1622 |
-
if ( ! empty( $this->requires_remapping['post'] ) ) {
|
1623 |
-
$this->post_process_posts( $this->requires_remapping['post'] );
|
1624 |
-
}
|
1625 |
-
if ( ! empty( $this->requires_remapping['comment'] ) ) {
|
1626 |
-
$this->post_process_comments( $this->requires_remapping['comment'] );
|
1627 |
-
}
|
1628 |
-
}
|
1629 |
-
|
1630 |
-
protected function post_process_posts( $todo ) {
|
1631 |
-
foreach ( $todo as $post_id => $_ ) {
|
1632 |
-
$this->logger->debug( sprintf(
|
1633 |
-
// Note: title intentionally not used to skip extra processing
|
1634 |
-
// for when debug logging is off
|
1635 |
-
__( 'Running post-processing for post %d', 'jupiterx-core' ),
|
1636 |
-
$post_id
|
1637 |
-
) );
|
1638 |
-
|
1639 |
-
$data = array();
|
1640 |
-
|
1641 |
-
$parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
|
1642 |
-
if ( ! empty( $parent_id ) ) {
|
1643 |
-
// Have we imported the parent now?
|
1644 |
-
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
1645 |
-
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
1646 |
-
} else {
|
1647 |
-
$this->logger->warning( sprintf(
|
1648 |
-
__( 'Could not find the post parent for "%s" (post #%d)', 'jupiterx-core' ),
|
1649 |
-
get_the_title( $post_id ),
|
1650 |
-
$post_id
|
1651 |
-
) );
|
1652 |
-
$this->logger->debug( sprintf(
|
1653 |
-
__( 'Post %d was imported with parent %d, but could not be found', 'jupiterx-core' ),
|
1654 |
-
$post_id,
|
1655 |
-
$parent_id
|
1656 |
-
) );
|
1657 |
-
}
|
1658 |
-
}
|
1659 |
-
|
1660 |
-
$author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
|
1661 |
-
if ( ! empty( $author_slug ) ) {
|
1662 |
-
// Have we imported the user now?
|
1663 |
-
if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
|
1664 |
-
$data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
|
1665 |
-
} else {
|
1666 |
-
$this->logger->warning( sprintf(
|
1667 |
-
__( 'Could not find the author for "%s" (post #%d)', 'jupiterx-core' ),
|
1668 |
-
get_the_title( $post_id ),
|
1669 |
-
$post_id
|
1670 |
-
) );
|
1671 |
-
$this->logger->debug( sprintf(
|
1672 |
-
__( 'Post %d was imported with author "%s", but could not be found', 'jupiterx-core' ),
|
1673 |
-
$post_id,
|
1674 |
-
$author_slug
|
1675 |
-
) );
|
1676 |
-
}
|
1677 |
-
}
|
1678 |
-
|
1679 |
-
$has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
|
1680 |
-
if ( ! empty( $has_attachments ) ) {
|
1681 |
-
$post = get_post( $post_id );
|
1682 |
-
$content = $post->post_content;
|
1683 |
-
|
1684 |
-
// Replace all the URLs we've got
|
1685 |
-
$new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
|
1686 |
-
if ( $new_content !== $content ) {
|
1687 |
-
$data['post_content'] = $new_content;
|
1688 |
-
}
|
1689 |
-
}
|
1690 |
-
|
1691 |
-
if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
|
1692 |
-
$this->post_process_menu_item( $post_id );
|
1693 |
-
}
|
1694 |
-
|
1695 |
-
// Do we have updates to make?
|
1696 |
-
if ( empty( $data ) ) {
|
1697 |
-
$this->logger->debug( sprintf(
|
1698 |
-
__( 'Post %d was marked for post-processing, but none was required.', 'jupiterx-core' ),
|
1699 |
-
$post_id
|
1700 |
-
) );
|
1701 |
-
continue;
|
1702 |
-
}
|
1703 |
-
|
1704 |
-
// Run the update
|
1705 |
-
$data['ID'] = $post_id;
|
1706 |
-
$result = wp_update_post( $data, true );
|
1707 |
-
if ( is_wp_error( $result ) ) {
|
1708 |
-
$this->logger->warning( sprintf(
|
1709 |
-
__( 'Could not update "%s" (post #%d) with mapped data', 'jupiterx-core' ),
|
1710 |
-
get_the_title( $post_id ),
|
1711 |
-
$post_id
|
1712 |
-
) );
|
1713 |
-
$this->logger->debug( $result->get_error_message() );
|
1714 |
-
continue;
|
1715 |
-
}
|
1716 |
-
|
1717 |
-
// Clear out our temporary meta keys
|
1718 |
-
delete_post_meta( $post_id, '_wxr_import_parent' );
|
1719 |
-
delete_post_meta( $post_id, '_wxr_import_user_slug' );
|
1720 |
-
delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
|
1721 |
-
}
|
1722 |
-
}
|
1723 |
-
|
1724 |
-
protected function post_process_menu_item( $post_id ) {
|
1725 |
-
$menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
|
1726 |
-
if ( empty( $menu_object_id ) ) {
|
1727 |
-
// No processing needed!
|
1728 |
-
return;
|
1729 |
-
}
|
1730 |
-
|
1731 |
-
$menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
1732 |
-
switch ( $menu_item_type ) {
|
1733 |
-
case 'taxonomy':
|
1734 |
-
if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
|
1735 |
-
$menu_object = $this->mapping['term_id'][ $menu_object_id ];
|
1736 |
-
}
|
1737 |
-
break;
|
1738 |
-
|
1739 |
-
case 'post_type':
|
1740 |
-
if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
|
1741 |
-
$menu_object = $this->mapping['post'][ $menu_object_id ];
|
1742 |
-
}
|
1743 |
-
break;
|
1744 |
-
|
1745 |
-
default:
|
1746 |
-
// Cannot handle this.
|
1747 |
-
return;
|
1748 |
-
}
|
1749 |
-
|
1750 |
-
if ( ! empty( $menu_object ) ) {
|
1751 |
-
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
|
1752 |
-
} else {
|
1753 |
-
$this->logger->warning( sprintf(
|
1754 |
-
__( 'Could not find the menu object for "%s" (post #%d)', 'jupiterx-core' ),
|
1755 |
-
get_the_title( $post_id ),
|
1756 |
-
$post_id
|
1757 |
-
) );
|
1758 |
-
$this->logger->debug( sprintf(
|
1759 |
-
__( 'Post %d was imported with object "%d" of type "%s", but could not be found', 'jupiterx-core' ),
|
1760 |
-
$post_id,
|
1761 |
-
$menu_object_id,
|
1762 |
-
$menu_item_type
|
1763 |
-
) );
|
1764 |
-
}
|
1765 |
-
|
1766 |
-
delete_post_meta( $post_id, '_wxr_import_menu_item' );
|
1767 |
-
}
|
1768 |
-
|
1769 |
-
|
1770 |
-
protected function post_process_comments( $todo ) {
|
1771 |
-
foreach ( $todo as $comment_id => $_ ) {
|
1772 |
-
$data = array();
|
1773 |
-
|
1774 |
-
$parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
|
1775 |
-
if ( ! empty( $parent_id ) ) {
|
1776 |
-
// Have we imported the parent now?
|
1777 |
-
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1778 |
-
$data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1779 |
-
} else {
|
1780 |
-
$this->logger->warning( sprintf(
|
1781 |
-
__( 'Could not find the comment parent for comment #%d', 'jupiterx-core' ),
|
1782 |
-
$comment_id
|
1783 |
-
) );
|
1784 |
-
$this->logger->debug( sprintf(
|
1785 |
-
__( 'Comment %d was imported with parent %d, but could not be found', 'jupiterx-core' ),
|
1786 |
-
$comment_id,
|
1787 |
-
$parent_id
|
1788 |
-
) );
|
1789 |
-
}
|
1790 |
-
}
|
1791 |
-
|
1792 |
-
$author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
|
1793 |
-
if ( ! empty( $author_id ) ) {
|
1794 |
-
// Have we imported the user now?
|
1795 |
-
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1796 |
-
$data['user_id'] = $this->mapping['user'][ $author_id ];
|
1797 |
-
} else {
|
1798 |
-
$this->logger->warning( sprintf(
|
1799 |
-
__( 'Could not find the author for comment #%d', 'jupiterx-core' ),
|
1800 |
-
$comment_id
|
1801 |
-
) );
|
1802 |
-
$this->logger->debug( sprintf(
|
1803 |
-
__( 'Comment %d was imported with author %d, but could not be found', 'jupiterx-core' ),
|
1804 |
-
$comment_id,
|
1805 |
-
$author_id
|
1806 |
-
) );
|
1807 |
-
}
|
1808 |
-
}
|
1809 |
-
|
1810 |
-
// Do we have updates to make?
|
1811 |
-
if ( empty( $data ) ) {
|
1812 |
-
continue;
|
1813 |
-
}
|
1814 |
-
|
1815 |
-
// Run the update
|
1816 |
-
$data['comment_ID'] = $comment_ID;
|
1817 |
-
$result = wp_update_comment( wp_slash( $data ) );
|
1818 |
-
if ( empty( $result ) ) {
|
1819 |
-
$this->logger->warning( sprintf(
|
1820 |
-
__( 'Could not update comment #%d with mapped data', 'jupiterx-core' ),
|
1821 |
-
$comment_id
|
1822 |
-
) );
|
1823 |
-
continue;
|
1824 |
-
}
|
1825 |
-
|
1826 |
-
// Clear out our temporary meta keys
|
1827 |
-
delete_comment_meta( $comment_id, '_wxr_import_parent' );
|
1828 |
-
delete_comment_meta( $comment_id, '_wxr_import_user' );
|
1829 |
-
}
|
1830 |
-
}
|
1831 |
-
|
1832 |
-
/**
|
1833 |
-
* Use stored mapping information to update old attachment URLs
|
1834 |
-
*/
|
1835 |
-
protected function replace_attachment_urls_in_content() {
|
1836 |
-
global $wpdb;
|
1837 |
-
// make sure we do the longest urls first, in case one is a substring of another
|
1838 |
-
uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
|
1839 |
-
|
1840 |
-
foreach ( $this->url_remap as $from_url => $to_url ) {
|
1841 |
-
// remap urls in post_content
|
1842 |
-
$query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
|
1843 |
-
$wpdb->query( $query );
|
1844 |
-
|
1845 |
-
// remap enclosure urls
|
1846 |
-
$query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
|
1847 |
-
$result = $wpdb->query( $query );
|
1848 |
-
}
|
1849 |
-
}
|
1850 |
-
|
1851 |
-
/**
|
1852 |
-
* Update _thumbnail_id meta to new, imported attachment IDs
|
1853 |
-
*/
|
1854 |
-
function remap_featured_images() {
|
1855 |
-
// cycle through posts that have a featured image
|
1856 |
-
foreach ( $this->featured_images as $post_id => $value ) {
|
1857 |
-
if ( isset( $this->processed_posts[ $value ] ) ) {
|
1858 |
-
$new_id = $this->processed_posts[ $value ];
|
1859 |
-
|
1860 |
-
// only update if there's a difference
|
1861 |
-
if ( $new_id !== $value ) {
|
1862 |
-
update_post_meta( $post_id, '_thumbnail_id', $new_id );
|
1863 |
-
}
|
1864 |
-
}
|
1865 |
-
}
|
1866 |
-
}
|
1867 |
-
|
1868 |
-
/**
|
1869 |
-
* Decide if the given meta key maps to information we will want to import
|
1870 |
-
*
|
1871 |
-
* @param string $key The meta key to check
|
1872 |
-
* @return string|bool The key if we do want to import, false if not
|
1873 |
-
*/
|
1874 |
-
public function is_valid_meta_key( $key ) {
|
1875 |
-
// skip attachment metadata since we'll regenerate it from scratch
|
1876 |
-
// skip _edit_lock as not relevant for import
|
1877 |
-
if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
|
1878 |
-
return false;
|
1879 |
-
}
|
1880 |
-
|
1881 |
-
return $key;
|
1882 |
-
}
|
1883 |
-
|
1884 |
-
/**
|
1885 |
-
* Decide what the maximum file size for downloaded attachments is.
|
1886 |
-
* Default is 0 (unlimited), can be filtered via import_attachment_size_limit
|
1887 |
-
*
|
1888 |
-
* @return int Maximum attachment file size to import
|
1889 |
-
*/
|
1890 |
-
protected function max_attachment_size() {
|
1891 |
-
return apply_filters( 'import_attachment_size_limit', 0 );
|
1892 |
-
}
|
1893 |
-
|
1894 |
-
/**
|
1895 |
-
* Added to http_request_timeout filter to force timeout at 60 seconds during import
|
1896 |
-
*
|
1897 |
-
* @access protected
|
1898 |
-
* @return int 60
|
1899 |
-
*/
|
1900 |
-
function bump_request_timeout($val) {
|
1901 |
-
return 60;
|
1902 |
-
}
|
1903 |
-
|
1904 |
-
// return the difference in length between two strings
|
1905 |
-
function cmpr_strlen( $a, $b ) {
|
1906 |
-
return strlen( $b ) - strlen( $a );
|
1907 |
-
}
|
1908 |
-
|
1909 |
-
/**
|
1910 |
-
* Prefill existing post data.
|
1911 |
-
*
|
1912 |
-
* This preloads all GUIDs into memory, allowing us to avoid hitting the
|
1913 |
-
* database when we need to check for existence. With larger imports, this
|
1914 |
-
* becomes prohibitively slow to perform SELECT queries on each.
|
1915 |
-
*
|
1916 |
-
* By preloading all this data into memory, it's a constant-time lookup in
|
1917 |
-
* PHP instead. However, this does use a lot more memory, so for sites doing
|
1918 |
-
* small imports onto a large site, it may be a better tradeoff to use
|
1919 |
-
* on-the-fly checking instead.
|
1920 |
-
*/
|
1921 |
-
protected function prefill_existing_posts() {
|
1922 |
-
global $wpdb;
|
1923 |
-
$posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
|
1924 |
-
|
1925 |
-
foreach ( $posts as $item ) {
|
1926 |
-
$this->exists['post'][ wp_specialchars_decode( $item->guid ) ] = $item->ID;
|
1927 |
-
}
|
1928 |
-
}
|
1929 |
-
|
1930 |
-
/**
|
1931 |
-
* Does the post exist?
|
1932 |
-
*
|
1933 |
-
* @param array $data Post data to check against.
|
1934 |
-
* @return int|bool Existing post ID if it exists, false otherwise.
|
1935 |
-
*/
|
1936 |
-
protected function post_exists( $data ) {
|
1937 |
-
// Constant-time lookup if we prefilled
|
1938 |
-
$exists_key = wp_specialchars_decode( $data['guid'] );
|
1939 |
-
|
1940 |
-
if ( $this->options['prefill_existing_posts'] ) {
|
1941 |
-
return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
|
1942 |
-
}
|
1943 |
-
|
1944 |
-
// No prefilling, but might have already handled it
|
1945 |
-
if ( isset( $this->exists['post'][ $exists_key ] ) ) {
|
1946 |
-
return $this->exists['post'][ $exists_key ];
|
1947 |
-
}
|
1948 |
-
|
1949 |
-
// Still nothing, try post_exists, and cache it
|
1950 |
-
$exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
|
1951 |
-
$this->exists['post'][ $exists_key ] = $exists;
|
1952 |
-
|
1953 |
-
return $exists;
|
1954 |
-
}
|
1955 |
-
|
1956 |
-
/**
|
1957 |
-
* Mark the post as existing.
|
1958 |
-
*
|
1959 |
-
* @param array $data Post data to mark as existing.
|
1960 |
-
* @param int $post_id Post ID.
|
1961 |
-
*/
|
1962 |
-
protected function mark_post_exists( $data, $post_id ) {
|
1963 |
-
$exists_key = $data['guid'];
|
1964 |
-
$this->exists['post'][ $exists_key ] = $post_id;
|
1965 |
-
}
|
1966 |
-
|
1967 |
-
/**
|
1968 |
-
* Prefill existing comment data.
|
1969 |
-
*
|
1970 |
-
* @see self::prefill_existing_posts() for justification of why this exists.
|
1971 |
-
*/
|
1972 |
-
protected function prefill_existing_comments() {
|
1973 |
-
global $wpdb;
|
1974 |
-
$posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
|
1975 |
-
|
1976 |
-
foreach ( $posts as $item ) {
|
1977 |
-
$exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
|
1978 |
-
$this->exists['comment'][ $exists_key ] = $item->comment_ID;
|
1979 |
-
}
|
1980 |
-
}
|
1981 |
-
|
1982 |
-
/**
|
1983 |
-
* Does the comment exist?
|
1984 |
-
*
|
1985 |
-
* @param array $data Comment data to check against.
|
1986 |
-
* @return int|bool Existing comment ID if it exists, false otherwise.
|
1987 |
-
*/
|
1988 |
-
protected function comment_exists( $data ) {
|
1989 |
-
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
1990 |
-
|
1991 |
-
// Constant-time lookup if we prefilled
|
1992 |
-
if ( $this->options['prefill_existing_comments'] ) {
|
1993 |
-
return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
|
1994 |
-
}
|
1995 |
-
|
1996 |
-
// No prefilling, but might have already handled it
|
1997 |
-
if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
|
1998 |
-
return $this->exists['comment'][ $exists_key ];
|
1999 |
-
}
|
2000 |
-
|
2001 |
-
// Still nothing, try comment_exists, and cache it
|
2002 |
-
$exists = comment_exists( $data['comment_author'], $data['comment_date'] );
|
2003 |
-
$this->exists['comment'][ $exists_key ] = $exists;
|
2004 |
-
|
2005 |
-
return $exists;
|
2006 |
-
}
|
2007 |
-
|
2008 |
-
/**
|
2009 |
-
* Mark the comment as existing.
|
2010 |
-
*
|
2011 |
-
* @param array $data Comment data to mark as existing.
|
2012 |
-
* @param int $comment_id Comment ID.
|
2013 |
-
*/
|
2014 |
-
protected function mark_comment_exists( $data, $comment_id ) {
|
2015 |
-
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2016 |
-
$this->exists['comment'][ $exists_key ] = $comment_id;
|
2017 |
-
}
|
2018 |
-
|
2019 |
-
/**
|
2020 |
-
* Prefill existing term data.
|
2021 |
-
*
|
2022 |
-
* @see self::prefill_existing_posts() for justification of why this exists.
|
2023 |
-
*/
|
2024 |
-
protected function prefill_existing_terms() {
|
2025 |
-
global $wpdb;
|
2026 |
-
$query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
|
2027 |
-
$query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
|
2028 |
-
$terms = $wpdb->get_results( $query );
|
2029 |
-
|
2030 |
-
foreach ( $terms as $item ) {
|
2031 |
-
$exists_key = sha1( $item->taxonomy . ':' . $item->slug );
|
2032 |
-
$this->exists['term'][ $exists_key ] = $item->term_id;
|
2033 |
-
}
|
2034 |
-
}
|
2035 |
-
|
2036 |
-
/**
|
2037 |
-
* Does the term exist?
|
2038 |
-
*
|
2039 |
-
* @param array $data Term data to check against.
|
2040 |
-
* @return int|bool Existing term ID if it exists, false otherwise.
|
2041 |
-
*/
|
2042 |
-
protected function term_exists( $data ) {
|
2043 |
-
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2044 |
-
|
2045 |
-
// Constant-time lookup if we prefilled
|
2046 |
-
if ( $this->options['prefill_existing_terms'] ) {
|
2047 |
-
return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
|
2048 |
-
}
|
2049 |
-
|
2050 |
-
// No prefilling, but might have already handled it
|
2051 |
-
if ( isset( $this->exists['term'][ $exists_key ] ) ) {
|
2052 |
-
return $this->exists['term'][ $exists_key ];
|
2053 |
-
}
|
2054 |
-
|
2055 |
-
// Still nothing, try comment_exists, and cache it
|
2056 |
-
$exists = term_exists( $data['slug'], $data['taxonomy'] );
|
2057 |
-
if ( is_array( $exists ) ) {
|
2058 |
-
$exists = $exists['term_id'];
|
2059 |
-
}
|
2060 |
-
|
2061 |
-
$this->exists['term'][ $exists_key ] = $exists;
|
2062 |
-
|
2063 |
-
return $exists;
|
2064 |
-
}
|
2065 |
-
|
2066 |
-
/**
|
2067 |
-
* Mark the term as existing.
|
2068 |
-
*
|
2069 |
-
* @param array $data Term data to mark as existing.
|
2070 |
-
* @param int $term_id Term ID.
|
2071 |
-
*/
|
2072 |
-
protected function mark_term_exists( $data, $term_id ) {
|
2073 |
-
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2074 |
-
$this->exists['term'][ $exists_key ] = $term_id;
|
2075 |
-
}
|
2076 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WXR Importer class.
|
4 |
+
*
|
5 |
+
* Main class of WordPress Importer v2 to handle import process.
|
6 |
+
*
|
7 |
+
* @package Jupiter
|
8 |
+
* @subpackage Template Import
|
9 |
+
* @since 6.0.3
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* The main class of WordPress Importer v2.
|
14 |
+
*
|
15 |
+
* @since 6.0.3
|
16 |
+
*
|
17 |
+
* @see https://github.com/humanmade/WordPress-Importer/blob/master/class-wxr-importer.php
|
18 |
+
*
|
19 |
+
* @codingStandardsIgnoreFile
|
20 |
+
* @SuppressWarnings(PHPMD)
|
21 |
+
* - Temporary suppress warning. Worry if we change the content of the class or change how
|
22 |
+
* the logical conditions work, it will cause some issues.
|
23 |
+
*/
|
24 |
+
class JupiterX_WXR_Importer extends WP_Importer {
|
25 |
+
/**
|
26 |
+
* Maximum supported WXR version
|
27 |
+
*/
|
28 |
+
const MAX_WXR_VERSION = 1.2;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Regular expression for checking if a post references an attachment
|
32 |
+
*
|
33 |
+
* Note: This is a quick, weak check just to exclude text-only posts. More
|
34 |
+
* vigorous checking is done later to verify.
|
35 |
+
*/
|
36 |
+
const REGEX_HAS_ATTACHMENT_REFS = '!
|
37 |
+
(
|
38 |
+
# Match anything with an image or attachment class
|
39 |
+
class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
|
40 |
+
|
|
41 |
+
# Match anything that looks like an upload URL
|
42 |
+
src=[\'"][^\'"]*(
|
43 |
+
[0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
|
44 |
+
|
|
45 |
+
content/uploads[^\'"]+
|
46 |
+
)[\'"]
|
47 |
+
)!ix';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Version of WXR we're importing.
|
51 |
+
*
|
52 |
+
* Defaults to 1.0 for compatibility. Typically overridden by a
|
53 |
+
* `<wp:wxr_version>` tag at the start of the file.
|
54 |
+
*
|
55 |
+
* @var string
|
56 |
+
*/
|
57 |
+
protected $version = '1.0';
|
58 |
+
|
59 |
+
// information to import from WXR file
|
60 |
+
protected $categories = array();
|
61 |
+
protected $tags = array();
|
62 |
+
protected $base_url = '';
|
63 |
+
|
64 |
+
// TODO: REMOVE THESE
|
65 |
+
protected $processed_terms = array();
|
66 |
+
protected $processed_posts = array();
|
67 |
+
protected $processed_menu_items = array();
|
68 |
+
protected $menu_item_orphans = array();
|
69 |
+
protected $missing_menu_items = array();
|
70 |
+
|
71 |
+
// NEW STYLE
|
72 |
+
protected $mapping = array();
|
73 |
+
protected $requires_remapping = array();
|
74 |
+
protected $exists = array();
|
75 |
+
protected $user_slug_override = array();
|
76 |
+
|
77 |
+
protected $url_remap = array();
|
78 |
+
protected $featured_images = array();
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Logger instance.
|
82 |
+
*
|
83 |
+
* @var JupiterX_Importer_Logger
|
84 |
+
*/
|
85 |
+
protected $logger;
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Import pages only.
|
89 |
+
*
|
90 |
+
* @var boolean
|
91 |
+
*/
|
92 |
+
protected $partial_import;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Constructor
|
96 |
+
*
|
97 |
+
* @param array $options {
|
98 |
+
* @var bool $prefill_existing_posts Should we prefill `post_exists` calls? (True prefills and uses more memory, false checks once per imported post and takes longer. Default is true.)
|
99 |
+
* @var bool $prefill_existing_comments Should we prefill `comment_exists` calls? (True prefills and uses more memory, false checks once per imported comment and takes longer. Default is true.)
|
100 |
+
* @var bool $prefill_existing_terms Should we prefill `term_exists` calls? (True prefills and uses more memory, false checks once per imported term and takes longer. Default is true.)
|
101 |
+
* @var bool $update_attachment_guids Should attachment GUIDs be updated to the new URL? (True updates the GUID, which keeps compatibility with v1, false doesn't update, and allows deduplication and reimporting. Default is false.)
|
102 |
+
* @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
|
103 |
+
* @var bool $aggressive_url_search Should we search/replace for URLs aggressively? (True searches all posts' content for old URLs and replaces, false checks for `<img class="wp-image-*">` only. Default is false.)
|
104 |
+
* @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
|
105 |
+
* }
|
106 |
+
*/
|
107 |
+
public function __construct( $options = array(), $partial_import = false ) {
|
108 |
+
$this->partial_import = $partial_import;
|
109 |
+
|
110 |
+
// Initialize some important variables
|
111 |
+
$empty_types = array(
|
112 |
+
'post' => array(),
|
113 |
+
'comment' => array(),
|
114 |
+
'term' => array(),
|
115 |
+
'user' => array(),
|
116 |
+
);
|
117 |
+
|
118 |
+
$this->mapping = $empty_types;
|
119 |
+
$this->mapping['user_slug'] = array();
|
120 |
+
$this->mapping['term_id'] = array();
|
121 |
+
$this->requires_remapping = $empty_types;
|
122 |
+
$this->exists = $empty_types;
|
123 |
+
|
124 |
+
$this->options = wp_parse_args( $options, array(
|
125 |
+
'prefill_existing_posts' => true,
|
126 |
+
'prefill_existing_comments' => true,
|
127 |
+
'prefill_existing_terms' => true,
|
128 |
+
'update_attachment_guids' => false,
|
129 |
+
'fetch_attachments' => false,
|
130 |
+
'aggressive_url_search' => false,
|
131 |
+
'default_author' => null,
|
132 |
+
) );
|
133 |
+
}
|
134 |
+
|
135 |
+
public function set_logger( $logger ) {
|
136 |
+
$this->logger = $logger;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Get a stream reader for the file.
|
141 |
+
*
|
142 |
+
* @param string $file Path to the XML file.
|
143 |
+
* @return XMLReader|WP_Error Reader instance on success, error otherwise.
|
144 |
+
*/
|
145 |
+
protected function get_reader( $file ) {
|
146 |
+
// Avoid loading external entities for security
|
147 |
+
$old_value = null;
|
148 |
+
if ( function_exists( 'libxml_disable_entity_loader' ) ) {
|
149 |
+
// $old_value = libxml_disable_entity_loader( true );
|
150 |
+
}
|
151 |
+
|
152 |
+
$reader = new XMLReader();
|
153 |
+
$status = $reader->open( $file );
|
154 |
+
|
155 |
+
if ( ! is_null( $old_value ) ) {
|
156 |
+
// libxml_disable_entity_loader( $old_value );
|
157 |
+
}
|
158 |
+
|
159 |
+
if ( ! $status ) {
|
160 |
+
return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'jupiterx-core' ) );
|
161 |
+
}
|
162 |
+
|
163 |
+
return $reader;
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* The main controller for the actual import stage.
|
168 |
+
*
|
169 |
+
* @param string $file Path to the WXR file for importing
|
170 |
+
*/
|
171 |
+
public function get_preliminary_information( $file ) {
|
172 |
+
// Let's run the actual importer now, woot
|
173 |
+
$reader = $this->get_reader( $file );
|
174 |
+
if ( is_wp_error( $reader ) ) {
|
175 |
+
return $reader;
|
176 |
+
}
|
177 |
+
|
178 |
+
// Set the version to compatibility mode first
|
179 |
+
$this->version = '1.0';
|
180 |
+
|
181 |
+
// Start parsing!
|
182 |
+
$data = new JupiterX_WXR_Import_Info();
|
183 |
+
while ( $reader->read() ) {
|
184 |
+
// Only deal with element opens
|
185 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
186 |
+
continue;
|
187 |
+
}
|
188 |
+
|
189 |
+
switch ( $reader->name ) {
|
190 |
+
case 'wp:wxr_version':
|
191 |
+
// Upgrade to the correct version
|
192 |
+
$this->version = $reader->readString();
|
193 |
+
|
194 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
195 |
+
$this->logger->warning( sprintf(
|
196 |
+
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'jupiterx-core' ),
|
197 |
+
$this->version,
|
198 |
+
self::MAX_WXR_VERSION
|
199 |
+
) );
|
200 |
+
}
|
201 |
+
|
202 |
+
// Handled everything in this node, move on to the next
|
203 |
+
$reader->next();
|
204 |
+
break;
|
205 |
+
|
206 |
+
case 'generator':
|
207 |
+
$data->generator = $reader->readString();
|
208 |
+
$reader->next();
|
209 |
+
break;
|
210 |
+
|
211 |
+
case 'title':
|
212 |
+
$data->title = $reader->readString();
|
213 |
+
$reader->next();
|
214 |
+
break;
|
215 |
+
|
216 |
+
case 'wp:base_site_url':
|
217 |
+
$data->siteurl = $reader->readString();
|
218 |
+
$reader->next();
|
219 |
+
break;
|
220 |
+
|
221 |
+
case 'wp:base_blog_url':
|
222 |
+
$data->home = $reader->readString();
|
223 |
+
$reader->next();
|
224 |
+
break;
|
225 |
+
|
226 |
+
case 'item':
|
227 |
+
$node = $reader->expand();
|
228 |
+
$parsed = $this->parse_post_node( $node );
|
229 |
+
if ( is_wp_error( $parsed ) ) {
|
230 |
+
$this->log_error( $parsed );
|
231 |
+
|
232 |
+
// Skip the rest of this post
|
233 |
+
$reader->next();
|
234 |
+
break;
|
235 |
+
}
|
236 |
+
|
237 |
+
if ( $parsed['data']['post_type'] === 'attachment' ) {
|
238 |
+
$data->media_count++;
|
239 |
+
} else {
|
240 |
+
$data->post_count++;
|
241 |
+
}
|
242 |
+
$data->comment_count += count( $parsed['comments'] );
|
243 |
+
|
244 |
+
// Handled everything in this node, move on to the next
|
245 |
+
$reader->next();
|
246 |
+
break;
|
247 |
+
|
248 |
+
case 'wp:category':
|
249 |
+
case 'wp:tag':
|
250 |
+
case 'wp:term':
|
251 |
+
$data->term_count++;
|
252 |
+
|
253 |
+
// Handled everything in this node, move on to the next
|
254 |
+
$reader->next();
|
255 |
+
break;
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
$data->version = $this->version;
|
260 |
+
|
261 |
+
return $data;
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* The main controller for the actual import stage.
|
266 |
+
*
|
267 |
+
* @param string $file Path to the WXR file for importing
|
268 |
+
*/
|
269 |
+
public function import( $file ) {
|
270 |
+
add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
|
271 |
+
add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
|
272 |
+
|
273 |
+
$result = $this->import_start( $file );
|
274 |
+
if ( is_wp_error( $result ) ) {
|
275 |
+
return $result;
|
276 |
+
}
|
277 |
+
|
278 |
+
// Let's run the actual importer now, woot
|
279 |
+
$reader = $this->get_reader( $file );
|
280 |
+
if ( is_wp_error( $reader ) ) {
|
281 |
+
return $reader;
|
282 |
+
}
|
283 |
+
|
284 |
+
// Set the version to compatibility mode first
|
285 |
+
$this->version = '1.0';
|
286 |
+
|
287 |
+
// Reset other variables
|
288 |
+
$this->base_url = '';
|
289 |
+
|
290 |
+
// Start parsing!
|
291 |
+
while ( $reader->read() ) {
|
292 |
+
// Only deal with element opens
|
293 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
294 |
+
continue;
|
295 |
+
}
|
296 |
+
|
297 |
+
if ( $reader->name !== 'item' && $this->partial_import ) {
|
298 |
+
continue;
|
299 |
+
}
|
300 |
+
|
301 |
+
switch ( $reader->name ) {
|
302 |
+
case 'wp:wxr_version':
|
303 |
+
// Upgrade to the correct version
|
304 |
+
$this->version = $reader->readString();
|
305 |
+
|
306 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
307 |
+
$this->logger->warning( sprintf(
|
308 |
+
__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'jupiterx-core' ),
|
309 |
+
$this->version,
|
310 |
+
self::MAX_WXR_VERSION
|
311 |
+
) );
|
312 |
+
}
|
313 |
+
|
314 |
+
// Handled everything in this node, move on to the next
|
315 |
+
$reader->next();
|
316 |
+
break;
|
317 |
+
|
318 |
+
case 'wp:base_site_url':
|
319 |
+
$this->base_url = $reader->readString();
|
320 |
+
|
321 |
+
// Handled everything in this node, move on to the next
|
322 |
+
$reader->next();
|
323 |
+
break;
|
324 |
+
|
325 |
+
case 'item':
|
326 |
+
$node = $reader->expand();
|
327 |
+
$parsed = $this->parse_post_node( $node );
|
328 |
+
if ( is_wp_error( $parsed ) ) {
|
329 |
+
$this->log_error( $parsed );
|
330 |
+
|
331 |
+
// Skip the rest of this post
|
332 |
+
$reader->next();
|
333 |
+
break;
|
334 |
+
}
|
335 |
+
|
336 |
+
if (
|
337 |
+
in_array( $parsed['data']['post_type'], [ 'nav_menu_item' ], true ) &&
|
338 |
+
$this->partial_import
|
339 |
+
) {
|
340 |
+
break;
|
341 |
+
}
|
342 |
+
|
343 |
+
$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
|
344 |
+
|
345 |
+
// Handled everything in this node, move on to the next
|
346 |
+
$reader->next();
|
347 |
+
break;
|
348 |
+
|
349 |
+
case 'wp:category':
|
350 |
+
$node = $reader->expand();
|
351 |
+
|
352 |
+
$parsed = $this->parse_term_node( $node, 'category' );
|
353 |
+
if ( is_wp_error( $parsed ) ) {
|
354 |
+
$this->log_error( $parsed );
|
355 |
+
|
356 |
+
// Skip the rest of this post
|
357 |
+
$reader->next();
|
358 |
+
break;
|
359 |
+
}
|
360 |
+
|
361 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
362 |
+
|
363 |
+
// Handled everything in this node, move on to the next
|
364 |
+
$reader->next();
|
365 |
+
break;
|
366 |
+
|
367 |
+
case 'wp:tag':
|
368 |
+
$node = $reader->expand();
|
369 |
+
|
370 |
+
$parsed = $this->parse_term_node( $node, 'tag' );
|
371 |
+
if ( is_wp_error( $parsed ) ) {
|
372 |
+
$this->log_error( $parsed );
|
373 |
+
|
374 |
+
// Skip the rest of this post
|
375 |
+
$reader->next();
|
376 |
+
break;
|
377 |
+
}
|
378 |
+
|
379 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
380 |
+
|
381 |
+
// Handled everything in this node, move on to the next
|
382 |
+
$reader->next();
|
383 |
+
break;
|
384 |
+
|
385 |
+
case 'wp:term':
|
386 |
+
$node = $reader->expand();
|
387 |
+
|
388 |
+
$parsed = $this->parse_term_node( $node );
|
389 |
+
if ( is_wp_error( $parsed ) ) {
|
390 |
+
$this->log_error( $parsed );
|
391 |
+
|
392 |
+
// Skip the rest of this post
|
393 |
+
$reader->next();
|
394 |
+
break;
|
395 |
+
}
|
396 |
+
|
397 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
398 |
+
|
399 |
+
// Handled everything in this node, move on to the next
|
400 |
+
$reader->next();
|
401 |
+
break;
|
402 |
+
|
403 |
+
default:
|
404 |
+
// Skip this node, probably handled by something already
|
405 |
+
break;
|
406 |
+
}
|
407 |
+
}
|
408 |
+
|
409 |
+
// Now that we've done the main processing, do any required
|
410 |
+
// post-processing and remapping.
|
411 |
+
$this->post_process();
|
412 |
+
|
413 |
+
if ( $this->options['aggressive_url_search'] ) {
|
414 |
+
$this->replace_attachment_urls_in_content();
|
415 |
+
}
|
416 |
+
// $this->remap_featured_images();
|
417 |
+
|
418 |
+
$this->import_end();
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Log an error instance to the logger.
|
423 |
+
*
|
424 |
+
* @param WP_Error $error Error instance to log.
|
425 |
+
*/
|
426 |
+
protected function log_error( WP_Error $error ) {
|
427 |
+
$this->logger->warning( $error->get_error_message() );
|
428 |
+
|
429 |
+
// Log the data as debug info too
|
430 |
+
$data = $error->get_error_data();
|
431 |
+
if ( ! empty( $data ) ) {
|
432 |
+
$this->logger->debug( var_export( $data, true ) );
|
433 |
+
}
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* Parses the WXR file and prepares us for the task of processing parsed data
|
438 |
+
*
|
439 |
+
* @param string $file Path to the WXR file for importing
|
440 |
+
*/
|
441 |
+
protected function import_start( $file ) {
|
442 |
+
if ( ! is_file( $file ) ) {
|
443 |
+
return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'jupiterx-core' ) );
|
444 |
+
}
|
445 |
+
|
446 |
+
// Suspend bunches of stuff in WP core
|
447 |
+
wp_defer_term_counting( true );
|
448 |
+
wp_defer_comment_counting( true );
|
449 |
+
wp_suspend_cache_invalidation( true );
|
450 |
+
|
451 |
+
// Prefill exists calls if told to
|
452 |
+
if ( $this->options['prefill_existing_posts'] ) {
|
453 |
+
$this->prefill_existing_posts();
|
454 |
+
}
|
455 |
+
if ( $this->options['prefill_existing_comments'] ) {
|
456 |
+
$this->prefill_existing_comments();
|
457 |
+
}
|
458 |
+
if ( $this->options['prefill_existing_terms'] ) {
|
459 |
+
$this->prefill_existing_terms();
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* Begin the import.
|
464 |
+
*
|
465 |
+
* Fires before the import process has begun. If you need to suspend
|
466 |
+
* caching or heavy processing on hooks, do so here.
|
467 |
+
*/
|
468 |
+
do_action( 'import_start' );
|
469 |
+
}
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Performs post-import cleanup of files and the cache
|
473 |
+
*/
|
474 |
+
protected function import_end() {
|
475 |
+
// Re-enable stuff in core
|
476 |
+
wp_suspend_cache_invalidation( false );
|
477 |
+
wp_cache_flush();
|
478 |
+
foreach ( get_taxonomies() as $tax ) {
|
479 |
+
delete_option( "{$tax}_children" );
|
480 |
+
_get_term_hierarchy( $tax );
|
481 |
+
}
|
482 |
+
|
483 |
+
wp_defer_term_counting( false );
|
484 |
+
wp_defer_comment_counting( false );
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Complete the import.
|
488 |
+
*
|
489 |
+
* Fires after the import process has finished. If you need to update
|
490 |
+
* your cache or re-enable processing, do so here.
|
491 |
+
*/
|
492 |
+
do_action( 'import_end' );
|
493 |
+
}
|
494 |
+
|
495 |
+
/**
|
496 |
+
* Set the user mapping.
|
497 |
+
*
|
498 |
+
* @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
|
499 |
+
*/
|
500 |
+
public function set_user_mapping( $mapping ) {
|
501 |
+
foreach ( $mapping as $map ) {
|
502 |
+
if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
|
503 |
+
$this->logger->warning( __( 'Invalid author mapping', 'jupiterx-core' ) );
|
504 |
+
$this->logger->debug( var_export( $map, true ) );
|
505 |
+
continue;
|
506 |
+
}
|
507 |
+
|
508 |
+
$old_slug = $map['old_slug'];
|
509 |
+
$old_id = $map['old_id'];
|
510 |
+
$new_id = $map['new_id'];
|
511 |
+
|
512 |
+
$this->mapping['user'][ $old_id ] = $new_id;
|
513 |
+
$this->mapping['user_slug'][ $old_slug ] = $new_id;
|
514 |
+
}
|
515 |
+
}
|
516 |
+
|
517 |
+
/**
|
518 |
+
* Set the user slug overrides.
|
519 |
+
*
|
520 |
+
* Allows overriding the slug in the import with a custom/renamed version.
|
521 |
+
*
|
522 |
+
* @param string[] $overrides Map of old slug to new slug.
|
523 |
+
*/
|
524 |
+
public function set_user_slug_overrides( $overrides ) {
|
525 |
+
foreach ( $overrides as $original => $renamed ) {
|
526 |
+
$this->user_slug_override[ $original ] = $renamed;
|
527 |
+
}
|
528 |
+
}
|
529 |
+
|
530 |
+
/**
|
531 |
+
* Parse a post node into post data.
|
532 |
+
*
|
533 |
+
* @param DOMElement $node Parent node of post data (typically `item`).
|
534 |
+
* @return array|WP_Error Post data array on success, error otherwise.
|
535 |
+
*/
|
536 |
+
protected function parse_post_node( $node ) {
|
537 |
+
$data = array();
|
538 |
+
$meta = array();
|
539 |
+
$comments = array();
|
540 |
+
$terms = array();
|
541 |
+
|
542 |
+
foreach ( $node->childNodes as $child ) {
|
543 |
+
// We only care about child elements
|
544 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
545 |
+
continue;
|
546 |
+
}
|
547 |
+
|
548 |
+
switch ( $child->tagName ) {
|
549 |
+
case 'wp:post_type':
|
550 |
+
$data['post_type'] = $child->textContent;
|
551 |
+
break;
|
552 |
+
|
553 |
+
case 'title':
|
554 |
+
$data['post_title'] = $child->textContent;
|
555 |
+
break;
|
556 |
+
|
557 |
+
case 'guid':
|
558 |
+
$data['guid'] = $child->textContent;
|
559 |
+
break;
|
560 |
+
|
561 |
+
case 'dc:creator':
|
562 |
+
$data['post_author'] = $child->textContent;
|
563 |
+
break;
|
564 |
+
|
565 |
+
case 'content:encoded':
|
566 |
+
$data['post_content'] = $child->textContent;
|
567 |
+
break;
|
568 |
+
|
569 |
+
case 'excerpt:encoded':
|
570 |
+
$data['post_excerpt'] = $child->textContent;
|
571 |
+
break;
|
572 |
+
|
573 |
+
case 'wp:post_id':
|
574 |
+
$data['post_id'] = $child->textContent;
|
575 |
+
break;
|
576 |
+
|
577 |
+
case 'wp:post_date':
|
578 |
+
$data['post_date'] = $child->textContent;
|
579 |
+
break;
|
580 |
+
|
581 |
+
case 'wp:post_date_gmt':
|
582 |
+
$data['post_date_gmt'] = $child->textContent;
|
583 |
+
break;
|
584 |
+
|
585 |
+
case 'wp:comment_status':
|
586 |
+
$data['comment_status'] = $child->textContent;
|
587 |
+
break;
|
588 |
+
|
589 |
+
case 'wp:ping_status':
|
590 |
+
$data['ping_status'] = $child->textContent;
|
591 |
+
break;
|
592 |
+
|
593 |
+
case 'wp:post_name':
|
594 |
+
$data['post_name'] = $child->textContent;
|
595 |
+
break;
|
596 |
+
|
597 |
+
case 'wp:status':
|
598 |
+
$data['post_status'] = $child->textContent;
|
599 |
+
|
600 |
+
if ( $data['post_status'] === 'auto-draft' ) {
|
601 |
+
// Bail now
|
602 |
+
return new WP_Error(
|
603 |
+
'wxr_importer.post.cannot_import_draft',
|
604 |
+
__( 'Cannot import auto-draft posts', 'jupiterx-core' ),
|
605 |
+
$data
|
606 |
+
);
|
607 |
+
}
|
608 |
+
break;
|
609 |
+
|
610 |
+
case 'wp:post_parent':
|
611 |
+
$data['post_parent'] = $child->textContent;
|
612 |
+
break;
|
613 |
+
|
614 |
+
case 'wp:menu_order':
|
615 |
+
$data['menu_order'] = $child->textContent;
|
616 |
+
break;
|
617 |
+
|
618 |
+
case 'wp:post_password':
|
619 |
+
$data['post_password'] = $child->textContent;
|
620 |
+
break;
|
621 |
+
|
622 |
+
case 'wp:is_sticky':
|
623 |
+
$data['is_sticky'] = $child->textContent;
|
624 |
+
break;
|
625 |
+
|
626 |
+
case 'wp:attachment_url':
|
627 |
+
$data['attachment_url'] = $child->textContent;
|
628 |
+
break;
|
629 |
+
|
630 |
+
case 'wp:postmeta':
|
631 |
+
$meta_item = $this->parse_meta_node( $child );
|
632 |
+
if ( ! empty( $meta_item ) ) {
|
633 |
+
$meta[] = $meta_item;
|
634 |
+
}
|
635 |
+
break;
|
636 |
+
|
637 |
+
case 'wp:comment':
|
638 |
+
$comment_item = $this->parse_comment_node( $child );
|
639 |
+
if ( ! empty( $comment_item ) ) {
|
640 |
+
$comments[] = $comment_item;
|
641 |
+
}
|
642 |
+
break;
|
643 |
+
|
644 |
+
case 'category':
|
645 |
+
$term_item = $this->parse_category_node( $child );
|
646 |
+
if ( ! empty( $term_item ) ) {
|
647 |
+
$terms[] = $term_item;
|
648 |
+
}
|
649 |
+
break;
|
650 |
+
}
|
651 |
+
}
|
652 |
+
|
653 |
+
return compact( 'data', 'meta', 'comments', 'terms' );
|
654 |
+
}
|
655 |
+
|
656 |
+
/**
|
657 |
+
* Create new posts based on import information
|
658 |
+
*
|
659 |
+
* Posts marked as having a parent which doesn't exist will become top level items.
|
660 |
+
* Doesn't create a new post if: the post type doesn't exist, the given post ID
|
661 |
+
* is already noted as imported or a post with the same title and date already exists.
|
662 |
+
* Note that new/updated terms, comments and meta are imported for the last of the above.
|
663 |
+
*/
|
664 |
+
protected function process_post( $data, $meta, $comments, $terms ) {
|
665 |
+
/**
|
666 |
+
* Pre-process post data.
|
667 |
+
*
|
668 |
+
* @param array $data Post data. (Return empty to skip.)
|
669 |
+
* @param array $meta Meta data.
|
670 |
+
* @param array $comments Comments on the post.
|
671 |
+
* @param array $terms Terms on the post.
|
672 |
+
*/
|
673 |
+
$data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
|
674 |
+
if ( empty( $data ) ) {
|
675 |
+
return false;
|
676 |
+
}
|
677 |
+
|
678 |
+
$original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
|
679 |
+
$parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
|
680 |
+
$author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
|
681 |
+
|
682 |
+
// Have we already processed this?
|
683 |
+
if ( isset( $this->mapping['post'][ $original_id ] ) ) {
|
684 |
+
return;
|
685 |
+
}
|
686 |
+
|
687 |
+
$post_type_object = get_post_type_object( $data['post_type'] );
|
688 |
+
|
689 |
+
// Is this type even valid?
|
690 |
+
if ( ! $post_type_object ) {
|
691 |
+
$this->logger->warning( sprintf(
|
692 |
+
__( 'Failed to import "%s": Invalid post type %s', 'jupiterx-core' ),
|
693 |
+
$data['post_title'],
|
694 |
+
$data['post_type']
|
695 |
+
) );
|
696 |
+
return false;
|
697 |
+
}
|
698 |
+
|
699 |
+
$post_exists = $this->post_exists( $data ) && ! $this->partial_import; // allow post duplication on partial import
|
700 |
+
if ( $post_exists ) {
|
701 |
+
$this->logger->info( sprintf(
|
702 |
+
__( '%s "%s" already exists.', 'jupiterx-core' ),
|
703 |
+
$post_type_object->labels->singular_name,
|
704 |
+
$data['post_title']
|
705 |
+
) );
|
706 |
+
|
707 |
+
/**
|
708 |
+
* Post processing already imported.
|
709 |
+
*
|
710 |
+
* @param array $data Raw data imported for the post.
|
711 |
+
*/
|
712 |
+
do_action( 'wxr_importer.process_already_imported.post', $data );
|
713 |
+
|
714 |
+
// Even though this post already exists, new comments might need importing
|
715 |
+
$this->process_comments( $comments, $original_id, $data, $post_exists );
|
716 |
+
|
717 |
+
return false;
|
718 |
+
}
|
719 |
+
|
720 |
+
// Map the parent post, or mark it as one we need to fix
|
721 |
+
$requires_remapping = false;
|
722 |
+
if ( $parent_id ) {
|
723 |
+
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
724 |
+
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
725 |
+
} else {
|
726 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
727 |
+
$requires_remapping = true;
|
728 |
+
|
729 |
+
$data['post_parent'] = 0;
|
730 |
+
}
|
731 |
+
}
|
732 |
+
|
733 |
+
// Map the author, or mark it as one we need to fix
|
734 |
+
$author = sanitize_user( $data['post_author'], true );
|
735 |
+
if ( empty( $author ) ) {
|
736 |
+
// Missing or invalid author, use default if available.
|
737 |
+
$data['post_author'] = $this->options['default_author'];
|
738 |
+
} elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
|
739 |
+
$data['post_author'] = $this->mapping['user_slug'][ $author ];
|
740 |
+
} else {
|
741 |
+
$meta[] = array( 'key' => '_wxr_import_user_slug', 'value' => $author );
|
742 |
+
$requires_remapping = true;
|
743 |
+
|
744 |
+
$data['post_author'] = (int) get_current_user_id();
|
745 |
+
}
|
746 |
+
|
747 |
+
// Does the post look like it contains attachment images?
|
748 |
+
if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
|
749 |
+
$meta[] = array( 'key' => '_wxr_import_has_attachment_refs', 'value' => true );
|
750 |
+
$requires_remapping = true;
|
751 |
+
}
|
752 |
+
|
753 |
+
// Whitelist to just the keys we allow
|
754 |
+
$postdata = array(
|
755 |
+
'import_id' => $data['post_id'],
|
756 |
+
);
|
757 |
+
$allowed = array(
|
758 |
+
'post_author' => true,
|
759 |
+
'post_date' => true,
|
760 |
+
'post_date_gmt' => true,
|
761 |
+
'post_content' => true,
|
762 |
+
'post_excerpt' => true,
|
763 |
+
'post_title' => true,
|
764 |
+
'post_status' => true,
|
765 |
+
'post_name' => true,
|
766 |
+
'comment_status' => true,
|
767 |
+
'ping_status' => true,
|
768 |
+
'guid' => true,
|
769 |
+
'post_parent' => true,
|
770 |
+
'menu_order' => true,
|
771 |
+
'post_type' => true,
|
772 |
+
'post_password' => true,
|
773 |
+
);
|
774 |
+
foreach ( $data as $key => $value ) {
|
775 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
776 |
+
continue;
|
777 |
+
}
|
778 |
+
|
779 |
+
$postdata[ $key ] = $data[ $key ];
|
780 |
+
}
|
781 |
+
|
782 |
+
$postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
|
783 |
+
|
784 |
+
if ( 'attachment' === $postdata['post_type'] ) {
|
785 |
+
if ( ! $this->options['fetch_attachments'] ) {
|
786 |
+
$this->logger->notice( sprintf(
|
787 |
+
__( 'Skipping attachment "%s", fetching attachments disabled', 'jupiterx-core' ),
|
788 |
+
$data['post_title']
|
789 |
+
) );
|
790 |
+
/**
|
791 |
+
* Post processing skipped.
|
792 |
+
*
|
793 |
+
* @param array $data Raw data imported for the post.
|
794 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
795 |
+
*/
|
796 |
+
do_action( 'wxr_importer.process_skipped.post', $data, $meta );
|
797 |
+
return false;
|
798 |
+
}
|
799 |
+
$remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
|
800 |
+
$post_id = $this->process_attachment( $postdata, $meta, $remote_url );
|
801 |
+
} else {
|
802 |
+
$post_id = wp_insert_post( $postdata, true );
|
803 |
+
do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
|
804 |
+
}
|
805 |
+
|
806 |
+
if ( is_wp_error( $post_id ) ) {
|
807 |
+
$this->logger->error( sprintf(
|
808 |
+
__( 'Failed to import "%s" (%s)', 'jupiterx-core' ),
|
809 |
+
$data['post_title'],
|
810 |
+
$post_type_object->labels->singular_name
|
811 |
+
) );
|
812 |
+
$this->logger->debug( $post_id->get_error_message() );
|
813 |
+
|
814 |
+
/**
|
815 |
+
* Post processing failed.
|
816 |
+
*
|
817 |
+
* @param WP_Error $post_id Error object.
|
818 |
+
* @param array $data Raw data imported for the post.
|
819 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
820 |
+
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
821 |
+
* @param array $terms Raw term data, already processed.
|
822 |
+
*/
|
823 |
+
do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
|
824 |
+
return false;
|
825 |
+
}
|
826 |
+
|
827 |
+
// Ensure stickiness is handled correctly too
|
828 |
+
if ( $data['is_sticky'] === '1' ) {
|
829 |
+
stick_post( $post_id );
|
830 |
+
}
|
831 |
+
|
832 |
+
// map pre-import ID to local ID
|
833 |
+
$this->mapping['post'][ $original_id ] = (int) $post_id;
|
834 |
+
if ( $requires_remapping ) {
|
835 |
+
$this->requires_remapping['post'][ $post_id ] = true;
|
836 |
+
}
|
837 |
+
$this->mark_post_exists( $data, $post_id );
|
838 |
+
|
839 |
+
$this->logger->info( sprintf(
|
840 |
+
__( 'Imported "%s" (%s)', 'jupiterx-core' ),
|
841 |
+
$data['post_title'],
|
842 |
+
$post_type_object->labels->singular_name
|
843 |
+
) );
|
844 |
+
$this->logger->debug( sprintf(
|
845 |
+
__( 'Post %d remapped to %d', 'jupiterx-core' ),
|
846 |
+
$original_id,
|
847 |
+
$post_id
|
848 |
+
) );
|
849 |
+
|
850 |
+
// Handle the terms too
|
851 |
+
$terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
|
852 |
+
|
853 |
+
if ( ! empty( $terms ) ) {
|
854 |
+
$term_ids = array();
|
855 |
+
foreach ( $terms as $term ) {
|
856 |
+
$taxonomy = $term['taxonomy'];
|
857 |
+
$key = sha1( $taxonomy . ':' . $term['slug'] );
|
858 |
+
|
859 |
+
if ( isset( $this->mapping['term'][ $key ] ) ) {
|
860 |
+
$term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
|
861 |
+
} else {
|
862 |
+
$meta[] = array( 'key' => '_wxr_import_term', 'value' => $term );
|
863 |
+
$requires_remapping = true;
|
864 |
+
}
|
865 |
+
}
|
866 |
+
|
867 |
+
foreach ( $term_ids as $tax => $ids ) {
|
868 |
+
$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
|
869 |
+
do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
|
870 |
+
}
|
871 |
+
}
|
872 |
+
|
873 |
+
$this->process_comments( $comments, $post_id, $data );
|
874 |
+
$this->process_post_meta( $meta, $post_id, $data );
|
875 |
+
|
876 |
+
if ( 'nav_menu_item' === $data['post_type'] ) {
|
877 |
+
$this->process_menu_item_meta( $post_id, $data, $meta );
|
878 |
+
}
|
879 |
+
|
880 |
+
/**
|
881 |
+
* Post processing completed.
|
882 |
+
*
|
883 |
+
* @param int $post_id New post ID.
|
884 |
+
* @param array $data Raw data imported for the post.
|
885 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
886 |
+
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
887 |
+
* @param array $terms Raw term data, already processed.
|
888 |
+
*/
|
889 |
+
do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
|
890 |
+
}
|
891 |
+
|
892 |
+
/**
|
893 |
+
* Attempt to create a new menu item from import data
|
894 |
+
*
|
895 |
+
* Fails for draft, orphaned menu items and those without an associated nav_menu
|
896 |
+
* or an invalid nav_menu term. If the post type or term object which the menu item
|
897 |
+
* represents doesn't exist then the menu item will not be imported (waits until the
|
898 |
+
* end of the import to retry again before discarding).
|
899 |
+
*
|
900 |
+
* @param array $item Menu item details from WXR file
|
901 |
+
*/
|
902 |
+
protected function process_menu_item_meta( $post_id, $data, $meta ) {
|
903 |
+
|
904 |
+
$item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
905 |
+
$original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
|
906 |
+
$object_id = null;
|
907 |
+
|
908 |
+
$this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
|
909 |
+
|
910 |
+
$requires_remapping = false;
|
911 |
+
switch ( $item_type ) {
|
912 |
+
case 'taxonomy':
|
913 |
+
if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
|
914 |
+
$object_id = $this->mapping['term_id'][ $original_object_id ];
|
915 |
+
} else {
|
916 |
+
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
917 |
+
$requires_remapping = true;
|
918 |
+
}
|
919 |
+
break;
|
920 |
+
|
921 |
+
case 'post_type':
|
922 |
+
if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
|
923 |
+
$object_id = $this->mapping['post'][ $original_object_id ];
|
924 |
+
} else {
|
925 |
+
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
926 |
+
$requires_remapping = true;
|
927 |
+
}
|
928 |
+
break;
|
929 |
+
|
930 |
+
case 'custom':
|
931 |
+
// Custom refers to itself, wonderfully easy.
|
932 |
+
$object_id = $post_id;
|
933 |
+
break;
|
934 |
+
|
935 |
+
default:
|
936 |
+
// associated object is missing or not imported yet, we'll retry later
|
937 |
+
$this->missing_menu_items[] = $item;
|
938 |
+
$this->logger->debug( 'Unknown menu item type' );
|
939 |
+
break;
|
940 |
+
}
|
941 |
+
|
942 |
+
if ( $requires_remapping ) {
|
943 |
+
$this->requires_remapping['post'][ $post_id ] = true;
|
944 |
+
}
|
945 |
+
|
946 |
+
if ( empty( $object_id ) ) {
|
947 |
+
// Nothing needed here.
|
948 |
+
return;
|
949 |
+
}
|
950 |
+
|
951 |
+
$this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
|
952 |
+
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
|
953 |
+
}
|
954 |
+
|
955 |
+
/**
|
956 |
+
* If fetching attachments is enabled then attempt to create a new attachment
|
957 |
+
*
|
958 |
+
* @param array $post Attachment post details from WXR
|
959 |
+
* @param string $url URL to fetch attachment from
|
960 |
+
* @return int|WP_Error Post ID on success, WP_Error otherwise
|
961 |
+
*/
|
962 |
+
protected function process_attachment( $post, $meta, $remote_url ) {
|
963 |
+
// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
|
964 |
+
// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
|
965 |
+
$post['upload_date'] = $post['post_date'];
|
966 |
+
foreach ( $meta as $meta_item ) {
|
967 |
+
if ( $meta_item['key'] !== '_wp_attached_file' ) {
|
968 |
+
continue;
|
969 |
+
}
|
970 |
+
|
971 |
+
if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
|
972 |
+
$post['upload_date'] = $matches[0];
|
973 |
+
}
|
974 |
+
break;
|
975 |
+
}
|
976 |
+
|
977 |
+
// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
|
978 |
+
if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
|
979 |
+
$remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
|
980 |
+
}
|
981 |
+
|
982 |
+
$upload = $this->fetch_remote_file( $remote_url, $post );
|
983 |
+
if ( is_wp_error( $upload ) ) {
|
984 |
+
return $upload;
|
985 |
+
}
|
986 |
+
|
987 |
+
$info = wp_check_filetype( $upload['file'] );
|
988 |
+
if ( ! $info ) {
|
989 |
+
return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'jupiterx-core' ) );
|
990 |
+
}
|
991 |
+
|
992 |
+
$post['post_mime_type'] = $info['type'];
|
993 |
+
|
994 |
+
// WP really likes using the GUID for display. Allow updating it.
|
995 |
+
// See https://core.trac.wordpress.org/ticket/33386
|
996 |
+
if ( $this->options['update_attachment_guids'] ) {
|
997 |
+
$post['guid'] = $upload['url'];
|
998 |
+
}
|
999 |
+
|
1000 |
+
// as per wp-admin/includes/upload.php
|
1001 |
+
$post_id = wp_insert_attachment( $post, $upload['file'] );
|
1002 |
+
if ( is_wp_error( $post_id ) ) {
|
1003 |
+
return $post_id;
|
1004 |
+
}
|
1005 |
+
|
1006 |
+
$attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
|
1007 |
+
wp_update_attachment_metadata( $post_id, $attachment_metadata );
|
1008 |
+
|
1009 |
+
// Map this image URL later if we need to
|
1010 |
+
$this->url_remap[ $remote_url ] = $upload['url'];
|
1011 |
+
|
1012 |
+
// If we have a HTTPS URL, ensure the HTTP URL gets replaced too
|
1013 |
+
if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
|
1014 |
+
$insecure_url = 'http' . substr( $remote_url, 5 );
|
1015 |
+
$this->url_remap[ $insecure_url ] = $upload['url'];
|
1016 |
+
}
|
1017 |
+
|
1018 |
+
if ( $this->options['aggressive_url_search'] ) {
|
1019 |
+
// remap resized image URLs, works by stripping the extension and remapping the URL stub.
|
1020 |
+
/*if ( preg_match( '!^image/!', $info['type'] ) ) {
|
1021 |
+
$parts = pathinfo( $remote_url );
|
1022 |
+
$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
|
1023 |
+
|
1024 |
+
$parts_new = pathinfo( $upload['url'] );
|
1025 |
+
$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
|
1026 |
+
|
1027 |
+
$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
|
1028 |
+
}*/
|
1029 |
+
}
|
1030 |
+
|
1031 |
+
return $post_id;
|
1032 |
+
}
|
1033 |
+
|
1034 |
+
/**
|
1035 |
+
* Parse a meta node into meta data.
|
1036 |
+
*
|
1037 |
+
* @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
|
1038 |
+
* @return array|null Meta data array on success, or null on error.
|
1039 |
+
*/
|
1040 |
+
protected function parse_meta_node( $node ) {
|
1041 |
+
foreach ( $node->childNodes as $child ) {
|
1042 |
+
// We only care about child elements
|
1043 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1044 |
+
continue;
|
1045 |
+
}
|
1046 |
+
|
1047 |
+
switch ( $child->tagName ) {
|
1048 |
+
case 'wp:meta_key':
|
1049 |
+
$key = $child->textContent;
|
1050 |
+
break;
|
1051 |
+
|
1052 |
+
case 'wp:meta_value':
|
1053 |
+
$value = $child->textContent;
|
1054 |
+
break;
|
1055 |
+
}
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
if ( empty( $key ) ) {
|
1059 |
+
return null;
|
1060 |
+
}
|
1061 |
+
|
1062 |
+
return compact( 'key', 'value' );
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
/**
|
1066 |
+
* Process and import post meta items.
|
1067 |
+
*
|
1068 |
+
* @param array $meta List of meta data arrays
|
1069 |
+
* @param int $post_id Post to associate with
|
1070 |
+
* @param array $post Post data
|
1071 |
+
* @return int|WP_Error Number of meta items imported on success, error otherwise.
|
1072 |
+
*/
|
1073 |
+
protected function process_post_meta( $meta, $post_id, $post ) {
|
1074 |
+
if ( empty( $meta ) ) {
|
1075 |
+
return true;
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
foreach ( $meta as $meta_item ) {
|
1079 |
+
/**
|
1080 |
+
* Pre-process post meta data.
|
1081 |
+
*
|
1082 |
+
* @param array $meta_item Meta data. (Return empty to skip.)
|
1083 |
+
* @param int $post_id Post the meta is attached to.
|
1084 |
+
*/
|
1085 |
+
$meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
|
1086 |
+
if ( empty( $meta_item ) ) {
|
1087 |
+
return false;
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
$key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
|
1091 |
+
$value = false;
|
1092 |
+
|
1093 |
+
if ( '_edit_last' === $key ) {
|
1094 |
+
$value = intval( $meta_item['value'] );
|
1095 |
+
if ( ! isset( $this->mapping['user'][ $value ] ) ) {
|
1096 |
+
// Skip!
|
1097 |
+
continue;
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
$value = $this->mapping['user'][ $value ];
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
if ( $key ) {
|
1104 |
+
// export gets meta straight from the DB so could have a serialized string
|
1105 |
+
if ( ! $value ) {
|
1106 |
+
$value = maybe_unserialize( $meta_item['value'] );
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
add_post_meta( $post_id, $key, $value );
|
1110 |
+
do_action( 'import_post_meta', $post_id, $key, $value );
|
1111 |
+
|
1112 |
+
// if the post has a featured image, take note of this in case of remap
|
1113 |
+
if ( '_thumbnail_id' === $key ) {
|
1114 |
+
$this->featured_images[ $post_id ] = (int) $value;
|
1115 |
+
}
|
1116 |
+
}
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
return true;
|
1120 |
+
}
|
1121 |
+
|
1122 |
+
/**
|
1123 |
+
* Parse a comment node into comment data.
|
1124 |
+
*
|
1125 |
+
* @param DOMElement $node Parent node of comment data (typically `wp:comment`).
|
1126 |
+
* @return array Comment data array.
|
1127 |
+
*/
|
1128 |
+
protected function parse_comment_node( $node ) {
|
1129 |
+
$data = array(
|
1130 |
+
'commentmeta' => array(),
|
1131 |
+
);
|
1132 |
+
|
1133 |
+
foreach ( $node->childNodes as $child ) {
|
1134 |
+
// We only care about child elements
|
1135 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1136 |
+
continue;
|
1137 |
+
}
|
1138 |
+
|
1139 |
+
switch ( $child->tagName ) {
|
1140 |
+
case 'wp:comment_id':
|
1141 |
+
$data['comment_id'] = $child->textContent;
|
1142 |
+
break;
|
1143 |
+
case 'wp:comment_author':
|
1144 |
+
$data['comment_author'] = $child->textContent;
|
1145 |
+
break;
|
1146 |
+
|
1147 |
+
case 'wp:comment_author_email':
|
1148 |
+
$data['comment_author_email'] = $child->textContent;
|
1149 |
+
break;
|
1150 |
+
|
1151 |
+
case 'wp:comment_author_IP':
|
1152 |
+
$data['comment_author_IP'] = $child->textContent;
|
1153 |
+
break;
|
1154 |
+
|
1155 |
+
case 'wp:comment_author_url':
|
1156 |
+
$data['comment_author_url'] = $child->textContent;
|
1157 |
+
break;
|
1158 |
+
|
1159 |
+
case 'wp:comment_user_id':
|
1160 |
+
$data['comment_user_id'] = $child->textContent;
|
1161 |
+
break;
|
1162 |
+
|
1163 |
+
case 'wp:comment_date':
|
1164 |
+
$data['comment_date'] = $child->textContent;
|
1165 |
+
break;
|
1166 |
+
|
1167 |
+
case 'wp:comment_date_gmt':
|
1168 |
+
$data['comment_date_gmt'] = $child->textContent;
|
1169 |
+
break;
|
1170 |
+
|
1171 |
+
case 'wp:comment_content':
|
1172 |
+
$data['comment_content'] = $child->textContent;
|
1173 |
+
break;
|
1174 |
+
|
1175 |
+
case 'wp:comment_approved':
|
1176 |
+
$data['comment_approved'] = $child->textContent;
|
1177 |
+
break;
|
1178 |
+
|
1179 |
+
case 'wp:comment_type':
|
1180 |
+
$data['comment_type'] = $child->textContent;
|
1181 |
+
break;
|
1182 |
+
|
1183 |
+
case 'wp:comment_parent':
|
1184 |
+
$data['comment_parent'] = $child->textContent;
|
1185 |
+
break;
|
1186 |
+
|
1187 |
+
case 'wp:commentmeta':
|
1188 |
+
$meta_item = $this->parse_meta_node( $child );
|
1189 |
+
if ( ! empty( $meta_item ) ) {
|
1190 |
+
$data['commentmeta'][] = $meta_item;
|
1191 |
+
}
|
1192 |
+
break;
|
1193 |
+
}
|
1194 |
+
}
|
1195 |
+
|
1196 |
+
return $data;
|
1197 |
+
}
|
1198 |
+
|
1199 |
+
/**
|
1200 |
+
* Process and import comment data.
|
1201 |
+
*
|
1202 |
+
* @param array $comments List of comment data arrays.
|
1203 |
+
* @param int $post_id Post to associate with.
|
1204 |
+
* @param array $post Post data.
|
1205 |
+
* @return int|WP_Error Number of comments imported on success, error otherwise.
|
1206 |
+
*/
|
1207 |
+
protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
|
1208 |
+
|
1209 |
+
$comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
|
1210 |
+
if ( empty( $comments ) ) {
|
1211 |
+
return 0;
|
1212 |
+
}
|
1213 |
+
|
1214 |
+
$num_comments = 0;
|
1215 |
+
|
1216 |
+
// Sort by ID to avoid excessive remapping later
|
1217 |
+
usort( $comments, array( $this, 'sort_comments_by_id' ) );
|
1218 |
+
|
1219 |
+
foreach ( $comments as $key => $comment ) {
|
1220 |
+
/**
|
1221 |
+
* Pre-process comment data
|
1222 |
+
*
|
1223 |
+
* @param array $comment Comment data. (Return empty to skip.)
|
1224 |
+
* @param int $post_id Post the comment is attached to.
|
1225 |
+
*/
|
1226 |
+
$comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
|
1227 |
+
if ( empty( $comment ) ) {
|
1228 |
+
return false;
|
1229 |
+
}
|
1230 |
+
|
1231 |
+
$original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
|
1232 |
+
$parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
|
1233 |
+
$author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
|
1234 |
+
|
1235 |
+
// if this is a new post we can skip the comment_exists() check
|
1236 |
+
// TODO: Check comment_exists for performance
|
1237 |
+
if ( $post_exists ) {
|
1238 |
+
$existing = $this->comment_exists( $comment );
|
1239 |
+
if ( $existing ) {
|
1240 |
+
|
1241 |
+
/**
|
1242 |
+
* Comment processing already imported.
|
1243 |
+
*
|
1244 |
+
* @param array $comment Raw data imported for the comment.
|
1245 |
+
*/
|
1246 |
+
do_action( 'wxr_importer.process_already_imported.comment', $comment );
|
1247 |
+
|
1248 |
+
$this->mapping['comment'][ $original_id ] = $existing;
|
1249 |
+
continue;
|
1250 |
+
}
|
1251 |
+
}
|
1252 |
+
|
1253 |
+
// Remove meta from the main array
|
1254 |
+
$meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
|
1255 |
+
unset( $comment['commentmeta'] );
|
1256 |
+
|
1257 |
+
// Map the parent comment, or mark it as one we need to fix
|
1258 |
+
$requires_remapping = false;
|
1259 |
+
if ( $parent_id ) {
|
1260 |
+
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1261 |
+
$comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1262 |
+
} else {
|
1263 |
+
// Prepare for remapping later
|
1264 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1265 |
+
$requires_remapping = true;
|
1266 |
+
|
1267 |
+
// Wipe the parent for now
|
1268 |
+
$comment['comment_parent'] = 0;
|
1269 |
+
}
|
1270 |
+
}
|
1271 |
+
|
1272 |
+
// Map the author, or mark it as one we need to fix
|
1273 |
+
if ( $author_id ) {
|
1274 |
+
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1275 |
+
$comment['user_id'] = $this->mapping['user'][ $author_id ];
|
1276 |
+
} else {
|
1277 |
+
// Prepare for remapping later
|
1278 |
+
$meta[] = array( 'key' => '_wxr_import_user', 'value' => $author_id );
|
1279 |
+
$requires_remapping = true;
|
1280 |
+
|
1281 |
+
// Wipe the user for now
|
1282 |
+
$comment['user_id'] = 0;
|
1283 |
+
}
|
1284 |
+
}
|
1285 |
+
|
1286 |
+
// Run standard core filters
|
1287 |
+
$comment['comment_post_ID'] = $post_id;
|
1288 |
+
$comment = wp_filter_comment( $comment );
|
1289 |
+
|
1290 |
+
// wp_insert_comment expects slashed data
|
1291 |
+
$comment_id = wp_insert_comment( wp_slash( $comment ) );
|
1292 |
+
$this->mapping['comment'][ $original_id ] = $comment_id;
|
1293 |
+
if ( $requires_remapping ) {
|
1294 |
+
$this->requires_remapping['comment'][ $comment_id ] = true;
|
1295 |
+
}
|
1296 |
+
$this->mark_comment_exists( $comment, $comment_id );
|
1297 |
+
|
1298 |
+
/**
|
1299 |
+
* Comment has been imported.
|
1300 |
+
*
|
1301 |
+
* @param int $comment_id New comment ID
|
1302 |
+
* @param array $comment Comment inserted (`comment_id` item refers to the original ID)
|
1303 |
+
* @param int $post_id Post parent of the comment
|
1304 |
+
* @param array $post Post data
|
1305 |
+
*/
|
1306 |
+
do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
|
1307 |
+
|
1308 |
+
// Process the meta items
|
1309 |
+
foreach ( $meta as $meta_item ) {
|
1310 |
+
$value = maybe_unserialize( $meta_item['value'] );
|
1311 |
+
add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
|
1312 |
+
}
|
1313 |
+
|
1314 |
+
/**
|
1315 |
+
* Post processing completed.
|
1316 |
+
*
|
1317 |
+
* @param int $post_id New post ID.
|
1318 |
+
* @param array $comment Raw data imported for the comment.
|
1319 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
1320 |
+
* @param array $post_id Parent post ID.
|
1321 |
+
*/
|
1322 |
+
do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
|
1323 |
+
|
1324 |
+
$num_comments++;
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
return $num_comments;
|
1328 |
+
}
|
1329 |
+
|
1330 |
+
protected function parse_category_node( $node ) {
|
1331 |
+
$data = array(
|
1332 |
+
// Default taxonomy to "category", since this is a `<category>` tag
|
1333 |
+
'taxonomy' => 'category',
|
1334 |
+
);
|
1335 |
+
$meta = array();
|
1336 |
+
|
1337 |
+
if ( $node->hasAttribute( 'domain' ) ) {
|
1338 |
+
$data['taxonomy'] = $node->getAttribute( 'domain' );
|
1339 |
+
}
|
1340 |
+
if ( $node->hasAttribute( 'nicename' ) ) {
|
1341 |
+
$data['slug'] = $node->getAttribute( 'nicename' );
|
1342 |
+
}
|
1343 |
+
|
1344 |
+
$data['name'] = $node->textContent;
|
1345 |
+
|
1346 |
+
if ( empty( $data['slug'] ) ) {
|
1347 |
+
return null;
|
1348 |
+
}
|
1349 |
+
|
1350 |
+
// Just for extra compatibility
|
1351 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
1352 |
+
$data['taxonomy'] = 'post_tag';
|
1353 |
+
}
|
1354 |
+
|
1355 |
+
return $data;
|
1356 |
+
}
|
1357 |
+
|
1358 |
+
/**
|
1359 |
+
* Callback for `usort` to sort comments by ID
|
1360 |
+
*
|
1361 |
+
* @param array $a Comment data for the first comment
|
1362 |
+
* @param array $b Comment data for the second comment
|
1363 |
+
* @return int
|
1364 |
+
*/
|
1365 |
+
public static function sort_comments_by_id( $a, $b ) {
|
1366 |
+
if ( empty( $a['comment_id'] ) ) {
|
1367 |
+
return 1;
|
1368 |
+
}
|
1369 |
+
|
1370 |
+
if ( empty( $b['comment_id'] ) ) {
|
1371 |
+
return -1;
|
1372 |
+
}
|
1373 |
+
|
1374 |
+
return $a['comment_id'] - $b['comment_id'];
|
1375 |
+
}
|
1376 |
+
|
1377 |
+
protected function parse_term_node( $node, $type = 'term' ) {
|
1378 |
+
$data = array();
|
1379 |
+
$meta = array();
|
1380 |
+
|
1381 |
+
$tag_name = array(
|
1382 |
+
'id' => 'wp:term_id',
|
1383 |
+
'taxonomy' => 'wp:term_taxonomy',
|
1384 |
+
'slug' => 'wp:term_slug',
|
1385 |
+
'parent' => 'wp:term_parent',
|
1386 |
+
'name' => 'wp:term_name',
|
1387 |
+
'description' => 'wp:term_description',
|
1388 |
+
);
|
1389 |
+
$taxonomy = null;
|
1390 |
+
|
1391 |
+
// Special casing!
|
1392 |
+
switch ( $type ) {
|
1393 |
+
case 'category':
|
1394 |
+
$tag_name['slug'] = 'wp:category_nicename';
|
1395 |
+
$tag_name['parent'] = 'wp:category_parent';
|
1396 |
+
$tag_name['name'] = 'wp:cat_name';
|
1397 |
+
$tag_name['description'] = 'wp:category_description';
|
1398 |
+
$tag_name['taxonomy'] = null;
|
1399 |
+
|
1400 |
+
$data['taxonomy'] = 'category';
|
1401 |
+
break;
|
1402 |
+
|
1403 |
+
case 'tag':
|
1404 |
+
$tag_name['slug'] = 'wp:tag_slug';
|
1405 |
+
$tag_name['parent'] = null;
|
1406 |
+
$tag_name['name'] = 'wp:tag_name';
|
1407 |
+
$tag_name['description'] = 'wp:tag_description';
|
1408 |
+
$tag_name['taxonomy'] = null;
|
1409 |
+
|
1410 |
+
$data['taxonomy'] = 'post_tag';
|
1411 |
+
break;
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
foreach ( $node->childNodes as $child ) {
|
1415 |
+
// We only care about child elements
|
1416 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1417 |
+
continue;
|
1418 |
+
}
|
1419 |
+
|
1420 |
+
$key = array_search( $child->tagName, $tag_name );
|
1421 |
+
if ( $key ) {
|
1422 |
+
$data[ $key ] = $child->textContent;
|
1423 |
+
}
|
1424 |
+
}
|
1425 |
+
|
1426 |
+
if ( empty( $data['taxonomy'] ) ) {
|
1427 |
+
return null;
|
1428 |
+
}
|
1429 |
+
|
1430 |
+
// Compatibility with WXR 1.0
|
1431 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
1432 |
+
$data['taxonomy'] = 'post_tag';
|
1433 |
+
}
|
1434 |
+
|
1435 |
+
return compact( 'data', 'meta' );
|
1436 |
+
}
|
1437 |
+
|
1438 |
+
protected function process_term( $data, $meta ) {
|
1439 |
+
/**
|
1440 |
+
* Pre-process term data.
|
1441 |
+
*
|
1442 |
+
* @param array $data Term data. (Return empty to skip.)
|
1443 |
+
* @param array $meta Meta data.
|
1444 |
+
*/
|
1445 |
+
$data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
|
1446 |
+
if ( empty( $data ) ) {
|
1447 |
+
return false;
|
1448 |
+
}
|
1449 |
+
|
1450 |
+
$original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
|
1451 |
+
$parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
|
1452 |
+
|
1453 |
+
$mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
1454 |
+
$existing = $this->term_exists( $data );
|
1455 |
+
if ( $existing ) {
|
1456 |
+
|
1457 |
+
/**
|
1458 |
+
* Term processing already imported.
|
1459 |
+
*
|
1460 |
+
* @param array $data Raw data imported for the term.
|
1461 |
+
*/
|
1462 |
+
do_action( 'wxr_importer.process_already_imported.term', $data );
|
1463 |
+
|
1464 |
+
$this->mapping['term'][ $mapping_key ] = $existing;
|
1465 |
+
$this->mapping['term_id'][ $original_id ] = $existing;
|
1466 |
+
return false;
|
1467 |
+
}
|
1468 |
+
|
1469 |
+
// WP really likes to repeat itself in export files
|
1470 |
+
if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
|
1471 |
+
return false;
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
$termdata = array();
|
1475 |
+
$allowed = array(
|
1476 |
+
'slug' => true,
|
1477 |
+
'description' => true,
|
1478 |
+
);
|
1479 |
+
|
1480 |
+
// Map the parent comment, or mark it as one we need to fix
|
1481 |
+
// TODO: add parent mapping and remapping
|
1482 |
+
/*$requires_remapping = false;
|
1483 |
+
if ( $parent_id ) {
|
1484 |
+
if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
|
1485 |
+
$data['parent'] = $this->mapping['term'][ $parent_id ];
|
1486 |
+
} else {
|
1487 |
+
// Prepare for remapping later
|
1488 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1489 |
+
$requires_remapping = true;
|
1490 |
+
|
1491 |
+
// Wipe the parent for now
|
1492 |
+
$data['parent'] = 0;
|
1493 |
+
}
|
1494 |
+
}*/
|
1495 |
+
|
1496 |
+
foreach ( $data as $key => $value ) {
|
1497 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
1498 |
+
continue;
|
1499 |
+
}
|
1500 |
+
|
1501 |
+
$termdata[ $key ] = $data[ $key ];
|
1502 |
+
}
|
1503 |
+
|
1504 |
+
$result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
|
1505 |
+
if ( is_wp_error( $result ) ) {
|
1506 |
+
$this->logger->warning( sprintf(
|
1507 |
+
__( 'Failed to import %s %s', 'jupiterx-core' ),
|
1508 |
+
$data['taxonomy'],
|
1509 |
+
$data['name']
|
1510 |
+
) );
|
1511 |
+
$this->logger->debug( $result->get_error_message() );
|
1512 |
+
do_action( 'wp_import_insert_term_failed', $result, $data );
|
1513 |
+
|
1514 |
+
/**
|
1515 |
+
* Term processing failed.
|
1516 |
+
*
|
1517 |
+
* @param WP_Error $result Error object.
|
1518 |
+
* @param array $data Raw data imported for the term.
|
1519 |
+
* @param array $meta Meta data supplied for the term.
|
1520 |
+
*/
|
1521 |
+
do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
|
1522 |
+
return false;
|
1523 |
+
}
|
1524 |
+
|
1525 |
+
$term_id = $result['term_id'];
|
1526 |
+
|
1527 |
+
$this->mapping['term'][ $mapping_key ] = $term_id;
|
1528 |
+
$this->mapping['term_id'][ $original_id ] = $term_id;
|
1529 |
+
|
1530 |
+
$this->logger->info( sprintf(
|
1531 |
+
__( 'Imported "%s" (%s)', 'jupiterx-core' ),
|
1532 |
+
$data['name'],
|
1533 |
+
$data['taxonomy']
|
1534 |
+
) );
|
1535 |
+
$this->logger->debug( sprintf(
|
1536 |
+
__( 'Term %d remapped to %d', 'jupiterx-core' ),
|
1537 |
+
$original_id,
|
1538 |
+
$term_id
|
1539 |
+
) );
|
1540 |
+
|
1541 |
+
do_action( 'wp_import_insert_term', $term_id, $data );
|
1542 |
+
|
1543 |
+
/**
|
1544 |
+
* Term processing completed.
|
1545 |
+
*
|
1546 |
+
* @param int $term_id New term ID.
|
1547 |
+
* @param array $data Raw data imported for the term.
|
1548 |
+
*/
|
1549 |
+
do_action( 'wxr_importer.processed.term', $term_id, $data );
|
1550 |
+
}
|
1551 |
+
|
1552 |
+
/**
|
1553 |
+
* Attempt to download a remote file attachment
|
1554 |
+
*
|
1555 |
+
* @param string $url URL of item to fetch
|
1556 |
+
* @param array $post Attachment details
|
1557 |
+
* @return array|WP_Error Local file location details on success, WP_Error otherwise
|
1558 |
+
*/
|
1559 |
+
protected function fetch_remote_file( $url, $post ) {
|
1560 |
+
// extract the file name and extension from the url
|
1561 |
+
$file_name = basename( $url );
|
1562 |
+
|
1563 |
+
// get placeholder file in the upload dir with a unique, sanitized filename
|
1564 |
+
$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
|
1565 |
+
if ( $upload['error'] ) {
|
1566 |
+
return new WP_Error( 'upload_dir_error', $upload['error'] );
|
1567 |
+
}
|
1568 |
+
|
1569 |
+
// fetch the remote url and write it to the placeholder file
|
1570 |
+
$response = wp_remote_get( $url, array(
|
1571 |
+
'stream' => true,
|
1572 |
+
'filename' => $upload['file'],
|
1573 |
+
) );
|
1574 |
+
|
1575 |
+
// request failed
|
1576 |
+
if ( is_wp_error( $response ) ) {
|
1577 |
+
unlink( $upload['file'] );
|
1578 |
+
return $response;
|
1579 |
+
}
|
1580 |
+
|
1581 |
+
$code = (int) wp_remote_retrieve_response_code( $response );
|
1582 |
+
|
1583 |
+
// make sure the fetch was successful
|
1584 |
+
if ( $code !== 200 ) {
|
1585 |
+
unlink( $upload['file'] );
|
1586 |
+
return new WP_Error(
|
1587 |
+
'import_file_error',
|
1588 |
+
sprintf(
|
1589 |
+
__( 'Remote server returned %1$d %2$s for %3$s', 'jupiterx-core' ),
|
1590 |
+
$code,
|
1591 |
+
get_status_header_desc( $code ),
|
1592 |
+
$url
|
1593 |
+
)
|
1594 |
+
);
|
1595 |
+
}
|
1596 |
+
|
1597 |
+
$filesize = filesize( $upload['file'] );
|
1598 |
+
$headers = wp_remote_retrieve_headers( $response );
|
1599 |
+
|
1600 |
+
if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
|
1601 |
+
unlink( $upload['file'] );
|
1602 |
+
return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'jupiterx-core' ) );
|
1603 |
+
}
|
1604 |
+
|
1605 |
+
if ( 0 === $filesize ) {
|
1606 |
+
unlink( $upload['file'] );
|
1607 |
+
return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'jupiterx-core' ) );
|
1608 |
+
}
|
1609 |
+
|
1610 |
+
$max_size = (int) $this->max_attachment_size();
|
1611 |
+
if ( ! empty( $max_size ) && $filesize > $max_size ) {
|
1612 |
+
unlink( $upload['file'] );
|
1613 |
+
$message = sprintf( __( 'Remote file is too large, limit is %s', 'jupiterx-core' ), size_format( $max_size ) );
|
1614 |
+
return new WP_Error( 'import_file_error', $message );
|
1615 |
+
}
|
1616 |
+
|
1617 |
+
return $upload;
|
1618 |
+
}
|
1619 |
+
|
1620 |
+
protected function post_process() {
|
1621 |
+
// Time to tackle any left-over bits
|
1622 |
+
if ( ! empty( $this->requires_remapping['post'] ) ) {
|
1623 |
+
$this->post_process_posts( $this->requires_remapping['post'] );
|
1624 |
+
}
|
1625 |
+
if ( ! empty( $this->requires_remapping['comment'] ) ) {
|
1626 |
+
$this->post_process_comments( $this->requires_remapping['comment'] );
|
1627 |
+
}
|
1628 |
+
}
|
1629 |
+
|
1630 |
+
protected function post_process_posts( $todo ) {
|
1631 |
+
foreach ( $todo as $post_id => $_ ) {
|
1632 |
+
$this->logger->debug( sprintf(
|
1633 |
+
// Note: title intentionally not used to skip extra processing
|
1634 |
+
// for when debug logging is off
|
1635 |
+
__( 'Running post-processing for post %d', 'jupiterx-core' ),
|
1636 |
+
$post_id
|
1637 |
+
) );
|
1638 |
+
|
1639 |
+
$data = array();
|
1640 |
+
|
1641 |
+
$parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
|
1642 |
+
if ( ! empty( $parent_id ) ) {
|
1643 |
+
// Have we imported the parent now?
|
1644 |
+
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
1645 |
+
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
1646 |
+
} else {
|
1647 |
+
$this->logger->warning( sprintf(
|
1648 |
+
__( 'Could not find the post parent for "%s" (post #%d)', 'jupiterx-core' ),
|
1649 |
+
get_the_title( $post_id ),
|
1650 |
+
$post_id
|
1651 |
+
) );
|
1652 |
+
$this->logger->debug( sprintf(
|
1653 |
+
__( 'Post %d was imported with parent %d, but could not be found', 'jupiterx-core' ),
|
1654 |
+
$post_id,
|
1655 |
+
$parent_id
|
1656 |
+
) );
|
1657 |
+
}
|
1658 |
+
}
|
1659 |
+
|
1660 |
+
$author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
|
1661 |
+
if ( ! empty( $author_slug ) ) {
|
1662 |
+
// Have we imported the user now?
|
1663 |
+
if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
|
1664 |
+
$data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
|
1665 |
+
} else {
|
1666 |
+
$this->logger->warning( sprintf(
|
1667 |
+
__( 'Could not find the author for "%s" (post #%d)', 'jupiterx-core' ),
|
1668 |
+
get_the_title( $post_id ),
|
1669 |
+
$post_id
|
1670 |
+
) );
|
1671 |
+
$this->logger->debug( sprintf(
|
1672 |
+
__( 'Post %d was imported with author "%s", but could not be found', 'jupiterx-core' ),
|
1673 |
+
$post_id,
|
1674 |
+
$author_slug
|
1675 |
+
) );
|
1676 |
+
}
|
1677 |
+
}
|
1678 |
+
|
1679 |
+
$has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
|
1680 |
+
if ( ! empty( $has_attachments ) ) {
|
1681 |
+
$post = get_post( $post_id );
|
1682 |
+
$content = $post->post_content;
|
1683 |
+
|
1684 |
+
// Replace all the URLs we've got
|
1685 |
+
$new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
|
1686 |
+
if ( $new_content !== $content ) {
|
1687 |
+
$data['post_content'] = $new_content;
|
1688 |
+
}
|
1689 |
+
}
|
1690 |
+
|
1691 |
+
if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
|
1692 |
+
$this->post_process_menu_item( $post_id );
|
1693 |
+
}
|
1694 |
+
|
1695 |
+
// Do we have updates to make?
|
1696 |
+
if ( empty( $data ) ) {
|
1697 |
+
$this->logger->debug( sprintf(
|
1698 |
+
__( 'Post %d was marked for post-processing, but none was required.', 'jupiterx-core' ),
|
1699 |
+
$post_id
|
1700 |
+
) );
|
1701 |
+
continue;
|
1702 |
+
}
|
1703 |
+
|
1704 |
+
// Run the update
|
1705 |
+
$data['ID'] = $post_id;
|
1706 |
+
$result = wp_update_post( $data, true );
|
1707 |
+
if ( is_wp_error( $result ) ) {
|
1708 |
+
$this->logger->warning( sprintf(
|
1709 |
+
__( 'Could not update "%s" (post #%d) with mapped data', 'jupiterx-core' ),
|
1710 |
+
get_the_title( $post_id ),
|
1711 |
+
$post_id
|
1712 |
+
) );
|
1713 |
+
$this->logger->debug( $result->get_error_message() );
|
1714 |
+
continue;
|
1715 |
+
}
|
1716 |
+
|
1717 |
+
// Clear out our temporary meta keys
|
1718 |
+
delete_post_meta( $post_id, '_wxr_import_parent' );
|
1719 |
+
delete_post_meta( $post_id, '_wxr_import_user_slug' );
|
1720 |
+
delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
|
1721 |
+
}
|
1722 |
+
}
|
1723 |
+
|
1724 |
+
protected function post_process_menu_item( $post_id ) {
|
1725 |
+
$menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
|
1726 |
+
if ( empty( $menu_object_id ) ) {
|
1727 |
+
// No processing needed!
|
1728 |
+
return;
|
1729 |
+
}
|
1730 |
+
|
1731 |
+
$menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
1732 |
+
switch ( $menu_item_type ) {
|
1733 |
+
case 'taxonomy':
|
1734 |
+
if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
|
1735 |
+
$menu_object = $this->mapping['term_id'][ $menu_object_id ];
|
1736 |
+
}
|
1737 |
+
break;
|
1738 |
+
|
1739 |
+
case 'post_type':
|
1740 |
+
if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
|
1741 |
+
$menu_object = $this->mapping['post'][ $menu_object_id ];
|
1742 |
+
}
|
1743 |
+
break;
|
1744 |
+
|
1745 |
+
default:
|
1746 |
+
// Cannot handle this.
|
1747 |
+
return;
|
1748 |
+
}
|
1749 |
+
|
1750 |
+
if ( ! empty( $menu_object ) ) {
|
1751 |
+
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
|
1752 |
+
} else {
|
1753 |
+
$this->logger->warning( sprintf(
|
1754 |
+
__( 'Could not find the menu object for "%s" (post #%d)', 'jupiterx-core' ),
|
1755 |
+
get_the_title( $post_id ),
|
1756 |
+
$post_id
|
1757 |
+
) );
|
1758 |
+
$this->logger->debug( sprintf(
|
1759 |
+
__( 'Post %d was imported with object "%d" of type "%s", but could not be found', 'jupiterx-core' ),
|
1760 |
+
$post_id,
|
1761 |
+
$menu_object_id,
|
1762 |
+
$menu_item_type
|
1763 |
+
) );
|
1764 |
+
}
|
1765 |
+
|
1766 |
+
delete_post_meta( $post_id, '_wxr_import_menu_item' );
|
1767 |
+
}
|
1768 |
+
|
1769 |
+
|
1770 |
+
protected function post_process_comments( $todo ) {
|
1771 |
+
foreach ( $todo as $comment_id => $_ ) {
|
1772 |
+
$data = array();
|
1773 |
+
|
1774 |
+
$parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
|
1775 |
+
if ( ! empty( $parent_id ) ) {
|
1776 |
+
// Have we imported the parent now?
|
1777 |
+
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1778 |
+
$data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1779 |
+
} else {
|
1780 |
+
$this->logger->warning( sprintf(
|
1781 |
+
__( 'Could not find the comment parent for comment #%d', 'jupiterx-core' ),
|
1782 |
+
$comment_id
|
1783 |
+
) );
|
1784 |
+
$this->logger->debug( sprintf(
|
1785 |
+
__( 'Comment %d was imported with parent %d, but could not be found', 'jupiterx-core' ),
|
1786 |
+
$comment_id,
|
1787 |
+
$parent_id
|
1788 |
+
) );
|
1789 |
+
}
|
1790 |
+
}
|
1791 |
+
|
1792 |
+
$author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
|
1793 |
+
if ( ! empty( $author_id ) ) {
|
1794 |
+
// Have we imported the user now?
|
1795 |
+
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1796 |
+
$data['user_id'] = $this->mapping['user'][ $author_id ];
|
1797 |
+
} else {
|
1798 |
+
$this->logger->warning( sprintf(
|
1799 |
+
__( 'Could not find the author for comment #%d', 'jupiterx-core' ),
|
1800 |
+
$comment_id
|
1801 |
+
) );
|
1802 |
+
$this->logger->debug( sprintf(
|
1803 |
+
__( 'Comment %d was imported with author %d, but could not be found', 'jupiterx-core' ),
|
1804 |
+
$comment_id,
|
1805 |
+
$author_id
|
1806 |
+
) );
|
1807 |
+
}
|
1808 |
+
}
|
1809 |
+
|
1810 |
+
// Do we have updates to make?
|
1811 |
+
if ( empty( $data ) ) {
|
1812 |
+
continue;
|
1813 |
+
}
|
1814 |
+
|
1815 |
+
// Run the update
|
1816 |
+
$data['comment_ID'] = $comment_ID;
|
1817 |
+
$result = wp_update_comment( wp_slash( $data ) );
|
1818 |
+
if ( empty( $result ) ) {
|
1819 |
+
$this->logger->warning( sprintf(
|
1820 |
+
__( 'Could not update comment #%d with mapped data', 'jupiterx-core' ),
|
1821 |
+
$comment_id
|
1822 |
+
) );
|
1823 |
+
continue;
|
1824 |
+
}
|
1825 |
+
|
1826 |
+
// Clear out our temporary meta keys
|
1827 |
+
delete_comment_meta( $comment_id, '_wxr_import_parent' );
|
1828 |
+
delete_comment_meta( $comment_id, '_wxr_import_user' );
|
1829 |
+
}
|
1830 |
+
}
|
1831 |
+
|
1832 |
+
/**
|
1833 |
+
* Use stored mapping information to update old attachment URLs
|
1834 |
+
*/
|
1835 |
+
protected function replace_attachment_urls_in_content() {
|
1836 |
+
global $wpdb;
|
1837 |
+
// make sure we do the longest urls first, in case one is a substring of another
|
1838 |
+
uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
|
1839 |
+
|
1840 |
+
foreach ( $this->url_remap as $from_url => $to_url ) {
|
1841 |
+
// remap urls in post_content
|
1842 |
+
$query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
|
1843 |
+
$wpdb->query( $query );
|
1844 |
+
|
1845 |
+
// remap enclosure urls
|
1846 |
+
$query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
|
1847 |
+
$result = $wpdb->query( $query );
|
1848 |
+
}
|
1849 |
+
}
|
1850 |
+
|
1851 |
+
/**
|
1852 |
+
* Update _thumbnail_id meta to new, imported attachment IDs
|
1853 |
+
*/
|
1854 |
+
function remap_featured_images() {
|
1855 |
+
// cycle through posts that have a featured image
|
1856 |
+
foreach ( $this->featured_images as $post_id => $value ) {
|
1857 |
+
if ( isset( $this->processed_posts[ $value ] ) ) {
|
1858 |
+
$new_id = $this->processed_posts[ $value ];
|
1859 |
+
|
1860 |
+
// only update if there's a difference
|
1861 |
+
if ( $new_id !== $value ) {
|
1862 |
+
update_post_meta( $post_id, '_thumbnail_id', $new_id );
|
1863 |
+
}
|
1864 |
+
}
|
1865 |
+
}
|
1866 |
+
}
|
1867 |
+
|
1868 |
+
/**
|
1869 |
+
* Decide if the given meta key maps to information we will want to import
|
1870 |
+
*
|
1871 |
+
* @param string $key The meta key to check
|
1872 |
+
* @return string|bool The key if we do want to import, false if not
|
1873 |
+
*/
|
1874 |
+
public function is_valid_meta_key( $key ) {
|
1875 |
+
// skip attachment metadata since we'll regenerate it from scratch
|
1876 |
+
// skip _edit_lock as not relevant for import
|
1877 |
+
if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
|
1878 |
+
return false;
|
1879 |
+
}
|
1880 |
+
|
1881 |
+
return $key;
|
1882 |
+
}
|
1883 |
+
|
1884 |
+
/**
|
1885 |
+
* Decide what the maximum file size for downloaded attachments is.
|
1886 |
+
* Default is 0 (unlimited), can be filtered via import_attachment_size_limit
|
1887 |
+
*
|
1888 |
+
* @return int Maximum attachment file size to import
|
1889 |
+
*/
|
1890 |
+
protected function max_attachment_size() {
|
1891 |
+
return apply_filters( 'import_attachment_size_limit', 0 );
|
1892 |
+
}
|
1893 |
+
|
1894 |
+
/**
|
1895 |
+
* Added to http_request_timeout filter to force timeout at 60 seconds during import
|
1896 |
+
*
|
1897 |
+
* @access protected
|
1898 |
+
* @return int 60
|
1899 |
+
*/
|
1900 |
+
function bump_request_timeout($val) {
|
1901 |
+
return 60;
|
1902 |
+
}
|
1903 |
+
|
1904 |
+
// return the difference in length between two strings
|
1905 |
+
function cmpr_strlen( $a, $b ) {
|
1906 |
+
return strlen( $b ) - strlen( $a );
|
1907 |
+
}
|
1908 |
+
|
1909 |
+
/**
|
1910 |
+
* Prefill existing post data.
|
1911 |
+
*
|
1912 |
+
* This preloads all GUIDs into memory, allowing us to avoid hitting the
|
1913 |
+
* database when we need to check for existence. With larger imports, this
|
1914 |
+
* becomes prohibitively slow to perform SELECT queries on each.
|
1915 |
+
*
|
1916 |
+
* By preloading all this data into memory, it's a constant-time lookup in
|
1917 |
+
* PHP instead. However, this does use a lot more memory, so for sites doing
|
1918 |
+
* small imports onto a large site, it may be a better tradeoff to use
|
1919 |
+
* on-the-fly checking instead.
|
1920 |
+
*/
|
1921 |
+
protected function prefill_existing_posts() {
|
1922 |
+
global $wpdb;
|
1923 |
+
$posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
|
1924 |
+
|
1925 |
+
foreach ( $posts as $item ) {
|
1926 |
+
$this->exists['post'][ wp_specialchars_decode( $item->guid ) ] = $item->ID;
|
1927 |
+
}
|
1928 |
+
}
|
1929 |
+
|
1930 |
+
/**
|
1931 |
+
* Does the post exist?
|
1932 |
+
*
|
1933 |
+
* @param array $data Post data to check against.
|
1934 |
+
* @return int|bool Existing post ID if it exists, false otherwise.
|
1935 |
+
*/
|
1936 |
+
protected function post_exists( $data ) {
|
1937 |
+
// Constant-time lookup if we prefilled
|
1938 |
+
$exists_key = wp_specialchars_decode( $data['guid'] );
|
1939 |
+
|
1940 |
+
if ( $this->options['prefill_existing_posts'] ) {
|
1941 |
+
return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
|
1942 |
+
}
|
1943 |
+
|
1944 |
+
// No prefilling, but might have already handled it
|
1945 |
+
if ( isset( $this->exists['post'][ $exists_key ] ) ) {
|
1946 |
+
return $this->exists['post'][ $exists_key ];
|
1947 |
+
}
|
1948 |
+
|
1949 |
+
// Still nothing, try post_exists, and cache it
|
1950 |
+
$exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
|
1951 |
+
$this->exists['post'][ $exists_key ] = $exists;
|
1952 |
+
|
1953 |
+
return $exists;
|
1954 |
+
}
|
1955 |
+
|
1956 |
+
/**
|
1957 |
+
* Mark the post as existing.
|
1958 |
+
*
|
1959 |
+
* @param array $data Post data to mark as existing.
|
1960 |
+
* @param int $post_id Post ID.
|
1961 |
+
*/
|
1962 |
+
protected function mark_post_exists( $data, $post_id ) {
|
1963 |
+
$exists_key = $data['guid'];
|
1964 |
+
$this->exists['post'][ $exists_key ] = $post_id;
|
1965 |
+
}
|
1966 |
+
|
1967 |
+
/**
|
1968 |
+
* Prefill existing comment data.
|
1969 |
+
*
|
1970 |
+
* @see self::prefill_existing_posts() for justification of why this exists.
|
1971 |
+
*/
|
1972 |
+
protected function prefill_existing_comments() {
|
1973 |
+
global $wpdb;
|
1974 |
+
$posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
|
1975 |
+
|
1976 |
+
foreach ( $posts as $item ) {
|
1977 |
+
$exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
|
1978 |
+
$this->exists['comment'][ $exists_key ] = $item->comment_ID;
|
1979 |
+
}
|
1980 |
+
}
|
1981 |
+
|
1982 |
+
/**
|
1983 |
+
* Does the comment exist?
|
1984 |
+
*
|
1985 |
+
* @param array $data Comment data to check against.
|
1986 |
+
* @return int|bool Existing comment ID if it exists, false otherwise.
|
1987 |
+
*/
|
1988 |
+
protected function comment_exists( $data ) {
|
1989 |
+
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
1990 |
+
|
1991 |
+
// Constant-time lookup if we prefilled
|
1992 |
+
if ( $this->options['prefill_existing_comments'] ) {
|
1993 |
+
return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
|
1994 |
+
}
|
1995 |
+
|
1996 |
+
// No prefilling, but might have already handled it
|
1997 |
+
if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
|
1998 |
+
return $this->exists['comment'][ $exists_key ];
|
1999 |
+
}
|
2000 |
+
|
2001 |
+
// Still nothing, try comment_exists, and cache it
|
2002 |
+
$exists = comment_exists( $data['comment_author'], $data['comment_date'] );
|
2003 |
+
$this->exists['comment'][ $exists_key ] = $exists;
|
2004 |
+
|
2005 |
+
return $exists;
|
2006 |
+
}
|
2007 |
+
|
2008 |
+
/**
|
2009 |
+
* Mark the comment as existing.
|
2010 |
+
*
|
2011 |
+
* @param array $data Comment data to mark as existing.
|
2012 |
+
* @param int $comment_id Comment ID.
|
2013 |
+
*/
|
2014 |
+
protected function mark_comment_exists( $data, $comment_id ) {
|
2015 |
+
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2016 |
+
$this->exists['comment'][ $exists_key ] = $comment_id;
|
2017 |
+
}
|
2018 |
+
|
2019 |
+
/**
|
2020 |
+
* Prefill existing term data.
|
2021 |
+
*
|
2022 |
+
* @see self::prefill_existing_posts() for justification of why this exists.
|
2023 |
+
*/
|
2024 |
+
protected function prefill_existing_terms() {
|
2025 |
+
global $wpdb;
|
2026 |
+
$query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
|
2027 |
+
$query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
|
2028 |
+
$terms = $wpdb->get_results( $query );
|
2029 |
+
|
2030 |
+
foreach ( $terms as $item ) {
|
2031 |
+
$exists_key = sha1( $item->taxonomy . ':' . $item->slug );
|
2032 |
+
$this->exists['term'][ $exists_key ] = $item->term_id;
|
2033 |
+
}
|
2034 |
+
}
|
2035 |
+
|
2036 |
+
/**
|
2037 |
+
* Does the term exist?
|
2038 |
+
*
|
2039 |
+
* @param array $data Term data to check against.
|
2040 |
+
* @return int|bool Existing term ID if it exists, false otherwise.
|
2041 |
+
*/
|
2042 |
+
protected function term_exists( $data ) {
|
2043 |
+
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2044 |
+
|
2045 |
+
// Constant-time lookup if we prefilled
|
2046 |
+
if ( $this->options['prefill_existing_terms'] ) {
|
2047 |
+
return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
|
2048 |
+
}
|
2049 |
+
|
2050 |
+
// No prefilling, but might have already handled it
|
2051 |
+
if ( isset( $this->exists['term'][ $exists_key ] ) ) {
|
2052 |
+
return $this->exists['term'][ $exists_key ];
|
2053 |
+
}
|
2054 |
+
|
2055 |
+
// Still nothing, try comment_exists, and cache it
|
2056 |
+
$exists = term_exists( $data['slug'], $data['taxonomy'] );
|
2057 |
+
if ( is_array( $exists ) ) {
|
2058 |
+
$exists = $exists['term_id'];
|
2059 |
+
}
|
2060 |
+
|
2061 |
+
$this->exists['term'][ $exists_key ] = $exists;
|
2062 |
+
|
2063 |
+
return $exists;
|
2064 |
+
}
|
2065 |
+
|
2066 |
+
/**
|
2067 |
+
* Mark the term as existing.
|
2068 |
+
*
|
2069 |
+
* @param array $data Term data to mark as existing.
|
2070 |
+
* @param int $term_id Term ID.
|
2071 |
+
*/
|
2072 |
+
protected function mark_term_exists( $data, $term_id ) {
|
2073 |
+
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2074 |
+
$this->exists['term'][ $exists_key ] = $term_id;
|
2075 |
+
}
|
2076 |
+
}
|
includes/control-panel/includes/logic-messages.php
CHANGED
@@ -1,456 +1,456 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! function_exists( 'jupiterx_logic_message_helper' ) ) {
|
3 |
-
/**
|
4 |
-
* This function is responsible to store every message we use in system , this way we can translate them or convert them
|
5 |
-
* to meaningfull messages in easy steps.
|
6 |
-
* also this way we can translate all third-party messages too
|
7 |
-
* We can pass some parameters in the message as long as we follow this format:
|
8 |
-
* array(
|
9 |
-
* '{param} is activated in {param}.', // Message will be displayed
|
10 |
-
* 'Artbees Captcha', // Will replace first {param}
|
11 |
-
* 'Jupiter', // Will replace second {param}
|
12 |
-
* 'Etc...', // Will replace third {param} (if exist), etc.
|
13 |
-
* )
|
14 |
-
*
|
15 |
-
* @author Reza Marandi <ross@artbees.net>
|
16 |
-
*
|
17 |
-
* @copyright Artbees LTD (c)
|
18 |
-
* @link https://artbees.net
|
19 |
-
* @version 5.5
|
20 |
-
* @package jupiter
|
21 |
-
*
|
22 |
-
* @param string $which_page Which page we should look for the message (for example : plugin-management , template-management , ..)
|
23 |
-
* @param string $which_string Which message we are looking for ?
|
24 |
-
* @param string $which_type Which message type is suitable to return ? (user_msg , system_msg)
|
25 |
-
*
|
26 |
-
* @return string replaced and prepared message
|
27 |
-
*/
|
28 |
-
function jupiterx_logic_message_helper( $which_page, $which_string, $which_type = 'user_msg' ) {
|
29 |
-
if ( empty( $which_page ) || empty( $which_string ) ) {
|
30 |
-
return null;
|
31 |
-
}
|
32 |
-
|
33 |
-
/*====================== FILESYSTEM ============================*/
|
34 |
-
$filesystem_messages = array(
|
35 |
-
array(
|
36 |
-
'sys_msg' => 'No filesystem credentials found!',
|
37 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
38 |
-
),
|
39 |
-
);
|
40 |
-
|
41 |
-
/*====================== TEST CASES ============================*/
|
42 |
-
$test_cases_messages = array(
|
43 |
-
array(
|
44 |
-
'sys_msg' => 'error 1 in 0x0x111',
|
45 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
46 |
-
),
|
47 |
-
array(
|
48 |
-
'sys_msg' => 'error 2 in 0x0x112',
|
49 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
50 |
-
),
|
51 |
-
array(
|
52 |
-
'sys_msg' => 'error 3 in 0x0x113',
|
53 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
54 |
-
),
|
55 |
-
array(
|
56 |
-
'sys_msg' => 'error 4 in 0x0x114 {param}',
|
57 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
58 |
-
),
|
59 |
-
array(
|
60 |
-
'sys_msg' => 'error 5 in {param} 0x0x114 {param} you can say {param}',
|
61 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
62 |
-
),
|
63 |
-
);
|
64 |
-
/*====================== PLUGIN MANAGEMENT ============================*/
|
65 |
-
$plugin_management_messages = array(
|
66 |
-
array(
|
67 |
-
'sys_msg' => 'Can not find plugin path in deactivate plugin func',
|
68 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 200)', 'jupiterx-core' ),
|
69 |
-
),
|
70 |
-
array(
|
71 |
-
'sys_msg' => 'Can not find plugin path in activate plugin func',
|
72 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 201)', 'jupiterx-core' ),
|
73 |
-
),
|
74 |
-
array(
|
75 |
-
'sys_msg' => 'Plugin successfully added and activated.',
|
76 |
-
'user_msg' => __( 'Your plugin has been successfully added and activated.', 'jupiterx-core' ),
|
77 |
-
),
|
78 |
-
array(
|
79 |
-
'sys_msg' => 'Plugin directory is not writable.',
|
80 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 202)', 'jupiterx-core' ),
|
81 |
-
),
|
82 |
-
array(
|
83 |
-
'sys_msg' => 'Successfull',
|
84 |
-
'user_msg' => __( 'Congratulations,your operation has been done successfully', 'jupiterx-core' ),
|
85 |
-
),
|
86 |
-
array(
|
87 |
-
'sys_msg' => 'Plugins source not found or it have invalid url',
|
88 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 203)', 'jupiterx-core' ),
|
89 |
-
),
|
90 |
-
array(
|
91 |
-
'sys_msg' => 'Can not find {param} plugin path.',
|
92 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 204)', 'jupiterx-core' ),
|
93 |
-
),
|
94 |
-
array(
|
95 |
-
'sys_msg' => 'Plugin parent directory is not writable - RPPM01x01.',
|
96 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 205)', 'jupiterx-core' ),
|
97 |
-
),
|
98 |
-
array(
|
99 |
-
'sys_msg' => 'Plugin directory is not writable - RPPM01x01',
|
100 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 206)', 'jupiterx-core' ),
|
101 |
-
),
|
102 |
-
array(
|
103 |
-
'sys_msg' => 'Can not remove directory of plugin - RPPM01x01-Directory',
|
104 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 207)', 'jupiterx-core' ),
|
105 |
-
),
|
106 |
-
array(
|
107 |
-
'sys_msg' => 'Can not remove directory of plugin - RPPM01x01-File',
|
108 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 208)', 'jupiterx-core' ),
|
109 |
-
),
|
110 |
-
array(
|
111 |
-
'sys_msg' => 'Plugin you want to remove is not exist - RPPM01x01',
|
112 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 209)', 'jupiterx-core' ),
|
113 |
-
),
|
114 |
-
array(
|
115 |
-
'sys_msg' => 'Plugin you want to remove is still activated , deactive it first - RPPM01x01.',
|
116 |
-
'user_msg' => __( 'To remove your plugin, please deactivate it first and then try again.', 'jupiterx-core' ),
|
117 |
-
),
|
118 |
-
array(
|
119 |
-
'sys_msg' => 'Can not find plugin head file name.',
|
120 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 210)', 'jupiterx-core' ),
|
121 |
-
),
|
122 |
-
array(
|
123 |
-
'sys_msg' => 'Plugin successfully Updated.',
|
124 |
-
'user_msg' => __( 'Your plugin have been successfully updated.', 'jupiterx-core' ),
|
125 |
-
),
|
126 |
-
array(
|
127 |
-
'sys_msg' => 'Plugin successfully Removed.',
|
128 |
-
'user_msg' => __( 'Your plugin have been successfully removed.', 'jupiterx-core' ),
|
129 |
-
),
|
130 |
-
array(
|
131 |
-
'sys_msg' => 'Plugin list is not an array , use install method instead.',
|
132 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 211)', 'jupiterx-core' ),
|
133 |
-
),
|
134 |
-
array(
|
135 |
-
'sys_msg' => 'The plugin ({param}) you are looking for is not exist.',
|
136 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 212)', 'jupiterx-core' ),
|
137 |
-
),
|
138 |
-
array(
|
139 |
-
'sys_msg' => 'Plugin list is empty',
|
140 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 213)', 'jupiterx-core' ),
|
141 |
-
),
|
142 |
-
array(
|
143 |
-
'sys_msg' => '{param} plugins installed successfully',
|
144 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 214)', 'jupiterx-core' ),
|
145 |
-
),
|
146 |
-
array(
|
147 |
-
'sys_msg' => 'Plugin you want to remove is not exist - RPPM01x01.',
|
148 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 215)', 'jupiterx-core' ),
|
149 |
-
),
|
150 |
-
array(
|
151 |
-
'sys_msg' => 'Undefined',
|
152 |
-
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 216)', 'jupiterx-core' ),
|
153 |
-
),
|
154 |
-
);
|
155 |
-
|
156 |
-
/*====================== ADDON MANAGEMENT ============================*/
|
157 |
-
$addon_management_messages = array(
|
158 |
-
array(
|
159 |
-
'sys_msg' => 'System problem , please call support',
|
160 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
161 |
-
),
|
162 |
-
array(
|
163 |
-
'sys_msg' => 'Successfull',
|
164 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
165 |
-
),
|
166 |
-
array(
|
167 |
-
'sys_msg' => 'System problem at installing , please call support',
|
168 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
169 |
-
),
|
170 |
-
array(
|
171 |
-
'sys_msg' => 'Add-on activated successfully',
|
172 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
173 |
-
),
|
174 |
-
array(
|
175 |
-
'sys_msg' => 'The Add-On you are looking for is not exist.',
|
176 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
177 |
-
),
|
178 |
-
array(
|
179 |
-
'sys_msg' => 'The Add-On directory is not writable , Change the permission first.',
|
180 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
181 |
-
),
|
182 |
-
array(
|
183 |
-
'sys_msg' => 'The Add-On removal process was not successfull.',
|
184 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
185 |
-
),
|
186 |
-
array(
|
187 |
-
'sys_msg' => 'Add-on removed successfully',
|
188 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
189 |
-
),
|
190 |
-
array(
|
191 |
-
'sys_msg' => 'Add-on you are looking for is not exist in API side',
|
192 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
193 |
-
),
|
194 |
-
array(
|
195 |
-
'sys_msg' => 'You have latest version of this add-on.',
|
196 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
197 |
-
),
|
198 |
-
array(
|
199 |
-
'sys_msg' => 'Add-on updated successfully',
|
200 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
201 |
-
),
|
202 |
-
);
|
203 |
-
|
204 |
-
/*====================== TEMPLATE MANAGEMENT ============================*/
|
205 |
-
$template_management_messages = array(
|
206 |
-
array(
|
207 |
-
'sys_msg' => 'System problem at installing , please contact support',
|
208 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
209 |
-
),
|
210 |
-
array(
|
211 |
-
'sys_msg' => 'Choose template first',
|
212 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
213 |
-
),
|
214 |
-
array(
|
215 |
-
'sys_msg' => 'Template assets are not completely exist - p1, Contact support.',
|
216 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
217 |
-
),
|
218 |
-
array(
|
219 |
-
'sys_msg' => 'System problem , please contact support',
|
220 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
221 |
-
),
|
222 |
-
array(
|
223 |
-
'sys_msg' => 'Successfull',
|
224 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
225 |
-
),
|
226 |
-
array(
|
227 |
-
'sys_msg' => 'Template list is not what we expected',
|
228 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
229 |
-
),
|
230 |
-
array(
|
231 |
-
'sys_msg' => 'Database reseted',
|
232 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
233 |
-
),
|
234 |
-
array(
|
235 |
-
'sys_msg' => 'Choose one template first',
|
236 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
237 |
-
),
|
238 |
-
array(
|
239 |
-
'sys_msg' => 'Template source URL is not validate',
|
240 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
241 |
-
),
|
242 |
-
array(
|
243 |
-
'sys_msg' => 'Uploaded to server',
|
244 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
245 |
-
),
|
246 |
-
array(
|
247 |
-
'sys_msg' => 'Cannot delete template zip file',
|
248 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
249 |
-
),
|
250 |
-
array(
|
251 |
-
'sys_msg' => 'Completed',
|
252 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
253 |
-
),
|
254 |
-
array(
|
255 |
-
'sys_msg' => 'Template assets are not completely exist - p2, Contact support.',
|
256 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
257 |
-
),
|
258 |
-
array(
|
259 |
-
'sys_msg' => 'Plugin set have wrong structure',
|
260 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
261 |
-
),
|
262 |
-
array(
|
263 |
-
'sys_msg' => '{param} plugins are installed.',
|
264 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
265 |
-
),
|
266 |
-
array(
|
267 |
-
'sys_msg' => 'Template contents were imported.',
|
268 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
269 |
-
),
|
270 |
-
array(
|
271 |
-
'sys_msg' => 'Navigation locations is configured.',
|
272 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
273 |
-
),
|
274 |
-
array(
|
275 |
-
'sys_msg' => 'Default homepage and Shop Page is configured.',
|
276 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
277 |
-
),
|
278 |
-
array(
|
279 |
-
'sys_msg' => 'Shop Page is configured.',
|
280 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
281 |
-
),
|
282 |
-
array(
|
283 |
-
'sys_msg' => 'Default homepage is configured.',
|
284 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
285 |
-
),
|
286 |
-
array(
|
287 |
-
'sys_msg' => 'Setup pages completed.',
|
288 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
289 |
-
),
|
290 |
-
array(
|
291 |
-
'sys_msg' => 'Template options is empty',
|
292 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
293 |
-
),
|
294 |
-
array(
|
295 |
-
'sys_msg' => 'Widgets are imported.',
|
296 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
297 |
-
),
|
298 |
-
array(
|
299 |
-
'sys_msg' => 'Can not remove source files',
|
300 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
301 |
-
),
|
302 |
-
array(
|
303 |
-
'sys_msg' => 'Widget data could not be read. Please try a different file.',
|
304 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
305 |
-
),
|
306 |
-
array(
|
307 |
-
'sys_msg' => 'Sidebar does not exist in theme (using Inactive)',
|
308 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
309 |
-
),
|
310 |
-
array(
|
311 |
-
'sys_msg' => 'Site does not support widget',
|
312 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
313 |
-
),
|
314 |
-
array(
|
315 |
-
'sys_msg' => 'Widget already exists',
|
316 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
317 |
-
),
|
318 |
-
array(
|
319 |
-
'sys_msg' => 'Imported',
|
320 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
321 |
-
),
|
322 |
-
array(
|
323 |
-
'sys_msg' => 'Imported to Inactive',
|
324 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
325 |
-
),
|
326 |
-
array(
|
327 |
-
'sys_msg' => 'Successfull',
|
328 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
329 |
-
),
|
330 |
-
array(
|
331 |
-
'sys_msg' => 'LayerSlider is not installed , install it first',
|
332 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
333 |
-
),
|
334 |
-
array(
|
335 |
-
'sys_msg' => 'LayerSlider is installed but not activated , activate it first',
|
336 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
337 |
-
),
|
338 |
-
array(
|
339 |
-
'sys_msg' => 'Backup created.',
|
340 |
-
'user_msg' => __( '', 'jupiterx-core' ),
|
341 |
-
),
|
342 |
-
array(
|
343 |
-
'sys_msg' => 'Not enough max_execution_time.',
|
344 |
-
'user_msg' => __( '' , 'jupiterx-core' ),
|
345 |
-
),
|
346 |
-
array(
|
347 |
-
'sys_msg' => 'Not enough memory_limit.',
|
348 |
-
'user_msg' => __( '' , 'jupiterx-core' ),
|
349 |
-
),
|
350 |
-
);
|
351 |
-
|
352 |
-
/*====================== DB MANAGEMENT ============================*/
|
353 |
-
$db_management_messages = array(
|
354 |
-
array(
|
355 |
-
'sys_msg' => 'Can not create backup db file.',
|
356 |
-
'user_msg' => '',
|
357 |
-
),
|
358 |
-
array(
|
359 |
-
'sys_msg' => 'Backup file is not created in right approach , try again.',
|
360 |
-
'user_msg' => '',
|
361 |
-
),
|
362 |
-
array(
|
363 |
-
'sys_msg' => 'Backup Successfuly created',
|
364 |
-
'user_msg' => '',
|
365 |
-
),
|
366 |
-
array(
|
367 |
-
'sys_msg' => 'Can not create index , Securesection',
|
368 |
-
'user_msg' => '',
|
369 |
-
),
|
370 |
-
array(
|
371 |
-
'sys_msg' => 'Can not create htaccess , Securesection',
|
372 |
-
'user_msg' => '',
|
373 |
-
),
|
374 |
-
);
|
375 |
-
|
376 |
-
/*====================== DECISION LOGIC ============================*/
|
377 |
-
switch ( $which_page ) {
|
378 |
-
case 'filesystem':
|
379 |
-
$data = $filesystem_messages;
|
380 |
-
break;
|
381 |
-
case 'test-cases':
|
382 |
-
$data = $test_cases_messages;
|
383 |
-
break;
|
384 |
-
case 'plugin-management':
|
385 |
-
$data = $plugin_management_messages;
|
386 |
-
break;
|
387 |
-
case 'addon-management':
|
388 |
-
$data = $addon_management_messages;
|
389 |
-
break;
|
390 |
-
case 'template-management':
|
391 |
-
$data = $template_management_messages;
|
392 |
-
break;
|
393 |
-
case 'db-management':
|
394 |
-
$data = $db_management_messages;
|
395 |
-
break;
|
396 |
-
case 'theme-options':
|
397 |
-
$data = $theme_options_messages;
|
398 |
-
break;
|
399 |
-
}
|
400 |
-
|
401 |
-
// Check if the which_string is array
|
402 |
-
$which_param = array();
|
403 |
-
if ( is_array( $which_string ) ) {
|
404 |
-
$which_param = $which_string;
|
405 |
-
if ( ! empty( $which_param[0] ) ) {
|
406 |
-
// Set back which_string as string, then remove it from which_param
|
407 |
-
$which_string = $which_param[0];
|
408 |
-
array_shift( $which_param );
|
409 |
-
}
|
410 |
-
}
|
411 |
-
|
412 |
-
$message_key = JupiterX_Control_Panel_Helpers::search_multdim( $data, 'sys_msg', $which_string );
|
413 |
-
if ( $message_key === false ) {
|
414 |
-
// LOG THIS SECTION
|
415 |
-
// DESC : This error message is not defined
|
416 |
-
return jupiterx_logic_message_output( $which_string, $which_param );
|
417 |
-
}
|
418 |
-
if ( ! empty( $data[ $message_key ]['user_msg'] ) && $which_type == 'user_msg' ) {
|
419 |
-
return jupiterx_logic_message_output( $data[ $message_key ]['user_msg'], $which_param );
|
420 |
-
} else {
|
421 |
-
// LOG THIS SECTION
|
422 |
-
// DESC : User message is not defined , DEFINE IT (Translate Department);
|
423 |
-
return jupiterx_logic_message_output( $data[ $message_key ]['sys_msg'], $which_param );
|
424 |
-
}
|
425 |
-
}
|
426 |
-
}
|
427 |
-
|
428 |
-
if ( ! function_exists( 'jupiterx_logic_message_output' ) ) {
|
429 |
-
/**
|
430 |
-
* Check the message format before return it. If the message need some parameter to pass, check the parameter
|
431 |
-
* then replace it with the correct ones.
|
432 |
-
*
|
433 |
-
* @param string $message Message will be displayed
|
434 |
-
* @param array $param Parameter to pass
|
435 |
-
* @return string Output of the message in text format
|
436 |
-
*/
|
437 |
-
function jupiterx_logic_message_output( $message = null, $param = array() ) {
|
438 |
-
if ( $message == null ) {
|
439 |
-
return 'Undefined';
|
440 |
-
}
|
441 |
-
|
442 |
-
// Check if param is not empty
|
443 |
-
if ( ! empty( $param ) ) {
|
444 |
-
// Count {param} that need to be replaced
|
445 |
-
$count = substr_count( $message, '{param}' );
|
446 |
-
if ( count( $param ) < $count ) {
|
447 |
-
$param = array_pad( $param, $count, '{param}' );
|
448 |
-
}
|
449 |
-
|
450 |
-
$message = str_replace( '{param}', '%s', $message );
|
451 |
-
$message = vsprintf( $message, $param );
|
452 |
-
}
|
453 |
-
|
454 |
-
return $message;
|
455 |
-
}
|
456 |
-
}
|
1 |
+
<?php
|
2 |
+
if ( ! function_exists( 'jupiterx_logic_message_helper' ) ) {
|
3 |
+
/**
|
4 |
+
* This function is responsible to store every message we use in system , this way we can translate them or convert them
|
5 |
+
* to meaningfull messages in easy steps.
|
6 |
+
* also this way we can translate all third-party messages too
|
7 |
+
* We can pass some parameters in the message as long as we follow this format:
|
8 |
+
* array(
|
9 |
+
* '{param} is activated in {param}.', // Message will be displayed
|
10 |
+
* 'Artbees Captcha', // Will replace first {param}
|
11 |
+
* 'Jupiter', // Will replace second {param}
|
12 |
+
* 'Etc...', // Will replace third {param} (if exist), etc.
|
13 |
+
* )
|
14 |
+
*
|
15 |
+
* @author Reza Marandi <ross@artbees.net>
|
16 |
+
*
|
17 |
+
* @copyright Artbees LTD (c)
|
18 |
+
* @link https://artbees.net
|
19 |
+
* @version 5.5
|
20 |
+
* @package jupiter
|
21 |
+
*
|
22 |
+
* @param string $which_page Which page we should look for the message (for example : plugin-management , template-management , ..)
|
23 |
+
* @param string $which_string Which message we are looking for ?
|
24 |
+
* @param string $which_type Which message type is suitable to return ? (user_msg , system_msg)
|
25 |
+
*
|
26 |
+
* @return string replaced and prepared message
|
27 |
+
*/
|
28 |
+
function jupiterx_logic_message_helper( $which_page, $which_string, $which_type = 'user_msg' ) {
|
29 |
+
if ( empty( $which_page ) || empty( $which_string ) ) {
|
30 |
+
return null;
|
31 |
+
}
|
32 |
+
|
33 |
+
/*====================== FILESYSTEM ============================*/
|
34 |
+
$filesystem_messages = array(
|
35 |
+
array(
|
36 |
+
'sys_msg' => 'No filesystem credentials found!',
|
37 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
38 |
+
),
|
39 |
+
);
|
40 |
+
|
41 |
+
/*====================== TEST CASES ============================*/
|
42 |
+
$test_cases_messages = array(
|
43 |
+
array(
|
44 |
+
'sys_msg' => 'error 1 in 0x0x111',
|
45 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
46 |
+
),
|
47 |
+
array(
|
48 |
+
'sys_msg' => 'error 2 in 0x0x112',
|
49 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
50 |
+
),
|
51 |
+
array(
|
52 |
+
'sys_msg' => 'error 3 in 0x0x113',
|
53 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
54 |
+
),
|
55 |
+
array(
|
56 |
+
'sys_msg' => 'error 4 in 0x0x114 {param}',
|
57 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
58 |
+
),
|
59 |
+
array(
|
60 |
+
'sys_msg' => 'error 5 in {param} 0x0x114 {param} you can say {param}',
|
61 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
62 |
+
),
|
63 |
+
);
|
64 |
+
/*====================== PLUGIN MANAGEMENT ============================*/
|
65 |
+
$plugin_management_messages = array(
|
66 |
+
array(
|
67 |
+
'sys_msg' => 'Can not find plugin path in deactivate plugin func',
|
68 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 200)', 'jupiterx-core' ),
|
69 |
+
),
|
70 |
+
array(
|
71 |
+
'sys_msg' => 'Can not find plugin path in activate plugin func',
|
72 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 201)', 'jupiterx-core' ),
|
73 |
+
),
|
74 |
+
array(
|
75 |
+
'sys_msg' => 'Plugin successfully added and activated.',
|
76 |
+
'user_msg' => __( 'Your plugin has been successfully added and activated.', 'jupiterx-core' ),
|
77 |
+
),
|
78 |
+
array(
|
79 |
+
'sys_msg' => 'Plugin directory is not writable.',
|
80 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 202)', 'jupiterx-core' ),
|
81 |
+
),
|
82 |
+
array(
|
83 |
+
'sys_msg' => 'Successfull',
|
84 |
+
'user_msg' => __( 'Congratulations,your operation has been done successfully', 'jupiterx-core' ),
|
85 |
+
),
|
86 |
+
array(
|
87 |
+
'sys_msg' => 'Plugins source not found or it have invalid url',
|
88 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 203)', 'jupiterx-core' ),
|
89 |
+
),
|
90 |
+
array(
|
91 |
+
'sys_msg' => 'Can not find {param} plugin path.',
|
92 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 204)', 'jupiterx-core' ),
|
93 |
+
),
|
94 |
+
array(
|
95 |
+
'sys_msg' => 'Plugin parent directory is not writable - RPPM01x01.',
|
96 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 205)', 'jupiterx-core' ),
|
97 |
+
),
|
98 |
+
array(
|
99 |
+
'sys_msg' => 'Plugin directory is not writable - RPPM01x01',
|
100 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 206)', 'jupiterx-core' ),
|
101 |
+
),
|
102 |
+
array(
|
103 |
+
'sys_msg' => 'Can not remove directory of plugin - RPPM01x01-Directory',
|
104 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 207)', 'jupiterx-core' ),
|
105 |
+
),
|
106 |
+
array(
|
107 |
+
'sys_msg' => 'Can not remove directory of plugin - RPPM01x01-File',
|
108 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 208)', 'jupiterx-core' ),
|
109 |
+
),
|
110 |
+
array(
|
111 |
+
'sys_msg' => 'Plugin you want to remove is not exist - RPPM01x01',
|
112 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 209)', 'jupiterx-core' ),
|
113 |
+
),
|
114 |
+
array(
|
115 |
+
'sys_msg' => 'Plugin you want to remove is still activated , deactive it first - RPPM01x01.',
|
116 |
+
'user_msg' => __( 'To remove your plugin, please deactivate it first and then try again.', 'jupiterx-core' ),
|
117 |
+
),
|
118 |
+
array(
|
119 |
+
'sys_msg' => 'Can not find plugin head file name.',
|
120 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 210)', 'jupiterx-core' ),
|
121 |
+
),
|
122 |
+
array(
|
123 |
+
'sys_msg' => 'Plugin successfully Updated.',
|
124 |
+
'user_msg' => __( 'Your plugin have been successfully updated.', 'jupiterx-core' ),
|
125 |
+
),
|
126 |
+
array(
|
127 |
+
'sys_msg' => 'Plugin successfully Removed.',
|
128 |
+
'user_msg' => __( 'Your plugin have been successfully removed.', 'jupiterx-core' ),
|
129 |
+
),
|
130 |
+
array(
|
131 |
+
'sys_msg' => 'Plugin list is not an array , use install method instead.',
|
132 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 211)', 'jupiterx-core' ),
|
133 |
+
),
|
134 |
+
array(
|
135 |
+
'sys_msg' => 'The plugin ({param}) you are looking for is not exist.',
|
136 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 212)', 'jupiterx-core' ),
|
137 |
+
),
|
138 |
+
array(
|
139 |
+
'sys_msg' => 'Plugin list is empty',
|
140 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 213)', 'jupiterx-core' ),
|
141 |
+
),
|
142 |
+
array(
|
143 |
+
'sys_msg' => '{param} plugins installed successfully',
|
144 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 214)', 'jupiterx-core' ),
|
145 |
+
),
|
146 |
+
array(
|
147 |
+
'sys_msg' => 'Plugin you want to remove is not exist - RPPM01x01.',
|
148 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 215)', 'jupiterx-core' ),
|
149 |
+
),
|
150 |
+
array(
|
151 |
+
'sys_msg' => 'Undefined',
|
152 |
+
'user_msg' => __( 'Whoops! We seem to be having some problems. Please contact Support and supply the number shown and we\'ll be happy to figure this out for you. (code 216)', 'jupiterx-core' ),
|
153 |
+
),
|
154 |
+
);
|
155 |
+
|
156 |
+
/*====================== ADDON MANAGEMENT ============================*/
|
157 |
+
$addon_management_messages = array(
|
158 |
+
array(
|
159 |
+
'sys_msg' => 'System problem , please call support',
|
160 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
161 |
+
),
|
162 |
+
array(
|
163 |
+
'sys_msg' => 'Successfull',
|
164 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
165 |
+
),
|
166 |
+
array(
|
167 |
+
'sys_msg' => 'System problem at installing , please call support',
|
168 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
169 |
+
),
|
170 |
+
array(
|
171 |
+
'sys_msg' => 'Add-on activated successfully',
|
172 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
173 |
+
),
|
174 |
+
array(
|
175 |
+
'sys_msg' => 'The Add-On you are looking for is not exist.',
|
176 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
177 |
+
),
|
178 |
+
array(
|
179 |
+
'sys_msg' => 'The Add-On directory is not writable , Change the permission first.',
|
180 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
181 |
+
),
|
182 |
+
array(
|
183 |
+
'sys_msg' => 'The Add-On removal process was not successfull.',
|
184 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
185 |
+
),
|
186 |
+
array(
|
187 |
+
'sys_msg' => 'Add-on removed successfully',
|
188 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
189 |
+
),
|
190 |
+
array(
|
191 |
+
'sys_msg' => 'Add-on you are looking for is not exist in API side',
|
192 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
193 |
+
),
|
194 |
+
array(
|
195 |
+
'sys_msg' => 'You have latest version of this add-on.',
|
196 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
197 |
+
),
|
198 |
+
array(
|
199 |
+
'sys_msg' => 'Add-on updated successfully',
|
200 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
201 |
+
),
|
202 |
+
);
|
203 |
+
|
204 |
+
/*====================== TEMPLATE MANAGEMENT ============================*/
|
205 |
+
$template_management_messages = array(
|
206 |
+
array(
|
207 |
+
'sys_msg' => 'System problem at installing , please contact support',
|
208 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
209 |
+
),
|
210 |
+
array(
|
211 |
+
'sys_msg' => 'Choose template first',
|
212 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
213 |
+
),
|
214 |
+
array(
|
215 |
+
'sys_msg' => 'Template assets are not completely exist - p1, Contact support.',
|
216 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
217 |
+
),
|
218 |
+
array(
|
219 |
+
'sys_msg' => 'System problem , please contact support',
|
220 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
221 |
+
),
|
222 |
+
array(
|
223 |
+
'sys_msg' => 'Successfull',
|
224 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
225 |
+
),
|
226 |
+
array(
|
227 |
+
'sys_msg' => 'Template list is not what we expected',
|
228 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
229 |
+
),
|
230 |
+
array(
|
231 |
+
'sys_msg' => 'Database reseted',
|
232 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
233 |
+
),
|
234 |
+
array(
|
235 |
+
'sys_msg' => 'Choose one template first',
|
236 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
237 |
+
),
|
238 |
+
array(
|
239 |
+
'sys_msg' => 'Template source URL is not validate',
|
240 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
241 |
+
),
|
242 |
+
array(
|
243 |
+
'sys_msg' => 'Uploaded to server',
|
244 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
245 |
+
),
|
246 |
+
array(
|
247 |
+
'sys_msg' => 'Cannot delete template zip file',
|
248 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
249 |
+
),
|
250 |
+
array(
|
251 |
+
'sys_msg' => 'Completed',
|
252 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
253 |
+
),
|
254 |
+
array(
|
255 |
+
'sys_msg' => 'Template assets are not completely exist - p2, Contact support.',
|
256 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
257 |
+
),
|
258 |
+
array(
|
259 |
+
'sys_msg' => 'Plugin set have wrong structure',
|
260 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
261 |
+
),
|
262 |
+
array(
|
263 |
+
'sys_msg' => '{param} plugins are installed.',
|
264 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
265 |
+
),
|
266 |
+
array(
|
267 |
+
'sys_msg' => 'Template contents were imported.',
|
268 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
269 |
+
),
|
270 |
+
array(
|
271 |
+
'sys_msg' => 'Navigation locations is configured.',
|
272 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
273 |
+
),
|
274 |
+
array(
|
275 |
+
'sys_msg' => 'Default homepage and Shop Page is configured.',
|
276 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
277 |
+
),
|
278 |
+
array(
|
279 |
+
'sys_msg' => 'Shop Page is configured.',
|
280 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
281 |
+
),
|
282 |
+
array(
|
283 |
+
'sys_msg' => 'Default homepage is configured.',
|
284 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
285 |
+
),
|
286 |
+
array(
|
287 |
+
'sys_msg' => 'Setup pages completed.',
|
288 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
289 |
+
),
|
290 |
+
array(
|
291 |
+
'sys_msg' => 'Template options is empty',
|
292 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
293 |
+
),
|
294 |
+
array(
|
295 |
+
'sys_msg' => 'Widgets are imported.',
|
296 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
297 |
+
),
|
298 |
+
array(
|
299 |
+
'sys_msg' => 'Can not remove source files',
|
300 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
301 |
+
),
|
302 |
+
array(
|
303 |
+
'sys_msg' => 'Widget data could not be read. Please try a different file.',
|
304 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
305 |
+
),
|
306 |
+
array(
|
307 |
+
'sys_msg' => 'Sidebar does not exist in theme (using Inactive)',
|
308 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
309 |
+
),
|
310 |
+
array(
|
311 |
+
'sys_msg' => 'Site does not support widget',
|
312 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
313 |
+
),
|
314 |
+
array(
|
315 |
+
'sys_msg' => 'Widget already exists',
|
316 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
317 |
+
),
|
318 |
+
array(
|
319 |
+
'sys_msg' => 'Imported',
|
320 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
321 |
+
),
|
322 |
+
array(
|
323 |
+
'sys_msg' => 'Imported to Inactive',
|
324 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
325 |
+
),
|
326 |
+
array(
|
327 |
+
'sys_msg' => 'Successfull',
|
328 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
329 |
+
),
|
330 |
+
array(
|
331 |
+
'sys_msg' => 'LayerSlider is not installed , install it first',
|
332 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
333 |
+
),
|
334 |
+
array(
|
335 |
+
'sys_msg' => 'LayerSlider is installed but not activated , activate it first',
|
336 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
337 |
+
),
|
338 |
+
array(
|
339 |
+
'sys_msg' => 'Backup created.',
|
340 |
+
'user_msg' => __( '', 'jupiterx-core' ),
|
341 |
+
),
|
342 |
+
array(
|
343 |
+
'sys_msg' => 'Not enough max_execution_time.',
|
344 |
+
'user_msg' => __( '' , 'jupiterx-core' ),
|
345 |
+
),
|
346 |
+
array(
|
347 |
+
'sys_msg' => 'Not enough memory_limit.',
|
348 |
+
'user_msg' => __( '' , 'jupiterx-core' ),
|
349 |
+
),
|
350 |
+
);
|
351 |
+
|
352 |
+
/*====================== DB MANAGEMENT ============================*/
|
353 |
+
$db_management_messages = array(
|
354 |
+
array(
|
355 |
+
'sys_msg' => 'Can not create backup db file.',
|
356 |
+
'user_msg' => '',
|
357 |
+
),
|
358 |
+
array(
|
359 |
+
'sys_msg' => 'Backup file is not created in right approach , try again.',
|
360 |
+
'user_msg' => '',
|
361 |
+
),
|
362 |
+
array(
|
363 |
+
'sys_msg' => 'Backup Successfuly created',
|
364 |
+
'user_msg' => '',
|
365 |
+
),
|
366 |
+
array(
|
367 |
+
'sys_msg' => 'Can not create index , Securesection',
|
368 |
+
'user_msg' => '',
|
369 |
+
),
|
370 |
+
array(
|
371 |
+
'sys_msg' => 'Can not create htaccess , Securesection',
|
372 |
+
'user_msg' => '',
|
373 |
+
),
|
374 |
+
);
|
375 |
+
|
376 |
+
/*====================== DECISION LOGIC ============================*/
|
377 |
+
switch ( $which_page ) {
|
378 |
+
case 'filesystem':
|
379 |
+
$data = $filesystem_messages;
|
380 |
+
break;
|
381 |
+
case 'test-cases':
|
382 |
+
$data = $test_cases_messages;
|
383 |
+
break;
|
384 |
+
case 'plugin-management':
|
385 |
+
$data = $plugin_management_messages;
|
386 |
+
break;
|
387 |
+
case 'addon-management':
|
388 |
+
$data = $addon_management_messages;
|
389 |
+
break;
|
390 |
+
case 'template-management':
|
391 |
+
$data = $template_management_messages;
|
392 |
+
break;
|
393 |
+
case 'db-management':
|
394 |
+
$data = $db_management_messages;
|
395 |
+
break;
|
396 |
+
case 'theme-options':
|
397 |
+
$data = $theme_options_messages;
|
398 |
+
break;
|
399 |
+
}
|
400 |
+
|
401 |
+
// Check if the which_string is array
|
402 |
+
$which_param = array();
|
403 |
+
if ( is_array( $which_string ) ) {
|
404 |
+
$which_param = $which_string;
|
405 |
+
if ( ! empty( $which_param[0] ) ) {
|
406 |
+
// Set back which_string as string, then remove it from which_param
|
407 |
+
$which_string = $which_param[0];
|
408 |
+
array_shift( $which_param );
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
+
$message_key = JupiterX_Control_Panel_Helpers::search_multdim( $data, 'sys_msg', $which_string );
|
413 |
+
if ( $message_key === false ) {
|
414 |
+
// LOG THIS SECTION
|
415 |
+
// DESC : This error message is not defined
|
416 |
+
return jupiterx_logic_message_output( $which_string, $which_param );
|
417 |
+
}
|
418 |
+
if ( ! empty( $data[ $message_key ]['user_msg'] ) && $which_type == 'user_msg' ) {
|
419 |
+
return jupiterx_logic_message_output( $data[ $message_key ]['user_msg'], $which_param );
|
420 |
+
} else {
|
421 |
+
// LOG THIS SECTION
|
422 |
+
// DESC : User message is not defined , DEFINE IT (Translate Department);
|
423 |
+
return jupiterx_logic_message_output( $data[ $message_key ]['sys_msg'], $which_param );
|
424 |
+
}
|
425 |
+
}
|
426 |
+
}
|
427 |
+
|
428 |
+
if ( ! function_exists( 'jupiterx_logic_message_output' ) ) {
|
429 |
+
/**
|
430 |
+
* Check the message format before return it. If the message need some parameter to pass, check the parameter
|
431 |
+
* then replace it with the correct ones.
|
432 |
+
*
|
433 |
+
* @param string $message Message will be displayed
|
434 |
+
* @param array $param Parameter to pass
|
435 |
+
* @return string Output of the message in text format
|
436 |
+
*/
|
437 |
+
function jupiterx_logic_message_output( $message = null, $param = array() ) {
|
438 |
+
if ( $message == null ) {
|
439 |
+
return 'Undefined';
|
440 |
+
}
|
441 |
+
|
442 |
+
// Check if param is not empty
|
443 |
+
if ( ! empty( $param ) ) {
|
444 |
+
// Count {param} that need to be replaced
|
445 |
+
$count = substr_count( $message, '{param}' );
|
446 |
+
if ( count( $param ) < $count ) {
|
447 |
+
$param = array_pad( $param, $count, '{param}' );
|
448 |
+
}
|
449 |
+
|
450 |
+
$message = str_replace( '{param}', '%s', $message );
|
451 |
+
$message = vsprintf( $message, $param );
|
452 |
+
}
|
453 |
+
|
454 |
+
return $message;
|
455 |
+
}
|
456 |
+
}
|
includes/control-panel/views/export-import-content.php
CHANGED
@@ -1,70 +1,77 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! JUPITERX_CONTROL_PANEL_EXPORT_IMPORT ) {
|
3 |
-
return;
|
4 |
-
}
|
5 |
-
?>
|
6 |
-
<div class="jupiterx-cp-pane-box bootstrap-wrapper">
|
7 |
-
<div class="alert alert-danger"><?php printf( __( 'The Export/Import feature is deprecated. To migrate/backup your website use <a href="%s" target="_blank">3rd-party plugins</a>.', 'jupiterx-core' ), 'https://wordpress.org/plugins/tags/backup/' ) ?></div>
|
8 |
-
<h3><?php esc_html_e( 'Export', 'jupiterx-core' ); ?></h3>
|
9 |
-
<div class="jupiterx-cp-export-wrap jupiterx-card mb-5">
|
10 |
-
<form class="jupiterx-cp-export-form">
|
11 |
-
<div class="jupiterx-card-body">
|
12 |
-
<div class="jupiterx-form-group">
|
13 |
-
<label for="filename">File Name</label>
|
14 |
-
<input type="text" class="jupiterx-form-control" id="filename" name="filename" placeholder="<?php echo get_bloginfo( 'name' )?>-jupiterx">
|
15 |
-
</div>
|
16 |
-
<br>
|
17 |
-
<div class="custom-control custom-checkbox">
|
18 |
-
<input checked="" class="custom-control-input" id="site-content" name="site-content" type="checkbox" value="Content">
|
19 |
-
<label class="custom-control-label" for="site-content">
|
20 |
-
<?php esc_html_e( 'Site Content', 'jupiterx-core' ); ?>
|
21 |
-
</label>
|
22 |
-
</input>
|
23 |
-
</div>
|
24 |
-
<div class="custom-control custom-checkbox">
|
25 |
-
<input checked="" class="custom-control-input" id="site-widgets" name="site-widgets" type="checkbox" value="Widgets">
|
26 |
-
<label class="custom-control-label" for="site-widgets">
|
27 |
-
<?php esc_html_e( 'Widgets', 'jupiterx-core' ); ?>
|
28 |
-
</label>
|
29 |
-
</input>
|
30 |
-
</div>
|
31 |
-
<div class="custom-control custom-checkbox">
|
32 |
-
<input checked="" class="custom-control-input" id="site-settings" name="site-settings" type="checkbox" value="Settings">
|
33 |
-
<label class="custom-control-label" for="site-settings">
|
34 |
-
<?php esc_html_e( 'Settings', 'jupiterx-core' ); ?>
|
35 |
-
</label>
|
36 |
-
</input>
|
37 |
-
</div>
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
</
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! JUPITERX_CONTROL_PANEL_EXPORT_IMPORT ) {
|
3 |
+
return;
|
4 |
+
}
|
5 |
+
?>
|
6 |
+
<div class="jupiterx-cp-pane-box bootstrap-wrapper">
|
7 |
+
<div class="alert alert-danger"><?php printf( __( 'The Export/Import feature is deprecated. To migrate/backup your website use <a href="%s" target="_blank">3rd-party plugins</a>.', 'jupiterx-core' ), 'https://wordpress.org/plugins/tags/backup/' ) ?></div>
|
8 |
+
<h3><?php esc_html_e( 'Export', 'jupiterx-core' ); ?></h3>
|
9 |
+
<div class="jupiterx-cp-export-wrap jupiterx-card mb-5">
|
10 |
+
<form class="jupiterx-cp-export-form">
|
11 |
+
<div class="jupiterx-card-body">
|
12 |
+
<div class="jupiterx-form-group">
|
13 |
+
<label for="filename">File Name</label>
|
14 |
+
<input type="text" class="jupiterx-form-control" id="filename" name="filename" placeholder="<?php echo get_bloginfo( 'name' )?>-jupiterx">
|
15 |
+
</div>
|
16 |
+
<br>
|
17 |
+
<div class="custom-control custom-checkbox">
|
18 |
+
<input checked="" class="custom-control-input" id="site-content" name="site-content" type="checkbox" value="Content">
|
19 |
+
<label class="custom-control-label" for="site-content">
|
20 |
+
<?php esc_html_e( 'Site Content', 'jupiterx-core' ); ?>
|
21 |
+
</label>
|
22 |
+
</input>
|
23 |
+
</div>
|
24 |
+
<div class="custom-control custom-checkbox">
|
25 |
+
<input checked="" class="custom-control-input" id="site-widgets" name="site-widgets" type="checkbox" value="Widgets">
|
26 |
+
<label class="custom-control-label" for="site-widgets">
|
27 |
+
<?php esc_html_e( 'Widgets', 'jupiterx-core' ); ?>
|
28 |
+
</label>
|
29 |
+
</input>
|
30 |
+
</div>
|
31 |
+
<div class="custom-control custom-checkbox">
|
32 |
+
<input checked="" class="custom-control-input" id="site-settings" name="site-settings" type="checkbox" value="Settings">
|
33 |
+
<label class="custom-control-label" for="site-settings">
|
34 |
+
<?php esc_html_e( 'Settings', 'jupiterx-core' ); ?>
|
35 |
+
</label>
|
36 |
+
</input>
|
37 |
+
</div>
|
38 |
+
<div class="custom-control custom-checkbox">
|
39 |
+
<input checked="" class="custom-control-input" id="custom-tables" name="custom-tables" type="checkbox" value="Custom Tables">
|
40 |
+
<label class="custom-control-label" for="custom-tables">
|
41 |
+
<?php esc_html_e( 'Custom Tables', 'jupiterx-core' ); ?>
|
42 |
+
</label>
|
43 |
+
</input>
|
44 |
+
</div>
|
45 |
+
</div>
|
46 |
+
<hr style="margin: 0;">
|
47 |
+
<div class="jupiterx-card-body">
|
48 |
+
<button class="btn btn-primary jupiterx-cp-export-btn" type="submit">
|
49 |
+
<?php esc_html_e( 'Export', 'jupiterx-core' ); ?>
|
50 |
+
</button>
|
51 |
+
</div>
|
52 |
+
</form>
|
53 |
+
</div>
|
54 |
+
<h3><?php esc_html_e( 'Import', 'jupiterx-core' ); ?></h3>
|
55 |
+
<div class="jupiterx-cp-import-wrap jupiterx-card">
|
56 |
+
<div class="jupiterx-card-body">
|
57 |
+
<div class="jupiterx-upload-wrap w-75">
|
58 |
+
<div class="input-group">
|
59 |
+
<input class="jupiterx-form-control" placeholder="Select a Zip file" type="text">
|
60 |
+
<div class="input-group-append">
|
61 |
+
<a class="btn btn-secondary jupiterx-cp-import-upload-btn" href="#">
|
62 |
+
<?php esc_html_e( 'Upload', 'jupiterx-core' ); ?>
|
63 |
+
</a>
|
64 |
+
</div>
|
65 |
+
</input>
|
66 |
+
</div>
|
67 |
+
</div>
|
68 |
+
</div>
|
69 |
+
<hr style="margin: 0;">
|
70 |
+
<div class="jupiterx-card-body">
|
71 |
+
<button class="btn btn-primary jupiterx-cp-import-btn" type="submit">
|
72 |
+
<?php esc_html_e( 'Import', 'jupiterx-core' ); ?>
|
73 |
+
</button>
|
74 |
+
</div>
|
75 |
+
|
76 |
+
</div>
|
77 |
+
</div>
|
includes/control-panel/views/image-sizes.php
CHANGED
@@ -1,64 +1,68 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Image sizes template.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel\Image_Sizes
|
6 |
-
*
|
7 |
-
* @since 1.2.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
if ( ! JUPITERX_CONTROL_PANEL_IMAGE_SIZES ) {
|
11 |
-
return;
|
12 |
-
}
|
13 |
-
?>
|
14 |
-
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-image-sizes">
|
15 |
-
<h3>
|
16 |
-
<?php esc_html_e( 'Image Sizes', 'jupiterx-core' ); ?>
|
17 |
-
<?php jupiterx_the_help_link( 'http://help.artbees.net/customizer/configuring-images/custom-size-for-images', esc_html__( 'Custom size for images', 'jupiterx-core' ) ); ?>
|
18 |
-
</h3>
|
19 |
-
<button type="button" class="btn btn-primary image-size-add-new-btn js__cp-clist-add-item">
|
20 |
-
<?php esc_html_e( 'Add a New Size', 'jupiterx-core' ); ?>
|
21 |
-
</button>
|
22 |
-
<div class="jupiterx-wrap jupiterx-img-size-wrap">
|
23 |
-
<div class="jupiterx-img-size">
|
24 |
-
<div class="jupiterx-img-size-list js__jupiterx-img-size-list clearfix mb-3">
|
25 |
-
<?php
|
26 |
-
foreach ( JupiterX_Control_Panel_Image_Sizes::get_available_image_sizes() as $size ) :
|
27 |
-
if ( ! empty( $size['size_n'] ) && ! empty( $size['size_w'] ) && ! empty( $size['size_h'] ) ) :
|
28 |
-
?>
|
29 |
-
<div class="jupiterx-img-size-item js__cp-image-size-item">
|
30 |
-
<div class="jupiterx-img-size-item-inner jupiterx-card">
|
31 |
-
<div class="jupiterx-card-body fetch-input-data">
|
32 |
-
<div class="js__size-name mb-3">
|
33 |
-
<strong><?php esc_html_e( 'Name', 'jupiterx-core' ); ?>:</strong> <?php echo wp_kses_post( $size['size_n'] ); ?>
|
34 |
-
</div>
|
35 |
-
<div class="js__size-dimension mb-3">
|
36 |
-
<strong><?php esc_html_e( 'Size', 'jupiterx-core' ); ?>:</strong> <?php echo wp_kses_post( $size['size_w'] ); ?>px <?php echo wp_kses_post( $size['size_h'] ); ?>px
|
37 |
-
</div>
|
38 |
-
<div class="js__size-crop mb-3">
|
39 |
-
<strong><?php esc_html_e( 'Crop', 'jupiterx-core' ); ?>:</strong>
|
40 |
-
<?php if ( 'on' === $size['size_c'] ) : ?>
|
41 |
-
<span class="status-state status-true"></span>
|
42 |
-
<?php else : ?>
|
43 |
-
<span class="status-state status-false"></span>
|
44 |
-
<?php endif; ?>
|
45 |
-
</div>
|
46 |
-
<button type="button" class="btn btn-outline-success js__cp-clist-edit-item mr-1"><?php esc_html_e( 'Edit', 'jupiterx-core' ); ?></button>
|
47 |
-
<button type="button" class="btn btn-outline-danger js__cp-clist-remove-item"><?php esc_html_e( 'Remove', 'jupiterx-core' ); ?></button>
|
48 |
-
<input name="size_n" type="hidden" value="<?php echo esc_attr( $size['size_n'] ); ?>" />
|
49 |
-
<input name="size_w" type="hidden" value="<?php echo esc_attr( $size['size_w'] ); ?>" />
|
50 |
-
<input name="size_h" type="hidden" value="<?php echo esc_attr( $size['size_h'] ); ?>" />
|
51 |
-
<input name="size_c" type="hidden" value="<?php echo esc_attr( $size['size_c'] ); ?>" />
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Image sizes template.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel\Image_Sizes
|
6 |
+
*
|
7 |
+
* @since 1.2.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
if ( ! JUPITERX_CONTROL_PANEL_IMAGE_SIZES ) {
|
11 |
+
return;
|
12 |
+
}
|
13 |
+
?>
|
14 |
+
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-image-sizes">
|
15 |
+
<h3>
|
16 |
+
<?php esc_html_e( 'Image Sizes', 'jupiterx-core' ); ?>
|
17 |
+
<?php jupiterx_the_help_link( 'http://help.artbees.net/customizer/configuring-images/custom-size-for-images', esc_html__( 'Custom size for images', 'jupiterx-core' ) ); ?>
|
18 |
+
</h3>
|
19 |
+
<button type="button" class="btn btn-primary image-size-add-new-btn js__cp-clist-add-item">
|
20 |
+
<?php esc_html_e( 'Add a New Size', 'jupiterx-core' ); ?>
|
21 |
+
</button>
|
22 |
+
<div class="jupiterx-wrap jupiterx-img-size-wrap">
|
23 |
+
<div class="jupiterx-img-size">
|
24 |
+
<div class="jupiterx-img-size-list js__jupiterx-img-size-list clearfix mb-3">
|
25 |
+
<?php
|
26 |
+
foreach ( JupiterX_Control_Panel_Image_Sizes::get_available_image_sizes() as $size ) :
|
27 |
+
if ( ! empty( $size['size_n'] ) && ! empty( $size['size_w'] ) && ! empty( $size['size_h'] ) ) :
|
28 |
+
?>
|
29 |
+
<div class="jupiterx-img-size-item js__cp-image-size-item">
|
30 |
+
<div class="jupiterx-img-size-item-inner jupiterx-card">
|
31 |
+
<div class="jupiterx-card-body fetch-input-data">
|
32 |
+
<div class="js__size-name mb-3">
|
33 |
+
<strong><?php esc_html_e( 'Name', 'jupiterx-core' ); ?>:</strong> <?php echo wp_kses_post( $size['size_n'] ); ?>
|
34 |
+
</div>
|
35 |
+
<div class="js__size-dimension mb-3">
|
36 |
+
<strong><?php esc_html_e( 'Size', 'jupiterx-core' ); ?>:</strong> <?php echo wp_kses_post( $size['size_w'] ); ?>px <?php echo wp_kses_post( $size['size_h'] ); ?>px
|
37 |
+
</div>
|
38 |
+
<div class="js__size-crop mb-3">
|
39 |
+
<strong><?php esc_html_e( 'Crop', 'jupiterx-core' ); ?>:</strong>
|
40 |
+
<?php if ( 'on' === $size['size_c'] ) : ?>
|
41 |
+
<span class="status-state status-true"></span>
|
42 |
+
<?php else : ?>
|
43 |
+
<span class="status-state status-false"></span>
|
44 |
+
<?php endif; ?>
|
45 |
+
</div>
|
46 |
+
<button type="button" class="btn btn-outline-success js__cp-clist-edit-item mr-1"><?php esc_html_e( 'Edit', 'jupiterx-core' ); ?></button>
|
47 |
+
<button type="button" class="btn btn-outline-danger js__cp-clist-remove-item"><?php esc_html_e( 'Remove', 'jupiterx-core' ); ?></button>
|
48 |
+
<input name="size_n" type="hidden" value="<?php echo esc_attr( $size['size_n'] ); ?>" />
|
49 |
+
<input name="size_w" type="hidden" value="<?php echo esc_attr( $size['size_w'] ); ?>" />
|
50 |
+
<input name="size_h" type="hidden" value="<?php echo esc_attr( $size['size_h'] ); ?>" />
|
51 |
+
<input name="size_c" type="hidden" value="<?php echo esc_attr( $size['size_c'] ); ?>" />
|
52 |
+
<?php if ( ! empty( $size['default'] ) ) : ?>
|
53 |
+
<input name="default" type="hidden" value="true" />
|
54 |
+
<input name="id" type="hidden" value="<?php echo esc_attr( $size['id'] ); ?>" />
|
55 |
+
<?php endif; ?>
|
56 |
+
</div>
|
57 |
+
</div>
|
58 |
+
</div>
|
59 |
+
<?php
|
60 |
+
endif;
|
61 |
+
endforeach;
|
62 |
+
?>
|
63 |
+
</div>
|
64 |
+
<div class="clearfix"></div>
|
65 |
+
</div>
|
66 |
+
<?php wp_nonce_field( 'ajax-image-sizes-options', 'security' ); ?>
|
67 |
+
</div>
|
68 |
+
</div>
|
includes/control-panel/views/install-plugins.php
CHANGED
@@ -1,56 +1,62 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! JUPITERX_CONTROL_PANEL_PLUGINS ) {
|
3 |
-
return;
|
4 |
-
}
|
5 |
-
|
6 |
-
$menu_items_access = get_site_option( 'menu_items' );
|
7 |
-
|
8 |
-
if ( is_multisite() && ! isset( $menu_items_access['plugins'] ) && ! current_user_can( 'manage_network_plugins' ) ) : ?>
|
9 |
-
<div class="jupiterx-cp-pane-box" id="jupiterx-no-plugins">
|
10 |
-
<div class="alert alert-warning" role="alert">
|
11 |
-
<?php esc_html_e( 'Now you are using a sub site which it\'s plugin functionalities are disabled by Network admin.', 'jupiterx' ); ?>
|
12 |
-
<?php esc_html_e( 'To have a full control over plugins, please go to My Sites > Network Admin > Settings and check Plugins option of "Enable administration menus" option. If you don\'t have access to the mentioned page, please contact Network Admin.', 'jupiterx' ); ?>
|
13 |
-
</div>
|
14 |
-
</div>
|
15 |
-
<?php
|
16 |
-
return;
|
17 |
-
endif;
|
18 |
-
|
19 |
-
$invalid = validate_active_plugins();
|
20 |
-
|
21 |
-
if ( ! empty( $invalid ) ) {
|
22 |
-
foreach ( $invalid as $plugin_file => $error ) {
|
23 |
-
echo '<div id="message" class="error"><p>';
|
24 |
-
printf(
|
25 |
-
/* translators: 1: plugin file, 2: error message */
|
26 |
-
__( 'The plugin %1$s has been <strong>deactivated</strong> due to an error: %2$s', 'jupiterx' ),
|
27 |
-
'<code>' . esc_html( $plugin_file ) . '</code>',
|
28 |
-
$error->get_error_message()
|
29 |
-
);
|
30 |
-
echo '</p></div>';
|
31 |
-
}
|
32 |
-
}
|
33 |
-
?>
|
34 |
-
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-plugins">
|
35 |
-
<div class="jupiterx-cp-plugins-list">
|
36 |
-
<div class="jupiterx-cp-plugins-header d-flex">
|
37 |
-
<h3 class="mb-0">
|
38 |
-
<?php esc_html_e( 'Plugins', 'jupiterx' ); ?>
|
39 |
-
<?php jupiterx_the_help_link( 'http://help.artbees.net/getting-started/plugins/installing-the-bundled-plugins', __( 'Installing the Bundled Plugins.', 'jupiterx' ) ); ?>
|
40 |
-
</h3>
|
41 |
-
<div class="btn-group jupiterx-cp-plugins-filter disabled" role="group">
|
42 |
-
<button type="button" class="btn btn-secondary" data-filter="all" disabled><?php esc_html_e( 'All', 'jupiterx' ); ?></button>
|
43 |
-
<button type="button" class="btn btn-outline-secondary" data-filter="active" disabled><?php esc_html_e( 'Active', 'jupiterx' ); ?></button>
|
44 |
-
<button type="button" class="btn btn-outline-secondary" data-filter="inactive" disabled><?php esc_html_e( 'Inactive', 'jupiterx' ); ?></button>
|
45 |
-
<?php
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! JUPITERX_CONTROL_PANEL_PLUGINS ) {
|
3 |
+
return;
|
4 |
+
}
|
5 |
+
|
6 |
+
$menu_items_access = get_site_option( 'menu_items' );
|
7 |
+
|
8 |
+
if ( is_multisite() && ! isset( $menu_items_access['plugins'] ) && ! current_user_can( 'manage_network_plugins' ) ) : ?>
|
9 |
+
<div class="jupiterx-cp-pane-box" id="jupiterx-no-plugins">
|
10 |
+
<div class="alert alert-warning" role="alert">
|
11 |
+
<?php esc_html_e( 'Now you are using a sub site which it\'s plugin functionalities are disabled by Network admin.', 'jupiterx' ); ?>
|
12 |
+
<?php esc_html_e( 'To have a full control over plugins, please go to My Sites > Network Admin > Settings and check Plugins option of "Enable administration menus" option. If you don\'t have access to the mentioned page, please contact Network Admin.', 'jupiterx' ); ?>
|
13 |
+
</div>
|
14 |
+
</div>
|
15 |
+
<?php
|
16 |
+
return;
|
17 |
+
endif;
|
18 |
+
|
19 |
+
$invalid = validate_active_plugins();
|
20 |
+
|
21 |
+
if ( ! empty( $invalid ) ) {
|
22 |
+
foreach ( $invalid as $plugin_file => $error ) {
|
23 |
+
echo '<div id="message" class="error"><p>';
|
24 |
+
printf(
|
25 |
+
/* translators: 1: plugin file, 2: error message */
|
26 |
+
__( 'The plugin %1$s has been <strong>deactivated</strong> due to an error: %2$s', 'jupiterx' ),
|
27 |
+
'<code>' . esc_html( $plugin_file ) . '</code>',
|
28 |
+
$error->get_error_message()
|
29 |
+
);
|
30 |
+
echo '</p></div>';
|
31 |
+
}
|
32 |
+
}
|
33 |
+
?>
|
34 |
+
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-plugins">
|
35 |
+
<div class="jupiterx-cp-plugins-list">
|
36 |
+
<div class="jupiterx-cp-plugins-header d-flex">
|
37 |
+
<h3 class="mb-0">
|
38 |
+
<?php esc_html_e( 'Plugins', 'jupiterx' ); ?>
|
39 |
+
<?php jupiterx_the_help_link( 'http://help.artbees.net/getting-started/plugins/installing-the-bundled-plugins', __( 'Installing the Bundled Plugins.', 'jupiterx' ) ); ?>
|
40 |
+
</h3>
|
41 |
+
<div class="btn-group jupiterx-cp-plugins-filter disabled" role="group">
|
42 |
+
<button type="button" class="btn btn-secondary" data-filter="all" disabled><?php esc_html_e( 'All', 'jupiterx' ); ?></button>
|
43 |
+
<button type="button" class="btn btn-outline-secondary" data-filter="active" disabled><?php esc_html_e( 'Active', 'jupiterx' ); ?></button>
|
44 |
+
<button type="button" class="btn btn-outline-secondary" data-filter="inactive" disabled><?php esc_html_e( 'Inactive', 'jupiterx' ); ?></button>
|
45 |
+
<?php
|
46 |
+
$is_update_available = false;
|
47 |
+
if ( class_exists( 'JupiterX_Control_Panel_Install_Plugins' ) ) {
|
48 |
+
$plugin_manager = new JupiterX_Control_Panel_Install_Plugins();
|
49 |
+
$is_update_available = $plugin_manager->is_update_available();
|
50 |
+
}
|
51 |
+
if ( $is_update_available && ! is_multisite() ) : ?>
|
52 |
+
<button type="button" class="btn btn-outline-secondary" data-filter="update" disabled><?php esc_html_e( 'Update available', 'jupiterx' ); ?></button>
|
53 |
+
<?php endif; ?>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
<div id="js__jupiterx-plugins" class="d-flex">
|
57 |
+
<svg class="jupiterx-spinner" width="50px" height="50px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
58 |
+
<circle class="jupiterx-spinner-path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
59 |
+
</svg>
|
60 |
+
</div>
|
61 |
+
</div>
|
62 |
+
</div>
|
includes/control-panel/views/install-templates.php
CHANGED
@@ -1,61 +1,61 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! JUPITERX_CONTROL_PANEL_TEMPLATES ) {
|
4 |
-
return;
|
5 |
-
}
|
6 |
-
|
7 |
-
$menu_items_access = get_site_option( 'menu_items' );
|
8 |
-
|
9 |
-
if ( is_multisite() && ! is_super_admin() ) : ?>
|
10 |
-
<div class="jupiterx-cp-pane-box" id="jupiterx-no-templates">
|
11 |
-
<div class="alert alert-warning" role="alert">
|
12 |
-
|
13 |
-
<?php esc_html_e( 'Template installation is only allowed for user with Super Admin role. Please contact your website\'s administrator.', 'jupiterx-core' ); ?>
|
14 |
-
<a href="https://themes.artbees.net/docs/installing-a-template/" target="_blank" >
|
15 |
-
<?php esc_html_e( 'Read More', 'jupiterx-core' ); ?>
|
16 |
-
</a>
|
17 |
-
</div>
|
18 |
-
</div>
|
19 |
-
<?php
|
20 |
-
endif;
|
21 |
-
|
22 |
-
$installed_template_data_attr = '';
|
23 |
-
$installed_template_id = jupiterx_get_option( 'template_installed_id', '' );
|
24 |
-
$installed_template_data_attr .= ' data-installed-template-id="' . esc_attr( $installed_template_id ) . '"';
|
25 |
-
$installed_template = jupiterx_get_option( 'template_installed', '' );
|
26 |
-
$installed_template_data_attr .= ' data-installed-template="' . esc_attr( $installed_template ) . '"';
|
27 |
-
wp_print_request_filesystem_credentials_modal();
|
28 |
-
?>
|
29 |
-
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-templates">
|
30 |
-
|
31 |
-
<!-- Restore Button wrap -->
|
32 |
-
<div id="js__restore-template-wrap" class="jupiterx-restore-template-wrap">
|
33 |
-
<a class="btn btn-primary jupiterx-button--restore-backup" id="js__restore-template-btn" href="#" data-content="" data-toggle="popover" data-placement="bottom">
|
34 |
-
<?php esc_html_e( 'Restore from Last Backup', 'jupiterx-core' ); ?>
|
35 |
-
</a>
|
36 |
-
</div>
|
37 |
-
<!-- End of Restore Button wrap -->
|
38 |
-
|
39 |
-
<!-- Installed Template wrap -->
|
40 |
-
<div id="js__installed-template-wrap" class="jupiterx-cp-installed-template">
|
41 |
-
<h3>
|
42 |
-
<?php esc_html_e( 'Installed Template', 'jupiterx-core' ); ?>
|
43 |
-
<?php jupiterx_the_help_link( 'http://help.artbees.net/getting-started/templates/installing-a-template', esc_html__( 'Installing a Template', 'jupiterx-core' ) ); ?>
|
44 |
-
</h3>
|
45 |
-
<div id="js__installed-template" <?php echo $installed_template_data_attr; ?>></div>
|
46 |
-
<div class="clearfix"></div>
|
47 |
-
</div>
|
48 |
-
<!-- End of installed template -->
|
49 |
-
|
50 |
-
<div class="jupiterx-cp-install-template">
|
51 |
-
<h3>
|
52 |
-
<?php esc_html_e( 'Templates', 'jupiterx-core' ); ?>
|
53 |
-
<?php jupiterx_the_help_link( 'http://help.artbees.net/getting-started/templates/installing-a-template', esc_html__( 'Installing a Template', 'jupiterx-core' ) ); ?>
|
54 |
-
</h3>
|
55 |
-
<?php
|
56 |
-
jupiterx_templates()->html( [
|
57 |
-
'posts_per_page' => 12,
|
58 |
-
] );
|
59 |
-
?>
|
60 |
-
</div>
|
61 |
-
</div>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if ( ! JUPITERX_CONTROL_PANEL_TEMPLATES ) {
|
4 |
+
return;
|
5 |
+
}
|
6 |
+
|
7 |
+
$menu_items_access = get_site_option( 'menu_items' );
|
8 |
+
|
9 |
+
if ( is_multisite() && ! is_super_admin() ) : ?>
|
10 |
+
<div class="jupiterx-cp-pane-box" id="jupiterx-no-templates">
|
11 |
+
<div class="alert alert-warning" role="alert">
|
12 |
+
|
13 |
+
<?php esc_html_e( 'Template installation is only allowed for user with Super Admin role. Please contact your website\'s administrator.', 'jupiterx-core' ); ?>
|
14 |
+
<a href="https://themes.artbees.net/docs/installing-a-template/" target="_blank" >
|
15 |
+
<?php esc_html_e( 'Read More', 'jupiterx-core' ); ?>
|
16 |
+
</a>
|
17 |
+
</div>
|
18 |
+
</div>
|
19 |
+
<?php
|
20 |
+
endif;
|
21 |
+
|
22 |
+
$installed_template_data_attr = '';
|
23 |
+
$installed_template_id = jupiterx_get_option( 'template_installed_id', '' );
|
24 |
+
$installed_template_data_attr .= ' data-installed-template-id="' . esc_attr( $installed_template_id ) . '"';
|
25 |
+
$installed_template = jupiterx_get_option( 'template_installed', '' );
|
26 |
+
$installed_template_data_attr .= ' data-installed-template="' . esc_attr( $installed_template ) . '"';
|
27 |
+
wp_print_request_filesystem_credentials_modal();
|
28 |
+
?>
|
29 |
+
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-templates">
|
30 |
+
|
31 |
+
<!-- Restore Button wrap -->
|
32 |
+
<div id="js__restore-template-wrap" class="jupiterx-restore-template-wrap">
|
33 |
+
<a class="btn btn-primary jupiterx-button--restore-backup" id="js__restore-template-btn" href="#" data-content="" data-toggle="popover" data-placement="bottom">
|
34 |
+
<?php esc_html_e( 'Restore from Last Backup', 'jupiterx-core' ); ?>
|
35 |
+
</a>
|
36 |
+
</div>
|
37 |
+
<!-- End of Restore Button wrap -->
|
38 |
+
|
39 |
+
<!-- Installed Template wrap -->
|
40 |
+
<div id="js__installed-template-wrap" class="jupiterx-cp-installed-template">
|
41 |
+
<h3>
|
42 |
+
<?php esc_html_e( 'Installed Template', 'jupiterx-core' ); ?>
|
43 |
+
<?php jupiterx_the_help_link( 'http://help.artbees.net/getting-started/templates/installing-a-template', esc_html__( 'Installing a Template', 'jupiterx-core' ) ); ?>
|
44 |
+
</h3>
|
45 |
+
<div id="js__installed-template" <?php echo $installed_template_data_attr; ?>></div>
|
46 |
+
<div class="clearfix"></div>
|
47 |
+
</div>
|
48 |
+
<!-- End of installed template -->
|
49 |
+
|
50 |
+
<div class="jupiterx-cp-install-template">
|
51 |
+
<h3>
|
52 |
+
<?php esc_html_e( 'Templates', 'jupiterx-core' ); ?>
|
53 |
+
<?php jupiterx_the_help_link( 'http://help.artbees.net/getting-started/templates/installing-a-template', esc_html__( 'Installing a Template', 'jupiterx-core' ) ); ?>
|
54 |
+
</h3>
|
55 |
+
<?php
|
56 |
+
jupiterx_templates()->html( [
|
57 |
+
'posts_per_page' => 12,
|
58 |
+
] );
|
59 |
+
?>
|
60 |
+
</div>
|
61 |
+
</div>
|
includes/control-panel/views/settings.php
CHANGED
@@ -1,103 +1,104 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Settings template.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel\Settings
|
6 |
-
*
|
7 |
-
* @since 1.4.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
if ( ! JUPITERX_CONTROL_PANEL_SETTINGS ) {
|
11 |
-
return;
|
12 |
-
}
|
13 |
-
?>
|
14 |
-
<div class="jupiterx-cp-pane-box bootstrap-wrapper">
|
15 |
-
<h3><?php esc_html_e( 'Settings', 'jupiterx-core' ); ?></h3>
|
16 |
-
<div class="jupiterx-cp-export-wrap">
|
17 |
-
<form class="jupiterx-cp-settings-form" action="#">
|
18 |
-
<div class="form-row">
|
19 |
-
<div class="form-group col-md-12">
|
20 |
-
<button type="button" class="btn btn-secondary jupiterx-cp-settings-flush"><?php esc_html_e( 'Flush Assets Cache', 'jupiterx-core' ); ?></button>
|
21 |
-
<span class="jupiterx-cp-settings-flush-feedback text-muted ml-2 d-none"><?php esc_html_e( 'Flushing...', 'jupiterx-core' ); ?></span>
|
22 |
-
<small class="form-text text-muted"><?php esc_html_e( 'Clear CSS, Javascript and images cached files. New cached versions will be compiled/created on page load.', 'jupiterx-core' ); ?></small>
|
23 |
-
</div>
|
24 |
-
<div class="col-md-12"><hr></div>
|
25 |
-
<div class="form-group col-md-6">
|
26 |
-
<label for="jupiterx-cp-settings-dev-mode"><?php esc_html_e( 'Development Mode', 'jupiterx-core' ); ?></label>
|
27 |
-
<input type="hidden" name="jupiterx_dev_mode" value="0">
|
28 |
-
<div class="jupiterx-switch">
|
29 |
-
<input type="checkbox" id="jupiterx-cp-settings-dev-mode" name="jupiterx_dev_mode" value="1" <?php checked( jupiterx_get_option( 'dev_mode' ), true ); ?>>
|
30 |
-
<label for="jupiterx-cp-settings-dev-mode"></label>
|
31 |
-
</div>
|
32 |
-
<small class="form-text text-muted"><?php esc_html_e( 'This option should be enabled while your website is in development.', 'jupiterx-core' ); ?></small>
|
33 |
-
</div>
|
34 |
-
<div class="form-group col-md-6">
|
35 |
-
<label for="jupiterx-cp-settings-cache-busting"><?php esc_html_e( 'Cache Busting', 'jupiterx-core' ); ?></label>
|
36 |
-
<input type="hidden" name="jupiterx_cache_busting" value="0">
|
37 |
-
<div class="jupiterx-switch">
|
38 |
-
<input type="checkbox" id="jupiterx-cp-settings-cache-busting" name="jupiterx_cache_busting" value="1" <?php checked( jupiterx_get_option( 'cache_busting', true ) ); ?>>
|
39 |
-
<label for="jupiterx-cp-settings-cache-busting"></label>
|
40 |
-
</div>
|
41 |
-
<small class="form-text text-muted"><?php esc_html_e( 'Enable cache busting technique.', 'jupiterx-core' ); ?></small>
|
42 |
-
</div>
|
43 |
-
<?php do_action( 'jupiterx_control_panel_after_theme_settings' ); ?>
|
44 |
-
<div class="col-md-12"><hr></div>
|
45 |
-
<div class="form-group col-md-12">
|
46 |
-
<label class="m-0"><?php esc_html_e( 'Custom Post Types', 'jupiterx-core' ); ?></label>
|
47 |
-
<small class="form-text text-muted mb-2"><?php esc_html_e( 'Enable Jupiter features (customizer, meta options, etc.) for these post types.', 'jupiterx-core' ); ?></small>
|
48 |
-
<input type="hidden" name="jupiterx_post_types" value="">
|
49 |
-
<?php $post_types = jupiterx_get_custom_post_types( 'objects' ); ?>
|
50 |
-
<?php
|
51 |
-
|
52 |
-
|
53 |
-
<?php echo '<
|
54 |
-
<?php echo '<
|
55 |
-
<?php echo '</
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
<?php
|
65 |
-
|
66 |
-
<
|
67 |
-
<
|
68 |
-
|
69 |
-
<
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
<
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
<
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
<
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
<
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
<
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
<
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
<
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
</div>
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Settings template.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel\Settings
|
6 |
+
*
|
7 |
+
* @since 1.4.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
if ( ! JUPITERX_CONTROL_PANEL_SETTINGS ) {
|
11 |
+
return;
|
12 |
+
}
|
13 |
+
?>
|
14 |
+
<div class="jupiterx-cp-pane-box bootstrap-wrapper">
|
15 |
+
<h3><?php esc_html_e( 'Settings', 'jupiterx-core' ); ?></h3>
|
16 |
+
<div class="jupiterx-cp-export-wrap">
|
17 |
+
<form class="jupiterx-cp-settings-form" action="#">
|
18 |
+
<div class="form-row">
|
19 |
+
<div class="form-group col-md-12">
|
20 |
+
<button type="button" class="btn btn-secondary jupiterx-cp-settings-flush"><?php esc_html_e( 'Flush Assets Cache', 'jupiterx-core' ); ?></button>
|
21 |
+
<span class="jupiterx-cp-settings-flush-feedback text-muted ml-2 d-none"><?php esc_html_e( 'Flushing...', 'jupiterx-core' ); ?></span>
|
22 |
+
<small class="form-text text-muted"><?php esc_html_e( 'Clear CSS, Javascript and images cached files. New cached versions will be compiled/created on page load.', 'jupiterx-core' ); ?></small>
|
23 |
+
</div>
|
24 |
+
<div class="col-md-12"><hr></div>
|
25 |
+
<div class="form-group col-md-6">
|
26 |
+
<label for="jupiterx-cp-settings-dev-mode"><?php esc_html_e( 'Development Mode', 'jupiterx-core' ); ?></label>
|
27 |
+
<input type="hidden" name="jupiterx_dev_mode" value="0">
|
28 |
+
<div class="jupiterx-switch">
|
29 |
+
<input type="checkbox" id="jupiterx-cp-settings-dev-mode" name="jupiterx_dev_mode" value="1" <?php checked( jupiterx_get_option( 'dev_mode' ), true ); ?>>
|
30 |
+
<label for="jupiterx-cp-settings-dev-mode"></label>
|
31 |
+
</div>
|
32 |
+
<small class="form-text text-muted"><?php esc_html_e( 'This option should be enabled while your website is in development.', 'jupiterx-core' ); ?></small>
|
33 |
+
</div>
|
34 |
+
<div class="form-group col-md-6">
|
35 |
+
<label for="jupiterx-cp-settings-cache-busting"><?php esc_html_e( 'Cache Busting', 'jupiterx-core' ); ?></label>
|
36 |
+
<input type="hidden" name="jupiterx_cache_busting" value="0">
|
37 |
+
<div class="jupiterx-switch">
|
38 |
+
<input type="checkbox" id="jupiterx-cp-settings-cache-busting" name="jupiterx_cache_busting" value="1" <?php checked( jupiterx_get_option( 'cache_busting', true ) ); ?>>
|
39 |
+
<label for="jupiterx-cp-settings-cache-busting"></label>
|
40 |
+
</div>
|
41 |
+
<small class="form-text text-muted"><?php esc_html_e( 'Enable cache busting technique.', 'jupiterx-core' ); ?></small>
|
42 |
+
</div>
|
43 |
+
<?php do_action( 'jupiterx_control_panel_after_theme_settings' ); ?>
|
44 |
+
<div class="col-md-12"><hr></div>
|
45 |
+
<div class="form-group col-md-12">
|
46 |
+
<label class="m-0"><?php esc_html_e( 'Custom Post Types', 'jupiterx-core' ); ?></label>
|
47 |
+
<small class="form-text text-muted mb-2"><?php esc_html_e( 'Enable Jupiter features (customizer, meta options, etc.) for these post types.', 'jupiterx-core' ); ?></small>
|
48 |
+
<input type="hidden" name="jupiterx_post_types" value="">
|
49 |
+
<?php $post_types = jupiterx_get_custom_post_types( 'objects' ); ?>
|
50 |
+
<?php $supported_post_types = jupiterx_get_option( 'post_types' ); ?>
|
51 |
+
<?php if ( ! empty( $post_types ) ) : ?>
|
52 |
+
<?php foreach ( $post_types as $id => $post_type ) : ?>
|
53 |
+
<?php echo '<div class="custom-control custom-checkbox">'; ?>
|
54 |
+
<?php echo '<input type="checkbox" class="custom-control-input" name="jupiterx_post_types[]" ' . ( ( is_array( $supported_post_types ) && in_array( $post_type->name, jupiterx_get_option( 'post_types' ), true ) ) ? 'checked="checked"' : '' ) . ' value="' . esc_attr( $post_type->name ) . '" id="jupiterx_post_type_' . esc_attr( $post_type->name ) . '">'; ?>
|
55 |
+
<?php echo '<label class="custom-control-label" for="jupiterx_post_type_' . esc_attr( $post_type->name ) . '">' . $post_type->label . '</label>'; ?>
|
56 |
+
<?php echo '</div>'; ?>
|
57 |
+
<?php endforeach; ?>
|
58 |
+
<?php else : ?>
|
59 |
+
<div class="jupiterx-settings-no-post-type">
|
60 |
+
<i class="jupiterx-icon-info-circle"></i><?php esc_html_e( 'No custom post type was found.', 'jupiterx-core' ); ?>
|
61 |
+
</div>
|
62 |
+
<?php endif; ?>
|
63 |
+
</div>
|
64 |
+
<?php do_action( 'jupiterx_control_panel_settings_white_label' ); ?>
|
65 |
+
<?php if ( jupiterx_is_premium() && class_exists( 'Jupiter_Donut' ) ) : ?>
|
66 |
+
<div class="col-md-12"><hr></div>
|
67 |
+
<h5 class="col-md-12 mb-3">Donut Plugin</h5>
|
68 |
+
<div class="form-group col-md-6">
|
69 |
+
<label for="jupiterx-cp-settings-donut-twitter-consumer-key"><?php esc_html_e( 'Twitter Consumer Key', 'jupiterx-core' ); ?></label>
|
70 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-twitter-consumer-key" value="<?php echo esc_attr( jupiterx_get_option( 'donut_twitter_consumer_key' ) ); ?>" name="jupiterx_donut_twitter_consumer_key">
|
71 |
+
</div>
|
72 |
+
<div class="form-group col-md-6">
|
73 |
+
<label for="jupiterx-cp-settings-donut-twitter-consumer-secret"><?php esc_html_e( 'Twitter Consumer Secret', 'jupiterx-core' ); ?></label>
|
74 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-twitter-consumer-secret" value="<?php echo esc_attr( jupiterx_get_option( 'donut_twitter_consumer_secret' ) ); ?>" name="jupiterx_donut_twitter_consumer_secret">
|
75 |
+
</div>
|
76 |
+
<div class="form-group col-md-6">
|
77 |
+
<label for="jupiterx-cp-settings-donut-twitter-access-token"><?php esc_html_e( 'Twitter Access Token', 'jupiterx-core' ); ?></label>
|
78 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-twitter-access-token" value="<?php echo esc_attr( jupiterx_get_option( 'donut_twitter_access_token' ) ); ?>" name="jupiterx_donut_twitter_access_token">
|
79 |
+
</div>
|
80 |
+
<div class="form-group col-md-6">
|
81 |
+
<label for="jupiterx-cp-settings-donut-twitter-access-token-secret"><?php esc_html_e( 'Twitter Access Token Secret', 'jupiterx-core' ); ?></label>
|
82 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-twitter-access-token-secret" value="<?php echo esc_attr( jupiterx_get_option( 'donut_twitter_access_token_secret' ) ); ?>" name="jupiterx_donut_twitter_access_token_secret">
|
83 |
+
</div>
|
84 |
+
<div class="form-group col-md-6">
|
85 |
+
<label for="jupiterx-cp-settings-donut-mailchimp-api-key"><?php esc_html_e( 'MailChimp API Key', 'jupiterx-core' ); ?></label>
|
86 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-mailchimp-api-key" value="<?php echo esc_attr( jupiterx_get_option( 'donut_mailchimp_api_key' ) ); ?>" name="jupiterx_donut_mailchimp_api_key">
|
87 |
+
</div>
|
88 |
+
<div class="form-group col-md-6">
|
89 |
+
<label for="jupiterx-cp-settings-donut-mailchimp-list-id"><?php esc_html_e( 'Mailchimp List ID', 'jupiterx-core' ); ?></label>
|
90 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-mailchimp-list-id" value="<?php echo esc_attr( jupiterx_get_option( 'donut_mailchimp_list_id' ) ); ?>" name="jupiterx_donut_mailchimp_list_id">
|
91 |
+
</div>
|
92 |
+
<div class="form-group col-md-6">
|
93 |
+
<label for="jupiterx-cp-settings-donut-google-maps-api-key"><?php esc_html_e( 'Google Maps API Key', 'jupiterx-core' ); ?></label>
|
94 |
+
<input type="text" class="jupiterx-form-control" id="jupiterx-cp-settings-donut-google-maps-api-key" value="<?php echo esc_attr( jupiterx_get_option( 'donut_google_maps_api_key' ) ); ?>" name="jupiterx_donut_google_maps_api_key">
|
95 |
+
</div>
|
96 |
+
<?php endif; ?>
|
97 |
+
</div>
|
98 |
+
<div class="mt-2">
|
99 |
+
<button type="submit" class="btn btn-primary"><?php esc_html_e( 'Save Settings', 'jupiterx-core' ); ?></button>
|
100 |
+
<span class="jupiterx-cp-settings-save-feedback text-muted ml-2 d-none"><?php esc_html_e( 'Saving...', 'jupiterx-core' ); ?></span>
|
101 |
+
</div>
|
102 |
+
</form>
|
103 |
+
</div>
|
104 |
+
</div>
|
includes/control-panel/views/system-status.php
CHANGED
@@ -1,929 +1,929 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! JUPITERX_CONTROL_PANEL_SYSTEM_STATUS ) {
|
3 |
-
return;
|
4 |
-
}
|
5 |
-
|
6 |
-
$sysinfo = JupiterX_Control_Panel_System_Status::compile_system_status();
|
7 |
-
$sysinfo_warnings = JupiterX_Control_Panel_System_Status::compile_system_status_warnings();
|
8 |
-
?>
|
9 |
-
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-system-status">
|
10 |
-
<h3>
|
11 |
-
<?php esc_html_e( 'System Status', 'jupiterx-core' ); ?>
|
12 |
-
<?php jupiterx_the_help_link( 'https://themes.artbees.net/docs/checking-server-requirements-x-theme/', __( 'Checking Server Requirements', 'jupiterx-core' ) ); ?>
|
13 |
-
</h3>
|
14 |
-
|
15 |
-
<a class="btn btn-primary jupiterx-button--get-system-report" href="#">
|
16 |
-
<?php esc_html_e( 'Get System Report', 'jupiterx-core' ); ?>
|
17 |
-
</a>
|
18 |
-
|
19 |
-
<div id="jupiterx-textarea--get-system-report">
|
20 |
-
<textarea readonly="readonly" onclick="this.focus();this.select()"></textarea>
|
21 |
-
</div>
|
22 |
-
<br>
|
23 |
-
<table class="table" cellspacing="0">
|
24 |
-
<thead class="thead-light">
|
25 |
-
<tr>
|
26 |
-
<th colspan="3" data-export-label="WordPress Environment">
|
27 |
-
<?php esc_html_e( 'WordPress Environment', 'jupiterx-core' ); ?>
|
28 |
-
</th>
|
29 |
-
</tr>
|
30 |
-
</thead>
|
31 |
-
<tbody>
|
32 |
-
<tr>
|
33 |
-
<td data-export-label="Home URL">
|
34 |
-
<?php esc_html_e( 'Home URL', 'jupiterx-core' ); ?>:
|
35 |
-
</td>
|
36 |
-
<td class="help">
|
37 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The URL of your site\'s homepage.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
38 |
-
</td>
|
39 |
-
|
40 |
-
<td><code><?php echo wp_kses_post( $sysinfo['home_url'] ); ?></code></td>
|
41 |
-
</tr>
|
42 |
-
<tr>
|
43 |
-
<td data-export-label="Site URL">
|
44 |
-
<?php esc_html_e( 'Site URL', 'jupiterx-core' ); ?>:
|
45 |
-
</td>
|
46 |
-
<td class="help">
|
47 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The root URL of your site.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
48 |
-
</td>
|
49 |
-
<td>
|
50 |
-
<code><?php echo esc_url( $sysinfo['site_url'] ); ?></code>
|
51 |
-
</td>
|
52 |
-
</tr>
|
53 |
-
<tr>
|
54 |
-
<td data-export-label="WP Content URL">
|
55 |
-
<?php esc_html_e( 'WP Content URL', 'jupiterx-core' ); ?>:
|
56 |
-
</td>
|
57 |
-
<td class="help">
|
58 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The URL of WordPress\'s content directory.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
59 |
-
</td>
|
60 |
-
<td>
|
61 |
-
<code><?php echo esc_url( $sysinfo['wp_content_url'] ); ?></code>
|
62 |
-
</td>
|
63 |
-
</tr>
|
64 |
-
<tr>
|
65 |
-
<td data-export-label="WP Upload Path">
|
66 |
-
<?php esc_html_e( 'WP Upload Path', 'jupiterx-core' ); ?>:
|
67 |
-
</td>
|
68 |
-
<td class="help">
|
69 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The absolute path to WordPress\'s upload directory.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
70 |
-
</td>
|
71 |
-
<td>
|
72 |
-
<code><?php echo esc_url( $sysinfo['wp_upload_dir'] ); ?></code>
|
73 |
-
</td>
|
74 |
-
</tr>
|
75 |
-
<tr>
|
76 |
-
<td data-export-label="WP Upload URL">
|
77 |
-
<?php esc_html_e( 'WP Upload URL', 'jupiterx-core' ); ?>:
|
78 |
-
</td>
|
79 |
-
<td class="help">
|
80 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The URL of WordPress\'s upload directory.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
81 |
-
</td>
|
82 |
-
<td>
|
83 |
-
<code><?php echo esc_url( $sysinfo['wp_upload_url'] ); ?></code>
|
84 |
-
</td>
|
85 |
-
</tr>
|
86 |
-
<tr>
|
87 |
-
<td data-export-label="WP Version">
|
88 |
-
<?php esc_html_e( 'WP Version', 'jupiterx-core' ); ?>:
|
89 |
-
</td>
|
90 |
-
<td class="help">
|
91 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The version of WordPress installed on your site.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
92 |
-
</td>
|
93 |
-
<td>
|
94 |
-
<?php bloginfo( 'version' ); ?>
|
95 |
-
</td>
|
96 |
-
</tr>
|
97 |
-
<tr>
|
98 |
-
<td data-export-label="WP Multisite">
|
99 |
-
<?php esc_html_e( 'WP Multisite', 'jupiterx-core' ); ?>:
|
100 |
-
</td>
|
101 |
-
<td class="help">
|
102 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Whether or not you have WordPress Multisite enabled.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
103 |
-
</td>
|
104 |
-
<td>
|
105 |
-
<?php if ( false == $sysinfo['wp_multisite'] ) : ?>
|
106 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
107 |
-
<?php else : ?>
|
108 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
109 |
-
<?php endif; ?>
|
110 |
-
</td>
|
111 |
-
</tr>
|
112 |
-
<tr>
|
113 |
-
<td data-export-label="Permalink Structure">
|
114 |
-
<?php esc_html_e( 'Permalink Structure', 'jupiterx-core' ); ?>:
|
115 |
-
</td>
|
116 |
-
<td class="help">
|
117 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The current permalink structure as defined in WordPress Settings->Permalinks.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
118 |
-
</td>
|
119 |
-
<td>
|
120 |
-
<code><?php echo esc_html( $sysinfo['permalink_structure'] ); ?></code>
|
121 |
-
</td>
|
122 |
-
</tr>
|
123 |
-
<?php $sof = $sysinfo['front_page_display']; ?>
|
124 |
-
<tr>
|
125 |
-
<td data-export-label="Front Page Display">
|
126 |
-
<?php esc_html_e( 'Front Page Display', 'jupiterx-core' ); ?>:
|
127 |
-
</td>
|
128 |
-
<td class="help">
|
129 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The current Reading mode of WordPress.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
130 |
-
</td>
|
131 |
-
<td><?php echo esc_html( $sof ); ?></td>
|
132 |
-
</tr>
|
133 |
-
|
134 |
-
<?php
|
135 |
-
if ( 'page' == $sof ) {
|
136 |
-
?>
|
137 |
-
<tr>
|
138 |
-
<td data-export-label="Front Page">
|
139 |
-
<?php esc_html_e( 'Front Page', 'jupiterx-core' ); ?>:
|
140 |
-
</td>
|
141 |
-
<td class="help">
|
142 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The currently selected page which acts as the site\'s Front Page.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
143 |
-
</td>
|
144 |
-
<td>
|
145 |
-
<?php echo esc_html( $sysinfo['front_page'] ); ?>
|
146 |
-
</td>
|
147 |
-
</tr>
|
148 |
-
<tr>
|
149 |
-
<td data-export-label="Posts Page">
|
150 |
-
<?php esc_html_e( 'Posts Page', 'jupiterx-core' ); ?>:
|
151 |
-
</td>
|
152 |
-
<td class="help">
|
153 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The currently selected page in where blog posts are displayed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
154 |
-
</td>
|
155 |
-
<td>
|
156 |
-
<?php echo esc_html( $sysinfo['posts_page'] ); ?>
|
157 |
-
</td>
|
158 |
-
</tr>
|
159 |
-
<?php
|
160 |
-
}
|
161 |
-
?>
|
162 |
-
<tr class="<?php esc_attr_e( isset( $sysinfo_warnings['wp_mem_limit'] ) ? 'jupiterx-sysinfo-warning' : '' ); ?>">
|
163 |
-
<td data-export-label="WP Memory Limit">
|
164 |
-
<?php esc_html_e( 'WP Memory Limit', 'jupiterx-core' ); ?>:
|
165 |
-
</td>
|
166 |
-
<td class="help">
|
167 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum amount of memory (RAM) that your site can use at one time.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
168 |
-
</td>
|
169 |
-
<td>
|
170 |
-
<span class="jupiterx-sysinfo-value">
|
171 |
-
<?php echo esc_html( $sysinfo['wp_mem_limit']['size'] ); ?>
|
172 |
-
</span>
|
173 |
-
<?php if ( isset( $sysinfo_warnings['wp_mem_limit'] ) ): ?>
|
174 |
-
<span class="jupiterx-sysinfo-warning-msg">
|
175 |
-
<i class="jupiterx-icon-info-circle"></i>
|
176 |
-
<?php echo $sysinfo_warnings['wp_mem_limit']['message']; ?>
|
177 |
-
</span>
|
178 |
-
<?php endif; ?>
|
179 |
-
</td>
|
180 |
-
</tr>
|
181 |
-
<tr>
|
182 |
-
<td data-export-label="Database Table Prefix">
|
183 |
-
<?php esc_html_e( 'Database Table Prefix', 'jupiterx-core' ); ?>:
|
184 |
-
</td>
|
185 |
-
<td class="help">
|
186 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The prefix structure of the current WordPress database.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
187 |
-
</td>
|
188 |
-
<td>
|
189 |
-
<?php echo esc_html( $sysinfo['db_table_prefix'] ); ?>
|
190 |
-
</td>
|
191 |
-
</tr>
|
192 |
-
<tr>
|
193 |
-
<td data-export-label="WP Debug Mode">
|
194 |
-
<?php esc_html_e( 'WP Debug Mode', 'jupiterx-core' ); ?>:
|
195 |
-
</td>
|
196 |
-
<td class="help">
|
197 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Displays whether or not WordPress is in Debug Mode.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
198 |
-
</td>
|
199 |
-
<td>
|
200 |
-
<?php if ( 'false' == $sysinfo['wp_debug'] ) : ?>
|
201 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
202 |
-
<?php else : ?>
|
203 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
204 |
-
<?php endif; ?>
|
205 |
-
</td>
|
206 |
-
</tr>
|
207 |
-
<tr>
|
208 |
-
<td data-export-label="Language">
|
209 |
-
<?php esc_html_e( 'Language', 'jupiterx-core' ); ?>:
|
210 |
-
</td>
|
211 |
-
<td class="help">
|
212 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The current language used by WordPress. Default = English', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
213 |
-
</td>
|
214 |
-
<td>
|
215 |
-
<?php echo esc_html( $sysinfo['wp_lang'] ); ?>
|
216 |
-
</td>
|
217 |
-
</tr>
|
218 |
-
<tr>
|
219 |
-
<td data-export-label="The Main WP Directory">
|
220 |
-
<?php esc_html_e( 'The Main WP Directory', 'jupiterx-core' ); ?>:
|
221 |
-
</td>
|
222 |
-
<td class="help">
|
223 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if main WP directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
224 |
-
</td>
|
225 |
-
<td>
|
226 |
-
<?php if ( wp_is_writable( $sysinfo['wp_writable'] ) ) : ?>
|
227 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
228 |
-
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
229 |
-
<?php else : ?>
|
230 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
231 |
-
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_writable'] ); ?></span>
|
232 |
-
<?php endif; ?>
|
233 |
-
</td>
|
234 |
-
</tr>
|
235 |
-
<tr>
|
236 |
-
<td data-export-label="The wp-content Directory">
|
237 |
-
<?php esc_html_e( 'The wp-content Directory', 'jupiterx-core' ); ?>:
|
238 |
-
</td>
|
239 |
-
<td class="help">
|
240 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if wp-content directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
241 |
-
</td>
|
242 |
-
<td>
|
243 |
-
<?php if ( wp_is_writable( $sysinfo['wp_content_writable'] ) ) : ?>
|
244 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
245 |
-
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
246 |
-
<?php else : ?>
|
247 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
248 |
-
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_content_writable'] ); ?></span>
|
249 |
-
<?php endif; ?>
|
250 |
-
</td>
|
251 |
-
</tr>
|
252 |
-
<tr>
|
253 |
-
<td data-export-label="The uploads Directory">
|
254 |
-
<?php esc_html_e( 'The uploads Directory', 'jupiterx-core' ); ?>:
|
255 |
-
</td>
|
256 |
-
<td class="help">
|
257 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if uploads directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
258 |
-
</td>
|
259 |
-
<td>
|
260 |
-
<?php if ( wp_is_writable( $sysinfo['wp_uploads_writable'] ) ) : ?>
|
261 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
262 |
-
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
263 |
-
<?php else : ?>
|
264 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
265 |
-
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_uploads_writable'] ); ?></span>
|
266 |
-
<?php endif; ?>
|
267 |
-
</td>
|
268 |
-
</tr>
|
269 |
-
<tr>
|
270 |
-
<td data-export-label="The plugins Directory">
|
271 |
-
<?php esc_html_e( 'The plugins Directory', 'jupiterx-core' ); ?>:
|
272 |
-
</td>
|
273 |
-
<td class="help">
|
274 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if plugins directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
275 |
-
</td>
|
276 |
-
<td>
|
277 |
-
<?php if ( wp_is_writable( $sysinfo['wp_plugins_writable'] ) ) : ?>
|
278 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
279 |
-
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
280 |
-
<?php else : ?>
|
281 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
282 |
-
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_plugins_writable'] ); ?></span>
|
283 |
-
<?php endif; ?>
|
284 |
-
</td>
|
285 |
-
</tr>
|
286 |
-
<tr>
|
287 |
-
<td data-export-label="The themes Directory">
|
288 |
-
<?php esc_html_e( 'The themes Directory', 'jupiterx-core' ); ?>:
|
289 |
-
</td>
|
290 |
-
<td class="help">
|
291 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if themes directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
292 |
-
</td>
|
293 |
-
<td>
|
294 |
-
<?php if ( wp_is_writable( $sysinfo['wp_themes_writable'] ) ) : ?>
|
295 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
296 |
-
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
297 |
-
<?php else : ?>
|
298 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
299 |
-
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_themes_writable'] ); ?></span>
|
300 |
-
<?php endif; ?>
|
301 |
-
</td>
|
302 |
-
</tr>
|
303 |
-
</tbody>
|
304 |
-
</table>
|
305 |
-
<br><br>
|
306 |
-
<table class="table" cellspacing="0">
|
307 |
-
<thead class="thead-light">
|
308 |
-
<tr>
|
309 |
-
<th colspan="3" data-export-label="Theme"><?php esc_html_e( 'Theme', 'jupiterx-core' ); ?></th>
|
310 |
-
</tr>
|
311 |
-
</thead>
|
312 |
-
<tbody>
|
313 |
-
<tr>
|
314 |
-
<td data-export-label="Name"><?php esc_html_e( 'Name', 'jupiterx-core' ); ?>:</td>
|
315 |
-
<td class="help">
|
316 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The name of the current active theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
317 |
-
</td>
|
318 |
-
<td><?php echo esc_html( $sysinfo['theme']['name'] ); ?></td>
|
319 |
-
</tr>
|
320 |
-
<tr>
|
321 |
-
<td data-export-label="Version"><?php esc_html_e( 'Version', 'jupiterx-core' ); ?>:</td>
|
322 |
-
<td class="help">
|
323 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The installed version of the current active theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
324 |
-
</td>
|
325 |
-
<td>
|
326 |
-
<?php echo esc_html( $sysinfo['theme']['version'] ); ?>
|
327 |
-
</td>
|
328 |
-
</tr>
|
329 |
-
<tr>
|
330 |
-
<td data-export-label="Author URL"><?php esc_html_e( 'Author URL', 'jupiterx-core' ); ?>:</td>
|
331 |
-
<td class="help">
|
332 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The theme developers URL.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
333 |
-
</td>
|
334 |
-
<td><?php echo esc_url( $sysinfo['theme']['author_uri'] ); ?></td>
|
335 |
-
</tr>
|
336 |
-
<tr>
|
337 |
-
<td data-export-label="Child Theme"><?php esc_html_e( 'Child Theme', 'jupiterx-core' ); ?>:</td>
|
338 |
-
<td class="help">
|
339 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Displays whether or not the current theme is a child theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
340 |
-
</td>
|
341 |
-
<td>
|
342 |
-
<?php if ( is_child_theme() ) : ?>
|
343 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
344 |
-
<?php else : ?>
|
345 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
346 |
-
<?php endif; ?>
|
347 |
-
</td>
|
348 |
-
</tr>
|
349 |
-
<?php if ( is_child_theme() ) : ?>
|
350 |
-
<tr>
|
351 |
-
<td data-export-label="Parent Theme Name"><?php esc_html_e( 'Parent Theme Name', 'jupiterx-core' ); ?>:
|
352 |
-
</td>
|
353 |
-
<td class="help">
|
354 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The name of the parent theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
355 |
-
</td>
|
356 |
-
<td><?php echo esc_html( $sysinfo['theme']['parent_name'] ); ?></td>
|
357 |
-
</tr>
|
358 |
-
<tr>
|
359 |
-
<td data-export-label="Parent Theme Version">
|
360 |
-
<?php esc_html_e( 'Parent Theme Version', 'jupiterx-core' ); ?>:
|
361 |
-
</td>
|
362 |
-
<td class="help">
|
363 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The installed version of the parent theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
364 |
-
</td>
|
365 |
-
<td><?php echo esc_html( $sysinfo['theme']['parent_version'] ); ?></td>
|
366 |
-
</tr>
|
367 |
-
<tr>
|
368 |
-
<td data-export-label="Parent Theme Author URL">
|
369 |
-
<?php esc_html_e( 'Parent Theme Author URL', 'jupiterx-core' ); ?>:
|
370 |
-
</td>
|
371 |
-
<td class="help">
|
372 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The parent theme developers URL.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
373 |
-
</td>
|
374 |
-
<td><?php echo esc_url( $sysinfo['theme']['parent_author_uri'] ); ?></td>
|
375 |
-
</tr>
|
376 |
-
<?php endif; ?>
|
377 |
-
</tbody>
|
378 |
-
</table>
|
379 |
-
<br><br>
|
380 |
-
|
381 |
-
<table class="table" cellspacing="0">
|
382 |
-
<thead class="thead-light">
|
383 |
-
<tr>
|
384 |
-
<th colspan="3" data-export-label="Browser">
|
385 |
-
<?php esc_html_e( 'Browser', 'jupiterx-core' ); ?>
|
386 |
-
</th>
|
387 |
-
</tr>
|
388 |
-
</thead>
|
389 |
-
<tbody>
|
390 |
-
<tr>
|
391 |
-
<td data-export-label="Browser Info">
|
392 |
-
<?php esc_html_e( 'Browser Info', 'jupiterx-core' ); ?>:
|
393 |
-
</td>
|
394 |
-
<td class="help">
|
395 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Information about web browser current in use.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
396 |
-
</td>
|
397 |
-
<td>
|
398 |
-
<?php
|
399 |
-
foreach ( $sysinfo['browser'] as $key => $value ) {
|
400 |
-
echo '<strong>' . esc_html( ucfirst( $key ) ) . '</strong>: ' . esc_html( $value ) . '<br/>';
|
401 |
-
}
|
402 |
-
?>
|
403 |
-
</td>
|
404 |
-
</tr>
|
405 |
-
</tbody>
|
406 |
-
</table>
|
407 |
-
<br><br>
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
<table class="table" cellspacing="0">
|
412 |
-
<thead class="thead-light">
|
413 |
-
<tr>
|
414 |
-
<th colspan="3" data-export-label="Server Environment">
|
415 |
-
<?php esc_html_e( 'Server Environment', 'jupiterx-core' ); ?>
|
416 |
-
</th>
|
417 |
-
</tr>
|
418 |
-
</thead>
|
419 |
-
<tbody>
|
420 |
-
<tr>
|
421 |
-
<td data-export-label="Server Info">
|
422 |
-
<?php esc_html_e( 'Server Info', 'jupiterx-core' ); ?>:
|
423 |
-
</td>
|
424 |
-
<td class="help">
|
425 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Information about the web server that is currently hosting your site.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
426 |
-
</td>
|
427 |
-
<td>
|
428 |
-
<?php echo esc_html( $sysinfo['server_info'] ); ?>
|
429 |
-
</td>
|
430 |
-
</tr>
|
431 |
-
<tr>
|
432 |
-
<td data-export-label="Localhost Environment">
|
433 |
-
<?php esc_html_e( 'Localhost Environment', 'jupiterx-core' ); ?>:
|
434 |
-
</td>
|
435 |
-
<td class="help">
|
436 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Is the server running in a localhost environment.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
437 |
-
</td>
|
438 |
-
<td>
|
439 |
-
<?php if ( 'true' == $sysinfo['localhost'] ) : ?>
|
440 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
441 |
-
<?php else : ?>
|
442 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
443 |
-
<?php endif; ?>
|
444 |
-
</td>
|
445 |
-
</tr>
|
446 |
-
<tr>
|
447 |
-
<td data-export-label="PHP Version">
|
448 |
-
<?php esc_html_e( 'PHP Version', 'jupiterx-core' ); ?>:
|
449 |
-
</td>
|
450 |
-
<td class="help">
|
451 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The version of PHP installed on your hosting server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
452 |
-
</td>
|
453 |
-
<td>
|
454 |
-
<?php echo esc_html( $sysinfo['php_ver'] ); ?>
|
455 |
-
</td>
|
456 |
-
</tr>
|
457 |
-
<tr>
|
458 |
-
<td data-export-label="ABSPATH">
|
459 |
-
<?php esc_html_e( 'ABSPATH', 'jupiterx-core' ); ?>:
|
460 |
-
</td>
|
461 |
-
<td class="help">
|
462 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The ABSPATH variable on the server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
463 |
-
</td>
|
464 |
-
<td>
|
465 |
-
<?php echo '<code>' . esc_html( $sysinfo['abspath'] ) . '</code>'; ?>
|
466 |
-
</td>
|
467 |
-
</tr>
|
468 |
-
|
469 |
-
<?php
|
470 |
-
if ( function_exists( 'ini_get' ) ) {
|
471 |
-
?>
|
472 |
-
<tr class="<?php esc_attr_e( isset( $sysinfo_warnings['php_mem_limit'] ) ? 'jupiterx-sysinfo-warning' : '' ); ?>">
|
473 |
-
<td data-export-label="PHP Memory Limit"><?php esc_html_e( 'PHP Memory Limit', 'jupiterx-core' ); ?>:</td>
|
474 |
-
<td class="help">
|
475 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The largest filesize that can be contained in one post.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
476 |
-
</td>
|
477 |
-
<td>
|
478 |
-
<span class="jupiterx-sysinfo-value">
|
479 |
-
<?php echo esc_html( $sysinfo['php_mem_limit']['size'] ); ?>
|
480 |
-
</span>
|
481 |
-
<?php if ( isset( $sysinfo_warnings['php_mem_limit'] ) ): ?>
|
482 |
-
<span class="jupiterx-sysinfo-warning-msg">
|
483 |
-
<i class="jupiterx-icon-info-circle"></i>
|
484 |
-
<?php echo $sysinfo_warnings['php_mem_limit']['message']; ?>
|
485 |
-
</span>
|
486 |
-
<?php endif; ?>
|
487 |
-
</td>
|
488 |
-
</tr>
|
489 |
-
<tr>
|
490 |
-
<td data-export-label="PHP Post Max Size"><?php esc_html_e( 'PHP Post Max Size', 'jupiterx-core' ); ?>:</td>
|
491 |
-
<td class="help">
|
492 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The largest filesize that can be contained in one post.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
493 |
-
</td>
|
494 |
-
<td><?php echo esc_html( $sysinfo['php_post_max_size'] ); ?></td>
|
495 |
-
</tr>
|
496 |
-
<tr>
|
497 |
-
<td data-export-label="PHP Time Limit"><?php esc_html_e( 'PHP Time Limit', 'jupiterx-core' ); ?>:</td>
|
498 |
-
<td class="help">
|
499 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'max_execution_time : The amount of time (in seconds) that your site will spend on a single operation before timing out (to avoid server lockups).', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
500 |
-
</td>
|
501 |
-
<td><?php echo esc_html( $sysinfo['php_time_limit'] ); ?></td>
|
502 |
-
</tr>
|
503 |
-
|
504 |
-
<tr>
|
505 |
-
<td data-export-label="PHP Max Input Vars"><?php esc_html_e( 'PHP Max Input Vars', 'jupiterx-core' ); ?>:</td>
|
506 |
-
<td class="help">
|
507 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum number of variables your server can use for a single function to avoid overloads.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
508 |
-
</td>
|
509 |
-
<td><?php echo esc_html( $sysinfo['php_max_input_var'] ); ?></td>
|
510 |
-
</tr>
|
511 |
-
|
512 |
-
<?php
|
513 |
-
if ( true == $sysinfo['suhosin_installed'] ) {
|
514 |
-
?>
|
515 |
-
<tr>
|
516 |
-
<td data-export-label="PHP Max Input Vars"><?php esc_html_e( 'Suhosin Max Request Vars', 'jupiterx-core' ); ?>:</td>
|
517 |
-
<td class="help">
|
518 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum number of variables your server running Suhosin can use for a single function to avoid overloads.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
519 |
-
</td>
|
520 |
-
<td><?php echo esc_html( $sysinfo['suhosin_request_max_vars'] ); ?></td>
|
521 |
-
</tr>
|
522 |
-
<tr>
|
523 |
-
<td data-export-label="PHP Max Input Vars"><?php esc_html_e( 'Suhosin Max Post Vars', 'jupiterx-core' ); ?>:</td>
|
524 |
-
<td class="help">
|
525 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum number of variables your server running Suhosin can use for a single function to avoid overloads.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
526 |
-
</td>
|
527 |
-
<td><?php echo esc_html( $sysinfo['suhosin_post_max_vars'] ); ?></td>
|
528 |
-
</tr>
|
529 |
-
<?php
|
530 |
-
}
|
531 |
-
?>
|
532 |
-
<tr>
|
533 |
-
<td data-export-label="PHP Display Errors"><?php esc_html_e( 'PHP Display Errors', 'jupiterx-core' ); ?>:</td>
|
534 |
-
<td class="help">
|
535 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Determines if PHP will display errors within the browser.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
536 |
-
</td>
|
537 |
-
<td>
|
538 |
-
<?php if ( 'false' == $sysinfo['php_display_errors'] ) : ?>
|
539 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
540 |
-
<?php else : ?>
|
541 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
542 |
-
<?php endif; ?>
|
543 |
-
</td>
|
544 |
-
</tr>
|
545 |
-
<?php
|
546 |
-
}
|
547 |
-
?>
|
548 |
-
<tr>
|
549 |
-
<td data-export-label="SUHOSIN Installed"><?php esc_html_e( 'SUHOSIN Installed', 'jupiterx-core' ); ?>:</td>
|
550 |
-
<td class="help">
|
551 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Suhosin is an advanced protection system for PHP installations. It was designed to protect your servers on the one hand against a number of well known problems in PHP applications and on the other hand against potential unknown vulnerabilities within these applications or the PHP core itself. If enabled on your server, Suhosin may need to be configured to increase its data submission limits.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
552 |
-
</td>
|
553 |
-
<td>
|
554 |
-
<?php if ( false == $sysinfo['suhosin_installed'] ) : ?>
|
555 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
556 |
-
<?php else : ?>
|
557 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
558 |
-
<?php endif; ?>
|
559 |
-
</td>
|
560 |
-
</tr>
|
561 |
-
|
562 |
-
<tr>
|
563 |
-
<td data-export-label="MySQL Version"><?php esc_html_e( 'MySQL Version', 'jupiterx-core' ); ?>:</td>
|
564 |
-
<td class="help">
|
565 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The version of MySQL installed on your hosting server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
566 |
-
</td>
|
567 |
-
<td><?php echo esc_html( $sysinfo['mysql_ver'] ); ?></td>
|
568 |
-
</tr>
|
569 |
-
<tr>
|
570 |
-
<td data-export-label="Max Upload Size"><?php esc_html_e( 'Max Upload Size', 'jupiterx-core' ); ?>:</td>
|
571 |
-
<td class="help">
|
572 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The largest filesize that can be uploaded to your WordPress installation.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
573 |
-
</td>
|
574 |
-
<td><?php echo esc_html( $sysinfo['max_upload_size'] ); ?></td>
|
575 |
-
</tr>
|
576 |
-
<tr>
|
577 |
-
<td data-export-label="Default Timezone is UTC">
|
578 |
-
<?php esc_html_e( 'Default Timezone is UTC', 'jupiterx-core' ); ?>:
|
579 |
-
</td>
|
580 |
-
<td class="help">
|
581 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The default timezone for your server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
582 |
-
</td>
|
583 |
-
<td>
|
584 |
-
<?php if ( 'false' == $sysinfo['def_tz_is_utc'] ) : ?>
|
585 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
586 |
-
<?php sprintf( __( 'Default timezone is %s - it should be UTC', 'jupiterx-core' ), esc_html( date_default_timezone_get() ) ); ?>
|
587 |
-
<?php else : ?>
|
588 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
589 |
-
<?php endif; ?>
|
590 |
-
</td>
|
591 |
-
</tr>
|
592 |
-
<tr>
|
593 |
-
|
594 |
-
<td data-export-label="PHP XML">
|
595 |
-
<?php esc_html_e( 'PHP XML', 'jupiterx-core' ); ?>:
|
596 |
-
</td>
|
597 |
-
<td class="help">
|
598 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Theme requires PHP XML Library to be installed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
599 |
-
</td>
|
600 |
-
<td>
|
601 |
-
<?php if ( 'false' == $sysinfo['phpxml'] ) : ?>
|
602 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
603 |
-
<?php else : ?>
|
604 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
605 |
-
<?php endif; ?>
|
606 |
-
</td>
|
607 |
-
</tr>
|
608 |
-
<tr>
|
609 |
-
<td data-export-label="MBString">
|
610 |
-
<?php esc_html_e( 'MBString', 'jupiterx-core' ); ?>:
|
611 |
-
</td>
|
612 |
-
<td class="help">
|
613 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Theme requires MBString PHP Library to be installed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
614 |
-
</td>
|
615 |
-
<td>
|
616 |
-
<?php if ( 'false' == $sysinfo['mbstring'] ) : ?>
|
617 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
618 |
-
<?php else : ?>
|
619 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
620 |
-
<?php endif; ?>
|
621 |
-
</td>
|
622 |
-
</tr>
|
623 |
-
<tr>
|
624 |
-
<td data-export-label="SimpleXML">
|
625 |
-
<?php esc_html_e( 'SimpleXML', 'jupiterx-core' ); ?>:
|
626 |
-
</td>
|
627 |
-
<td class="help">
|
628 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Theme requires SimpleXML PHP Library to be installed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
629 |
-
</td>
|
630 |
-
<td>
|
631 |
-
<?php if ( 'false' == $sysinfo['simplexml'] ) : ?>
|
632 |
-
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
633 |
-
<?php else : ?>
|
634 |
-
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
635 |
-
<?php endif; ?>
|
636 |
-
</td>
|
637 |
-
</tr>
|
638 |
-
<?php
|
639 |
-
$posting = array();
|
640 |
-
|
641 |
-
$posting['fsockopen_curl']['name'] = esc_html__( 'Fsockopen/cURL', 'jupiterx-core' );
|
642 |
-
$posting['fsockopen_curl']['help'] = esc_attr__( 'Used when communicating with remote services with PHP.', 'jupiterx-core' );
|
643 |
-
|
644 |
-
if ( 'true' == $sysinfo['fsockopen_curl'] ) {
|
645 |
-
$posting['fsockopen_curl']['success'] = true;
|
646 |
-
} else {
|
647 |
-
$posting['fsockopen_curl']['success'] = false;
|
648 |
-
$posting['fsockopen_curl']['note'] = esc_html__( 'Your server does not have fsockopen or cURL enabled - cURL is used to communicate with other servers. Please contact your hosting provider.', 'jupiterx-core' );
|
649 |
-
}
|
650 |
-
|
651 |
-
$posting['soap_client']['name'] = esc_html__( 'SoapClient', 'jupiterx-core' );
|
652 |
-
$posting['soap_client']['help'] = esc_attr__( 'Some webservices like shipping use SOAP to get information from remote servers, for example, live shipping quotes from FedEx require SOAP to be installed.', 'jupiterx-core' );
|
653 |
-
|
654 |
-
if ( true == $sysinfo['soap_client'] ) {
|
655 |
-
$posting['soap_client']['success'] = true;
|
656 |
-
} else {
|
657 |
-
$posting['soap_client']['success'] = false;
|
658 |
-
$posting['soap_client']['note'] = sprintf( __( 'Your server does not have the <a href="%s">SOAP Client</a> class enabled - some gateway plugins which use SOAP may not work as expected.', 'jupiterx-core' ), 'http://php.net/manual/en/class.soapclient.php' );
|
659 |
-
}
|
660 |
-
|
661 |
-
$posting['dom_document']['name'] = esc_html__( 'DOMDocument', 'jupiterx-core' );
|
662 |
-
$posting['dom_document']['help'] = esc_attr__( 'HTML/Multipart emails use DOMDocument to generate inline CSS in templates.', 'jupiterx-core' );
|
663 |
-
|
664 |
-
if ( true == $sysinfo['dom_document'] ) {
|
665 |
-
$posting['dom_document']['success'] = true;
|
666 |
-
} else {
|
667 |
-
$posting['dom_document']['success'] = false;
|
668 |
-
$posting['dom_document']['note'] = sprintf( __( 'Your server does not have the <a href="%s">DOMDocument</a> class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument.', 'jupiterx-core' ), 'http://php.net/manual/en/class.domdocument.php' );
|
669 |
-
}
|
670 |
-
|
671 |
-
|
672 |
-
$posting['gzip']['name'] = esc_html__( 'GZip', 'jupiterx-core' );
|
673 |
-
$posting['gzip']['help'] = esc_attr__( 'GZip (gzopen) is used to open the GEOIP database from MaxMind.', 'jupiterx-core' );
|
674 |
-
|
675 |
-
if ( true == $sysinfo['gzip'] ) {
|
676 |
-
$posting['gzip']['success'] = true;
|
677 |
-
} else {
|
678 |
-
$posting['gzip']['success'] = false;
|
679 |
-
$posting['gzip']['note'] = sprintf( __( 'Your server does not support the <a href="%s">gzopen</a> function - this is required to use the GeoIP database from MaxMind. The API fallback will be used instead for geolocation.', 'jupiterx-core' ), 'http://php.net/manual/en/zlib.installation.php' );
|
680 |
-
}
|
681 |
-
|
682 |
-
// Zip Archive.
|
683 |
-
$posting['zip_archive']['name'] = esc_html__( 'Zip Archive', 'jupiterx-core' );
|
684 |
-
$posting['zip_archive']['help'] = esc_attr__( 'Used to read or write ZIP compressed archives and the files inside them.', 'jupiterx-core' );
|
685 |
-
|
686 |
-
if ( class_exists( 'ZipArchive' ) ) {
|
687 |
-
$posting['zip_archive']['success'] = true;
|
688 |
-
} else {
|
689 |
-
$posting['zip_archive']['note'] = esc_html__( 'ZipArchive library is missing. Install the Zip extension. Contact your hosting provider.', 'jupiterx-core' );
|
690 |
-
$posting['zip_archive']['success'] = false;
|
691 |
-
}
|
692 |
-
|
693 |
-
// Iconv.
|
694 |
-
$posting['iconv']['name'] = esc_html__( 'Iconv', 'jupiterx-core' );
|
695 |
-
$posting['iconv']['help'] = esc_attr__( 'Used in CSS parser to handle the character set conversion.', 'jupiterx-core' );
|
696 |
-
|
697 |
-
if ( extension_loaded( 'iconv' ) ) {
|
698 |
-
$posting['iconv']['success'] = true;
|
699 |
-
} else {
|
700 |
-
$posting['iconv']['note'] = esc_html__( 'Iconv library is missing. Install the iconv extension. Contact your hosting provider.', 'jupiterx-core' );
|
701 |
-
$posting['iconv']['success'] = false;
|
702 |
-
}
|
703 |
-
|
704 |
-
// Echo the fields.
|
705 |
-
foreach ( $posting as $post ) {
|
706 |
-
$mark = ! empty( $post['success'] ) ? 'yes' : 'error';
|
707 |
-
?>
|
708 |
-
<tr>
|
709 |
-
<td data-export-label="<?php echo esc_html( $post['name'] ); ?>">
|
710 |
-
<?php echo esc_html( $post['name'] ); ?>:
|
711 |
-
</td>
|
712 |
-
<td class="help">
|
713 |
-
<a class="jupiterx-tooltip" data-content="<?php echo isset( $post['help'] ) ? wp_kses_post( $post['help'] ) : ''; ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
714 |
-
</td>
|
715 |
-
<td>
|
716 |
-
<?php echo ! empty( $post['success'] ) ? '<span class="status-invisible">True</span><span class="status-state status-true"></span>' : '<span class="status-invisible">False</span><span class="status-state status-false"></span>'; ?>
|
717 |
-
<?php echo ! empty( $post['note'] ) ? wp_kses_data( $post['note'] ) : ''; ?>
|
718 |
-
</td>
|
719 |
-
</tr>
|
720 |
-
<?php
|
721 |
-
}
|
722 |
-
?>
|
723 |
-
<tr data-jupiterx-ajax="http_requests">
|
724 |
-
<td data-export-label="HTTP Requests">
|
725 |
-
<?php esc_html_e( 'HTTP Requests', 'jupiterx-core' ); ?>:
|
726 |
-
</td>
|
727 |
-
<td class="help">
|
728 |
-
<a class="jupiterx-tooltip" data-content="<?php esc_attr_e( 'Check if HTTP requests (get, post and ...) are working properly.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
729 |
-
</td>
|
730 |
-
<td>
|
731 |
-
<span class="status-state"><span class="spinner is-active"></span></span>
|
732 |
-
<span class="status-text"></span>
|
733 |
-
</td>
|
734 |
-
</tr>
|
735 |
-
<tr data-jupiterx-ajax="artbees_server">
|
736 |
-
<td data-export-label="Communication with artbees.net">
|
737 |
-
<?php esc_html_e( 'Communication with artbees.net', 'jupiterx-core' ); ?>:
|
738 |
-
</td>
|
739 |
-
<td class="help">
|
740 |
-
<a class="jupiterx-tooltip" data-content="<?php esc_attr_e( 'Check if you have proper access to artbees.net server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
741 |
-
</td>
|
742 |
-
<td>
|
743 |
-
<span class="status-state"><span class="spinner is-active"></span></span>
|
744 |
-
<span class="status-text"></span>
|
745 |
-
</td>
|
746 |
-
</tr>
|
747 |
-
</tbody>
|
748 |
-
</table>
|
749 |
-
<br><br>
|
750 |
-
|
751 |
-
<table class="table" cellspacing="0">
|
752 |
-
<thead class="thead-light">
|
753 |
-
<tr>
|
754 |
-
<th colspan="3" data-export-label="Database">
|
755 |
-
<?php esc_html_e( 'Database', 'jupiterx-core' ); ?>
|
756 |
-
</th>
|
757 |
-
</tr>
|
758 |
-
</thead>
|
759 |
-
<tbody>
|
760 |
-
<tr>
|
761 |
-
<td data-export-label="Database Info">
|
762 |
-
<?php esc_html_e( 'Database Size', 'jupiterx-core' ); ?>:
|
763 |
-
</td>
|
764 |
-
<td class="help">
|
765 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Information about database.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
766 |
-
</td>
|
767 |
-
<td>
|
768 |
-
<?php
|
769 |
-
|
770 |
-
global $wpdb;
|
771 |
-
$total_size = 0;
|
772 |
-
$data_usage = 0;
|
773 |
-
$index_usage = 0;
|
774 |
-
|
775 |
-
foreach ( $wpdb->tables('all') as $table ) {
|
776 |
-
$sql = $wpdb->prepare( "SHOW TABLE STATUS LIKE %s", $table );
|
777 |
-
$results = $wpdb->get_results( $sql, ARRAY_A );
|
778 |
-
|
779 |
-
if ( ! isset( $results[0] ) ) {
|
780 |
-
continue;
|
781 |
-
}
|
782 |
-
|
783 |
-
$data_usage += $results[0]['Data_length'];
|
784 |
-
$index_usage += $results[0]['Index_length'];
|
785 |
-
}
|
786 |
-
|
787 |
-
$total_size = round( ($data_usage + $index_usage) / ( 1024 * 1024 ), 2 );
|
788 |
-
echo $total_size . 'MB';
|
789 |
-
?>
|
790 |
-
</td>
|
791 |
-
</tr>
|
792 |
-
|
793 |
-
<?php
|
794 |
-
|
795 |
-
$prefix = $wpdb->prefix;
|
796 |
-
|
797 |
-
$tables = [
|
798 |
-
'options',
|
799 |
-
'links',
|
800 |
-
'commentmeta',
|
801 |
-
'term_relationships',
|
802 |
-
'postmeta',
|
803 |
-
'posts',
|
804 |
-
'term_taxonomy',
|
805 |
-
'terms',
|
806 |
-
'comments',
|
807 |
-
'termmeta',
|
808 |
-
];
|
809 |
-
|
810 |
-
$users_tables = [
|
811 |
-
'usermeta',
|
812 |
-
'users
|
813 |
-
];
|
814 |
-
|
815 |
-
$multisite_only_tables = [
|
816 |
-
'blogs',
|
817 |
-
'blogs_versions ',
|
818 |
-
'registration_log',
|
819 |
-
'signups',
|
820 |
-
'site',
|
821 |
-
'sitemeta',
|
822 |
-
];
|
823 |
-
|
824 |
-
// Order of conditions should not be changed.
|
825 |
-
if ( ! is_multisite() ) {
|
826 |
-
$tables = array_merge( $tables, $users_tables );
|
827 |
-
}
|
828 |
-
|
829 |
-
if ( is_multisite() && is_super_admin() ) {
|
830 |
-
$tables = array_merge( $tables, $users_tables, $multisite_only_tables );
|
831 |
-
}
|
832 |
-
|
833 |
-
foreach ( $tables as $key => $wp_table ) {
|
834 |
-
$tables[ $key ] = $wpdb->prefix . $wp_table;
|
835 |
-
}
|
836 |
-
|
837 |
-
foreach ( $tables as $table ) {
|
838 |
-
$sql = $wpdb->prepare( "SHOW TABLE STATUS LIKE %s", $table );
|
839 |
-
$results = $wpdb->get_results( $sql, ARRAY_A );
|
840 |
-
|
841 |
-
if ( ! isset( $results[0] ) ) {
|
842 |
-
continue;
|
843 |
-
}
|
844 |
-
|
845 |
-
$data_usage = $results[0]['Data_length'];
|
846 |
-
$index_usage = $results[0]['Index_length'];
|
847 |
-
?>
|
848 |
-
<tr>
|
849 |
-
<td data-export-label="<?php echo esc_attr( $table ); ?> Info">
|
850 |
-
<?php echo esc_html( $table ); ?>:
|
851 |
-
</td>
|
852 |
-
<td></td>
|
853 |
-
<td>
|
854 |
-
<?php
|
855 |
-
$total_size = round( ($data_usage + $index_usage) / ( 1024 * 1024 ), 2 );
|
856 |
-
echo $total_size . ' MB';
|
857 |
-
?>
|
858 |
-
</td>
|
859 |
-
</tr>
|
860 |
-
<?php
|
861 |
-
}
|
862 |
-
|
863 |
-
?>
|
864 |
-
</tbody>
|
865 |
-
<tr>
|
866 |
-
<td data-export-label="Theme Mods Info">
|
867 |
-
<?php esc_html_e( 'Theme Mods Size', 'jupiterx-core' ); ?>:
|
868 |
-
</td>
|
869 |
-
<td class="help">
|
870 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Size of customizer options.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
871 |
-
</td>
|
872 |
-
<td>
|
873 |
-
<?php
|
874 |
-
$mods = get_theme_mods();
|
875 |
-
$has_numeric_value = false;
|
876 |
-
|
877 |
-
foreach ( $mods as $key => $value ) {
|
878 |
-
if ( is_numeric( $key ) ) {
|
879 |
-
$has_numeric_value = true;
|
880 |
-
break;
|
881 |
-
}
|
882 |
-
}
|
883 |
-
?>
|
884 |
-
<span class="jupiterx-cp-inline-text"><?php echo round( mb_strlen( serialize( get_theme_mods() ) ) / ( 1024 ), 2 ) . ' KB'; ?></span>
|
885 |
-
<?php if ( $has_numeric_value ) : ?>
|
886 |
-
<span><a href="#" id="jupiterx-mods-cleanup" class="button button-secondary" data-nonce="<?php echo esc_attr( wp_create_nonce( 'jupiterx_mods_cleanup' ) ); ?>"> <?php esc_html_e( 'Cleanup', 'jupiterx-core' ); ?></a></span>
|
887 |
-
<?php endif; ?>
|
888 |
-
</td>
|
889 |
-
</tr>
|
890 |
-
</table>
|
891 |
-
<br><br>
|
892 |
-
|
893 |
-
<table class="table" cellspacing="0">
|
894 |
-
<thead class="thead-light">
|
895 |
-
<tr>
|
896 |
-
<th colspan="3" data-export-label="Active Plugins (<?php echo esc_html( count( (array) get_option( 'active_plugins' ) ) ); ?>)">
|
897 |
-
<?php esc_html_e( 'Active Plugins', 'jupiterx-core' ); ?> (<?php echo esc_html( count( (array) get_option( 'active_plugins' ) ) ); ?>)
|
898 |
-
</th>
|
899 |
-
</tr>
|
900 |
-
</thead>
|
901 |
-
<tbody>
|
902 |
-
<?php
|
903 |
-
foreach ( $sysinfo['plugins'] as $name => $plugin_data ) {
|
904 |
-
|
905 |
-
if ( ! empty( $plugin_data['Name'] ) ) {
|
906 |
-
$plugin_name = esc_html( $plugin_data['Name'] );
|
907 |
-
|
908 |
-
if ( ! empty( $plugin_data['PluginURI'] ) ) {
|
909 |
-
$plugin_name = '<a href="' . esc_url( $plugin_data['PluginURI'] ) . '" title="' . esc_attr__( 'Visit plugin homepage', 'jupiterx-core' ) . '">' . esc_html( $plugin_name ) . '</a>';
|
910 |
-
}
|
911 |
-
?>
|
912 |
-
<tr>
|
913 |
-
<td><?php echo wp_kses_post( $plugin_name ); ?></td>
|
914 |
-
<td class="help">
|
915 |
-
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr( strip_tags( $plugin_data['Description'] ) ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
916 |
-
</td>
|
917 |
-
<td>
|
918 |
-
<?php echo sprintf( _x( 'by %s', 'by author', 'jupiterx-core' ), wp_kses_post( $plugin_data['Author'] ) ) . ' – ' . esc_html( $plugin_data['Version'] ); ?>
|
919 |
-
</td>
|
920 |
-
</tr>
|
921 |
-
<?php
|
922 |
-
}
|
923 |
-
}
|
924 |
-
?>
|
925 |
-
</tbody>
|
926 |
-
</table>
|
927 |
-
|
928 |
-
</div>
|
929 |
-
</div>
|
1 |
+
<?php
|
2 |
+
if ( ! JUPITERX_CONTROL_PANEL_SYSTEM_STATUS ) {
|
3 |
+
return;
|
4 |
+
}
|
5 |
+
|
6 |
+
$sysinfo = JupiterX_Control_Panel_System_Status::compile_system_status();
|
7 |
+
$sysinfo_warnings = JupiterX_Control_Panel_System_Status::compile_system_status_warnings();
|
8 |
+
?>
|
9 |
+
<div class="jupiterx-cp-pane-box" id="jupiterx-cp-system-status">
|
10 |
+
<h3>
|
11 |
+
<?php esc_html_e( 'System Status', 'jupiterx-core' ); ?>
|
12 |
+
<?php jupiterx_the_help_link( 'https://themes.artbees.net/docs/checking-server-requirements-x-theme/', __( 'Checking Server Requirements', 'jupiterx-core' ) ); ?>
|
13 |
+
</h3>
|
14 |
+
|
15 |
+
<a class="btn btn-primary jupiterx-button--get-system-report" href="#">
|
16 |
+
<?php esc_html_e( 'Get System Report', 'jupiterx-core' ); ?>
|
17 |
+
</a>
|
18 |
+
|
19 |
+
<div id="jupiterx-textarea--get-system-report">
|
20 |
+
<textarea readonly="readonly" onclick="this.focus();this.select()"></textarea>
|
21 |
+
</div>
|
22 |
+
<br>
|
23 |
+
<table class="table" cellspacing="0">
|
24 |
+
<thead class="thead-light">
|
25 |
+
<tr>
|
26 |
+
<th colspan="3" data-export-label="WordPress Environment">
|
27 |
+
<?php esc_html_e( 'WordPress Environment', 'jupiterx-core' ); ?>
|
28 |
+
</th>
|
29 |
+
</tr>
|
30 |
+
</thead>
|
31 |
+
<tbody>
|
32 |
+
<tr>
|
33 |
+
<td data-export-label="Home URL">
|
34 |
+
<?php esc_html_e( 'Home URL', 'jupiterx-core' ); ?>:
|
35 |
+
</td>
|
36 |
+
<td class="help">
|
37 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The URL of your site\'s homepage.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
38 |
+
</td>
|
39 |
+
|
40 |
+
<td><code><?php echo wp_kses_post( $sysinfo['home_url'] ); ?></code></td>
|
41 |
+
</tr>
|
42 |
+
<tr>
|
43 |
+
<td data-export-label="Site URL">
|
44 |
+
<?php esc_html_e( 'Site URL', 'jupiterx-core' ); ?>:
|
45 |
+
</td>
|
46 |
+
<td class="help">
|
47 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The root URL of your site.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
48 |
+
</td>
|
49 |
+
<td>
|
50 |
+
<code><?php echo esc_url( $sysinfo['site_url'] ); ?></code>
|
51 |
+
</td>
|
52 |
+
</tr>
|
53 |
+
<tr>
|
54 |
+
<td data-export-label="WP Content URL">
|
55 |
+
<?php esc_html_e( 'WP Content URL', 'jupiterx-core' ); ?>:
|
56 |
+
</td>
|
57 |
+
<td class="help">
|
58 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The URL of WordPress\'s content directory.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
59 |
+
</td>
|
60 |
+
<td>
|
61 |
+
<code><?php echo esc_url( $sysinfo['wp_content_url'] ); ?></code>
|
62 |
+
</td>
|
63 |
+
</tr>
|
64 |
+
<tr>
|
65 |
+
<td data-export-label="WP Upload Path">
|
66 |
+
<?php esc_html_e( 'WP Upload Path', 'jupiterx-core' ); ?>:
|
67 |
+
</td>
|
68 |
+
<td class="help">
|
69 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The absolute path to WordPress\'s upload directory.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
70 |
+
</td>
|
71 |
+
<td>
|
72 |
+
<code><?php echo esc_url( $sysinfo['wp_upload_dir'] ); ?></code>
|
73 |
+
</td>
|
74 |
+
</tr>
|
75 |
+
<tr>
|
76 |
+
<td data-export-label="WP Upload URL">
|
77 |
+
<?php esc_html_e( 'WP Upload URL', 'jupiterx-core' ); ?>:
|
78 |
+
</td>
|
79 |
+
<td class="help">
|
80 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The URL of WordPress\'s upload directory.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
81 |
+
</td>
|
82 |
+
<td>
|
83 |
+
<code><?php echo esc_url( $sysinfo['wp_upload_url'] ); ?></code>
|
84 |
+
</td>
|
85 |
+
</tr>
|
86 |
+
<tr>
|
87 |
+
<td data-export-label="WP Version">
|
88 |
+
<?php esc_html_e( 'WP Version', 'jupiterx-core' ); ?>:
|
89 |
+
</td>
|
90 |
+
<td class="help">
|
91 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The version of WordPress installed on your site.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
92 |
+
</td>
|
93 |
+
<td>
|
94 |
+
<?php bloginfo( 'version' ); ?>
|
95 |
+
</td>
|
96 |
+
</tr>
|
97 |
+
<tr>
|
98 |
+
<td data-export-label="WP Multisite">
|
99 |
+
<?php esc_html_e( 'WP Multisite', 'jupiterx-core' ); ?>:
|
100 |
+
</td>
|
101 |
+
<td class="help">
|
102 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Whether or not you have WordPress Multisite enabled.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
103 |
+
</td>
|
104 |
+
<td>
|
105 |
+
<?php if ( false == $sysinfo['wp_multisite'] ) : ?>
|
106 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
107 |
+
<?php else : ?>
|
108 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
109 |
+
<?php endif; ?>
|
110 |
+
</td>
|
111 |
+
</tr>
|
112 |
+
<tr>
|
113 |
+
<td data-export-label="Permalink Structure">
|
114 |
+
<?php esc_html_e( 'Permalink Structure', 'jupiterx-core' ); ?>:
|
115 |
+
</td>
|
116 |
+
<td class="help">
|
117 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The current permalink structure as defined in WordPress Settings->Permalinks.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
118 |
+
</td>
|
119 |
+
<td>
|
120 |
+
<code><?php echo esc_html( $sysinfo['permalink_structure'] ); ?></code>
|
121 |
+
</td>
|
122 |
+
</tr>
|
123 |
+
<?php $sof = $sysinfo['front_page_display']; ?>
|
124 |
+
<tr>
|
125 |
+
<td data-export-label="Front Page Display">
|
126 |
+
<?php esc_html_e( 'Front Page Display', 'jupiterx-core' ); ?>:
|
127 |
+
</td>
|
128 |
+
<td class="help">
|
129 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The current Reading mode of WordPress.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
130 |
+
</td>
|
131 |
+
<td><?php echo esc_html( $sof ); ?></td>
|
132 |
+
</tr>
|
133 |
+
|
134 |
+
<?php
|
135 |
+
if ( 'page' == $sof ) {
|
136 |
+
?>
|
137 |
+
<tr>
|
138 |
+
<td data-export-label="Front Page">
|
139 |
+
<?php esc_html_e( 'Front Page', 'jupiterx-core' ); ?>:
|
140 |
+
</td>
|
141 |
+
<td class="help">
|
142 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The currently selected page which acts as the site\'s Front Page.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
143 |
+
</td>
|
144 |
+
<td>
|
145 |
+
<?php echo esc_html( $sysinfo['front_page'] ); ?>
|
146 |
+
</td>
|
147 |
+
</tr>
|
148 |
+
<tr>
|
149 |
+
<td data-export-label="Posts Page">
|
150 |
+
<?php esc_html_e( 'Posts Page', 'jupiterx-core' ); ?>:
|
151 |
+
</td>
|
152 |
+
<td class="help">
|
153 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The currently selected page in where blog posts are displayed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
154 |
+
</td>
|
155 |
+
<td>
|
156 |
+
<?php echo esc_html( $sysinfo['posts_page'] ); ?>
|
157 |
+
</td>
|
158 |
+
</tr>
|
159 |
+
<?php
|
160 |
+
}
|
161 |
+
?>
|
162 |
+
<tr class="<?php esc_attr_e( isset( $sysinfo_warnings['wp_mem_limit'] ) ? 'jupiterx-sysinfo-warning' : '' ); ?>">
|
163 |
+
<td data-export-label="WP Memory Limit">
|
164 |
+
<?php esc_html_e( 'WP Memory Limit', 'jupiterx-core' ); ?>:
|
165 |
+
</td>
|
166 |
+
<td class="help">
|
167 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum amount of memory (RAM) that your site can use at one time.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
168 |
+
</td>
|
169 |
+
<td>
|
170 |
+
<span class="jupiterx-sysinfo-value">
|
171 |
+
<?php echo esc_html( $sysinfo['wp_mem_limit']['size'] ); ?>
|
172 |
+
</span>
|
173 |
+
<?php if ( isset( $sysinfo_warnings['wp_mem_limit'] ) ): ?>
|
174 |
+
<span class="jupiterx-sysinfo-warning-msg">
|
175 |
+
<i class="jupiterx-icon-info-circle"></i>
|
176 |
+
<?php echo $sysinfo_warnings['wp_mem_limit']['message']; ?>
|
177 |
+
</span>
|
178 |
+
<?php endif; ?>
|
179 |
+
</td>
|
180 |
+
</tr>
|
181 |
+
<tr>
|
182 |
+
<td data-export-label="Database Table Prefix">
|
183 |
+
<?php esc_html_e( 'Database Table Prefix', 'jupiterx-core' ); ?>:
|
184 |
+
</td>
|
185 |
+
<td class="help">
|
186 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The prefix structure of the current WordPress database.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
187 |
+
</td>
|
188 |
+
<td>
|
189 |
+
<?php echo esc_html( $sysinfo['db_table_prefix'] ); ?>
|
190 |
+
</td>
|
191 |
+
</tr>
|
192 |
+
<tr>
|
193 |
+
<td data-export-label="WP Debug Mode">
|
194 |
+
<?php esc_html_e( 'WP Debug Mode', 'jupiterx-core' ); ?>:
|
195 |
+
</td>
|
196 |
+
<td class="help">
|
197 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Displays whether or not WordPress is in Debug Mode.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
198 |
+
</td>
|
199 |
+
<td>
|
200 |
+
<?php if ( 'false' == $sysinfo['wp_debug'] ) : ?>
|
201 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
202 |
+
<?php else : ?>
|
203 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
204 |
+
<?php endif; ?>
|
205 |
+
</td>
|
206 |
+
</tr>
|
207 |
+
<tr>
|
208 |
+
<td data-export-label="Language">
|
209 |
+
<?php esc_html_e( 'Language', 'jupiterx-core' ); ?>:
|
210 |
+
</td>
|
211 |
+
<td class="help">
|
212 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The current language used by WordPress. Default = English', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
213 |
+
</td>
|
214 |
+
<td>
|
215 |
+
<?php echo esc_html( $sysinfo['wp_lang'] ); ?>
|
216 |
+
</td>
|
217 |
+
</tr>
|
218 |
+
<tr>
|
219 |
+
<td data-export-label="The Main WP Directory">
|
220 |
+
<?php esc_html_e( 'The Main WP Directory', 'jupiterx-core' ); ?>:
|
221 |
+
</td>
|
222 |
+
<td class="help">
|
223 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if main WP directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
224 |
+
</td>
|
225 |
+
<td>
|
226 |
+
<?php if ( wp_is_writable( $sysinfo['wp_writable'] ) ) : ?>
|
227 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
228 |
+
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
229 |
+
<?php else : ?>
|
230 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
231 |
+
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_writable'] ); ?></span>
|
232 |
+
<?php endif; ?>
|
233 |
+
</td>
|
234 |
+
</tr>
|
235 |
+
<tr>
|
236 |
+
<td data-export-label="The wp-content Directory">
|
237 |
+
<?php esc_html_e( 'The wp-content Directory', 'jupiterx-core' ); ?>:
|
238 |
+
</td>
|
239 |
+
<td class="help">
|
240 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if wp-content directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
241 |
+
</td>
|
242 |
+
<td>
|
243 |
+
<?php if ( wp_is_writable( $sysinfo['wp_content_writable'] ) ) : ?>
|
244 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
245 |
+
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
246 |
+
<?php else : ?>
|
247 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
248 |
+
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_content_writable'] ); ?></span>
|
249 |
+
<?php endif; ?>
|
250 |
+
</td>
|
251 |
+
</tr>
|
252 |
+
<tr>
|
253 |
+
<td data-export-label="The uploads Directory">
|
254 |
+
<?php esc_html_e( 'The uploads Directory', 'jupiterx-core' ); ?>:
|
255 |
+
</td>
|
256 |
+
<td class="help">
|
257 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if uploads directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
258 |
+
</td>
|
259 |
+
<td>
|
260 |
+
<?php if ( wp_is_writable( $sysinfo['wp_uploads_writable'] ) ) : ?>
|
261 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
262 |
+
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
263 |
+
<?php else : ?>
|
264 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
265 |
+
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_uploads_writable'] ); ?></span>
|
266 |
+
<?php endif; ?>
|
267 |
+
</td>
|
268 |
+
</tr>
|
269 |
+
<tr>
|
270 |
+
<td data-export-label="The plugins Directory">
|
271 |
+
<?php esc_html_e( 'The plugins Directory', 'jupiterx-core' ); ?>:
|
272 |
+
</td>
|
273 |
+
<td class="help">
|
274 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if plugins directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
275 |
+
</td>
|
276 |
+
<td>
|
277 |
+
<?php if ( wp_is_writable( $sysinfo['wp_plugins_writable'] ) ) : ?>
|
278 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
279 |
+
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
280 |
+
<?php else : ?>
|
281 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
282 |
+
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_plugins_writable'] ); ?></span>
|
283 |
+
<?php endif; ?>
|
284 |
+
</td>
|
285 |
+
</tr>
|
286 |
+
<tr>
|
287 |
+
<td data-export-label="The themes Directory">
|
288 |
+
<?php esc_html_e( 'The themes Directory', 'jupiterx-core' ); ?>:
|
289 |
+
</td>
|
290 |
+
<td class="help">
|
291 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Check if themes directory is writable.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
292 |
+
</td>
|
293 |
+
<td>
|
294 |
+
<?php if ( wp_is_writable( $sysinfo['wp_themes_writable'] ) ) : ?>
|
295 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
296 |
+
<span><?php esc_html_e( 'Writable', 'jupiterx-core' ); ?></span>
|
297 |
+
<?php else : ?>
|
298 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
299 |
+
<span><?php printf( __( 'Make sure <code>%s</code> directory is writable.', 'jupiterx-core' ), $sysinfo['wp_themes_writable'] ); ?></span>
|
300 |
+
<?php endif; ?>
|
301 |
+
</td>
|
302 |
+
</tr>
|
303 |
+
</tbody>
|
304 |
+
</table>
|
305 |
+
<br><br>
|
306 |
+
<table class="table" cellspacing="0">
|
307 |
+
<thead class="thead-light">
|
308 |
+
<tr>
|
309 |
+
<th colspan="3" data-export-label="Theme"><?php esc_html_e( 'Theme', 'jupiterx-core' ); ?></th>
|
310 |
+
</tr>
|
311 |
+
</thead>
|
312 |
+
<tbody>
|
313 |
+
<tr>
|
314 |
+
<td data-export-label="Name"><?php esc_html_e( 'Name', 'jupiterx-core' ); ?>:</td>
|
315 |
+
<td class="help">
|
316 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The name of the current active theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
317 |
+
</td>
|
318 |
+
<td><?php echo esc_html( $sysinfo['theme']['name'] ); ?></td>
|
319 |
+
</tr>
|
320 |
+
<tr>
|
321 |
+
<td data-export-label="Version"><?php esc_html_e( 'Version', 'jupiterx-core' ); ?>:</td>
|
322 |
+
<td class="help">
|
323 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The installed version of the current active theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
324 |
+
</td>
|
325 |
+
<td>
|
326 |
+
<?php echo esc_html( $sysinfo['theme']['version'] ); ?>
|
327 |
+
</td>
|
328 |
+
</tr>
|
329 |
+
<tr>
|
330 |
+
<td data-export-label="Author URL"><?php esc_html_e( 'Author URL', 'jupiterx-core' ); ?>:</td>
|
331 |
+
<td class="help">
|
332 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The theme developers URL.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
333 |
+
</td>
|
334 |
+
<td><?php echo esc_url( $sysinfo['theme']['author_uri'] ); ?></td>
|
335 |
+
</tr>
|
336 |
+
<tr>
|
337 |
+
<td data-export-label="Child Theme"><?php esc_html_e( 'Child Theme', 'jupiterx-core' ); ?>:</td>
|
338 |
+
<td class="help">
|
339 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Displays whether or not the current theme is a child theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
340 |
+
</td>
|
341 |
+
<td>
|
342 |
+
<?php if ( is_child_theme() ) : ?>
|
343 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
344 |
+
<?php else : ?>
|
345 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
346 |
+
<?php endif; ?>
|
347 |
+
</td>
|
348 |
+
</tr>
|
349 |
+
<?php if ( is_child_theme() ) : ?>
|
350 |
+
<tr>
|
351 |
+
<td data-export-label="Parent Theme Name"><?php esc_html_e( 'Parent Theme Name', 'jupiterx-core' ); ?>:
|
352 |
+
</td>
|
353 |
+
<td class="help">
|
354 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The name of the parent theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
355 |
+
</td>
|
356 |
+
<td><?php echo esc_html( $sysinfo['theme']['parent_name'] ); ?></td>
|
357 |
+
</tr>
|
358 |
+
<tr>
|
359 |
+
<td data-export-label="Parent Theme Version">
|
360 |
+
<?php esc_html_e( 'Parent Theme Version', 'jupiterx-core' ); ?>:
|
361 |
+
</td>
|
362 |
+
<td class="help">
|
363 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The installed version of the parent theme.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
364 |
+
</td>
|
365 |
+
<td><?php echo esc_html( $sysinfo['theme']['parent_version'] ); ?></td>
|
366 |
+
</tr>
|
367 |
+
<tr>
|
368 |
+
<td data-export-label="Parent Theme Author URL">
|
369 |
+
<?php esc_html_e( 'Parent Theme Author URL', 'jupiterx-core' ); ?>:
|
370 |
+
</td>
|
371 |
+
<td class="help">
|
372 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The parent theme developers URL.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
373 |
+
</td>
|
374 |
+
<td><?php echo esc_url( $sysinfo['theme']['parent_author_uri'] ); ?></td>
|
375 |
+
</tr>
|
376 |
+
<?php endif; ?>
|
377 |
+
</tbody>
|
378 |
+
</table>
|
379 |
+
<br><br>
|
380 |
+
|
381 |
+
<table class="table" cellspacing="0">
|
382 |
+
<thead class="thead-light">
|
383 |
+
<tr>
|
384 |
+
<th colspan="3" data-export-label="Browser">
|
385 |
+
<?php esc_html_e( 'Browser', 'jupiterx-core' ); ?>
|
386 |
+
</th>
|
387 |
+
</tr>
|
388 |
+
</thead>
|
389 |
+
<tbody>
|
390 |
+
<tr>
|
391 |
+
<td data-export-label="Browser Info">
|
392 |
+
<?php esc_html_e( 'Browser Info', 'jupiterx-core' ); ?>:
|
393 |
+
</td>
|
394 |
+
<td class="help">
|
395 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Information about web browser current in use.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
396 |
+
</td>
|
397 |
+
<td>
|
398 |
+
<?php
|
399 |
+
foreach ( $sysinfo['browser'] as $key => $value ) {
|
400 |
+
echo '<strong>' . esc_html( ucfirst( $key ) ) . '</strong>: ' . esc_html( $value ) . '<br/>';
|
401 |
+
}
|
402 |
+
?>
|
403 |
+
</td>
|
404 |
+
</tr>
|
405 |
+
</tbody>
|
406 |
+
</table>
|
407 |
+
<br><br>
|
408 |
+
|
409 |
+
|
410 |
+
|
411 |
+
<table class="table" cellspacing="0">
|
412 |
+
<thead class="thead-light">
|
413 |
+
<tr>
|
414 |
+
<th colspan="3" data-export-label="Server Environment">
|
415 |
+
<?php esc_html_e( 'Server Environment', 'jupiterx-core' ); ?>
|
416 |
+
</th>
|
417 |
+
</tr>
|
418 |
+
</thead>
|
419 |
+
<tbody>
|
420 |
+
<tr>
|
421 |
+
<td data-export-label="Server Info">
|
422 |
+
<?php esc_html_e( 'Server Info', 'jupiterx-core' ); ?>:
|
423 |
+
</td>
|
424 |
+
<td class="help">
|
425 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Information about the web server that is currently hosting your site.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
426 |
+
</td>
|
427 |
+
<td>
|
428 |
+
<?php echo esc_html( $sysinfo['server_info'] ); ?>
|
429 |
+
</td>
|
430 |
+
</tr>
|
431 |
+
<tr>
|
432 |
+
<td data-export-label="Localhost Environment">
|
433 |
+
<?php esc_html_e( 'Localhost Environment', 'jupiterx-core' ); ?>:
|
434 |
+
</td>
|
435 |
+
<td class="help">
|
436 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Is the server running in a localhost environment.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
437 |
+
</td>
|
438 |
+
<td>
|
439 |
+
<?php if ( 'true' == $sysinfo['localhost'] ) : ?>
|
440 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
441 |
+
<?php else : ?>
|
442 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
443 |
+
<?php endif; ?>
|
444 |
+
</td>
|
445 |
+
</tr>
|
446 |
+
<tr>
|
447 |
+
<td data-export-label="PHP Version">
|
448 |
+
<?php esc_html_e( 'PHP Version', 'jupiterx-core' ); ?>:
|
449 |
+
</td>
|
450 |
+
<td class="help">
|
451 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The version of PHP installed on your hosting server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
452 |
+
</td>
|
453 |
+
<td>
|
454 |
+
<?php echo esc_html( $sysinfo['php_ver'] ); ?>
|
455 |
+
</td>
|
456 |
+
</tr>
|
457 |
+
<tr>
|
458 |
+
<td data-export-label="ABSPATH">
|
459 |
+
<?php esc_html_e( 'ABSPATH', 'jupiterx-core' ); ?>:
|
460 |
+
</td>
|
461 |
+
<td class="help">
|
462 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The ABSPATH variable on the server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
463 |
+
</td>
|
464 |
+
<td>
|
465 |
+
<?php echo '<code>' . esc_html( $sysinfo['abspath'] ) . '</code>'; ?>
|
466 |
+
</td>
|
467 |
+
</tr>
|
468 |
+
|
469 |
+
<?php
|
470 |
+
if ( function_exists( 'ini_get' ) ) {
|
471 |
+
?>
|
472 |
+
<tr class="<?php esc_attr_e( isset( $sysinfo_warnings['php_mem_limit'] ) ? 'jupiterx-sysinfo-warning' : '' ); ?>">
|
473 |
+
<td data-export-label="PHP Memory Limit"><?php esc_html_e( 'PHP Memory Limit', 'jupiterx-core' ); ?>:</td>
|
474 |
+
<td class="help">
|
475 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The largest filesize that can be contained in one post.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
476 |
+
</td>
|
477 |
+
<td>
|
478 |
+
<span class="jupiterx-sysinfo-value">
|
479 |
+
<?php echo esc_html( $sysinfo['php_mem_limit']['size'] ); ?>
|
480 |
+
</span>
|
481 |
+
<?php if ( isset( $sysinfo_warnings['php_mem_limit'] ) ): ?>
|
482 |
+
<span class="jupiterx-sysinfo-warning-msg">
|
483 |
+
<i class="jupiterx-icon-info-circle"></i>
|
484 |
+
<?php echo $sysinfo_warnings['php_mem_limit']['message']; ?>
|
485 |
+
</span>
|
486 |
+
<?php endif; ?>
|
487 |
+
</td>
|
488 |
+
</tr>
|
489 |
+
<tr>
|
490 |
+
<td data-export-label="PHP Post Max Size"><?php esc_html_e( 'PHP Post Max Size', 'jupiterx-core' ); ?>:</td>
|
491 |
+
<td class="help">
|
492 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The largest filesize that can be contained in one post.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
493 |
+
</td>
|
494 |
+
<td><?php echo esc_html( $sysinfo['php_post_max_size'] ); ?></td>
|
495 |
+
</tr>
|
496 |
+
<tr>
|
497 |
+
<td data-export-label="PHP Time Limit"><?php esc_html_e( 'PHP Time Limit', 'jupiterx-core' ); ?>:</td>
|
498 |
+
<td class="help">
|
499 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'max_execution_time : The amount of time (in seconds) that your site will spend on a single operation before timing out (to avoid server lockups).', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
500 |
+
</td>
|
501 |
+
<td><?php echo esc_html( $sysinfo['php_time_limit'] ); ?></td>
|
502 |
+
</tr>
|
503 |
+
|
504 |
+
<tr>
|
505 |
+
<td data-export-label="PHP Max Input Vars"><?php esc_html_e( 'PHP Max Input Vars', 'jupiterx-core' ); ?>:</td>
|
506 |
+
<td class="help">
|
507 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum number of variables your server can use for a single function to avoid overloads.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
508 |
+
</td>
|
509 |
+
<td><?php echo esc_html( $sysinfo['php_max_input_var'] ); ?></td>
|
510 |
+
</tr>
|
511 |
+
|
512 |
+
<?php
|
513 |
+
if ( true == $sysinfo['suhosin_installed'] ) {
|
514 |
+
?>
|
515 |
+
<tr>
|
516 |
+
<td data-export-label="PHP Max Input Vars"><?php esc_html_e( 'Suhosin Max Request Vars', 'jupiterx-core' ); ?>:</td>
|
517 |
+
<td class="help">
|
518 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum number of variables your server running Suhosin can use for a single function to avoid overloads.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
519 |
+
</td>
|
520 |
+
<td><?php echo esc_html( $sysinfo['suhosin_request_max_vars'] ); ?></td>
|
521 |
+
</tr>
|
522 |
+
<tr>
|
523 |
+
<td data-export-label="PHP Max Input Vars"><?php esc_html_e( 'Suhosin Max Post Vars', 'jupiterx-core' ); ?>:</td>
|
524 |
+
<td class="help">
|
525 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The maximum number of variables your server running Suhosin can use for a single function to avoid overloads.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
526 |
+
</td>
|
527 |
+
<td><?php echo esc_html( $sysinfo['suhosin_post_max_vars'] ); ?></td>
|
528 |
+
</tr>
|
529 |
+
<?php
|
530 |
+
}
|
531 |
+
?>
|
532 |
+
<tr>
|
533 |
+
<td data-export-label="PHP Display Errors"><?php esc_html_e( 'PHP Display Errors', 'jupiterx-core' ); ?>:</td>
|
534 |
+
<td class="help">
|
535 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Determines if PHP will display errors within the browser.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
536 |
+
</td>
|
537 |
+
<td>
|
538 |
+
<?php if ( 'false' == $sysinfo['php_display_errors'] ) : ?>
|
539 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
540 |
+
<?php else : ?>
|
541 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
542 |
+
<?php endif; ?>
|
543 |
+
</td>
|
544 |
+
</tr>
|
545 |
+
<?php
|
546 |
+
}
|
547 |
+
?>
|
548 |
+
<tr>
|
549 |
+
<td data-export-label="SUHOSIN Installed"><?php esc_html_e( 'SUHOSIN Installed', 'jupiterx-core' ); ?>:</td>
|
550 |
+
<td class="help">
|
551 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Suhosin is an advanced protection system for PHP installations. It was designed to protect your servers on the one hand against a number of well known problems in PHP applications and on the other hand against potential unknown vulnerabilities within these applications or the PHP core itself. If enabled on your server, Suhosin may need to be configured to increase its data submission limits.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
552 |
+
</td>
|
553 |
+
<td>
|
554 |
+
<?php if ( false == $sysinfo['suhosin_installed'] ) : ?>
|
555 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
556 |
+
<?php else : ?>
|
557 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
558 |
+
<?php endif; ?>
|
559 |
+
</td>
|
560 |
+
</tr>
|
561 |
+
|
562 |
+
<tr>
|
563 |
+
<td data-export-label="MySQL Version"><?php esc_html_e( 'MySQL Version', 'jupiterx-core' ); ?>:</td>
|
564 |
+
<td class="help">
|
565 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The version of MySQL installed on your hosting server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
566 |
+
</td>
|
567 |
+
<td><?php echo esc_html( $sysinfo['mysql_ver'] ); ?></td>
|
568 |
+
</tr>
|
569 |
+
<tr>
|
570 |
+
<td data-export-label="Max Upload Size"><?php esc_html_e( 'Max Upload Size', 'jupiterx-core' ); ?>:</td>
|
571 |
+
<td class="help">
|
572 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The largest filesize that can be uploaded to your WordPress installation.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
573 |
+
</td>
|
574 |
+
<td><?php echo esc_html( $sysinfo['max_upload_size'] ); ?></td>
|
575 |
+
</tr>
|
576 |
+
<tr>
|
577 |
+
<td data-export-label="Default Timezone is UTC">
|
578 |
+
<?php esc_html_e( 'Default Timezone is UTC', 'jupiterx-core' ); ?>:
|
579 |
+
</td>
|
580 |
+
<td class="help">
|
581 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'The default timezone for your server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
582 |
+
</td>
|
583 |
+
<td>
|
584 |
+
<?php if ( 'false' == $sysinfo['def_tz_is_utc'] ) : ?>
|
585 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
586 |
+
<?php sprintf( __( 'Default timezone is %s - it should be UTC', 'jupiterx-core' ), esc_html( date_default_timezone_get() ) ); ?>
|
587 |
+
<?php else : ?>
|
588 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
589 |
+
<?php endif; ?>
|
590 |
+
</td>
|
591 |
+
</tr>
|
592 |
+
<tr>
|
593 |
+
|
594 |
+
<td data-export-label="PHP XML">
|
595 |
+
<?php esc_html_e( 'PHP XML', 'jupiterx-core' ); ?>:
|
596 |
+
</td>
|
597 |
+
<td class="help">
|
598 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Theme requires PHP XML Library to be installed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
599 |
+
</td>
|
600 |
+
<td>
|
601 |
+
<?php if ( 'false' == $sysinfo['phpxml'] ) : ?>
|
602 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
603 |
+
<?php else : ?>
|
604 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
605 |
+
<?php endif; ?>
|
606 |
+
</td>
|
607 |
+
</tr>
|
608 |
+
<tr>
|
609 |
+
<td data-export-label="MBString">
|
610 |
+
<?php esc_html_e( 'MBString', 'jupiterx-core' ); ?>:
|
611 |
+
</td>
|
612 |
+
<td class="help">
|
613 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Theme requires MBString PHP Library to be installed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
614 |
+
</td>
|
615 |
+
<td>
|
616 |
+
<?php if ( 'false' == $sysinfo['mbstring'] ) : ?>
|
617 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
618 |
+
<?php else : ?>
|
619 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
620 |
+
<?php endif; ?>
|
621 |
+
</td>
|
622 |
+
</tr>
|
623 |
+
<tr>
|
624 |
+
<td data-export-label="SimpleXML">
|
625 |
+
<?php esc_html_e( 'SimpleXML', 'jupiterx-core' ); ?>:
|
626 |
+
</td>
|
627 |
+
<td class="help">
|
628 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Theme requires SimpleXML PHP Library to be installed.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
629 |
+
</td>
|
630 |
+
<td>
|
631 |
+
<?php if ( 'false' == $sysinfo['simplexml'] ) : ?>
|
632 |
+
<span class="status-invisible">False</span><span class="status-state status-false"></span>
|
633 |
+
<?php else : ?>
|
634 |
+
<span class="status-invisible">True</span><span class="status-state status-true"></span>
|
635 |
+
<?php endif; ?>
|
636 |
+
</td>
|
637 |
+
</tr>
|
638 |
+
<?php
|
639 |
+
$posting = array();
|
640 |
+
|
641 |
+
$posting['fsockopen_curl']['name'] = esc_html__( 'Fsockopen/cURL', 'jupiterx-core' );
|
642 |
+
$posting['fsockopen_curl']['help'] = esc_attr__( 'Used when communicating with remote services with PHP.', 'jupiterx-core' );
|
643 |
+
|
644 |
+
if ( 'true' == $sysinfo['fsockopen_curl'] ) {
|
645 |
+
$posting['fsockopen_curl']['success'] = true;
|
646 |
+
} else {
|
647 |
+
$posting['fsockopen_curl']['success'] = false;
|
648 |
+
$posting['fsockopen_curl']['note'] = esc_html__( 'Your server does not have fsockopen or cURL enabled - cURL is used to communicate with other servers. Please contact your hosting provider.', 'jupiterx-core' );
|
649 |
+
}
|
650 |
+
|
651 |
+
$posting['soap_client']['name'] = esc_html__( 'SoapClient', 'jupiterx-core' );
|
652 |
+
$posting['soap_client']['help'] = esc_attr__( 'Some webservices like shipping use SOAP to get information from remote servers, for example, live shipping quotes from FedEx require SOAP to be installed.', 'jupiterx-core' );
|
653 |
+
|
654 |
+
if ( true == $sysinfo['soap_client'] ) {
|
655 |
+
$posting['soap_client']['success'] = true;
|
656 |
+
} else {
|
657 |
+
$posting['soap_client']['success'] = false;
|
658 |
+
$posting['soap_client']['note'] = sprintf( __( 'Your server does not have the <a href="%s">SOAP Client</a> class enabled - some gateway plugins which use SOAP may not work as expected.', 'jupiterx-core' ), 'http://php.net/manual/en/class.soapclient.php' );
|
659 |
+
}
|
660 |
+
|
661 |
+
$posting['dom_document']['name'] = esc_html__( 'DOMDocument', 'jupiterx-core' );
|
662 |
+
$posting['dom_document']['help'] = esc_attr__( 'HTML/Multipart emails use DOMDocument to generate inline CSS in templates.', 'jupiterx-core' );
|
663 |
+
|
664 |
+
if ( true == $sysinfo['dom_document'] ) {
|
665 |
+
$posting['dom_document']['success'] = true;
|
666 |
+
} else {
|
667 |
+
$posting['dom_document']['success'] = false;
|
668 |
+
$posting['dom_document']['note'] = sprintf( __( 'Your server does not have the <a href="%s">DOMDocument</a> class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument.', 'jupiterx-core' ), 'http://php.net/manual/en/class.domdocument.php' );
|
669 |
+
}
|
670 |
+
|
671 |
+
|
672 |
+
$posting['gzip']['name'] = esc_html__( 'GZip', 'jupiterx-core' );
|
673 |
+
$posting['gzip']['help'] = esc_attr__( 'GZip (gzopen) is used to open the GEOIP database from MaxMind.', 'jupiterx-core' );
|
674 |
+
|
675 |
+
if ( true == $sysinfo['gzip'] ) {
|
676 |
+
$posting['gzip']['success'] = true;
|
677 |
+
} else {
|
678 |
+
$posting['gzip']['success'] = false;
|
679 |
+
$posting['gzip']['note'] = sprintf( __( 'Your server does not support the <a href="%s">gzopen</a> function - this is required to use the GeoIP database from MaxMind. The API fallback will be used instead for geolocation.', 'jupiterx-core' ), 'http://php.net/manual/en/zlib.installation.php' );
|
680 |
+
}
|
681 |
+
|
682 |
+
// Zip Archive.
|
683 |
+
$posting['zip_archive']['name'] = esc_html__( 'Zip Archive', 'jupiterx-core' );
|
684 |
+
$posting['zip_archive']['help'] = esc_attr__( 'Used to read or write ZIP compressed archives and the files inside them.', 'jupiterx-core' );
|
685 |
+
|
686 |
+
if ( class_exists( 'ZipArchive' ) ) {
|
687 |
+
$posting['zip_archive']['success'] = true;
|
688 |
+
} else {
|
689 |
+
$posting['zip_archive']['note'] = esc_html__( 'ZipArchive library is missing. Install the Zip extension. Contact your hosting provider.', 'jupiterx-core' );
|
690 |
+
$posting['zip_archive']['success'] = false;
|
691 |
+
}
|
692 |
+
|
693 |
+
// Iconv.
|
694 |
+
$posting['iconv']['name'] = esc_html__( 'Iconv', 'jupiterx-core' );
|
695 |
+
$posting['iconv']['help'] = esc_attr__( 'Used in CSS parser to handle the character set conversion.', 'jupiterx-core' );
|
696 |
+
|
697 |
+
if ( extension_loaded( 'iconv' ) ) {
|
698 |
+
$posting['iconv']['success'] = true;
|
699 |
+
} else {
|
700 |
+
$posting['iconv']['note'] = esc_html__( 'Iconv library is missing. Install the iconv extension. Contact your hosting provider.', 'jupiterx-core' );
|
701 |
+
$posting['iconv']['success'] = false;
|
702 |
+
}
|
703 |
+
|
704 |
+
// Echo the fields.
|
705 |
+
foreach ( $posting as $post ) {
|
706 |
+
$mark = ! empty( $post['success'] ) ? 'yes' : 'error';
|
707 |
+
?>
|
708 |
+
<tr>
|
709 |
+
<td data-export-label="<?php echo esc_html( $post['name'] ); ?>">
|
710 |
+
<?php echo esc_html( $post['name'] ); ?>:
|
711 |
+
</td>
|
712 |
+
<td class="help">
|
713 |
+
<a class="jupiterx-tooltip" data-content="<?php echo isset( $post['help'] ) ? wp_kses_post( $post['help'] ) : ''; ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
714 |
+
</td>
|
715 |
+
<td>
|
716 |
+
<?php echo ! empty( $post['success'] ) ? '<span class="status-invisible">True</span><span class="status-state status-true"></span>' : '<span class="status-invisible">False</span><span class="status-state status-false"></span>'; ?>
|
717 |
+
<?php echo ! empty( $post['note'] ) ? wp_kses_data( $post['note'] ) : ''; ?>
|
718 |
+
</td>
|
719 |
+
</tr>
|
720 |
+
<?php
|
721 |
+
}
|
722 |
+
?>
|
723 |
+
<tr data-jupiterx-ajax="http_requests">
|
724 |
+
<td data-export-label="HTTP Requests">
|
725 |
+
<?php esc_html_e( 'HTTP Requests', 'jupiterx-core' ); ?>:
|
726 |
+
</td>
|
727 |
+
<td class="help">
|
728 |
+
<a class="jupiterx-tooltip" data-content="<?php esc_attr_e( 'Check if HTTP requests (get, post and ...) are working properly.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
729 |
+
</td>
|
730 |
+
<td>
|
731 |
+
<span class="status-state"><span class="spinner is-active"></span></span>
|
732 |
+
<span class="status-text"></span>
|
733 |
+
</td>
|
734 |
+
</tr>
|
735 |
+
<tr data-jupiterx-ajax="artbees_server">
|
736 |
+
<td data-export-label="Communication with artbees.net">
|
737 |
+
<?php esc_html_e( 'Communication with artbees.net', 'jupiterx-core' ); ?>:
|
738 |
+
</td>
|
739 |
+
<td class="help">
|
740 |
+
<a class="jupiterx-tooltip" data-content="<?php esc_attr_e( 'Check if you have proper access to artbees.net server.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
741 |
+
</td>
|
742 |
+
<td>
|
743 |
+
<span class="status-state"><span class="spinner is-active"></span></span>
|
744 |
+
<span class="status-text"></span>
|
745 |
+
</td>
|
746 |
+
</tr>
|
747 |
+
</tbody>
|
748 |
+
</table>
|
749 |
+
<br><br>
|
750 |
+
|
751 |
+
<table class="table" cellspacing="0">
|
752 |
+
<thead class="thead-light">
|
753 |
+
<tr>
|
754 |
+
<th colspan="3" data-export-label="Database">
|
755 |
+
<?php esc_html_e( 'Database', 'jupiterx-core' ); ?>
|
756 |
+
</th>
|
757 |
+
</tr>
|
758 |
+
</thead>
|
759 |
+
<tbody>
|
760 |
+
<tr>
|
761 |
+
<td data-export-label="Database Info">
|
762 |
+
<?php esc_html_e( 'Database Size', 'jupiterx-core' ); ?>:
|
763 |
+
</td>
|
764 |
+
<td class="help">
|
765 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Information about database.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
766 |
+
</td>
|
767 |
+
<td>
|
768 |
+
<?php
|
769 |
+
|
770 |
+
global $wpdb;
|
771 |
+
$total_size = 0;
|
772 |
+
$data_usage = 0;
|
773 |
+
$index_usage = 0;
|
774 |
+
|
775 |
+
foreach ( $wpdb->tables('all') as $table ) {
|
776 |
+
$sql = $wpdb->prepare( "SHOW TABLE STATUS LIKE %s", $table );
|
777 |
+
$results = $wpdb->get_results( $sql, ARRAY_A );
|
778 |
+
|
779 |
+
if ( ! isset( $results[0] ) ) {
|
780 |
+
continue;
|
781 |
+
}
|
782 |
+
|
783 |
+
$data_usage += $results[0]['Data_length'];
|
784 |
+
$index_usage += $results[0]['Index_length'];
|
785 |
+
}
|
786 |
+
|
787 |
+
$total_size = round( ($data_usage + $index_usage) / ( 1024 * 1024 ), 2 );
|
788 |
+
echo $total_size . 'MB';
|
789 |
+
?>
|
790 |
+
</td>
|
791 |
+
</tr>
|
792 |
+
|
793 |
+
<?php
|
794 |
+
|
795 |
+
$prefix = $wpdb->prefix;
|
796 |
+
|
797 |
+
$tables = [
|
798 |
+
'options',
|
799 |
+
'links',
|
800 |
+
'commentmeta',
|
801 |
+
'term_relationships',
|
802 |
+
'postmeta',
|
803 |
+
'posts',
|
804 |
+
'term_taxonomy',
|
805 |
+
'terms',
|
806 |
+
'comments',
|
807 |
+
'termmeta',
|
808 |
+
];
|
809 |
+
|
810 |
+
$users_tables = [
|
811 |
+
'usermeta',
|
812 |
+
'users',
|
813 |
+
];
|
814 |
+
|
815 |
+
$multisite_only_tables = [
|
816 |
+
'blogs',
|
817 |
+
'blogs_versions ',
|
818 |
+
'registration_log',
|
819 |
+
'signups',
|
820 |
+
'site',
|
821 |
+
'sitemeta',
|
822 |
+
];
|
823 |
+
|
824 |
+
// Order of conditions should not be changed.
|
825 |
+
if ( ! is_multisite() ) {
|
826 |
+
$tables = array_merge( $tables, $users_tables );
|
827 |
+
}
|
828 |
+
|
829 |
+
if ( is_multisite() && is_super_admin() ) {
|
830 |
+
$tables = array_merge( $tables, $users_tables, $multisite_only_tables );
|
831 |
+
}
|
832 |
+
|
833 |
+
foreach ( $tables as $key => $wp_table ) {
|
834 |
+
$tables[ $key ] = $wpdb->prefix . $wp_table;
|
835 |
+
}
|
836 |
+
|
837 |
+
foreach ( $tables as $table ) {
|
838 |
+
$sql = $wpdb->prepare( "SHOW TABLE STATUS LIKE %s", $table );
|
839 |
+
$results = $wpdb->get_results( $sql, ARRAY_A );
|
840 |
+
|
841 |
+
if ( ! isset( $results[0] ) ) {
|
842 |
+
continue;
|
843 |
+
}
|
844 |
+
|
845 |
+
$data_usage = $results[0]['Data_length'];
|
846 |
+
$index_usage = $results[0]['Index_length'];
|
847 |
+
?>
|
848 |
+
<tr>
|
849 |
+
<td data-export-label="<?php echo esc_attr( $table ); ?> Info">
|
850 |
+
<?php echo esc_html( $table ); ?>:
|
851 |
+
</td>
|
852 |
+
<td></td>
|
853 |
+
<td>
|
854 |
+
<?php
|
855 |
+
$total_size = round( ($data_usage + $index_usage) / ( 1024 * 1024 ), 2 );
|
856 |
+
echo $total_size . ' MB';
|
857 |
+
?>
|
858 |
+
</td>
|
859 |
+
</tr>
|
860 |
+
<?php
|
861 |
+
}
|
862 |
+
|
863 |
+
?>
|
864 |
+
</tbody>
|
865 |
+
<tr>
|
866 |
+
<td data-export-label="Theme Mods Info">
|
867 |
+
<?php esc_html_e( 'Theme Mods Size', 'jupiterx-core' ); ?>:
|
868 |
+
</td>
|
869 |
+
<td class="help">
|
870 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr__( 'Size of customizer options.', 'jupiterx-core' ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
871 |
+
</td>
|
872 |
+
<td>
|
873 |
+
<?php
|
874 |
+
$mods = get_theme_mods();
|
875 |
+
$has_numeric_value = false;
|
876 |
+
|
877 |
+
foreach ( $mods as $key => $value ) {
|
878 |
+
if ( is_numeric( $key ) ) {
|
879 |
+
$has_numeric_value = true;
|
880 |
+
break;
|
881 |
+
}
|
882 |
+
}
|
883 |
+
?>
|
884 |
+
<span class="jupiterx-cp-inline-text"><?php echo round( mb_strlen( serialize( get_theme_mods() ) ) / ( 1024 ), 2 ) . ' KB'; ?></span>
|
885 |
+
<?php if ( $has_numeric_value ) : ?>
|
886 |
+
<span><a href="#" id="jupiterx-mods-cleanup" class="button button-secondary" data-nonce="<?php echo esc_attr( wp_create_nonce( 'jupiterx_mods_cleanup' ) ); ?>"> <?php esc_html_e( 'Cleanup', 'jupiterx-core' ); ?></a></span>
|
887 |
+
<?php endif; ?>
|
888 |
+
</td>
|
889 |
+
</tr>
|
890 |
+
</table>
|
891 |
+
<br><br>
|
892 |
+
|
893 |
+
<table class="table" cellspacing="0">
|
894 |
+
<thead class="thead-light">
|
895 |
+
<tr>
|
896 |
+
<th colspan="3" data-export-label="Active Plugins (<?php echo esc_html( count( (array) get_option( 'active_plugins' ) ) ); ?>)">
|
897 |
+
<?php esc_html_e( 'Active Plugins', 'jupiterx-core' ); ?> (<?php echo esc_html( count( (array) get_option( 'active_plugins' ) ) ); ?>)
|
898 |
+
</th>
|
899 |
+
</tr>
|
900 |
+
</thead>
|
901 |
+
<tbody>
|
902 |
+
<?php
|
903 |
+
foreach ( $sysinfo['plugins'] as $name => $plugin_data ) {
|
904 |
+
|
905 |
+
if ( ! empty( $plugin_data['Name'] ) ) {
|
906 |
+
$plugin_name = esc_html( $plugin_data['Name'] );
|
907 |
+
|
908 |
+
if ( ! empty( $plugin_data['PluginURI'] ) ) {
|
909 |
+
$plugin_name = '<a href="' . esc_url( $plugin_data['PluginURI'] ) . '" title="' . esc_attr__( 'Visit plugin homepage', 'jupiterx-core' ) . '">' . esc_html( $plugin_name ) . '</a>';
|
910 |
+
}
|
911 |
+
?>
|
912 |
+
<tr>
|
913 |
+
<td><?php echo wp_kses_post( $plugin_name ); ?></td>
|
914 |
+
<td class="help">
|
915 |
+
<a class="jupiterx-tooltip" data-content="<?php echo esc_attr( strip_tags( $plugin_data['Description'] ) ); ?>" href="#" data-toggle="popover" data-placement="top"></a>
|
916 |
+
</td>
|
917 |
+
<td>
|
918 |
+
<?php echo sprintf( _x( 'by %s', 'by author', 'jupiterx-core' ), wp_kses_post( $plugin_data['Author'] ) ) . ' – ' . esc_html( $plugin_data['Version'] ); ?>
|
919 |
+
</td>
|
920 |
+
</tr>
|
921 |
+
<?php
|
922 |
+
}
|
923 |
+
}
|
924 |
+
?>
|
925 |
+
</tbody>
|
926 |
+
</table>
|
927 |
+
|
928 |
+
</div>
|
929 |
+
</div>
|
includes/custom-fields/title-bar.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Add Jupiter Post Options > Title Bar meta options.
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Custom_fields
|
6 |
-
*
|
7 |
-
* @since 1.9.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
add_action( 'jupiterx_custom_field_post_types', 'jupiterx_add_title_bar_field' );
|
11 |
-
/**
|
12 |
-
* Add title bar field to the new page/post/portfolio. Add due to prevent content creation rule.
|
13 |
-
*
|
14 |
-
* @since 1.9.0
|
15 |
-
*
|
16 |
-
* @return void
|
17 |
-
*/
|
18 |
-
function jupiterx_add_title_bar_field() {
|
19 |
-
if ( ! class_exists( 'acf' ) ) {
|
20 |
-
return;
|
21 |
-
}
|
22 |
-
$key = 'field_jupiterx_post_title_bar';
|
23 |
-
$parent = 'group_jupiterx_post';
|
24 |
-
|
25 |
-
acf_add_local_field( [
|
26 |
-
'key' => "{$key}_subtitle",
|
27 |
-
'parent' => $parent,
|
28 |
-
'label' => __( 'Subtitle', 'jupiterx-core' ),
|
29 |
-
'name' => 'jupiterx_title_bar_subtitle',
|
30 |
-
'type' => 'textarea',
|
31 |
-
'rows' => '3',
|
32 |
-
] );
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Add Jupiter Post Options > Title Bar meta options.
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Custom_fields
|
6 |
+
*
|
7 |
+
* @since 1.9.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
add_action( 'jupiterx_custom_field_post_types', 'jupiterx_add_title_bar_field' );
|
11 |
+
/**
|
12 |
+
* Add title bar field to the new page/post/portfolio. Add due to prevent content creation rule.
|
13 |
+
*
|
14 |
+
* @since 1.9.0
|
15 |
+
*
|
16 |
+
* @return void
|
17 |
+
*/
|
18 |
+
function jupiterx_add_title_bar_field() {
|
19 |
+
if ( ! class_exists( 'acf' ) ) {
|
20 |
+
return;
|
21 |
+
}
|
22 |
+
$key = 'field_jupiterx_post_title_bar';
|
23 |
+
$parent = 'group_jupiterx_post';
|
24 |
+
|
25 |
+
acf_add_local_field( [
|
26 |
+
'key' => "{$key}_subtitle",
|
27 |
+
'parent' => $parent,
|
28 |
+
'label' => __( 'Subtitle', 'jupiterx-core' ),
|
29 |
+
'name' => 'jupiterx_title_bar_subtitle',
|
30 |
+
'type' => 'textarea',
|
31 |
+
'rows' => '3',
|
32 |
+
] );
|
33 |
+
}
|
includes/customizer/api/classes/class-multilingual.php
CHANGED
@@ -1,448 +1,448 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// phpcs:ignoreFile
|
4 |
-
/**
|
5 |
-
* If Polylang is active:
|
6 |
-
* - save and retrieve customizer setting per language.
|
7 |
-
* - on front-page, set options and theme mod for the selected language.
|
8 |
-
*
|
9 |
-
* Inspired by https://github.com/fastlinemedia/customizer-export-import
|
10 |
-
*
|
11 |
-
* @package JupiterX\Framework\API\Customizer
|
12 |
-
*/
|
13 |
-
|
14 |
-
if ( ! function_exists( 'pll_current_language' ) && ! class_exists( 'SitePress' ) ) {
|
15 |
-
return;
|
16 |
-
}
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Functionality for multilingual customizer.
|
20 |
-
*
|
21 |
-
* @since 1.0.0
|
22 |
-
*
|
23 |
-
* @package JupiterX\Framework\API\Customizer
|
24 |
-
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
25 |
-
*/
|
26 |
-
class CoreCustomizerMultilingual {
|
27 |
-
|
28 |
-
public static function init() {
|
29 |
-
$self = new self();
|
30 |
-
|
31 |
-
// Disable detect browser language, will return default language instead.
|
32 |
-
add_filter( 'pll_preferred_language', '__return_false' );
|
33 |
-
|
34 |
-
add_action( 'customize_controls_enqueue_scripts', [ __CLASS__, 'add_lang_to_customizer_previewer' ], 9 );
|
35 |
-
add_action( 'wp_before_admin_bar_render', [ __CLASS__, 'on_wp_before_admin_bar_render' ], 100 );
|
36 |
-
add_action( 'admin_menu', [ __CLASS__, 'on_admin_menu' ], 100 );
|
37 |
-
add_action( 'after_setup_theme', [ __CLASS__, 'remove_filters' ], 5 );
|
38 |
-
|
39 |
-
$theme_stylesheet_slug = get_option( 'stylesheet' );
|
40 |
-
$option_types = [ 'blogname', 'blogdescription', 'site_icon' ];
|
41 |
-
|
42 |
-
if ( ! ( defined('DOING_AJAX') && DOING_AJAX && isset( $_POST['action'] ) && in_array( $_POST['action'], [ 'jupiterx_cp_cleanup_mods', 'abb_install_template_procedure' ], true ) ) ) {
|
43 |
-
// Get theme mod options.
|
44 |
-
add_filter( 'option_theme_mods_' . $theme_stylesheet_slug, [ $self, 'on_option_theme_mods_get' ], 10, 1 );
|
45 |
-
// Update theme mod options.
|
46 |
-
add_filter( 'pre_update_option_theme_mods_' . $theme_stylesheet_slug, [ $self, 'on_option_theme_mods_update' ], 10, 2 );
|
47 |
-
}
|
48 |
-
|
49 |
-
foreach ( $option_types as $option_type ) {
|
50 |
-
add_filter( 'pre_option_' . $option_type, [ $self, 'on_wp_option_get' ], 10, 3 ); // get_option hook.
|
51 |
-
add_filter( 'pre_update_option_' . $option_type, [ $self, 'on_wp_option_update' ], 10, 3 ); // update_option hook.
|
52 |
-
}
|
53 |
-
|
54 |
-
return $self;
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Remove bloginfo update filters. As we save options per language in this class, we don't need WPML functionality.
|
59 |
-
*
|
60 |
-
* @since 1.0.0
|
61 |
-
*
|
62 |
-
* @return void
|
63 |
-
*/
|
64 |
-
public static function remove_filters() {
|
65 |
-
global $WPML_String_Translation; // @phpcs:ignore
|
66 |
-
remove_filter( 'pre_update_option_blogname', [ $WPML_String_Translation, 'pre_update_option_blogname' ], 5 ); // @phpcs:ignore
|
67 |
-
remove_filter( 'pre_update_option_blogdescription', [ $WPML_String_Translation, 'pre_update_option_blogdescription' ], 5 ); // @phpcs:ignore
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Get current language.
|
72 |
-
*
|
73 |
-
* @since 1.0.0
|
74 |
-
*
|
75 |
-
* @return string|bool $language|false Current language or false when none of Polylang & WPML are active.
|
76 |
-
*/
|
77 |
-
public static function get_language() {
|
78 |
-
if ( function_exists( 'pll_current_language' ) ) {
|
79 |
-
$language = pll_current_language();
|
80 |
-
|
81 |
-
if ( ! $language ) {
|
82 |
-
$language = pll_default_language();
|
83 |
-
}
|
84 |
-
|
85 |
-
return $language;
|
86 |
-
}
|
87 |
-
|
88 |
-
if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
|
89 |
-
return ICL_LANGUAGE_CODE;
|
90 |
-
}
|
91 |
-
|
92 |
-
return false;
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Get a list of active languages with extra parameters like name and slug.
|
97 |
-
*
|
98 |
-
* @since 1.0.0
|
99 |
-
*
|
100 |
-
* @return array|bool $languages|false List of active languages or false when none of Polylang & WPML are active.
|
101 |
-
*/
|
102 |
-
public static function get_languages_list() {
|
103 |
-
if ( function_exists( 'pll_current_language' ) ) {
|
104 |
-
return get_option( '_transient_pll_languages_list' );
|
105 |
-
}
|
106 |
-
|
107 |
-
if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
|
108 |
-
$list = icl_get_languages( 'skip_missing=1' );
|
109 |
-
$languages = [];
|
110 |
-
|
111 |
-
foreach ( $list as $language ) {
|
112 |
-
$temp = [];
|
113 |
-
$temp['name'] = $language['native_name'];
|
114 |
-
$temp['slug'] = $language['code'];
|
115 |
-
$languages[] = $temp;
|
116 |
-
}
|
117 |
-
|
118 |
-
return $languages;
|
119 |
-
}
|
120 |
-
|
121 |
-
return false;
|
122 |
-
}
|
123 |
-
|
124 |
-
/**
|
125 |
-
* Get a proper option key per plugin.
|
126 |
-
*
|
127 |
-
* @since 1.0.0
|
128 |
-
*
|
129 |
-
* @return string|bool Option key or false when none of Polylang & WPML are active.
|
130 |
-
*/
|
131 |
-
public static function get_option_key() {
|
132 |
-
if ( function_exists( 'pll_current_language' ) ) {
|
133 |
-
return '_customizer_polylang_settings_';
|
134 |
-
}
|
135 |
-
|
136 |
-
if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
|
137 |
-
return '_customizer_wpml_settings_';
|
138 |
-
}
|
139 |
-
|
140 |
-
return false;
|
141 |
-
}
|
142 |
-
|
143 |
-
/**
|
144 |
-
* Get home URL of current language.
|
145 |
-
*
|
146 |
-
* @param string $language current language.
|
147 |
-
*
|
148 |
-
* @since 1.0.0
|
149 |
-
*
|
150 |
-
* @return string|bool Home URL of current language or false when none of Polylang & WPML are active.
|
151 |
-
*/
|
152 |
-
public static function get_home_url( $language ) {
|
153 |
-
if ( function_exists( 'pll_current_language' ) ) {
|
154 |
-
return pll_home_url( $language );
|
155 |
-
}
|
156 |
-
|
157 |
-
if ( class_exists( 'SitePress' ) ) {
|
158 |
-
global $sitepress;
|
159 |
-
return $sitepress->language_url( $language );
|
160 |
-
}
|
161 |
-
|
162 |
-
return false;
|
163 |
-
}
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Helper to fetch custom customizer db content.
|
167 |
-
*
|
168 |
-
* @since 1.3.0
|
169 |
-
*
|
170 |
-
* @return mixed Customizer array or false.
|
171 |
-
*/
|
172 |
-
protected function get_custom_customizer_option() {
|
173 |
-
$current_language = self::get_language();
|
174 |
-
$theme_slug = get_option( 'template' );
|
175 |
-
$option_prefix = str_replace( '-', '_', $theme_slug );
|
176 |
-
$option_name = $option_prefix . self::get_option_key() . $current_language;
|
177 |
-
|
178 |
-
return get_option( $option_name, false );
|
179 |
-
}
|
180 |
-
|
181 |
-
/**
|
182 |
-
* Helper to update custom customizer db content.
|
183 |
-
*
|
184 |
-
* @since 1.3.0
|
185 |
-
*
|
186 |
-
* @param mixed $data Data to insert.
|
187 |
-
*
|
188 |
-
* @return bool Success.
|
189 |
-
*/
|
190 |
-
protected function update_custom_customizer_option( $data ) {
|
191 |
-
$current_language = self::get_language();
|
192 |
-
$theme_slug = get_option( 'template' );
|
193 |
-
$option_prefix = str_replace( '-', '_', $theme_slug );
|
194 |
-
$option_name = $option_prefix . self::get_option_key() . $current_language;
|
195 |
-
|
196 |
-
return update_option( $option_name, $data );
|
197 |
-
}
|
198 |
-
|
199 |
-
/**
|
200 |
-
* Helper
|
201 |
-
*
|
202 |
-
* @since 1.3.0
|
203 |
-
*
|
204 |
-
* @return bool If the current language is the default language.
|
205 |
-
*/
|
206 |
-
protected function current_lang_not_default() {
|
207 |
-
if ( class_exists( 'SitePress' ) ) {
|
208 |
-
global $sitepress;
|
209 |
-
return $sitepress->get_current_language() !== $sitepress->get_default_language();
|
210 |
-
}
|
211 |
-
|
212 |
-
return pll_current_language() !== pll_default_language();
|
213 |
-
}
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Check the custom db field on get_option hook to be able to return custom language value.
|
217 |
-
* If the current language is default, then return from default wp option
|
218 |
-
*
|
219 |
-
* @since 1.3.0
|
220 |
-
*
|
221 |
-
* @param bool $pre_option This is false. If something else is returned wp exits the check in db and uses this value.
|
222 |
-
* @param string $option Option name asked for.
|
223 |
-
* @param mixed $default Default value, second args when asking for options.
|
224 |
-
*
|
225 |
-
* @return mixed
|
226 |
-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
227 |
-
*/
|
228 |
-
public function on_wp_option_get( $pre_option, $option, $default ) {
|
229 |
-
|
230 |
-
// If not the default language, then skip the custom check and wp will the use default options.
|
231 |
-
if ( $this->current_lang_not_default() ) {
|
232 |
-
$data = $this->get_custom_customizer_option();
|
233 |
-
|
234 |
-
// Found the custom option. Move on.
|
235 |
-
if ( is_array( $data ) && isset( $data['options'] ) && isset( $data['options'][ $option ] ) ) {
|
236 |
-
return $data['options'][ $option ];
|
237 |
-
}
|
238 |
-
}
|
239 |
-
|
240 |
-
return $default;
|
241 |
-
}
|
242 |
-
|
243 |
-
/**
|
244 |
-
* Update the custom db field on get_option hook.
|
245 |
-
* If the current language is not default, then return old value to prevent from saving to default wp option.
|
246 |
-
*
|
247 |
-
* @since 1.3.0
|
248 |
-
*
|
249 |
-
* @param mixed $value The new, unserialized option value.
|
250 |
-
* @param mixed $old_value The old option value.
|
251 |
-
* @param string $option Option name.
|
252 |
-
*
|
253 |
-
* @return mixed
|
254 |
-
*/
|
255 |
-
public function on_wp_option_update( $value, $old_value, $option ) {
|
256 |
-
// Fetch custom option db field.
|
257 |
-
$data = $this->get_custom_customizer_option();
|
258 |
-
$theme_slug = get_option( 'template' );
|
259 |
-
// If false, the field hasn't been created yet, so it must be created.
|
260 |
-
if ( false === $data ) {
|
261 |
-
$data = [
|
262 |
-
'template' => $theme_slug,
|
263 |
-
'mods' => [],
|
264 |
-
'options' => [],
|
265 |
-
];
|
266 |
-
}
|
267 |
-
|
268 |
-
// Make sure the options array exists. We are going to use it soon.
|
269 |
-
if ( ! isset( $data['options'] ) ) {
|
270 |
-
$data['options'] = [];
|
271 |
-
}
|
272 |
-
|
273 |
-
$data['options'][ $option ] = $value;
|
274 |
-
|
275 |
-
// Update option value in custom db field. (Not necessary to save for default language since it uses default wp option fields for values when get option).
|
276 |
-
$this->update_custom_customizer_option( $data );
|
277 |
-
|
278 |
-
// If the current language is not the default language, prevent saving to option table by passing the old value back. It will then exit after the filter.
|
279 |
-
if ( $this->current_lang_not_default() ) {
|
280 |
-
return $old_value;
|
281 |
-
}
|
282 |
-
|
283 |
-
return $value;
|
284 |
-
}
|
285 |
-
|
286 |
-
/**
|
287 |
-
* Check the custom db field on get_option customizer field option name hook to be able to return custom language value.
|
288 |
-
* Parse arguments with default wp customizer values to make sure all are present in the return.
|
289 |
-
*
|
290 |
-
* @since 1.3.0
|
291 |
-
*
|
292 |
-
* @param array $value The customizer settings.
|
293 |
-
*
|
294 |
-
* @return array
|
295 |
-
*/
|
296 |
-
public function on_option_theme_mods_get( $value ) {
|
297 |
-
$data = $this->get_custom_customizer_option();
|
298 |
-
|
299 |
-
if ( isset( $data['mods'] ) && is_array( $data['mods'] ) && ! empty( $data['mods'] ) ) {
|
300 |
-
$value = wp_parse_args( $data['mods'], $value );
|
301 |
-
}
|
302 |
-
|
303 |
-
return $value;
|
304 |
-
}
|
305 |
-
|
306 |
-
/**
|
307 |
-
* Update custom customizer option.
|
308 |
-
* If the current language is not default, then return old value to prevent from saving to customizer wp option.
|
309 |
-
*
|
310 |
-
* @since 1.3.0
|
311 |
-
*
|
312 |
-
* @param mixed $value The new, unserialized option value.
|
313 |
-
* @param mixed $old_value The old option value.
|
314 |
-
*/
|
315 |
-
public function on_option_theme_mods_update( $value, $old_value ) {
|
316 |
-
|
317 |
-
$current_data = $this->get_custom_customizer_option();
|
318 |
-
$theme_slug = get_option( 'template' );
|
319 |
-
|
320 |
-
$data = [
|
321 |
-
'template' => $theme_slug,
|
322 |
-
'mods' => isset( $current_data['mods'] ) ? $current_data['mods'] : [],
|
323 |
-
'options' => isset( $current_data['options'] ) ? $current_data['options'] : [],
|
324 |
-
];
|
325 |
-
|
326 |
-
if ( is_array( $value ) && ! empty( $value ) ) {
|
327 |
-
foreach ( $value as $key => $val ) {
|
328 |
-
$data['mods'][ $key ] = $val;
|
329 |
-
}
|
330 |
-
}
|
331 |
-
$this->update_custom_customizer_option( $data );
|
332 |
-
|
333 |
-
if ( $this->current_lang_not_default() ) {
|
334 |
-
return $old_value;
|
335 |
-
}
|
336 |
-
|
337 |
-
return $value;
|
338 |
-
}
|
339 |
-
|
340 |
-
/**
|
341 |
-
* If Polylang activated, set the preview url and add select language control
|
342 |
-
*
|
343 |
-
* @author soderlind
|
344 |
-
* @version 1.0.0
|
345 |
-
* @link https://gist.github.com/soderlind/1908634f5eb0c1f69428666dd2a291d0
|
346 |
-
*
|
347 |
-
* @since 1.0.0
|
348 |
-
*/
|
349 |
-
public static function add_lang_to_customizer_previewer() {
|
350 |
-
$languages = self::get_languages_list();
|
351 |
-
|
352 |
-
if ( ! $languages ) {
|
353 |
-
return;
|
354 |
-
}
|
355 |
-
|
356 |
-
$handle = 'dss-add-lang-to-template';
|
357 |
-
$js_path_url = trailingslashit( apply_filters( 'scp_js_path_url', get_stylesheet_directory_uri() . '/js/' ) );
|
358 |
-
$src = $js_path_url . 'customizer-multilingual.js';
|
359 |
-
$deps = [ 'customize-controls' ];
|
360 |
-
wp_enqueue_script( $handle, $src, $deps, JUPITERX_VERSION, true );
|
361 |
-
$language = ( empty( $_REQUEST['lang'] ) ) ? self::get_language() : $_REQUEST['lang']; // @phpcs:ignore
|
362 |
-
|
363 |
-
if ( empty( $language ) ) {
|
364 |
-
$language = self::default_language();
|
365 |
-
}
|
366 |
-
|
367 |
-
$url = add_query_arg( 'lang', $language, self::get_home_url( $language ) );
|
368 |
-
|
369 |
-
wp_add_inline_script(
|
370 |
-
$handle,
|
371 |
-
sprintf(
|
372 |
-
'JupiterXCustomizerMultilingual.init( %s );', wp_json_encode(
|
373 |
-
[
|
374 |
-
'url' => $url,
|
375 |
-
'languages' => $languages,
|
376 |
-
'current_language' => $language,
|
377 |
-
'switcher_text' => __( 'Language:', 'jupiterx-core' ),
|
378 |
-
]
|
379 |
-
)
|
380 |
-
), 'after'
|
381 |
-
);
|
382 |
-
}
|
383 |
-
|
384 |
-
/**
|
385 |
-
* Append lang="contrycode" to the customizer url in the adminbar
|
386 |
-
*
|
387 |
-
* @since 1.0.0
|
388 |
-
*
|
389 |
-
* @return void
|
390 |
-
*/
|
391 |
-
public static function on_wp_before_admin_bar_render() {
|
392 |
-
global $wp_admin_bar;
|
393 |
-
$customize_node = $wp_admin_bar->get_node( 'customize' );
|
394 |
-
if ( ! empty( $customize_node ) ) {
|
395 |
-
$customize_node->href = add_query_arg( 'lang', self::get_language(), $customize_node->href );
|
396 |
-
$wp_admin_bar->add_node( $customize_node );
|
397 |
-
}
|
398 |
-
}
|
399 |
-
|
400 |
-
/**
|
401 |
-
* Append lang="contrycode" to the customizer url in the Admin->Apperance->Customize menu
|
402 |
-
*
|
403 |
-
* @since 1.0.0
|
404 |
-
*
|
405 |
-
* @return void
|
406 |
-
*/
|
407 |
-
public static function on_admin_menu() {
|
408 |
-
global $menu, $submenu;
|
409 |
-
$parent = 'themes.php';
|
410 |
-
if ( ! isset( $submenu[ $parent ] ) ) {
|
411 |
-
return;
|
412 |
-
}
|
413 |
-
foreach ( $submenu[ $parent ] as $k => $d ) {
|
414 |
-
if ( 'customize' === $d['1'] ) {
|
415 |
-
$submenu[ $parent ][ $k ]['2'] = add_query_arg( 'lang', self::get_language(), $submenu[ $parent ][ $k ]['2'] ); // @phpcs:ignore
|
416 |
-
break;
|
417 |
-
}
|
418 |
-
}
|
419 |
-
}
|
420 |
-
|
421 |
-
}
|
422 |
-
|
423 |
-
CoreCustomizerMultilingual::init();
|
424 |
-
|
425 |
-
if ( class_exists( 'WP_Customize_Setting' ) ) {
|
426 |
-
/**
|
427 |
-
* A class that extends WP_Customize_Setting so we can access
|
428 |
-
* the protected updated method when importing options.
|
429 |
-
*
|
430 |
-
* @since 0.3
|
431 |
-
*/
|
432 |
-
final class Customizermultilingialoption extends WP_Customize_Setting { // @phpcs:ignore
|
433 |
-
|
434 |
-
|
435 |
-
/**
|
436 |
-
* Import an option value for this setting.
|
437 |
-
*
|
438 |
-
* @since 0.3
|
439 |
-
*
|
440 |
-
* @param mixed $value The option value.
|
441 |
-
*
|
442 |
-
* @return void
|
443 |
-
*/
|
444 |
-
public function import( $value ) {
|
445 |
-
$this->update( $value );
|
446 |
-
}
|
447 |
-
}
|
448 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// phpcs:ignoreFile
|
4 |
+
/**
|
5 |
+
* If Polylang is active:
|
6 |
+
* - save and retrieve customizer setting per language.
|
7 |
+
* - on front-page, set options and theme mod for the selected language.
|
8 |
+
*
|
9 |
+
* Inspired by https://github.com/fastlinemedia/customizer-export-import
|
10 |
+
*
|
11 |
+
* @package JupiterX\Framework\API\Customizer
|
12 |
+
*/
|
13 |
+
|
14 |
+
if ( ! function_exists( 'pll_current_language' ) && ! class_exists( 'SitePress' ) ) {
|
15 |
+
return;
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Functionality for multilingual customizer.
|
20 |
+
*
|
21 |
+
* @since 1.0.0
|
22 |
+
*
|
23 |
+
* @package JupiterX\Framework\API\Customizer
|
24 |
+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
25 |
+
*/
|
26 |
+
class CoreCustomizerMultilingual {
|
27 |
+
|
28 |
+
public static function init() {
|
29 |
+
$self = new self();
|
30 |
+
|
31 |
+
// Disable detect browser language, will return default language instead.
|
32 |
+
add_filter( 'pll_preferred_language', '__return_false' );
|
33 |
+
|
34 |
+
add_action( 'customize_controls_enqueue_scripts', [ __CLASS__, 'add_lang_to_customizer_previewer' ], 9 );
|
35 |
+
add_action( 'wp_before_admin_bar_render', [ __CLASS__, 'on_wp_before_admin_bar_render' ], 100 );
|
36 |
+
add_action( 'admin_menu', [ __CLASS__, 'on_admin_menu' ], 100 );
|
37 |
+
add_action( 'after_setup_theme', [ __CLASS__, 'remove_filters' ], 5 );
|
38 |
+
|
39 |
+
$theme_stylesheet_slug = get_option( 'stylesheet' );
|
40 |
+
$option_types = [ 'blogname', 'blogdescription', 'site_icon' ];
|
41 |
+
|
42 |
+
if ( ! ( defined('DOING_AJAX') && DOING_AJAX && isset( $_POST['action'] ) && in_array( $_POST['action'], [ 'jupiterx_cp_cleanup_mods', 'abb_install_template_procedure' ], true ) ) ) {
|
43 |
+
// Get theme mod options.
|
44 |
+
add_filter( 'option_theme_mods_' . $theme_stylesheet_slug, [ $self, 'on_option_theme_mods_get' ], 10, 1 );
|
45 |
+
// Update theme mod options.
|
46 |
+
add_filter( 'pre_update_option_theme_mods_' . $theme_stylesheet_slug, [ $self, 'on_option_theme_mods_update' ], 10, 2 );
|
47 |
+
}
|
48 |
+
|
49 |
+
foreach ( $option_types as $option_type ) {
|
50 |
+
add_filter( 'pre_option_' . $option_type, [ $self, 'on_wp_option_get' ], 10, 3 ); // get_option hook.
|
51 |
+
add_filter( 'pre_update_option_' . $option_type, [ $self, 'on_wp_option_update' ], 10, 3 ); // update_option hook.
|
52 |
+
}
|
53 |
+
|
54 |
+
return $self;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Remove bloginfo update filters. As we save options per language in this class, we don't need WPML functionality.
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
*
|
62 |
+
* @return void
|
63 |
+
*/
|
64 |
+
public static function remove_filters() {
|
65 |
+
global $WPML_String_Translation; // @phpcs:ignore
|
66 |
+
remove_filter( 'pre_update_option_blogname', [ $WPML_String_Translation, 'pre_update_option_blogname' ], 5 ); // @phpcs:ignore
|
67 |
+
remove_filter( 'pre_update_option_blogdescription', [ $WPML_String_Translation, 'pre_update_option_blogdescription' ], 5 ); // @phpcs:ignore
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Get current language.
|
72 |
+
*
|
73 |
+
* @since 1.0.0
|
74 |
+
*
|
75 |
+
* @return string|bool $language|false Current language or false when none of Polylang & WPML are active.
|
76 |
+
*/
|
77 |
+
public static function get_language() {
|
78 |
+
if ( function_exists( 'pll_current_language' ) ) {
|
79 |
+
$language = pll_current_language();
|
80 |
+
|
81 |
+
if ( ! $language ) {
|
82 |
+
$language = pll_default_language();
|
83 |
+
}
|
84 |
+
|
85 |
+
return $language;
|
86 |
+
}
|
87 |
+
|
88 |
+
if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
|
89 |
+
return ICL_LANGUAGE_CODE;
|
90 |
+
}
|
91 |
+
|
92 |
+
return false;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Get a list of active languages with extra parameters like name and slug.
|
97 |
+
*
|
98 |
+
* @since 1.0.0
|
99 |
+
*
|
100 |
+
* @return array|bool $languages|false List of active languages or false when none of Polylang & WPML are active.
|
101 |
+
*/
|
102 |
+
public static function get_languages_list() {
|
103 |
+
if ( function_exists( 'pll_current_language' ) ) {
|
104 |
+
return get_option( '_transient_pll_languages_list' );
|
105 |
+
}
|
106 |
+
|
107 |
+
if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
|
108 |
+
$list = icl_get_languages( 'skip_missing=1' );
|
109 |
+
$languages = [];
|
110 |
+
|
111 |
+
foreach ( $list as $language ) {
|
112 |
+
$temp = [];
|
113 |
+
$temp['name'] = $language['native_name'];
|
114 |
+
$temp['slug'] = $language['code'];
|
115 |
+
$languages[] = $temp;
|
116 |
+
}
|
117 |
+
|
118 |
+
return $languages;
|
119 |
+
}
|
120 |
+
|
121 |
+
return false;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Get a proper option key per plugin.
|
126 |
+
*
|
127 |
+
* @since 1.0.0
|
128 |
+
*
|
129 |
+
* @return string|bool Option key or false when none of Polylang & WPML are active.
|
130 |
+
*/
|
131 |
+
public static function get_option_key() {
|
132 |
+
if ( function_exists( 'pll_current_language' ) ) {
|
133 |
+
return '_customizer_polylang_settings_';
|
134 |
+
}
|
135 |
+
|
136 |
+
if ( class_exists( 'SitePress' ) && defined( 'ICL_LANGUAGE_CODE' ) ) {
|
137 |
+
return '_customizer_wpml_settings_';
|
138 |
+
}
|
139 |
+
|
140 |
+
return false;
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Get home URL of current language.
|
145 |
+
*
|
146 |
+
* @param string $language current language.
|
147 |
+
*
|
148 |
+
* @since 1.0.0
|
149 |
+
*
|
150 |
+
* @return string|bool Home URL of current language or false when none of Polylang & WPML are active.
|
151 |
+
*/
|
152 |
+
public static function get_home_url( $language ) {
|
153 |
+
if ( function_exists( 'pll_current_language' ) ) {
|
154 |
+
return pll_home_url( $language );
|
155 |
+
}
|
156 |
+
|
157 |
+
if ( class_exists( 'SitePress' ) ) {
|
158 |
+
global $sitepress;
|
159 |
+
return $sitepress->language_url( $language );
|
160 |
+
}
|
161 |
+
|
162 |
+
return false;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Helper to fetch custom customizer db content.
|
167 |
+
*
|
168 |
+
* @since 1.3.0
|
169 |
+
*
|
170 |
+
* @return mixed Customizer array or false.
|
171 |
+
*/
|
172 |
+
protected function get_custom_customizer_option() {
|
173 |
+
$current_language = self::get_language();
|
174 |
+
$theme_slug = get_option( 'template' );
|
175 |
+
$option_prefix = str_replace( '-', '_', $theme_slug );
|
176 |
+
$option_name = $option_prefix . self::get_option_key() . $current_language;
|
177 |
+
|
178 |
+
return get_option( $option_name, false );
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Helper to update custom customizer db content.
|
183 |
+
*
|
184 |
+
* @since 1.3.0
|
185 |
+
*
|
186 |
+
* @param mixed $data Data to insert.
|
187 |
+
*
|
188 |
+
* @return bool Success.
|
189 |
+
*/
|
190 |
+
protected function update_custom_customizer_option( $data ) {
|
191 |
+
$current_language = self::get_language();
|
192 |
+
$theme_slug = get_option( 'template' );
|
193 |
+
$option_prefix = str_replace( '-', '_', $theme_slug );
|
194 |
+
$option_name = $option_prefix . self::get_option_key() . $current_language;
|
195 |
+
|
196 |
+
return update_option( $option_name, $data );
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Helper
|
201 |
+
*
|
202 |
+
* @since 1.3.0
|
203 |
+
*
|
204 |
+
* @return bool If the current language is the default language.
|
205 |
+
*/
|
206 |
+
protected function current_lang_not_default() {
|
207 |
+
if ( class_exists( 'SitePress' ) ) {
|
208 |
+
global $sitepress;
|
209 |
+
return $sitepress->get_current_language() !== $sitepress->get_default_language();
|
210 |
+
}
|
211 |
+
|
212 |
+
return pll_current_language() !== pll_default_language();
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Check the custom db field on get_option hook to be able to return custom language value.
|
217 |
+
* If the current language is default, then return from default wp option
|
218 |
+
*
|
219 |
+
* @since 1.3.0
|
220 |
+
*
|
221 |
+
* @param bool $pre_option This is false. If something else is returned wp exits the check in db and uses this value.
|
222 |
+
* @param string $option Option name asked for.
|
223 |
+
* @param mixed $default Default value, second args when asking for options.
|
224 |
+
*
|
225 |
+
* @return mixed
|
226 |
+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
227 |
+
*/
|
228 |
+
public function on_wp_option_get( $pre_option, $option, $default ) {
|
229 |
+
|
230 |
+
// If not the default language, then skip the custom check and wp will the use default options.
|
231 |
+
if ( $this->current_lang_not_default() ) {
|
232 |
+
$data = $this->get_custom_customizer_option();
|
233 |
+
|
234 |
+
// Found the custom option. Move on.
|
235 |
+
if ( is_array( $data ) && isset( $data['options'] ) && isset( $data['options'][ $option ] ) ) {
|
236 |
+
return $data['options'][ $option ];
|
237 |
+
}
|
238 |
+
}
|
239 |
+
|
240 |
+
return $default;
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Update the custom db field on get_option hook.
|
245 |
+
* If the current language is not default, then return old value to prevent from saving to default wp option.
|
246 |
+
*
|
247 |
+
* @since 1.3.0
|
248 |
+
*
|
249 |
+
* @param mixed $value The new, unserialized option value.
|
250 |
+
* @param mixed $old_value The old option value.
|
251 |
+
* @param string $option Option name.
|
252 |
+
*
|
253 |
+
* @return mixed
|
254 |
+
*/
|
255 |
+
public function on_wp_option_update( $value, $old_value, $option ) {
|
256 |
+
// Fetch custom option db field.
|
257 |
+
$data = $this->get_custom_customizer_option();
|
258 |
+
$theme_slug = get_option( 'template' );
|
259 |
+
// If false, the field hasn't been created yet, so it must be created.
|
260 |
+
if ( false === $data ) {
|
261 |
+
$data = [
|
262 |
+
'template' => $theme_slug,
|
263 |
+
'mods' => [],
|
264 |
+
'options' => [],
|
265 |
+
];
|
266 |
+
}
|
267 |
+
|
268 |
+
// Make sure the options array exists. We are going to use it soon.
|
269 |
+
if ( ! isset( $data['options'] ) ) {
|
270 |
+
$data['options'] = [];
|
271 |
+
}
|
272 |
+
|
273 |
+
$data['options'][ $option ] = $value;
|
274 |
+
|
275 |
+
// Update option value in custom db field. (Not necessary to save for default language since it uses default wp option fields for values when get option).
|
276 |
+
$this->update_custom_customizer_option( $data );
|
277 |
+
|
278 |
+
// If the current language is not the default language, prevent saving to option table by passing the old value back. It will then exit after the filter.
|
279 |
+
if ( $this->current_lang_not_default() ) {
|
280 |
+
return $old_value;
|
281 |
+
}
|
282 |
+
|
283 |
+
return $value;
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* Check the custom db field on get_option customizer field option name hook to be able to return custom language value.
|
288 |
+
* Parse arguments with default wp customizer values to make sure all are present in the return.
|
289 |
+
*
|
290 |
+
* @since 1.3.0
|
291 |
+
*
|
292 |
+
* @param array $value The customizer settings.
|
293 |
+
*
|
294 |
+
* @return array
|
295 |
+
*/
|
296 |
+
public function on_option_theme_mods_get( $value ) {
|
297 |
+
$data = $this->get_custom_customizer_option();
|
298 |
+
|
299 |
+
if ( isset( $data['mods'] ) && is_array( $data['mods'] ) && ! empty( $data['mods'] ) ) {
|
300 |
+
$value = wp_parse_args( $data['mods'], $value );
|
301 |
+
}
|
302 |
+
|
303 |
+
return $value;
|
304 |
+
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Update custom customizer option.
|
308 |
+
* If the current language is not default, then return old value to prevent from saving to customizer wp option.
|
309 |
+
*
|
310 |
+
* @since 1.3.0
|
311 |
+
*
|
312 |
+
* @param mixed $value The new, unserialized option value.
|
313 |
+
* @param mixed $old_value The old option value.
|
314 |
+
*/
|
315 |
+
public function on_option_theme_mods_update( $value, $old_value ) {
|
316 |
+
|
317 |
+
$current_data = $this->get_custom_customizer_option();
|
318 |
+
$theme_slug = get_option( 'template' );
|
319 |
+
|
320 |
+
$data = [
|
321 |
+
'template' => $theme_slug,
|
322 |
+
'mods' => isset( $current_data['mods'] ) ? $current_data['mods'] : [],
|
323 |
+
'options' => isset( $current_data['options'] ) ? $current_data['options'] : [],
|
324 |
+
];
|
325 |
+
|
326 |
+
if ( is_array( $value ) && ! empty( $value ) ) {
|
327 |
+
foreach ( $value as $key => $val ) {
|
328 |
+
$data['mods'][ $key ] = $val;
|
329 |
+
}
|
330 |
+
}
|
331 |
+
$this->update_custom_customizer_option( $data );
|
332 |
+
|
333 |
+
if ( $this->current_lang_not_default() ) {
|
334 |
+
return $old_value;
|
335 |
+
}
|
336 |
+
|
337 |
+
return $value;
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* If Polylang activated, set the preview url and add select language control
|
342 |
+
*
|
343 |
+
* @author soderlind
|
344 |
+
* @version 1.0.0
|
345 |
+
* @link https://gist.github.com/soderlind/1908634f5eb0c1f69428666dd2a291d0
|
346 |
+
*
|
347 |
+
* @since 1.0.0
|
348 |
+
*/
|
349 |
+
public static function add_lang_to_customizer_previewer() {
|
350 |
+
$languages = self::get_languages_list();
|
351 |
+
|
352 |
+
if ( ! $languages ) {
|
353 |
+
return;
|
354 |
+
}
|
355 |
+
|
356 |
+
$handle = 'dss-add-lang-to-template';
|
357 |
+
$js_path_url = trailingslashit( apply_filters( 'scp_js_path_url', get_stylesheet_directory_uri() . '/js/' ) );
|
358 |
+
$src = $js_path_url . 'customizer-multilingual.js';
|
359 |
+
$deps = [ 'customize-controls' ];
|
360 |
+
wp_enqueue_script( $handle, $src, $deps, JUPITERX_VERSION, true );
|
361 |
+
$language = ( empty( $_REQUEST['lang'] ) ) ? self::get_language() : $_REQUEST['lang']; // @phpcs:ignore
|
362 |
+
|
363 |
+
if ( empty( $language ) ) {
|
364 |
+
$language = self::default_language();
|
365 |
+
}
|
366 |
+
|
367 |
+
$url = add_query_arg( 'lang', $language, self::get_home_url( $language ) );
|
368 |
+
|
369 |
+
wp_add_inline_script(
|
370 |
+
$handle,
|
371 |
+
sprintf(
|
372 |
+
'JupiterXCustomizerMultilingual.init( %s );', wp_json_encode(
|
373 |
+
[
|
374 |
+
'url' => $url,
|
375 |
+
'languages' => $languages,
|
376 |
+
'current_language' => $language,
|
377 |
+
'switcher_text' => __( 'Language:', 'jupiterx-core' ),
|
378 |
+
]
|
379 |
+
)
|
380 |
+
), 'after'
|
381 |
+
);
|
382 |
+
}
|
383 |
+
|
384 |
+
/**
|
385 |
+
* Append lang="contrycode" to the customizer url in the adminbar
|
386 |
+
*
|
387 |
+
* @since 1.0.0
|
388 |
+
*
|
389 |
+
* @return void
|
390 |
+
*/
|
391 |
+
public static function on_wp_before_admin_bar_render() {
|
392 |
+
global $wp_admin_bar;
|
393 |
+
$customize_node = $wp_admin_bar->get_node( 'customize' );
|
394 |
+
if ( ! empty( $customize_node ) ) {
|
395 |
+
$customize_node->href = add_query_arg( 'lang', self::get_language(), $customize_node->href );
|
396 |
+
$wp_admin_bar->add_node( $customize_node );
|
397 |
+
}
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Append lang="contrycode" to the customizer url in the Admin->Apperance->Customize menu
|
402 |
+
*
|
403 |
+
* @since 1.0.0
|
404 |
+
*
|
405 |
+
* @return void
|
406 |
+
*/
|
407 |
+
public static function on_admin_menu() {
|
408 |
+
global $menu, $submenu;
|
409 |
+
$parent = 'themes.php';
|
410 |
+
if ( ! isset( $submenu[ $parent ] ) ) {
|
411 |
+
return;
|
412 |
+
}
|
413 |
+
foreach ( $submenu[ $parent ] as $k => $d ) {
|
414 |
+
if ( 'customize' === $d['1'] ) {
|
415 |
+
$submenu[ $parent ][ $k ]['2'] = add_query_arg( 'lang', self::get_language(), $submenu[ $parent ][ $k ]['2'] ); // @phpcs:ignore
|
416 |
+
break;
|
417 |
+
}
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
}
|
422 |
+
|
423 |
+
CoreCustomizerMultilingual::init();
|
424 |
+
|
425 |
+
if ( class_exists( 'WP_Customize_Setting' ) ) {
|
426 |
+
/**
|
427 |
+
* A class that extends WP_Customize_Setting so we can access
|
428 |
+
* the protected updated method when importing options.
|
429 |
+
*
|
430 |
+
* @since 0.3
|
431 |
+
*/
|
432 |
+
final class Customizermultilingialoption extends WP_Customize_Setting { // @phpcs:ignore
|
433 |
+
|
434 |
+
|
435 |
+
/**
|
436 |
+
* Import an option value for this setting.
|
437 |
+
*
|
438 |
+
* @since 0.3
|
439 |
+
*
|
440 |
+
* @param mixed $value The option value.
|
441 |
+
*
|
442 |
+
* @return void
|
443 |
+
*/
|
444 |
+
public function import( $value ) {
|
445 |
+
$this->update( $value );
|
446 |
+
}
|
447 |
+
}
|
448 |
+
}
|
includes/customizer/api/classes/class-status.php
CHANGED
@@ -1,64 +1,64 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class handles status debug utils for customizer.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Run status debug.
|
17 |
-
*
|
18 |
-
* @since 1.0.0
|
19 |
-
* @ignore
|
20 |
-
* @access private
|
21 |
-
*
|
22 |
-
* @package JupiterX\Framework\API\Customizer
|
23 |
-
*/
|
24 |
-
final class JupiterX_Customizer_Status {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Construct the class.
|
28 |
-
*
|
29 |
-
* @since 1.0.0
|
30 |
-
*/
|
31 |
-
public function __construct() {
|
32 |
-
add_action( 'init', [ $this, 'render_settings_table' ] );
|
33 |
-
}
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Construct the class.
|
37 |
-
*
|
38 |
-
* @since 1.0.0
|
39 |
-
*/
|
40 |
-
public function render_settings_table() {
|
41 |
-
$exclude_type = [ 'jupiterx-divider', 'jupiterx-label', 'jupiterx-child-popup' ];
|
42 |
-
|
43 |
-
?>
|
44 |
-
<table class="table">
|
45 |
-
<thead>
|
46 |
-
<tr>
|
47 |
-
<th><?php esc_html_e( 'Customizer Settings Name', 'jupiterx-core' ); ?></th>
|
48 |
-
<th><?php esc_html_e( 'Control Type', 'jupiterx-core' ); ?></th>
|
49 |
-
</tr>
|
50 |
-
</thead>
|
51 |
-
<tbody>
|
52 |
-
<?php foreach ( JupiterX_Customizer::$settings as $id => $setting ) : ?>
|
53 |
-
<?php if ( ! in_array( $setting['type'], $exclude_type, true ) ) : ?>
|
54 |
-
<tr>
|
55 |
-
<td><?php echo esc_html( $id ); // @codingStandardsIgnoreLine ?></td>
|
56 |
-
<td><?php echo esc_html( $setting['type'] ); // @codingStandardsIgnoreLine ?></td>
|
57 |
-
</tr>
|
58 |
-
<?php endif; ?>
|
59 |
-
<?php endforeach; ?>
|
60 |
-
</tbody>
|
61 |
-
</table>
|
62 |
-
<?php
|
63 |
-
}
|
64 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class handles status debug utils for customizer.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Run status debug.
|
17 |
+
*
|
18 |
+
* @since 1.0.0
|
19 |
+
* @ignore
|
20 |
+
* @access private
|
21 |
+
*
|
22 |
+
* @package JupiterX\Framework\API\Customizer
|
23 |
+
*/
|
24 |
+
final class JupiterX_Customizer_Status {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Construct the class.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
*/
|
31 |
+
public function __construct() {
|
32 |
+
add_action( 'init', [ $this, 'render_settings_table' ] );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Construct the class.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*/
|
40 |
+
public function render_settings_table() {
|
41 |
+
$exclude_type = [ 'jupiterx-divider', 'jupiterx-label', 'jupiterx-child-popup' ];
|
42 |
+
|
43 |
+
?>
|
44 |
+
<table class="table">
|
45 |
+
<thead>
|
46 |
+
<tr>
|
47 |
+
<th><?php esc_html_e( 'Customizer Settings Name', 'jupiterx-core' ); ?></th>
|
48 |
+
<th><?php esc_html_e( 'Control Type', 'jupiterx-core' ); ?></th>
|
49 |
+
</tr>
|
50 |
+
</thead>
|
51 |
+
<tbody>
|
52 |
+
<?php foreach ( JupiterX_Customizer::$settings as $id => $setting ) : ?>
|
53 |
+
<?php if ( ! in_array( $setting['type'], $exclude_type, true ) ) : ?>
|
54 |
+
<tr>
|
55 |
+
<td><?php echo esc_html( $id ); // @codingStandardsIgnoreLine ?></td>
|
56 |
+
<td><?php echo esc_html( $setting['type'] ); // @codingStandardsIgnoreLine ?></td>
|
57 |
+
</tr>
|
58 |
+
<?php endif; ?>
|
59 |
+
<?php endforeach; ?>
|
60 |
+
</tbody>
|
61 |
+
</table>
|
62 |
+
<?php
|
63 |
+
}
|
64 |
+
}
|
includes/customizer/api/customizer.php
CHANGED
@@ -1,295 +1,295 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class handles API for customizer.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
if ( ! class_exists( 'JupiterX_Customizer' ) ) {
|
16 |
-
/**
|
17 |
-
* Customizer wrapper class.
|
18 |
-
*
|
19 |
-
* @since 1.0.0
|
20 |
-
* @ignore
|
21 |
-
* @access private
|
22 |
-
*
|
23 |
-
* @package JupiterX\Framework\API\Customizer
|
24 |
-
*/
|
25 |
-
final class JupiterX_Customizer {
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Registered panels.
|
29 |
-
*
|
30 |
-
* @since 1.0.0
|
31 |
-
*
|
32 |
-
* @var array
|
33 |
-
*/
|
34 |
-
public static $panels = [];
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Registered sections.
|
38 |
-
*
|
39 |
-
* @since 1.0.0
|
40 |
-
*
|
41 |
-
* @var array
|
42 |
-
*/
|
43 |
-
public static $sections = [];
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Registered settings.
|
47 |
-
*
|
48 |
-
* @since 1.0.0
|
49 |
-
*
|
50 |
-
* @var array
|
51 |
-
*/
|
52 |
-
public static $settings = [];
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Configuration ID.
|
56 |
-
*
|
57 |
-
* Defined for Kirki.
|
58 |
-
*
|
59 |
-
* @since 1.0.0
|
60 |
-
*
|
61 |
-
* @var string
|
62 |
-
*/
|
63 |
-
public static $config_id = 'jupiterx';
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Section types.
|
67 |
-
*
|
68 |
-
* @since 1.0.0
|
69 |
-
*
|
70 |
-
* @var array
|
71 |
-
*/
|
72 |
-
public static $section_types = [
|
73 |
-
'kirki-popup' => 'JupiterX_Customizer_Section_Popup',
|
74 |
-
'kirki-pane' => 'JupiterX_Customizer_Section_Pane',
|
75 |
-
'kirki-jupiterx-link' => 'JupiterX_Customizer_Section_Link',
|
76 |
-
];
|
77 |
-
|
78 |
-
/**
|
79 |
-
* Control types.
|
80 |
-
*
|
81 |
-
* @since 1.0.0
|
82 |
-
*
|
83 |
-
* @var array
|
84 |
-
*/
|
85 |
-
public static $control_types = [
|
86 |
-
'jupiterx-input' => 'JupiterX_Customizer_Control_Input',
|
87 |
-
'jupiterx-text' => 'JupiterX_Customizer_Control_Text',
|
88 |
-
'jupiterx-textarea' => 'JupiterX_Customizer_Control_Textarea',
|
89 |
-
'jupiterx-select' => 'JupiterX_Customizer_Control_Select',
|
90 |
-
'jupiterx-toggle' => 'JupiterX_Customizer_Control_Toggle',
|
91 |
-
'jupiterx-choose' => 'JupiterX_Customizer_Control_Choose',
|
92 |
-
'jupiterx-multicheck' => 'JupiterX_Customizer_Control_Multicheck',
|
93 |
-
'jupiterx-divider' => 'JupiterX_Customizer_Control_Divider',
|
94 |
-
'jupiterx-label' => 'JupiterX_Customizer_Control_Label',
|
95 |
-
'jupiterx-alert' => 'JupiterX_Customizer_Control_Alert',
|
96 |
-
'jupiterx-position' => 'JupiterX_Customizer_Control_Position',
|
97 |
-
'jupiterx-color' => 'JupiterX_Customizer_Control_Color',
|
98 |
-
'jupiterx-image' => 'JupiterX_Customizer_Control_Image',
|
99 |
-
'jupiterx-radio-image' => 'JupiterX_Customizer_Control_Radio_Image',
|
100 |
-
'jupiterx-child-popup' => 'JupiterX_Customizer_Control_Child_Popup',
|
101 |
-
'jupiterx-popup' => 'JupiterX_Customizer_Control_Popup',
|
102 |
-
'jupiterx-box-model' => 'JupiterX_Customizer_Control_Box_Model',
|
103 |
-
'jupiterx-fonts' => 'JupiterX_Customizer_Control_Fonts',
|
104 |
-
'jupiterx-font' => 'JupiterX_Customizer_Control_Font',
|
105 |
-
'jupiterx-exceptions' => 'JupiterX_Customizer_Control_Exceptions',
|
106 |
-
'jupiterx-template' => 'JupiterX_Customizer_Control_Template',
|
107 |
-
'jupiterx-pro-box' => 'JupiterX_Customizer_Control_PRO_Box',
|
108 |
-
];
|
109 |
-
|
110 |
-
/**
|
111 |
-
* Group control types.
|
112 |
-
*
|
113 |
-
* @since 1.0.0
|
114 |
-
*
|
115 |
-
* @var array
|
116 |
-
*/
|
117 |
-
public static $group_control_types = [
|
118 |
-
'jupiterx-background' => 'JupiterX_Customizer_Group_Control_Background',
|
119 |
-
'jupiterx-box-shadow' => 'JupiterX_Customizer_Group_Control_Box_Shadow',
|
120 |
-
'jupiterx-typography' => 'JupiterX_Customizer_Group_Control_Typography',
|
121 |
-
'jupiterx-border' => 'JupiterX_Customizer_Group_Control_Border',
|
122 |
-
];
|
123 |
-
|
124 |
-
/**
|
125 |
-
* Responsive devices media query.
|
126 |
-
*
|
127 |
-
* @since 1.0.0
|
128 |
-
*
|
129 |
-
* @var array
|
130 |
-
*/
|
131 |
-
public static $responsive_devices = [
|
132 |
-
'desktop' => 'global',
|
133 |
-
'tablet' => '@media (max-width: 767.98px)',
|
134 |
-
'mobile' => '@media (max-width: 575.98px)',
|
135 |
-
];
|
136 |
-
|
137 |
-
/**
|
138 |
-
* Store panel.
|
139 |
-
*
|
140 |
-
* @since 1.0.0
|
141 |
-
*
|
142 |
-
* @param string $id ID of the panel.
|
143 |
-
* @param array $args Arguments of the panel.
|
144 |
-
*/
|
145 |
-
public static function add_panel( $id = '', $args = [] ) {
|
146 |
-
if ( empty( $id ) ) {
|
147 |
-
return;
|
148 |
-
}
|
149 |
-
|
150 |
-
/**
|
151 |
-
* Run action before section added.
|
152 |
-
*
|
153 |
-
* @since 1.3.0
|
154 |
-
*/
|
155 |
-
do_action( "{$id}_before_panel" );
|
156 |
-
|
157 |
-
// Add panel to stack.
|
158 |
-
self::$panels[ $id ] = $args;
|
159 |
-
|
160 |
-
/**
|
161 |
-
* Run action after panel added.
|
162 |
-
*
|
163 |
-
* @since 1.3.0
|
164 |
-
*/
|
165 |
-
do_action( "{$id}_after_panel" );
|
166 |
-
}
|
167 |
-
|
168 |
-
/**
|
169 |
-
* Store section.
|
170 |
-
*
|
171 |
-
* @since 1.0.0
|
172 |
-
*
|
173 |
-
* @param string $id ID of the section.
|
174 |
-
* @param array $args Arguments of the section.
|
175 |
-
*/
|
176 |
-
public static function add_section( $id = '', $args = [] ) {
|
177 |
-
if ( empty( $id ) ) {
|
178 |
-
return;
|
179 |
-
}
|
180 |
-
|
181 |
-
/**
|
182 |
-
* Run action before section added.
|
183 |
-
*
|
184 |
-
* @since 1.3.0
|
185 |
-
*/
|
186 |
-
do_action( "{$id}_before_section" );
|
187 |
-
|
188 |
-
/**
|
189 |
-
* Add section to stack.
|
190 |
-
*/
|
191 |
-
self::$sections[ $id ] = array_merge( [ 'priority' => 160 ], $args );
|
192 |
-
|
193 |
-
/**
|
194 |
-
* Run action after section added.
|
195 |
-
*
|
196 |
-
* @since 1.3.0
|
197 |
-
*/
|
198 |
-
do_action( "{$id}_after_section" );
|
199 |
-
}
|
200 |
-
|
201 |
-
/**
|
202 |
-
* Update section.
|
203 |
-
*
|
204 |
-
* @since 1.3.0
|
205 |
-
*
|
206 |
-
* @param string $id Section ID.
|
207 |
-
* @param array $args Section arguments.
|
208 |
-
*/
|
209 |
-
public static function update_section( $id, $args = [] ) {
|
210 |
-
if ( ! isset( self::$sections[ $id ] ) ) {
|
211 |
-
return;
|
212 |
-
}
|
213 |
-
|
214 |
-
$section = self::$sections[ $id ];
|
215 |
-
|
216 |
-
self::$sections[ $id ] = array_merge( $section, $args );
|
217 |
-
}
|
218 |
-
|
219 |
-
/**
|
220 |
-
* Store settings.
|
221 |
-
*
|
222 |
-
* @since 1.0.0
|
223 |
-
*
|
224 |
-
* @param array $args Arguments of the field.
|
225 |
-
*/
|
226 |
-
public static function add_field( $args = [] ) {
|
227 |
-
if ( ! isset( $args['type'] ) && ! isset( $args['settings'] ) ) {
|
228 |
-
return;
|
229 |
-
}
|
230 |
-
|
231 |
-
/**
|
232 |
-
* Run action before field added.
|
233 |
-
*
|
234 |
-
* @since 1.3.0
|
235 |
-
*/
|
236 |
-
do_action( "{$args['settings']}_before_field" );
|
237 |
-
|
238 |
-
/**
|
239 |
-
* Add the field to stack.
|
240 |
-
*/
|
241 |
-
self::$settings[ $args['settings'] ] = $args;
|
242 |
-
|
243 |
-
/**
|
244 |
-
* Run action after field added.
|
245 |
-
*
|
246 |
-
* @since 1.3.0
|
247 |
-
*/
|
248 |
-
do_action( "{$args['settings']}_after_field" );
|
249 |
-
}
|
250 |
-
|
251 |
-
/**
|
252 |
-
* Add responsive field.
|
253 |
-
*
|
254 |
-
* @since 1.0.0
|
255 |
-
*
|
256 |
-
* @param array $args Arguments of the field.
|
257 |
-
*/
|
258 |
-
public static function add_responsive_field( $args = [] ) {
|
259 |
-
$args['responsive'] = true;
|
260 |
-
|
261 |
-
self::add_field( $args );
|
262 |
-
}
|
263 |
-
|
264 |
-
/**
|
265 |
-
* Update field.
|
266 |
-
*
|
267 |
-
* @since 1.3.0
|
268 |
-
*
|
269 |
-
* @param string $id Field ID.
|
270 |
-
* @param array $args Field arguments.
|
271 |
-
*/
|
272 |
-
public static function update_field( $id, $args = [] ) {
|
273 |
-
if ( ! isset( self::$settings[ $id ] ) ) {
|
274 |
-
return;
|
275 |
-
}
|
276 |
-
|
277 |
-
$settings = self::$settings[ $id ];
|
278 |
-
|
279 |
-
self::$settings[ $id ] = array_merge( $settings, $args );
|
280 |
-
}
|
281 |
-
|
282 |
-
/**
|
283 |
-
* Remove field.
|
284 |
-
*
|
285 |
-
* @since 1.3.0
|
286 |
-
*
|
287 |
-
* @param string $id ID of the field.
|
288 |
-
*/
|
289 |
-
public static function remove_field( $id ) {
|
290 |
-
if ( isset( self::$settings[ $id ] ) ) {
|
291 |
-
unset( self::$settings[ $id ] );
|
292 |
-
}
|
293 |
-
}
|
294 |
-
}
|
295 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class handles API for customizer.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
if ( ! class_exists( 'JupiterX_Customizer' ) ) {
|
16 |
+
/**
|
17 |
+
* Customizer wrapper class.
|
18 |
+
*
|
19 |
+
* @since 1.0.0
|
20 |
+
* @ignore
|
21 |
+
* @access private
|
22 |
+
*
|
23 |
+
* @package JupiterX\Framework\API\Customizer
|
24 |
+
*/
|
25 |
+
final class JupiterX_Customizer {
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Registered panels.
|
29 |
+
*
|
30 |
+
* @since 1.0.0
|
31 |
+
*
|
32 |
+
* @var array
|
33 |
+
*/
|
34 |
+
public static $panels = [];
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Registered sections.
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @var array
|
42 |
+
*/
|
43 |
+
public static $sections = [];
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Registered settings.
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @var array
|
51 |
+
*/
|
52 |
+
public static $settings = [];
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Configuration ID.
|
56 |
+
*
|
57 |
+
* Defined for Kirki.
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*
|
61 |
+
* @var string
|
62 |
+
*/
|
63 |
+
public static $config_id = 'jupiterx';
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Section types.
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @var array
|
71 |
+
*/
|
72 |
+
public static $section_types = [
|
73 |
+
'kirki-popup' => 'JupiterX_Customizer_Section_Popup',
|
74 |
+
'kirki-pane' => 'JupiterX_Customizer_Section_Pane',
|
75 |
+
'kirki-jupiterx-link' => 'JupiterX_Customizer_Section_Link',
|
76 |
+
];
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Control types.
|
80 |
+
*
|
81 |
+
* @since 1.0.0
|
82 |
+
*
|
83 |
+
* @var array
|
84 |
+
*/
|
85 |
+
public static $control_types = [
|
86 |
+
'jupiterx-input' => 'JupiterX_Customizer_Control_Input',
|
87 |
+
'jupiterx-text' => 'JupiterX_Customizer_Control_Text',
|
88 |
+
'jupiterx-textarea' => 'JupiterX_Customizer_Control_Textarea',
|
89 |
+
'jupiterx-select' => 'JupiterX_Customizer_Control_Select',
|
90 |
+
'jupiterx-toggle' => 'JupiterX_Customizer_Control_Toggle',
|
91 |
+
'jupiterx-choose' => 'JupiterX_Customizer_Control_Choose',
|
92 |
+
'jupiterx-multicheck' => 'JupiterX_Customizer_Control_Multicheck',
|
93 |
+
'jupiterx-divider' => 'JupiterX_Customizer_Control_Divider',
|
94 |
+
'jupiterx-label' => 'JupiterX_Customizer_Control_Label',
|
95 |
+
'jupiterx-alert' => 'JupiterX_Customizer_Control_Alert',
|
96 |
+
'jupiterx-position' => 'JupiterX_Customizer_Control_Position',
|
97 |
+
'jupiterx-color' => 'JupiterX_Customizer_Control_Color',
|
98 |
+
'jupiterx-image' => 'JupiterX_Customizer_Control_Image',
|
99 |
+
'jupiterx-radio-image' => 'JupiterX_Customizer_Control_Radio_Image',
|
100 |
+
'jupiterx-child-popup' => 'JupiterX_Customizer_Control_Child_Popup',
|
101 |
+
'jupiterx-popup' => 'JupiterX_Customizer_Control_Popup',
|
102 |
+
'jupiterx-box-model' => 'JupiterX_Customizer_Control_Box_Model',
|
103 |
+
'jupiterx-fonts' => 'JupiterX_Customizer_Control_Fonts',
|
104 |
+
'jupiterx-font' => 'JupiterX_Customizer_Control_Font',
|
105 |
+
'jupiterx-exceptions' => 'JupiterX_Customizer_Control_Exceptions',
|
106 |
+
'jupiterx-template' => 'JupiterX_Customizer_Control_Template',
|
107 |
+
'jupiterx-pro-box' => 'JupiterX_Customizer_Control_PRO_Box',
|
108 |
+
];
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Group control types.
|
112 |
+
*
|
113 |
+
* @since 1.0.0
|
114 |
+
*
|
115 |
+
* @var array
|
116 |
+
*/
|
117 |
+
public static $group_control_types = [
|
118 |
+
'jupiterx-background' => 'JupiterX_Customizer_Group_Control_Background',
|
119 |
+
'jupiterx-box-shadow' => 'JupiterX_Customizer_Group_Control_Box_Shadow',
|
120 |
+
'jupiterx-typography' => 'JupiterX_Customizer_Group_Control_Typography',
|
121 |
+
'jupiterx-border' => 'JupiterX_Customizer_Group_Control_Border',
|
122 |
+
];
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Responsive devices media query.
|
126 |
+
*
|
127 |
+
* @since 1.0.0
|
128 |
+
*
|
129 |
+
* @var array
|
130 |
+
*/
|
131 |
+
public static $responsive_devices = [
|
132 |
+
'desktop' => 'global',
|
133 |
+
'tablet' => '@media (max-width: 767.98px)',
|
134 |
+
'mobile' => '@media (max-width: 575.98px)',
|
135 |
+
];
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Store panel.
|
139 |
+
*
|
140 |
+
* @since 1.0.0
|
141 |
+
*
|
142 |
+
* @param string $id ID of the panel.
|
143 |
+
* @param array $args Arguments of the panel.
|
144 |
+
*/
|
145 |
+
public static function add_panel( $id = '', $args = [] ) {
|
146 |
+
if ( empty( $id ) ) {
|
147 |
+
return;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Run action before section added.
|
152 |
+
*
|
153 |
+
* @since 1.3.0
|
154 |
+
*/
|
155 |
+
do_action( "{$id}_before_panel" );
|
156 |
+
|
157 |
+
// Add panel to stack.
|
158 |
+
self::$panels[ $id ] = $args;
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Run action after panel added.
|
162 |
+
*
|
163 |
+
* @since 1.3.0
|
164 |
+
*/
|
165 |
+
do_action( "{$id}_after_panel" );
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Store section.
|
170 |
+
*
|
171 |
+
* @since 1.0.0
|
172 |
+
*
|
173 |
+
* @param string $id ID of the section.
|
174 |
+
* @param array $args Arguments of the section.
|
175 |
+
*/
|
176 |
+
public static function add_section( $id = '', $args = [] ) {
|
177 |
+
if ( empty( $id ) ) {
|
178 |
+
return;
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Run action before section added.
|
183 |
+
*
|
184 |
+
* @since 1.3.0
|
185 |
+
*/
|
186 |
+
do_action( "{$id}_before_section" );
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Add section to stack.
|
190 |
+
*/
|
191 |
+
self::$sections[ $id ] = array_merge( [ 'priority' => 160 ], $args );
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Run action after section added.
|
195 |
+
*
|
196 |
+
* @since 1.3.0
|
197 |
+
*/
|
198 |
+
do_action( "{$id}_after_section" );
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Update section.
|
203 |
+
*
|
204 |
+
* @since 1.3.0
|
205 |
+
*
|
206 |
+
* @param string $id Section ID.
|
207 |
+
* @param array $args Section arguments.
|
208 |
+
*/
|
209 |
+
public static function update_section( $id, $args = [] ) {
|
210 |
+
if ( ! isset( self::$sections[ $id ] ) ) {
|
211 |
+
return;
|
212 |
+
}
|
213 |
+
|
214 |
+
$section = self::$sections[ $id ];
|
215 |
+
|
216 |
+
self::$sections[ $id ] = array_merge( $section, $args );
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Store settings.
|
221 |
+
*
|
222 |
+
* @since 1.0.0
|
223 |
+
*
|
224 |
+
* @param array $args Arguments of the field.
|
225 |
+
*/
|
226 |
+
public static function add_field( $args = [] ) {
|
227 |
+
if ( ! isset( $args['type'] ) && ! isset( $args['settings'] ) ) {
|
228 |
+
return;
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Run action before field added.
|
233 |
+
*
|
234 |
+
* @since 1.3.0
|
235 |
+
*/
|
236 |
+
do_action( "{$args['settings']}_before_field" );
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Add the field to stack.
|
240 |
+
*/
|
241 |
+
self::$settings[ $args['settings'] ] = $args;
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Run action after field added.
|
245 |
+
*
|
246 |
+
* @since 1.3.0
|
247 |
+
*/
|
248 |
+
do_action( "{$args['settings']}_after_field" );
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Add responsive field.
|
253 |
+
*
|
254 |
+
* @since 1.0.0
|
255 |
+
*
|
256 |
+
* @param array $args Arguments of the field.
|
257 |
+
*/
|
258 |
+
public static function add_responsive_field( $args = [] ) {
|
259 |
+
$args['responsive'] = true;
|
260 |
+
|
261 |
+
self::add_field( $args );
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Update field.
|
266 |
+
*
|
267 |
+
* @since 1.3.0
|
268 |
+
*
|
269 |
+
* @param string $id Field ID.
|
270 |
+
* @param array $args Field arguments.
|
271 |
+
*/
|
272 |
+
public static function update_field( $id, $args = [] ) {
|
273 |
+
if ( ! isset( self::$settings[ $id ] ) ) {
|
274 |
+
return;
|
275 |
+
}
|
276 |
+
|
277 |
+
$settings = self::$settings[ $id ];
|
278 |
+
|
279 |
+
self::$settings[ $id ] = array_merge( $settings, $args );
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Remove field.
|
284 |
+
*
|
285 |
+
* @since 1.3.0
|
286 |
+
*
|
287 |
+
* @param string $id ID of the field.
|
288 |
+
*/
|
289 |
+
public static function remove_field( $id ) {
|
290 |
+
if ( isset( self::$settings[ $id ] ) ) {
|
291 |
+
unset( self::$settings[ $id ] );
|
292 |
+
}
|
293 |
+
}
|
294 |
+
}
|
295 |
+
}
|
includes/customizer/api/includes/base/class-control.php
CHANGED
@@ -1,243 +1,243 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class is a common class for all the controls.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Control base class.
|
17 |
-
*
|
18 |
-
* This is a special section for rendering tabs and child popups controls inside the Popup section.
|
19 |
-
*
|
20 |
-
* @since 1.0.0
|
21 |
-
* @ignore
|
22 |
-
* @access private
|
23 |
-
*
|
24 |
-
* @package JupiterX\Framework\API\Customizer
|
25 |
-
*/
|
26 |
-
class JupiterX_Customizer_Base_Control extends WP_Customize_Control {
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Column size of the control.
|
30 |
-
*
|
31 |
-
* @since 1.0.0
|
32 |
-
*
|
33 |
-
* @var string
|
34 |
-
*/
|
35 |
-
public $column = '12';
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Empty label.
|
39 |
-
*
|
40 |
-
* @since 1.0.0
|
41 |
-
*
|
42 |
-
* @var string
|
43 |
-
*/
|
44 |
-
public $label_empty = false;
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Used to automatically generate all CSS output.
|
48 |
-
*
|
49 |
-
* @since 1.0.0
|
50 |
-
*
|
51 |
-
* @var array
|
52 |
-
*/
|
53 |
-
public $output = [];
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Whitelisting the "required" argument.
|
57 |
-
*
|
58 |
-
* @since 1.0.0
|
59 |
-
*
|
60 |
-
* @var array
|
61 |
-
*/
|
62 |
-
public $required = [];
|
63 |
-
|
64 |
-
/**
|
65 |
-
* Attributes for the control wrapper.
|
66 |
-
*
|
67 |
-
* @since 1.0.0
|
68 |
-
*
|
69 |
-
* @var array
|
70 |
-
*/
|
71 |
-
public $control_attrs = [];
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Responsive control.
|
75 |
-
*
|
76 |
-
* @since 1.0.0
|
77 |
-
*
|
78 |
-
* @var array
|
79 |
-
*/
|
80 |
-
public $responsive = false;
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Refresh the parameters passed to the JavaScript via JSON.
|
84 |
-
*
|
85 |
-
* @since 1.0.0
|
86 |
-
*/
|
87 |
-
public function to_json() {
|
88 |
-
parent::to_json();
|
89 |
-
|
90 |
-
$this->json['default'] = $this->setting->default;
|
91 |
-
|
92 |
-
if ( isset( $this->default ) ) {
|
93 |
-
$this->json['default'] = $this->default;
|
94 |
-
}
|
95 |
-
|
96 |
-
// Add this to whitelist `active_callback` from Kirki.
|
97 |
-
$this->json['required'] = $this->required;
|
98 |
-
|
99 |
-
// Output.
|
100 |
-
$this->json['output'] = $this->output;
|
101 |
-
|
102 |
-
// Responsive.
|
103 |
-
$this->json['responsive'] = (bool) $this->responsive;
|
104 |
-
|
105 |
-
// Value.
|
106 |
-
$this->json['value'] = $this->value();
|
107 |
-
|
108 |
-
// Choices.
|
109 |
-
$this->json['choices'] = $this->choices;
|
110 |
-
|
111 |
-
// The link.
|
112 |
-
$this->json['link'] = $this->get_link();
|
113 |
-
|
114 |
-
// The ID.
|
115 |
-
$this->json['id'] = $this->id;
|
116 |
-
|
117 |
-
// Empty label.
|
118 |
-
$this->json['labelEmpty'] = $this->label_empty;
|
119 |
-
|
120 |
-
// Input attributes.
|
121 |
-
$this->json['inputAttrs'] = '';
|
122 |
-
|
123 |
-
foreach ( $this->input_attrs as $attr => $value ) {
|
124 |
-
$this->json['inputAttrs'] .= $attr . '="' . esc_attr( $value ) . '" ';
|
125 |
-
}
|
126 |
-
|
127 |
-
// Control wrapper attributes.
|
128 |
-
$this->json['controlAttrs'] = '';
|
129 |
-
|
130 |
-
foreach ( $this->control_attrs as $attr => $value ) {
|
131 |
-
$this->json['controlAttrs'] .= $attr . '="' . esc_attr( $value ) . '" ';
|
132 |
-
}
|
133 |
-
}
|
134 |
-
|
135 |
-
/**
|
136 |
-
* Renders the control wrapper and calls $this->render_content() for the internals.
|
137 |
-
*
|
138 |
-
* @since 1.0.0
|
139 |
-
*/
|
140 |
-
protected function render() {
|
141 |
-
$id = 'customize-control-' . str_replace( [ '[', ']' ], [ '-', '' ], $this->id );
|
142 |
-
$class = sprintf( 'jupiterx-col-%1$s customize-control customize-control-%2$s', $this->column, $this->type );
|
143 |
-
|
144 |
-
if ( $this->responsive ) {
|
145 |
-
$class .= ' customize-control-responsive';
|
146 |
-
}
|
147 |
-
|
148 |
-
printf( '<li id="%s" class="%s">', esc_attr( $id ), esc_attr( $class ) );
|
149 |
-
$this->render_content();
|
150 |
-
echo '</li>';
|
151 |
-
}
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Render the control's content.
|
155 |
-
*
|
156 |
-
* Allows the content to be overridden without having to rewrite the wrapper in `$this::render()`.
|
157 |
-
*
|
158 |
-
* Supports basic input types `text`, `checkbox`, `textarea`, `radio`, `select` and `dropdown-pages`.
|
159 |
-
* Additional input types such as `email`, `url`, `number`, `hidden` and `date` are supported implicitly.
|
160 |
-
*
|
161 |
-
* Control content can alternately be rendered in JS. See WP_Customize_Control::print_template().
|
162 |
-
*
|
163 |
-
* @since 1.0.0
|
164 |
-
*/
|
165 |
-
protected function render_content() {}
|
166 |
-
|
167 |
-
/**
|
168 |
-
* An Underscore (JS) template for this control's content (but not its container).
|
169 |
-
*
|
170 |
-
* Class variables for this control class are available in the `data` JS object;
|
171 |
-
* export custom variables by overriding {@see WP_Customize_Control::to_json()}.
|
172 |
-
*
|
173 |
-
* @see WP_Customize_Control::print_template()
|
174 |
-
*
|
175 |
-
* Preferably not to overwrite this function, use the `control_template` function
|
176 |
-
* to render the control template. Overwriting this only allows for some special
|
177 |
-
* occasion or if your control doesn't need to render the label and description.
|
178 |
-
*
|
179 |
-
* @since 1.0.0
|
180 |
-
*/
|
181 |
-
protected function content_template() {
|
182 |
-
?>
|
183 |
-
<# viewport = [ 'global' ] #>
|
184 |
-
<# if ( data.responsive ) { #>
|
185 |
-
<#
|
186 |
-
viewport = [ 'desktop', 'tablet', 'mobile' ]
|
187 |
-
responsive = {
|
188 |
-
link: data.link,
|
189 |
-
id: data.id,
|
190 |
-
property: ! _.isUndefined( data.property ) ? data.property : '',
|
191 |
-
value: data.value || {}
|
192 |
-
}
|
193 |
-
#>
|
194 |
-
<div class="jupiterx-responsive-control">
|
195 |
-
<# } #>
|
196 |
-
<# if ( data.label ) { #>
|
197 |
-
<span class="customize-control-title">{{ data.label }}</span>
|
198 |
-
<# } else if ( data.labelEmpty ) { #>
|
199 |
-
<span class="customize-control-title"> </span>
|
200 |
-
<# } #>
|
201 |
-
<# if ( data.description ) { #>
|
202 |
-
<span class="description customize-control-description">{{ data.description }}</span>
|
203 |
-
<# } #>
|
204 |
-
<# _.each( viewport, function ( device ) { #>
|
205 |
-
<# if ( data.responsive ) { #>
|
206 |
-
<#
|
207 |
-
data.link = responsive.link + ' data-setting-viewport-link="' + device + '"'
|
208 |
-
data.id = responsive.id + '_' + device
|
209 |
-
data.value = responsive.value[device] || ''
|
210 |
-
#>
|
211 |
-
<div class="jupiterx-viewport jupiterx-viewport-{{ device }}">
|
212 |
-
<# } #>
|
213 |
-
<?php $this->control_template(); ?>
|
214 |
-
<# if ( data.responsive ) { #>
|
215 |
-
</div>
|
216 |
-
<# } #>
|
217 |
-
<# } ) #>
|
218 |
-
<# if ( data.responsive ) { #>
|
219 |
-
<div class="jupiterx-responsive-switcher">
|
220 |
-
<div class="jupiterx-responsive-switcher-buttons">
|
221 |
-
<# _.each( viewport, function ( device ) { #>
|
222 |
-
<a class="jupiterx-responsive-switcher-button jupiterx-responsive-switcher-{{ device }}" data-device="{{ device }}">
|
223 |
-
<span class="jupiterx-responsive-switcher-icon">
|
224 |
-
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_assets_url() ); ?>/img/device-{{ device }}.svg">
|
225 |
-
</span>
|
226 |
-
</a>
|
227 |
-
<# } ) #>
|
228 |
-
</div>
|
229 |
-
</div>
|
230 |
-
</div>
|
231 |
-
<# } #>
|
232 |
-
<?php
|
233 |
-
}
|
234 |
-
|
235 |
-
/**
|
236 |
-
* An Underscore (JS) template for control wrapper.
|
237 |
-
*
|
238 |
-
* Use to create the control template.
|
239 |
-
*
|
240 |
-
* @since 1.0.0
|
241 |
-
*/
|
242 |
-
protected function control_template() {}
|
243 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class is a common class for all the controls.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Control base class.
|
17 |
+
*
|
18 |
+
* This is a special section for rendering tabs and child popups controls inside the Popup section.
|
19 |
+
*
|
20 |
+
* @since 1.0.0
|
21 |
+
* @ignore
|
22 |
+
* @access private
|
23 |
+
*
|
24 |
+
* @package JupiterX\Framework\API\Customizer
|
25 |
+
*/
|
26 |
+
class JupiterX_Customizer_Base_Control extends WP_Customize_Control {
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Column size of the control.
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @var string
|
34 |
+
*/
|
35 |
+
public $column = '12';
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Empty label.
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @var string
|
43 |
+
*/
|
44 |
+
public $label_empty = false;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Used to automatically generate all CSS output.
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @var array
|
52 |
+
*/
|
53 |
+
public $output = [];
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Whitelisting the "required" argument.
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @var array
|
61 |
+
*/
|
62 |
+
public $required = [];
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Attributes for the control wrapper.
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
*
|
69 |
+
* @var array
|
70 |
+
*/
|
71 |
+
public $control_attrs = [];
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Responsive control.
|
75 |
+
*
|
76 |
+
* @since 1.0.0
|
77 |
+
*
|
78 |
+
* @var array
|
79 |
+
*/
|
80 |
+
public $responsive = false;
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Refresh the parameters passed to the JavaScript via JSON.
|
84 |
+
*
|
85 |
+
* @since 1.0.0
|
86 |
+
*/
|
87 |
+
public function to_json() {
|
88 |
+
parent::to_json();
|
89 |
+
|
90 |
+
$this->json['default'] = $this->setting->default;
|
91 |
+
|
92 |
+
if ( isset( $this->default ) ) {
|
93 |
+
$this->json['default'] = $this->default;
|
94 |
+
}
|
95 |
+
|
96 |
+
// Add this to whitelist `active_callback` from Kirki.
|
97 |
+
$this->json['required'] = $this->required;
|
98 |
+
|
99 |
+
// Output.
|
100 |
+
$this->json['output'] = $this->output;
|
101 |
+
|
102 |
+
// Responsive.
|
103 |
+
$this->json['responsive'] = (bool) $this->responsive;
|
104 |
+
|
105 |
+
// Value.
|
106 |
+
$this->json['value'] = $this->value();
|
107 |
+
|
108 |
+
// Choices.
|
109 |
+
$this->json['choices'] = $this->choices;
|
110 |
+
|
111 |
+
// The link.
|
112 |
+
$this->json['link'] = $this->get_link();
|
113 |
+
|
114 |
+
// The ID.
|
115 |
+
$this->json['id'] = $this->id;
|
116 |
+
|
117 |
+
// Empty label.
|
118 |
+
$this->json['labelEmpty'] = $this->label_empty;
|
119 |
+
|
120 |
+
// Input attributes.
|
121 |
+
$this->json['inputAttrs'] = '';
|
122 |
+
|
123 |
+
foreach ( $this->input_attrs as $attr => $value ) {
|
124 |
+
$this->json['inputAttrs'] .= $attr . '="' . esc_attr( $value ) . '" ';
|
125 |
+
}
|
126 |
+
|
127 |
+
// Control wrapper attributes.
|
128 |
+
$this->json['controlAttrs'] = '';
|
129 |
+
|
130 |
+
foreach ( $this->control_attrs as $attr => $value ) {
|
131 |
+
$this->json['controlAttrs'] .= $attr . '="' . esc_attr( $value ) . '" ';
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Renders the control wrapper and calls $this->render_content() for the internals.
|
137 |
+
*
|
138 |
+
* @since 1.0.0
|
139 |
+
*/
|
140 |
+
protected function render() {
|
141 |
+
$id = 'customize-control-' . str_replace( [ '[', ']' ], [ '-', '' ], $this->id );
|
142 |
+
$class = sprintf( 'jupiterx-col-%1$s customize-control customize-control-%2$s', $this->column, $this->type );
|
143 |
+
|
144 |
+
if ( $this->responsive ) {
|
145 |
+
$class .= ' customize-control-responsive';
|
146 |
+
}
|
147 |
+
|
148 |
+
printf( '<li id="%s" class="%s">', esc_attr( $id ), esc_attr( $class ) );
|
149 |
+
$this->render_content();
|
150 |
+
echo '</li>';
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Render the control's content.
|
155 |
+
*
|
156 |
+
* Allows the content to be overridden without having to rewrite the wrapper in `$this::render()`.
|
157 |
+
*
|
158 |
+
* Supports basic input types `text`, `checkbox`, `textarea`, `radio`, `select` and `dropdown-pages`.
|
159 |
+
* Additional input types such as `email`, `url`, `number`, `hidden` and `date` are supported implicitly.
|
160 |
+
*
|
161 |
+
* Control content can alternately be rendered in JS. See WP_Customize_Control::print_template().
|
162 |
+
*
|
163 |
+
* @since 1.0.0
|
164 |
+
*/
|
165 |
+
protected function render_content() {}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* An Underscore (JS) template for this control's content (but not its container).
|
169 |
+
*
|
170 |
+
* Class variables for this control class are available in the `data` JS object;
|
171 |
+
* export custom variables by overriding {@see WP_Customize_Control::to_json()}.
|
172 |
+
*
|
173 |
+
* @see WP_Customize_Control::print_template()
|
174 |
+
*
|
175 |
+
* Preferably not to overwrite this function, use the `control_template` function
|
176 |
+
* to render the control template. Overwriting this only allows for some special
|
177 |
+
* occasion or if your control doesn't need to render the label and description.
|
178 |
+
*
|
179 |
+
* @since 1.0.0
|
180 |
+
*/
|
181 |
+
protected function content_template() {
|
182 |
+
?>
|
183 |
+
<# viewport = [ 'global' ] #>
|
184 |
+
<# if ( data.responsive ) { #>
|
185 |
+
<#
|
186 |
+
viewport = [ 'desktop', 'tablet', 'mobile' ]
|
187 |
+
responsive = {
|
188 |
+
link: data.link,
|
189 |
+
id: data.id,
|
190 |
+
property: ! _.isUndefined( data.property ) ? data.property : '',
|
191 |
+
value: data.value || {}
|
192 |
+
}
|
193 |
+
#>
|
194 |
+
<div class="jupiterx-responsive-control">
|
195 |
+
<# } #>
|
196 |
+
<# if ( data.label ) { #>
|
197 |
+
<span class="customize-control-title">{{ data.label }}</span>
|
198 |
+
<# } else if ( data.labelEmpty ) { #>
|
199 |
+
<span class="customize-control-title"> </span>
|
200 |
+
<# } #>
|
201 |
+
<# if ( data.description ) { #>
|
202 |
+
<span class="description customize-control-description">{{ data.description }}</span>
|
203 |
+
<# } #>
|
204 |
+
<# _.each( viewport, function ( device ) { #>
|
205 |
+
<# if ( data.responsive ) { #>
|
206 |
+
<#
|
207 |
+
data.link = responsive.link + ' data-setting-viewport-link="' + device + '"'
|
208 |
+
data.id = responsive.id + '_' + device
|
209 |
+
data.value = responsive.value[device] || ''
|
210 |
+
#>
|
211 |
+
<div class="jupiterx-viewport jupiterx-viewport-{{ device }}">
|
212 |
+
<# } #>
|
213 |
+
<?php $this->control_template(); ?>
|
214 |
+
<# if ( data.responsive ) { #>
|
215 |
+
</div>
|
216 |
+
<# } #>
|
217 |
+
<# } ) #>
|
218 |
+
<# if ( data.responsive ) { #>
|
219 |
+
<div class="jupiterx-responsive-switcher">
|
220 |
+
<div class="jupiterx-responsive-switcher-buttons">
|
221 |
+
<# _.each( viewport, function ( device ) { #>
|
222 |
+
<a class="jupiterx-responsive-switcher-button jupiterx-responsive-switcher-{{ device }}" data-device="{{ device }}">
|
223 |
+
<span class="jupiterx-responsive-switcher-icon">
|
224 |
+
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_assets_url() ); ?>/img/device-{{ device }}.svg">
|
225 |
+
</span>
|
226 |
+
</a>
|
227 |
+
<# } ) #>
|
228 |
+
</div>
|
229 |
+
</div>
|
230 |
+
</div>
|
231 |
+
<# } #>
|
232 |
+
<?php
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* An Underscore (JS) template for control wrapper.
|
237 |
+
*
|
238 |
+
* Use to create the control template.
|
239 |
+
*
|
240 |
+
* @since 1.0.0
|
241 |
+
*/
|
242 |
+
protected function control_template() {}
|
243 |
+
}
|
includes/customizer/api/includes/base/class-group-control.php
CHANGED
@@ -1,264 +1,264 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class is a common class for all the group controls.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Group control base class.
|
17 |
-
*
|
18 |
-
* @since 1.0.0
|
19 |
-
* @ignore
|
20 |
-
* @access private
|
21 |
-
*
|
22 |
-
* @package JupiterX\Framework\API\Customizer
|
23 |
-
*/
|
24 |
-
class JupiterX_Customizer_Base_Group_Control extends JupiterX_Customizer_Base_Control {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Fields for this control.
|
28 |
-
*
|
29 |
-
* @since 1.0.0
|
30 |
-
*
|
31 |
-
* @var string
|
32 |
-
*/
|
33 |
-
public $fields = [];
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Exclude fields for this control.
|
37 |
-
*
|
38 |
-
* @since 1.0.0
|
39 |
-
*
|
40 |
-
* @var string
|
41 |
-
*/
|
42 |
-
public $exclude = [];
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Include fields for this control.
|
46 |
-
*
|
47 |
-
* @since 1.0.0
|
48 |
-
*
|
49 |
-
* @var string
|
50 |
-
*/
|
51 |
-
public $include = [];
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Use to add, edit or remove field arguments.
|
55 |
-
*
|
56 |
-
* @since 1.0.4
|
57 |
-
*
|
58 |
-
* @var array
|
59 |
-
*/
|
60 |
-
public $filter_fields = [];
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Refresh the parameters passed to the JavaScript via JSON.
|
64 |
-
*
|
65 |
-
* @since 1.0.0
|
66 |
-
*/
|
67 |
-
public function to_json() {
|
68 |
-
parent::to_json();
|
69 |
-
|
70 |
-
// Set the fields for this control.
|
71 |
-
$this->set_fields();
|
72 |
-
|
73 |
-
// Include fields.
|
74 |
-
$this->include_fields();
|
75 |
-
|
76 |
-
// Exclude fields.
|
77 |
-
$this->exclude_fields();
|
78 |
-
|
79 |
-
// Filter fields.
|
80 |
-
$this->filter_fields();
|
81 |
-
|
82 |
-
// Get fields.
|
83 |
-
$this->json['fields'] = $this->get_fields();
|
84 |
-
}
|
85 |
-
|
86 |
-
/**
|
87 |
-
* Set the fields for this control.
|
88 |
-
*
|
89 |
-
* @since 1.0.0
|
90 |
-
*/
|
91 |
-
protected function set_fields() {}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Add field.
|
95 |
-
*
|
96 |
-
* @since 1.0.0
|
97 |
-
*
|
98 |
-
* @param string $property Property name of field.
|
99 |
-
* @param array $args Field arguments.
|
100 |
-
*/
|
101 |
-
final protected function add_field( $property, $args ) {
|
102 |
-
$this->fields[ $property ] = array_merge( $args, [
|
103 |
-
'id' => sprintf( '%1$s_%2$s', $this->id, $property ),
|
104 |
-
'property' => $property,
|
105 |
-
'responsive' => $this->responsive && isset( $args['responsive'] ) ? true : false,
|
106 |
-
] );
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Update field.
|
111 |
-
*
|
112 |
-
* @since 1.0.0
|
113 |
-
*
|
114 |
-
* @param string $id ID of the field.
|
115 |
-
* @param array $args Arguments of the field.
|
116 |
-
*/
|
117 |
-
final protected function update_field( $id = '', $args ) {
|
118 |
-
if ( ! isset( $this->fields[ $id ] ) ) {
|
119 |
-
return;
|
120 |
-
}
|
121 |
-
|
122 |
-
$field = array_merge( $this->fields[ $id ], $args );
|
123 |
-
|
124 |
-
$this->fields[ $id ] = $field;
|
125 |
-
}
|
126 |
-
|
127 |
-
/**
|
128 |
-
* Get the fields for this control.
|
129 |
-
*
|
130 |
-
* @since 1.0.0
|
131 |
-
*/
|
132 |
-
final protected function get_fields() {
|
133 |
-
foreach ( $this->fields as $property => $field ) {
|
134 |
-
if ( ! $field['responsive'] ) {
|
135 |
-
$this->fields[ $property ]['value'] = $this->get_control_value( $property, $field );
|
136 |
-
}
|
137 |
-
|
138 |
-
if ( $field['responsive'] ) {
|
139 |
-
$this->fields[ $property ]['value'] = $this->get_responsive_control_value( $property, $field );
|
140 |
-
}
|
141 |
-
}
|
142 |
-
|
143 |
-
return $this->fields;
|
144 |
-
}
|
145 |
-
|
146 |
-
/**
|
147 |
-
* Include fields.
|
148 |
-
*
|
149 |
-
* @since 1.0.0
|
150 |
-
*/
|
151 |
-
protected function include_fields() {}
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Exclude fields.
|
155 |
-
*
|
156 |
-
* @since 1.0.0
|
157 |
-
*/
|
158 |
-
protected function exclude_fields() {
|
159 |
-
if ( empty( $this->exclude ) ) {
|
160 |
-
return;
|
161 |
-
}
|
162 |
-
|
163 |
-
$exclude = $this->exclude;
|
164 |
-
|
165 |
-
$this->fields = array_filter( $this->fields, function( $field ) use ( $exclude ) {
|
166 |
-
return ! in_array( $field['property'], $exclude, true );
|
167 |
-
} );
|
168 |
-
}
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Filter fields before ppassing to JSON.
|
172 |
-
*
|
173 |
-
* @since 1.0.4
|
174 |
-
*/
|
175 |
-
protected function filter_fields() {
|
176 |
-
if ( empty( $this->filter_fields ) || ! is_array( $this->filter_fields ) ) {
|
177 |
-
return;
|
178 |
-
}
|
179 |
-
|
180 |
-
foreach ( $this->filter_fields as $property => $args ) {
|
181 |
-
if ( isset( $this->fields[ $property ] ) ) {
|
182 |
-
$this->fields[ $property ] = array_merge( $this->fields[ $property ], $args );
|
183 |
-
}
|
184 |
-
}
|
185 |
-
}
|
186 |
-
|
187 |
-
/**
|
188 |
-
* Get the control value.
|
189 |
-
*
|
190 |
-
* @since 1.0.0
|
191 |
-
*
|
192 |
-
* @param array $property Field property name.
|
193 |
-
* @param array $field Control field.
|
194 |
-
*
|
195 |
-
* @return array Property value.
|
196 |
-
*/
|
197 |
-
final protected function get_control_value( $property, $field ) {
|
198 |
-
if ( $this->responsive && isset( $this->json['value']['desktop'][ $property ] ) ) {
|
199 |
-
return $this->json['value']['desktop'][ $property ];
|
200 |
-
}
|
201 |
-
|
202 |
-
if ( isset( $this->json['value'][ $property ] ) ) {
|
203 |
-
return $this->json['value'][ $property ];
|
204 |
-
}
|
205 |
-
|
206 |
-
if ( isset( $field['default'] ) ) {
|
207 |
-
return $field['default'];
|
208 |
-
}
|
209 |
-
|
210 |
-
return null;
|
211 |
-
}
|
212 |
-
|
213 |
-
/**
|
214 |
-
* Get the responsive control value.
|
215 |
-
*
|
216 |
-
* @since 1.0.0
|
217 |
-
*
|
218 |
-
* @param array $property Field property name.
|
219 |
-
* @param array $field Control field.
|
220 |
-
*
|
221 |
-
* @return array Property value.
|
222 |
-
*/
|
223 |
-
final protected function get_responsive_control_value( $property, $field ) {
|
224 |
-
$value = [];
|
225 |
-
|
226 |
-
foreach ( JupiterX_Customizer::$responsive_devices as $device => $media_query ) {
|
227 |
-
if ( isset( $this->json['value'][ $device ][ $property ] ) ) {
|
228 |
-
$value[ $device ] = $this->json['value'][ $device ][ $property ];
|
229 |
-
continue;
|
230 |
-
}
|
231 |
-
|
232 |
-
if ( isset( $field['default'][ $device ] ) ) {
|
233 |
-
$value[ $device ] = $field['default'][ $device ];
|
234 |
-
continue;
|
235 |
-
}
|
236 |
-
}
|
237 |
-
|
238 |
-
return $value;
|
239 |
-
}
|
240 |
-
|
241 |
-
/**
|
242 |
-
* Render the control's static content.
|
243 |
-
*
|
244 |
-
* @since 1.0.0
|
245 |
-
*/
|
246 |
-
final protected function render_content() {
|
247 |
-
?>
|
248 |
-
<?php if ( ! empty( $this->label ) ) : ?>
|
249 |
-
<span class="customize-control-title"><?php echo wp_kses_post( $this->label ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
|
250 |
-
<?php endif; ?>
|
251 |
-
<?php if ( ! empty( $this->description ) ) : ?>
|
252 |
-
<span class="description customize-control-description"><?php echo wp_kses_post( $this->description ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
|
253 |
-
<?php endif; ?>
|
254 |
-
<ul class="jupiterx-group-controls jupiterx-row"></ul>
|
255 |
-
<?php
|
256 |
-
}
|
257 |
-
|
258 |
-
/**
|
259 |
-
* Don't render a JS template for this.
|
260 |
-
*
|
261 |
-
* @since 1.0.0
|
262 |
-
*/
|
263 |
-
final protected function content_template() {}
|
264 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class is a common class for all the group controls.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Group control base class.
|
17 |
+
*
|
18 |
+
* @since 1.0.0
|
19 |
+
* @ignore
|
20 |
+
* @access private
|
21 |
+
*
|
22 |
+
* @package JupiterX\Framework\API\Customizer
|
23 |
+
*/
|
24 |
+
class JupiterX_Customizer_Base_Group_Control extends JupiterX_Customizer_Base_Control {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Fields for this control.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
*
|
31 |
+
* @var string
|
32 |
+
*/
|
33 |
+
public $fields = [];
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Exclude fields for this control.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
public $exclude = [];
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Include fields for this control.
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @var string
|
50 |
+
*/
|
51 |
+
public $include = [];
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Use to add, edit or remove field arguments.
|
55 |
+
*
|
56 |
+
* @since 1.0.4
|
57 |
+
*
|
58 |
+
* @var array
|
59 |
+
*/
|
60 |
+
public $filter_fields = [];
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Refresh the parameters passed to the JavaScript via JSON.
|
64 |
+
*
|
65 |
+
* @since 1.0.0
|
66 |
+
*/
|
67 |
+
public function to_json() {
|
68 |
+
parent::to_json();
|
69 |
+
|
70 |
+
// Set the fields for this control.
|
71 |
+
$this->set_fields();
|
72 |
+
|
73 |
+
// Include fields.
|
74 |
+
$this->include_fields();
|
75 |
+
|
76 |
+
// Exclude fields.
|
77 |
+
$this->exclude_fields();
|
78 |
+
|
79 |
+
// Filter fields.
|
80 |
+
$this->filter_fields();
|
81 |
+
|
82 |
+
// Get fields.
|
83 |
+
$this->json['fields'] = $this->get_fields();
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Set the fields for this control.
|
88 |
+
*
|
89 |
+
* @since 1.0.0
|
90 |
+
*/
|
91 |
+
protected function set_fields() {}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Add field.
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
*
|
98 |
+
* @param string $property Property name of field.
|
99 |
+
* @param array $args Field arguments.
|
100 |
+
*/
|
101 |
+
final protected function add_field( $property, $args ) {
|
102 |
+
$this->fields[ $property ] = array_merge( $args, [
|
103 |
+
'id' => sprintf( '%1$s_%2$s', $this->id, $property ),
|
104 |
+
'property' => $property,
|
105 |
+
'responsive' => $this->responsive && isset( $args['responsive'] ) ? true : false,
|
106 |
+
] );
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Update field.
|
111 |
+
*
|
112 |
+
* @since 1.0.0
|
113 |
+
*
|
114 |
+
* @param string $id ID of the field.
|
115 |
+
* @param array $args Arguments of the field.
|
116 |
+
*/
|
117 |
+
final protected function update_field( $id = '', $args ) {
|
118 |
+
if ( ! isset( $this->fields[ $id ] ) ) {
|
119 |
+
return;
|
120 |
+
}
|
121 |
+
|
122 |
+
$field = array_merge( $this->fields[ $id ], $args );
|
123 |
+
|
124 |
+
$this->fields[ $id ] = $field;
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Get the fields for this control.
|
129 |
+
*
|
130 |
+
* @since 1.0.0
|
131 |
+
*/
|
132 |
+
final protected function get_fields() {
|
133 |
+
foreach ( $this->fields as $property => $field ) {
|
134 |
+
if ( ! $field['responsive'] ) {
|
135 |
+
$this->fields[ $property ]['value'] = $this->get_control_value( $property, $field );
|
136 |
+
}
|
137 |
+
|
138 |
+
if ( $field['responsive'] ) {
|
139 |
+
$this->fields[ $property ]['value'] = $this->get_responsive_control_value( $property, $field );
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
return $this->fields;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Include fields.
|
148 |
+
*
|
149 |
+
* @since 1.0.0
|
150 |
+
*/
|
151 |
+
protected function include_fields() {}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Exclude fields.
|
155 |
+
*
|
156 |
+
* @since 1.0.0
|
157 |
+
*/
|
158 |
+
protected function exclude_fields() {
|
159 |
+
if ( empty( $this->exclude ) ) {
|
160 |
+
return;
|
161 |
+
}
|
162 |
+
|
163 |
+
$exclude = $this->exclude;
|
164 |
+
|
165 |
+
$this->fields = array_filter( $this->fields, function( $field ) use ( $exclude ) {
|
166 |
+
return ! in_array( $field['property'], $exclude, true );
|
167 |
+
} );
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Filter fields before ppassing to JSON.
|
172 |
+
*
|
173 |
+
* @since 1.0.4
|
174 |
+
*/
|
175 |
+
protected function filter_fields() {
|
176 |
+
if ( empty( $this->filter_fields ) || ! is_array( $this->filter_fields ) ) {
|
177 |
+
return;
|
178 |
+
}
|
179 |
+
|
180 |
+
foreach ( $this->filter_fields as $property => $args ) {
|
181 |
+
if ( isset( $this->fields[ $property ] ) ) {
|
182 |
+
$this->fields[ $property ] = array_merge( $this->fields[ $property ], $args );
|
183 |
+
}
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Get the control value.
|
189 |
+
*
|
190 |
+
* @since 1.0.0
|
191 |
+
*
|
192 |
+
* @param array $property Field property name.
|
193 |
+
* @param array $field Control field.
|
194 |
+
*
|
195 |
+
* @return array Property value.
|
196 |
+
*/
|
197 |
+
final protected function get_control_value( $property, $field ) {
|
198 |
+
if ( $this->responsive && isset( $this->json['value']['desktop'][ $property ] ) ) {
|
199 |
+
return $this->json['value']['desktop'][ $property ];
|
200 |
+
}
|
201 |
+
|
202 |
+
if ( isset( $this->json['value'][ $property ] ) ) {
|
203 |
+
return $this->json['value'][ $property ];
|
204 |
+
}
|
205 |
+
|
206 |
+
if ( isset( $field['default'] ) ) {
|
207 |
+
return $field['default'];
|
208 |
+
}
|
209 |
+
|
210 |
+
return null;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Get the responsive control value.
|
215 |
+
*
|
216 |
+
* @since 1.0.0
|
217 |
+
*
|
218 |
+
* @param array $property Field property name.
|
219 |
+
* @param array $field Control field.
|
220 |
+
*
|
221 |
+
* @return array Property value.
|
222 |
+
*/
|
223 |
+
final protected function get_responsive_control_value( $property, $field ) {
|
224 |
+
$value = [];
|
225 |
+
|
226 |
+
foreach ( JupiterX_Customizer::$responsive_devices as $device => $media_query ) {
|
227 |
+
if ( isset( $this->json['value'][ $device ][ $property ] ) ) {
|
228 |
+
$value[ $device ] = $this->json['value'][ $device ][ $property ];
|
229 |
+
continue;
|
230 |
+
}
|
231 |
+
|
232 |
+
if ( isset( $field['default'][ $device ] ) ) {
|
233 |
+
$value[ $device ] = $field['default'][ $device ];
|
234 |
+
continue;
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
return $value;
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Render the control's static content.
|
243 |
+
*
|
244 |
+
* @since 1.0.0
|
245 |
+
*/
|
246 |
+
final protected function render_content() {
|
247 |
+
?>
|
248 |
+
<?php if ( ! empty( $this->label ) ) : ?>
|
249 |
+
<span class="customize-control-title"><?php echo wp_kses_post( $this->label ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
|
250 |
+
<?php endif; ?>
|
251 |
+
<?php if ( ! empty( $this->description ) ) : ?>
|
252 |
+
<span class="description customize-control-description"><?php echo wp_kses_post( $this->description ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
|
253 |
+
<?php endif; ?>
|
254 |
+
<ul class="jupiterx-group-controls jupiterx-row"></ul>
|
255 |
+
<?php
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Don't render a JS template for this.
|
260 |
+
*
|
261 |
+
* @since 1.0.0
|
262 |
+
*/
|
263 |
+
final protected function content_template() {}
|
264 |
+
}
|
includes/customizer/api/includes/base/class-input-group.php
CHANGED
@@ -1,103 +1,103 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Base class for control with input group icon, text and unit.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Base input group class.
|
17 |
-
*
|
18 |
-
* @since 1.0.0
|
19 |
-
* @ignore
|
20 |
-
* @access private
|
21 |
-
*
|
22 |
-
* @package JupiterX\Framework\API\Customizer
|
23 |
-
*/
|
24 |
-
class JupiterX_Customizer_Base_Input_Group extends JupiterX_Customizer_Base_Control {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Control's input group text.
|
28 |
-
*
|
29 |
-
* @since 1.0.0
|
30 |
-
*
|
31 |
-
* @var string
|
32 |
-
*/
|
33 |
-
public $text = '';
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Control's input group icon.
|
37 |
-
*
|
38 |
-
* @since 1.0.0
|
39 |
-
*
|
40 |
-
* @var string
|
41 |
-
*/
|
42 |
-
public $icon = '';
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Refresh the parameters passed to the JavaScript via JSON.
|
46 |
-
*
|
47 |
-
* @since 1.0.0
|
48 |
-
*/
|
49 |
-
public function to_json() {
|
50 |
-
parent::to_json();
|
51 |
-
|
52 |
-
$this->json['text'] = $this->text;
|
53 |
-
$this->json['icon'] = $this->icon;
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* An Underscore (JS) template for control wrapper.
|
58 |
-
*
|
59 |
-
* Use to create the control template.
|
60 |
-
*
|
61 |
-
* @since 1.0.0
|
62 |
-
*/
|
63 |
-
protected function control_template() {
|
64 |
-
?>
|
65 |
-
<#
|
66 |
-
hasText = ! _.isUndefined( data.text ) && ! _.isEmpty( data.text )
|
67 |
-
hasIcon = ! _.isUndefined( data.icon ) && ! _.isEmpty( data.icon )
|
68 |
-
controlClass = 'jupiterx-control ' + data.type + '-control'
|
69 |
-
controlClass += ( hasIcon || hasText ) ? ' jupiterx-input-group' : ''
|
70 |
-
controlClass += ( hasIcon ) ? ' has-icon' : ''
|
71 |
-
controlClass += ( hasText ) ? ' has-text' : ''
|
72 |
-
#>
|
73 |
-
<div class="{{ controlClass }}" {{{ data.controlAttrs }}}>
|
74 |
-
<?php
|
75 |
-
$this->group_prefix_template();
|
76 |
-
$this->group_field_template();
|
77 |
-
?>
|
78 |
-
</div>
|
79 |
-
<?php
|
80 |
-
}
|
81 |
-
|
82 |
-
/**
|
83 |
-
* An Underscore (JS) template for field prefix.
|
84 |
-
*
|
85 |
-
* @since 1.0.0
|
86 |
-
*/
|
87 |
-
protected function group_prefix_template() {
|
88 |
-
?>
|
89 |
-
<# if ( hasText ) { #>
|
90 |
-
<span class="jupiterx-input-group-text">{{ data.text }}</span>
|
91 |
-
<# } else if ( hasIcon ) { #>
|
92 |
-
<span class="jupiterx-input-group-icon"><img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_assets_url() ); ?>/img/{{ data.icon }}.svg" /></span>
|
93 |
-
<# } #>
|
94 |
-
<?php
|
95 |
-
}
|
96 |
-
|
97 |
-
/**
|
98 |
-
* An Underscore (JS) template for control field.
|
99 |
-
*
|
100 |
-
* @since 1.0.0
|
101 |
-
*/
|
102 |
-
protected function group_field_template() {}
|
103 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Base class for control with input group icon, text and unit.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Base input group class.
|
17 |
+
*
|
18 |
+
* @since 1.0.0
|
19 |
+
* @ignore
|
20 |
+
* @access private
|
21 |
+
*
|
22 |
+
* @package JupiterX\Framework\API\Customizer
|
23 |
+
*/
|
24 |
+
class JupiterX_Customizer_Base_Input_Group extends JupiterX_Customizer_Base_Control {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Control's input group text.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
*
|
31 |
+
* @var string
|
32 |
+
*/
|
33 |
+
public $text = '';
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Control's input group icon.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
public $icon = '';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Refresh the parameters passed to the JavaScript via JSON.
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*/
|
49 |
+
public function to_json() {
|
50 |
+
parent::to_json();
|
51 |
+
|
52 |
+
$this->json['text'] = $this->text;
|
53 |
+
$this->json['icon'] = $this->icon;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* An Underscore (JS) template for control wrapper.
|
58 |
+
*
|
59 |
+
* Use to create the control template.
|
60 |
+
*
|
61 |
+
* @since 1.0.0
|
62 |
+
*/
|
63 |
+
protected function control_template() {
|
64 |
+
?>
|
65 |
+
<#
|
66 |
+
hasText = ! _.isUndefined( data.text ) && ! _.isEmpty( data.text )
|
67 |
+
hasIcon = ! _.isUndefined( data.icon ) && ! _.isEmpty( data.icon )
|
68 |
+
controlClass = 'jupiterx-control ' + data.type + '-control'
|
69 |
+
controlClass += ( hasIcon || hasText ) ? ' jupiterx-input-group' : ''
|
70 |
+
controlClass += ( hasIcon ) ? ' has-icon' : ''
|
71 |
+
controlClass += ( hasText ) ? ' has-text' : ''
|
72 |
+
#>
|
73 |
+
<div class="{{ controlClass }}" {{{ data.controlAttrs }}}>
|
74 |
+
<?php
|
75 |
+
$this->group_prefix_template();
|
76 |
+
$this->group_field_template();
|
77 |
+
?>
|
78 |
+
</div>
|
79 |
+
<?php
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* An Underscore (JS) template for field prefix.
|
84 |
+
*
|
85 |
+
* @since 1.0.0
|
86 |
+
*/
|
87 |
+
protected function group_prefix_template() {
|
88 |
+
?>
|
89 |
+
<# if ( hasText ) { #>
|
90 |
+
<span class="jupiterx-input-group-text">{{ data.text }}</span>
|
91 |
+
<# } else if ( hasIcon ) { #>
|
92 |
+
<span class="jupiterx-input-group-icon"><img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_assets_url() ); ?>/img/{{ data.icon }}.svg" /></span>
|
93 |
+
<# } #>
|
94 |
+
<?php
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* An Underscore (JS) template for control field.
|
99 |
+
*
|
100 |
+
* @since 1.0.0
|
101 |
+
*/
|
102 |
+
protected function group_field_template() {}
|
103 |
+
}
|
includes/customizer/api/includes/class-autoloader.php
CHANGED
@@ -1,119 +1,119 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class handles customizer function.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*
|
9 |
-
* @todo Enhance the Customizer autoloading code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
// Exit if accessed directly.
|
13 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
-
exit;
|
15 |
-
}
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Extends WordPress customizer capability.
|
19 |
-
*
|
20 |
-
* @since 1.0.0
|
21 |
-
* @ignore
|
22 |
-
* @access private
|
23 |
-
*
|
24 |
-
* @package JupiterX\Framework\API\Customizer
|
25 |
-
*/
|
26 |
-
final class JupiterX_Core_Customizer_Autoloader {
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Directory maps.
|
30 |
-
*
|
31 |
-
* @since 1.0.0
|
32 |
-
*
|
33 |
-
* @var array
|
34 |
-
*/
|
35 |
-
public $dir_map = [
|
36 |
-
'base' => 'includes/base',
|
37 |
-
'control' => 'includes/control',
|
38 |
-
'group-control' => 'includes/control/group',
|
39 |
-
'output' => 'includes/output',
|
40 |
-
'section' => 'includes/section',
|
41 |
-
'kirki-extend-base' => 'modules/kirki-extend/base',
|
42 |
-
'kirki-extend-output' => 'modules/kirki-extend/output',
|
43 |
-
'kirki-extend' => 'modules/kirki-extend',
|
44 |
-
'get-variables' => 'modules/compiler',
|
45 |
-
'compiler' => 'modules/compiler',
|
46 |
-
'post-message' => 'modules/post-message',
|
47 |
-
'elementor' => 'modules/elementor',
|
48 |
-
];
|
49 |
-
|
50 |
-
/**
|
51 |
-
* Construct the class.
|
52 |
-
*
|
53 |
-
* @since 1.0.0
|
54 |
-
*/
|
55 |
-
public function __construct() {
|
56 |
-
spl_autoload_register( [ $this, 'autoload' ] );
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Customizer autoload function.
|
61 |
-
*
|
62 |
-
* @since 1.0.0
|
63 |
-
*
|
64 |
-
* @param string $class_name The class name from spl_autoload_register.
|
65 |
-
*/
|
66 |
-
public function autoload( $class_name ) {
|
67 |
-
if ( class_exists( $class_name ) || 0 !== stripos( $class_name, 'JupiterX_Customizer_' ) ) {
|
68 |
-
return;
|
69 |
-
}
|
70 |
-
|
71 |
-
// Assumed file name.
|
72 |
-
$file_name = strtolower( str_replace( [ 'JupiterX_Customizer_', '_' ], [ '', '-' ], $class_name ) );
|
73 |
-
|
74 |
-
// Get path attributes.
|
75 |
-
$path = $this->get_path( $file_name );
|
76 |
-
|
77 |
-
// Create full path.
|
78 |
-
$full_path = sprintf( '%1$s/%2$s', $path['dir'], $path['name'] );
|
79 |
-
|
80 |
-
if ( file_exists( $full_path ) ) {
|
81 |
-
include_once $full_path;
|
82 |
-
}
|
83 |
-
}
|
84 |
-
|
85 |
-
/**
|
86 |
-
* Get the file.
|
87 |
-
*
|
88 |
-
* @since 1.0.0
|
89 |
-
*
|
90 |
-
* @param string $file_name Assumed file name.
|
91 |
-
*
|
92 |
-
* @return array Path attributes.
|
93 |
-
*/
|
94 |
-
public function get_path( $file_name ) {
|
95 |
-
$path = [
|
96 |
-
'dir' => 'includes',
|
97 |
-
'name' => $file_name,
|
98 |
-
];
|
99 |
-
|
100 |
-
// Change dir and file name if found in directory map.
|
101 |
-
foreach ( $this->dir_map as $key => $dir ) {
|
102 |
-
if ( 0 === stripos( $file_name, $key ) ) {
|
103 |
-
$path = [
|
104 |
-
'dir' => $dir,
|
105 |
-
'name' => str_replace( $key . '-', '', $file_name ),
|
106 |
-
];
|
107 |
-
break;
|
108 |
-
}
|
109 |
-
}
|
110 |
-
|
111 |
-
return [
|
112 |
-
'dir' => wp_normalize_path( JUPITERX_CORE_CUSTOMIZER_PATH . $path['dir'] ),
|
113 |
-
'name' => sprintf( 'class-%1$s.php', $path['name'] ),
|
114 |
-
];
|
115 |
-
}
|
116 |
-
}
|
117 |
-
|
118 |
-
// Initialize autoloader.
|
119 |
-
new JupiterX_Core_Customizer_Autoloader();
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class handles customizer function.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @todo Enhance the Customizer autoloading code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
// Exit if accessed directly.
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit;
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Extends WordPress customizer capability.
|
19 |
+
*
|
20 |
+
* @since 1.0.0
|
21 |
+
* @ignore
|
22 |
+
* @access private
|
23 |
+
*
|
24 |
+
* @package JupiterX\Framework\API\Customizer
|
25 |
+
*/
|
26 |
+
final class JupiterX_Core_Customizer_Autoloader {
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Directory maps.
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @var array
|
34 |
+
*/
|
35 |
+
public $dir_map = [
|
36 |
+
'base' => 'includes/base',
|
37 |
+
'control' => 'includes/control',
|
38 |
+
'group-control' => 'includes/control/group',
|
39 |
+
'output' => 'includes/output',
|
40 |
+
'section' => 'includes/section',
|
41 |
+
'kirki-extend-base' => 'modules/kirki-extend/base',
|
42 |
+
'kirki-extend-output' => 'modules/kirki-extend/output',
|
43 |
+
'kirki-extend' => 'modules/kirki-extend',
|
44 |
+
'get-variables' => 'modules/compiler',
|
45 |
+
'compiler' => 'modules/compiler',
|
46 |
+
'post-message' => 'modules/post-message',
|
47 |
+
'elementor' => 'modules/elementor',
|
48 |
+
];
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Construct the class.
|
52 |
+
*
|
53 |
+
* @since 1.0.0
|
54 |
+
*/
|
55 |
+
public function __construct() {
|
56 |
+
spl_autoload_register( [ $this, 'autoload' ] );
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Customizer autoload function.
|
61 |
+
*
|
62 |
+
* @since 1.0.0
|
63 |
+
*
|
64 |
+
* @param string $class_name The class name from spl_autoload_register.
|
65 |
+
*/
|
66 |
+
public function autoload( $class_name ) {
|
67 |
+
if ( class_exists( $class_name ) || 0 !== stripos( $class_name, 'JupiterX_Customizer_' ) ) {
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
|
71 |
+
// Assumed file name.
|
72 |
+
$file_name = strtolower( str_replace( [ 'JupiterX_Customizer_', '_' ], [ '', '-' ], $class_name ) );
|
73 |
+
|
74 |
+
// Get path attributes.
|
75 |
+
$path = $this->get_path( $file_name );
|
76 |
+
|
77 |
+
// Create full path.
|
78 |
+
$full_path = sprintf( '%1$s/%2$s', $path['dir'], $path['name'] );
|
79 |
+
|
80 |
+
if ( file_exists( $full_path ) ) {
|
81 |
+
include_once $full_path;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Get the file.
|
87 |
+
*
|
88 |
+
* @since 1.0.0
|
89 |
+
*
|
90 |
+
* @param string $file_name Assumed file name.
|
91 |
+
*
|
92 |
+
* @return array Path attributes.
|
93 |
+
*/
|
94 |
+
public function get_path( $file_name ) {
|
95 |
+
$path = [
|
96 |
+
'dir' => 'includes',
|
97 |
+
'name' => $file_name,
|
98 |
+
];
|
99 |
+
|
100 |
+
// Change dir and file name if found in directory map.
|
101 |
+
foreach ( $this->dir_map as $key => $dir ) {
|
102 |
+
if ( 0 === stripos( $file_name, $key ) ) {
|
103 |
+
$path = [
|
104 |
+
'dir' => $dir,
|
105 |
+
'name' => str_replace( $key . '-', '', $file_name ),
|
106 |
+
];
|
107 |
+
break;
|
108 |
+
}
|
109 |
+
}
|
110 |
+
|
111 |
+
return [
|
112 |
+
'dir' => wp_normalize_path( JUPITERX_CORE_CUSTOMIZER_PATH . $path['dir'] ),
|
113 |
+
'name' => sprintf( 'class-%1$s.php', $path['name'] ),
|
114 |
+
];
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
// Initialize autoloader.
|
119 |
+
new JupiterX_Core_Customizer_Autoloader();
|
includes/customizer/api/includes/class-templates.php
CHANGED
@@ -1,163 +1,163 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class handles printing custom templates in Customizer preview.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Print custom templates.
|
17 |
-
*
|
18 |
-
* @since 1.0.0
|
19 |
-
* @ignore
|
20 |
-
* @access private
|
21 |
-
*
|
22 |
-
* @package JupiterX\Framework\API\Customizer
|
23 |
-
*/
|
24 |
-
final class JupiterX_Core_Customizer_Templates {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Construct the class.
|
28 |
-
*
|
29 |
-
* @since 1.0.0
|
30 |
-
*/
|
31 |
-
public function __construct() {
|
32 |
-
add_action( 'customize_controls_print_footer_scripts', [ $this, 'render_templates' ], 0 );
|
33 |
-
}
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Print templates in Customizer page.
|
37 |
-
*
|
38 |
-
* @since 1.0.0
|
39 |
-
* @SuppressWarnings(PHPMD.ElseExpression)
|
40 |
-
*/
|
41 |
-
public function render_templates() {
|
42 |
-
?>
|
43 |
-
<script type="text/html" id="tmpl-customize-jupiterx-popup-content">
|
44 |
-
<div id="customize-jupiterx-popup-content" class="jupiterx-popup">
|
45 |
-
<div id="customize-jupiterx-popup-controls" class="jupiterx-popup-container"></div>
|
46 |
-
</div>
|
47 |
-
</script>
|
48 |
-
|
49 |
-
<script type="text/html" id="tmpl-customize-jupiterx-popup-child">
|
50 |
-
<div class="jupiterx-popup-child">
|
51 |
-
<div class="jupiterx-child-popup active">
|
52 |
-
<# if ( data.title ) { #>
|
53 |
-
<div class="jupiterx-child-popup-header">
|
54 |
-
<h3 class="jupiterx-child-popup-title">{{{ data.title }}}</h3>
|
55 |
-
<div class="jupiterx-child-popup-header-buttons">
|
56 |
-
<button class="jupiterx-child-popup-button jupiterx-child-popup-close">
|
57 |
-
<span class="dashicons dashicons-no"></span>
|
58 |
-
<span class="screen-reader-text"><?php esc_html_e( 'Close', 'jupiterx-core' ); ?></span>
|
59 |
-
</button>
|
60 |
-
</div>
|
61 |
-
</div>
|
62 |
-
<# } #>
|
63 |
-
<div class="jupiterx-child-popup-content"></div>
|
64 |
-
</div>
|
65 |
-
</div>
|
66 |
-
</script>
|
67 |
-
|
68 |
-
<script type="text/html" id="tmpl-customize-jupiterx-fonts-control-preview">
|
69 |
-
<div class="jupiterx-fonts-control-preview" data-font-family="{{ data.name }}">
|
70 |
-
<span class="jupiterx-fonts-control-preview-family">{{{ data.name }}}</span>
|
71 |
-
<h3 class="jupiterx-fonts-control-preview-sample" style="font-family: {{ data.value || data.name }};"><?php esc_html_e( 'The spectate before us was indeed sublime.', 'jupiterx-core' ); ?></h3>
|
72 |
-
<button class="jupiterx-fonts-control-preview-remove">
|
73 |
-
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_assets_url() ); ?>/img/x-white.svg" />
|
74 |
-
<span class="screen-reader-text"><?php esc_html_e( 'Remove', 'jupiterx-core' ); ?></span>
|
75 |
-
</button>
|
76 |
-
</div>
|
77 |
-
</script>
|
78 |
-
|
79 |
-
<script type="text/html" id="tmpl-customize-jupiterx-fonts-control-selector">
|
80 |
-
<div class="jupiterx-fonts-control-popup jupiterx-popup-child">
|
81 |
-
<div class="jupiterx-child-popup active">
|
82 |
-
<div class="jupiterx-child-popup-content">
|
83 |
-
<div class="jupiterx-fonts-control-selector">
|
84 |
-
<div class="jupiterx-fonts-control-selector-preview">
|
85 |
-
<h3 class="jupiterx-fonts-control-selector-sample"><?php esc_html_e( 'The spectate before us was indeed sublime.', 'jupiterx-core' ); ?></h3>
|
86 |
-
</div>
|
87 |
-
<span class="customize-control-title"><?php esc_html_e( 'Select a Font Family', 'jupiterx-core' ); ?></span>
|
88 |
-
<div class="jupiterx-fonts-control-selector-group">
|
89 |
-
<div class="jupiterx-fonts-control-selector-families">
|
90 |
-
<div class="jupiterx-control jupiterx-select-control">
|
91 |
-
<select class="jupiterx-select-control-field">
|
92 |
-
<# _.each( data.fontFamilies, function( props, name ) { #>
|
93 |
-
<# type = props.type || props #>
|
94 |
-
<# value = props.value || name #>
|
95 |
-
<option data-type="{{ type }}" value="{{ value }}">{{{ name }}}</option>
|
96 |
-
<# } ); #>
|
97 |
-
</select>
|
98 |
-
</div>
|
99 |
-
</div>
|
100 |
-
<div class="jupiterx-fonts-control-selector-filters">
|
101 |
-
<div class="jupiterx-control jupiterx-select-control">
|
102 |
-
<select class="jupiterx-select-control-field">
|
103 |
-
<option value=""><?php esc_html_e( 'All Fonts', 'jupiterx-core' ); ?></option>
|
104 |
-
<# _.each( data.fontTypes, function( fontName, fontType ) { #>
|
105 |
-
<# disabled = fontName.indexOf('jupiterx-pro-badge') != -1 ? 'disabled' : '' #>
|
106 |
-
<option value="{{ fontType }}" {{ disabled }}><span>{{ fontName }}</span></option>
|
107 |
-
<# } ); #>
|
108 |
-
</select>
|
109 |
-
</div>
|
110 |
-
</div>
|
111 |
-
</div>
|
112 |
-
<div class="jupiterx-fonts-control-selector-buttons">
|
113 |
-
<button class="jupiterx-fonts-control-selector-cancel jupiterx-button jupiterx-button-danger">
|
114 |
-
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_icon_url( 'x' ) ); ?>">
|
115 |
-
<span class="screen-reader-text"><?php esc_html_e( 'Cancel', 'jupiterx-core' ); ?></span>
|
116 |
-
</button>
|
117 |
-
<button class="jupiterx-fonts-control-selector-submit jupiterx-button">
|
118 |
-
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_icon_url( 'check' ) ); ?>">
|
119 |
-
<span class="screen-reader-text"><?php esc_html_e( 'Submit', 'jupiterx-core' ); ?></span>
|
120 |
-
</button>
|
121 |
-
</div>
|
122 |
-
</div>
|
123 |
-
</div>
|
124 |
-
</div>
|
125 |
-
</div>
|
126 |
-
</script>
|
127 |
-
|
128 |
-
<script type="text/html" id="tmpl-customize-jupiterx-exceptions-control-group">
|
129 |
-
<div class="jupiterx-exceptions-control-group">
|
130 |
-
<h3>{{{ data.text }}}</h3>
|
131 |
-
<button class="jupiterx-exceptions-control-remove jupiterx-button jupiterx-button-outline jupiterx-button-danger jupiterx-button-small" data-id="{{ data.id }}"><?php esc_html_e( 'Remove', 'jupiterx-core' ); ?></button>
|
132 |
-
<ul class="jupiterx-row jupiterx-group-controls"></ul>
|
133 |
-
</div>
|
134 |
-
</script>
|
135 |
-
|
136 |
-
<script type="text/html" id="tmpl-customize-jupiterx-pro-preview-lightbox">
|
137 |
-
<div class="jupiterx-pro-preview">
|
138 |
-
<div class="jupiterx-pro-preview-header">
|
139 |
-
<a class="jupiterx-pro-preview-back" href="#"><span class="jupiterx-icon-arrow-left-solid"></span> <?php esc_html_e( 'Back', 'jupiterx-core' ); ?></a>
|
140 |
-
<?php if ( jupiterx_is_premium() ) : ?>
|
141 |
-
<span>
|
142 |
-
<span class="jupiterx-pro-preview-modal-description"><?php esc_html_e( 'Activate Jupiter X to unlock this feature', 'jupiterx-core' ); ?></span>
|
143 |
-
<a href="<?php echo esc_attr( jupiterx_upgrade_link( 'customizer' ) ); ?>" class="jupiterx-pro-preview-upgrade jupiterx-upgrade-modal-trigger" target="_blank"><?php esc_html_e( 'Activate Now', 'jupiterx-core' ); ?></a>
|
144 |
-
</span>
|
145 |
-
<?php else : ?>
|
146 |
-
<a class="jupiterx-pro-preview-upgrade" href="<?php echo esc_attr( jupiterx_upgrade_link( 'customizer' ) ); ?>" target="_blank"><?php esc_html_e( 'Upgrade to Jupiter X Pro', 'jupiterx-core' ); ?></a>
|
147 |
-
<?php endif; ?>
|
148 |
-
</div>
|
149 |
-
<div class="jupiterx-pro-preview-content">
|
150 |
-
<div class="jupiterx-pro-preview-container">
|
151 |
-
<# if ( data.preview ) { #>
|
152 |
-
<img class="jupiterx-pro-preview-image" src="{{ data.preview }}" />
|
153 |
-
<# } #>
|
154 |
-
</div>
|
155 |
-
</div>
|
156 |
-
</div>
|
157 |
-
</script>
|
158 |
-
<?php
|
159 |
-
}
|
160 |
-
}
|
161 |
-
|
162 |
-
// Initialize.
|
163 |
-
new JupiterX_Core_Customizer_Templates();
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class handles printing custom templates in Customizer preview.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Print custom templates.
|
17 |
+
*
|
18 |
+
* @since 1.0.0
|
19 |
+
* @ignore
|
20 |
+
* @access private
|
21 |
+
*
|
22 |
+
* @package JupiterX\Framework\API\Customizer
|
23 |
+
*/
|
24 |
+
final class JupiterX_Core_Customizer_Templates {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Construct the class.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
*/
|
31 |
+
public function __construct() {
|
32 |
+
add_action( 'customize_controls_print_footer_scripts', [ $this, 'render_templates' ], 0 );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Print templates in Customizer page.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
* @SuppressWarnings(PHPMD.ElseExpression)
|
40 |
+
*/
|
41 |
+
public function render_templates() {
|
42 |
+
?>
|
43 |
+
<script type="text/html" id="tmpl-customize-jupiterx-popup-content">
|
44 |
+
<div id="customize-jupiterx-popup-content" class="jupiterx-popup">
|
45 |
+
<div id="customize-jupiterx-popup-controls" class="jupiterx-popup-container"></div>
|
46 |
+
</div>
|
47 |
+
</script>
|
48 |
+
|
49 |
+
<script type="text/html" id="tmpl-customize-jupiterx-popup-child">
|
50 |
+
<div class="jupiterx-popup-child">
|
51 |
+
<div class="jupiterx-child-popup active">
|
52 |
+
<# if ( data.title ) { #>
|
53 |
+
<div class="jupiterx-child-popup-header">
|
54 |
+
<h3 class="jupiterx-child-popup-title">{{{ data.title }}}</h3>
|
55 |
+
<div class="jupiterx-child-popup-header-buttons">
|
56 |
+
<button class="jupiterx-child-popup-button jupiterx-child-popup-close">
|
57 |
+
<span class="dashicons dashicons-no"></span>
|
58 |
+
<span class="screen-reader-text"><?php esc_html_e( 'Close', 'jupiterx-core' ); ?></span>
|
59 |
+
</button>
|
60 |
+
</div>
|
61 |
+
</div>
|
62 |
+
<# } #>
|
63 |
+
<div class="jupiterx-child-popup-content"></div>
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
</script>
|
67 |
+
|
68 |
+
<script type="text/html" id="tmpl-customize-jupiterx-fonts-control-preview">
|
69 |
+
<div class="jupiterx-fonts-control-preview" data-font-family="{{ data.name }}">
|
70 |
+
<span class="jupiterx-fonts-control-preview-family">{{{ data.name }}}</span>
|
71 |
+
<h3 class="jupiterx-fonts-control-preview-sample" style="font-family: {{ data.value || data.name }};"><?php esc_html_e( 'The spectate before us was indeed sublime.', 'jupiterx-core' ); ?></h3>
|
72 |
+
<button class="jupiterx-fonts-control-preview-remove">
|
73 |
+
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_assets_url() ); ?>/img/x-white.svg" />
|
74 |
+
<span class="screen-reader-text"><?php esc_html_e( 'Remove', 'jupiterx-core' ); ?></span>
|
75 |
+
</button>
|
76 |
+
</div>
|
77 |
+
</script>
|
78 |
+
|
79 |
+
<script type="text/html" id="tmpl-customize-jupiterx-fonts-control-selector">
|
80 |
+
<div class="jupiterx-fonts-control-popup jupiterx-popup-child">
|
81 |
+
<div class="jupiterx-child-popup active">
|
82 |
+
<div class="jupiterx-child-popup-content">
|
83 |
+
<div class="jupiterx-fonts-control-selector">
|
84 |
+
<div class="jupiterx-fonts-control-selector-preview">
|
85 |
+
<h3 class="jupiterx-fonts-control-selector-sample"><?php esc_html_e( 'The spectate before us was indeed sublime.', 'jupiterx-core' ); ?></h3>
|
86 |
+
</div>
|
87 |
+
<span class="customize-control-title"><?php esc_html_e( 'Select a Font Family', 'jupiterx-core' ); ?></span>
|
88 |
+
<div class="jupiterx-fonts-control-selector-group">
|
89 |
+
<div class="jupiterx-fonts-control-selector-families">
|
90 |
+
<div class="jupiterx-control jupiterx-select-control">
|
91 |
+
<select class="jupiterx-select-control-field">
|
92 |
+
<# _.each( data.fontFamilies, function( props, name ) { #>
|
93 |
+
<# type = props.type || props #>
|
94 |
+
<# value = props.value || name #>
|
95 |
+
<option data-type="{{ type }}" value="{{ value }}">{{{ name }}}</option>
|
96 |
+
<# } ); #>
|
97 |
+
</select>
|
98 |
+
</div>
|
99 |
+
</div>
|
100 |
+
<div class="jupiterx-fonts-control-selector-filters">
|
101 |
+
<div class="jupiterx-control jupiterx-select-control">
|
102 |
+
<select class="jupiterx-select-control-field">
|
103 |
+
<option value=""><?php esc_html_e( 'All Fonts', 'jupiterx-core' ); ?></option>
|
104 |
+
<# _.each( data.fontTypes, function( fontName, fontType ) { #>
|
105 |
+
<# disabled = fontName.indexOf('jupiterx-pro-badge') != -1 ? 'disabled' : '' #>
|
106 |
+
<option value="{{ fontType }}" {{ disabled }}><span>{{ fontName }}</span></option>
|
107 |
+
<# } ); #>
|
108 |
+
</select>
|
109 |
+
</div>
|
110 |
+
</div>
|
111 |
+
</div>
|
112 |
+
<div class="jupiterx-fonts-control-selector-buttons">
|
113 |
+
<button class="jupiterx-fonts-control-selector-cancel jupiterx-button jupiterx-button-danger">
|
114 |
+
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_icon_url( 'x' ) ); ?>">
|
115 |
+
<span class="screen-reader-text"><?php esc_html_e( 'Cancel', 'jupiterx-core' ); ?></span>
|
116 |
+
</button>
|
117 |
+
<button class="jupiterx-fonts-control-selector-submit jupiterx-button">
|
118 |
+
<img src="<?php echo esc_url( JupiterX_Customizer_Utils::get_icon_url( 'check' ) ); ?>">
|
119 |
+
<span class="screen-reader-text"><?php esc_html_e( 'Submit', 'jupiterx-core' ); ?></span>
|
120 |
+
</button>
|
121 |
+
</div>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
</div>
|
125 |
+
</div>
|
126 |
+
</script>
|
127 |
+
|
128 |
+
<script type="text/html" id="tmpl-customize-jupiterx-exceptions-control-group">
|
129 |
+
<div class="jupiterx-exceptions-control-group">
|
130 |
+
<h3>{{{ data.text }}}</h3>
|
131 |
+
<button class="jupiterx-exceptions-control-remove jupiterx-button jupiterx-button-outline jupiterx-button-danger jupiterx-button-small" data-id="{{ data.id }}"><?php esc_html_e( 'Remove', 'jupiterx-core' ); ?></button>
|
132 |
+
<ul class="jupiterx-row jupiterx-group-controls"></ul>
|
133 |
+
</div>
|
134 |
+
</script>
|
135 |
+
|
136 |
+
<script type="text/html" id="tmpl-customize-jupiterx-pro-preview-lightbox">
|
137 |
+
<div class="jupiterx-pro-preview">
|
138 |
+
<div class="jupiterx-pro-preview-header">
|
139 |
+
<a class="jupiterx-pro-preview-back" href="#"><span class="jupiterx-icon-arrow-left-solid"></span> <?php esc_html_e( 'Back', 'jupiterx-core' ); ?></a>
|
140 |
+
<?php if ( jupiterx_is_premium() ) : ?>
|
141 |
+
<span>
|
142 |
+
<span class="jupiterx-pro-preview-modal-description"><?php esc_html_e( 'Activate Jupiter X to unlock this feature', 'jupiterx-core' ); ?></span>
|
143 |
+
<a href="<?php echo esc_attr( jupiterx_upgrade_link( 'customizer' ) ); ?>" class="jupiterx-pro-preview-upgrade jupiterx-upgrade-modal-trigger" target="_blank"><?php esc_html_e( 'Activate Now', 'jupiterx-core' ); ?></a>
|
144 |
+
</span>
|
145 |
+
<?php else : ?>
|
146 |
+
<a class="jupiterx-pro-preview-upgrade" href="<?php echo esc_attr( jupiterx_upgrade_link( 'customizer' ) ); ?>" target="_blank"><?php esc_html_e( 'Upgrade to Jupiter X Pro', 'jupiterx-core' ); ?></a>
|
147 |
+
<?php endif; ?>
|
148 |
+
</div>
|
149 |
+
<div class="jupiterx-pro-preview-content">
|
150 |
+
<div class="jupiterx-pro-preview-container">
|
151 |
+
<# if ( data.preview ) { #>
|
152 |
+
<img class="jupiterx-pro-preview-image" src="{{ data.preview }}" />
|
153 |
+
<# } #>
|
154 |
+
</div>
|
155 |
+
</div>
|
156 |
+
</div>
|
157 |
+
</script>
|
158 |
+
<?php
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
// Initialize.
|
163 |
+
new JupiterX_Core_Customizer_Templates();
|
includes/customizer/api/includes/control/class-alert.php
CHANGED
@@ -1,89 +1,89 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Handles alert control class.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Alert control class.
|
17 |
-
*
|
18 |
-
* @since 1.0.0
|
19 |
-
* @ignore
|
20 |
-
* @access private
|
21 |
-
*
|
22 |
-
* @package JupiterX\Framework\API\Customizer
|
23 |
-
*/
|
24 |
-
class JupiterX_Customizer_Control_Alert extends JupiterX_Customizer_Base_Control {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Control's type.
|
28 |
-
*
|
29 |
-
* @since 1.0.0
|
30 |
-
*
|
31 |
-
* @var string
|
32 |
-
*/
|
33 |
-
public $type = 'jupiterx-alert';
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Control's alert type.
|
37 |
-
*
|
38 |
-
* @since 1.0.0
|
39 |
-
*
|
40 |
-
* @var string
|
41 |
-
*/
|
42 |
-
public $jupiterx_type = 'warning';
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Control's alert url.
|
46 |
-
*
|
47 |
-
* @since 1.0.0
|
48 |
-
*
|
49 |
-
* @var string
|
50 |
-
*/
|
51 |
-
public $jupiterx_url = '#';
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Refresh the parameters passed to the JavaScript via JSON.
|
55 |
-
*
|
56 |
-
* @since 1.0.0
|
57 |
-
*/
|
58 |
-
public function to_json() {
|
59 |
-
parent::to_json();
|
60 |
-
|
61 |
-
$this->json['jupiterxType'] = $this->jupiterx_type;
|
62 |
-
$this->json['jupiterxUrl'] = $this->jupiterx_url;
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* An Underscore (JS) template for this control's content (but not its container).
|
67 |
-
*
|
68 |
-
* Class variables for this control class are available in the `data` JS object;
|
69 |
-
* export custom variables by overriding {@see WP_Customize_Control::to_json()}.
|
70 |
-
*
|
71 |
-
* @see WP_Customize_Control::print_template()
|
72 |
-
*
|
73 |
-
* @since 1.0.0
|
74 |
-
*/
|
75 |
-
protected function content_template() {
|
76 |
-
?>
|
77 |
-
<# type = data.jupiterxType ? 'jupiterx-alert-control-' + data.jupiterxType : '' #>
|
78 |
-
<div class="jupiterx-control jupiterx-alert-control {{ type }}" role="alert">
|
79 |
-
<span class="dashicons dashicons-warning"></span>
|
80 |
-
<span class="jupiterx-alert-control-text">
|
81 |
-
{{ data.label }}
|
82 |
-
<a class="jupiterx-alert-control-link" href="{{ data.jupiterxUrl }}" target="_blank">
|
83 |
-
<?php esc_html_e( 'Learn more', 'jupiterx-core' ); ?>
|
84 |
-
</a>
|
85 |
-
</span>
|
86 |
-
</div>
|
87 |
-
<?php
|
88 |
-
}
|
89 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handles alert control class.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Alert control class.
|
17 |
+
*
|
18 |
+
* @since 1.0.0
|
19 |
+
* @ignore
|
20 |
+
* @access private
|
21 |
+
*
|
22 |
+
* @package JupiterX\Framework\API\Customizer
|
23 |
+
*/
|
24 |
+
class JupiterX_Customizer_Control_Alert extends JupiterX_Customizer_Base_Control {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Control's type.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
*
|
31 |
+
* @var string
|
32 |
+
*/
|
33 |
+
public $type = 'jupiterx-alert';
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Control's alert type.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
public $jupiterx_type = 'warning';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Control's alert url.
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @var string
|
50 |
+
*/
|
51 |
+
public $jupiterx_url = '#';
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Refresh the parameters passed to the JavaScript via JSON.
|
55 |
+
*
|
56 |
+
* @since 1.0.0
|
57 |
+
*/
|
58 |
+
public function to_json() {
|
59 |
+
parent::to_json();
|
60 |
+
|
61 |
+
$this->json['jupiterxType'] = $this->jupiterx_type;
|
62 |
+
$this->json['jupiterxUrl'] = $this->jupiterx_url;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* An Underscore (JS) template for this control's content (but not its container).
|
67 |
+
*
|
68 |
+
* Class variables for this control class are available in the `data` JS object;
|
69 |
+
* export custom variables by overriding {@see WP_Customize_Control::to_json()}.
|
70 |
+
*
|
71 |
+
* @see WP_Customize_Control::print_template()
|
72 |
+
*
|
73 |
+
* @since 1.0.0
|
74 |
+
*/
|
75 |
+
protected function content_template() {
|
76 |
+
?>
|
77 |
+
<# type = data.jupiterxType ? 'jupiterx-alert-control-' + data.jupiterxType : '' #>
|
78 |
+
<div class="jupiterx-control jupiterx-alert-control {{ type }}" role="alert">
|
79 |
+
<span class="dashicons dashicons-warning"></span>
|
80 |
+
<span class="jupiterx-alert-control-text">
|
81 |
+
{{ data.label }}
|
82 |
+
<a class="jupiterx-alert-control-link" href="{{ data.jupiterxUrl }}" target="_blank">
|
83 |
+
<?php esc_html_e( 'Learn more', 'jupiterx-core' ); ?>
|
84 |
+
</a>
|
85 |
+
</span>
|
86 |
+
</div>
|
87 |
+
<?php
|
88 |
+
}
|
89 |
+
}
|
includes/customizer/api/includes/control/class-box-model.php
CHANGED
@@ -1,210 +1,210 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Handles box model control class.
|
4 |
-
*
|
5 |
-
* @package JupiterX\Framework\API\Customizer
|
6 |
-
*
|
7 |
-
* @since 1.0.0
|
8 |
-
*/
|
9 |
-
|
10 |
-
// Exit if accessed directly.
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Box model control class.
|
17 |
-
*
|
18 |
-
* @since 1.0.0
|
19 |
-
* @ignore
|
20 |
-
* @access private
|
21 |
-
*
|
22 |
-
* @package JupiterX\Framework\API\Customizer
|
23 |
-
*/
|
24 |
-
class JupiterX_Customizer_Control_Box_Model extends JupiterX_Customizer_Base_Control {
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Control's type.
|
28 |
-
*
|
29 |
-
* @since 1.0.0
|
30 |
-
*
|
31 |
-
* @var string
|
32 |
-
*/
|
33 |
-
public $type = 'jupiterx-box-model';
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Control's exclude box model parts.
|
37 |
-
*
|
38 |
-
* @since 1.0.0
|
39 |
-
*
|
40 |
-
* @var string
|
41 |
-
*/
|
42 |
-
public $exclude = [];
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Control's disable box model parts.
|
46 |
-
*
|
47 |
-
* @since 1.0.0
|
48 |
-
*
|
49 |
-
* @var string
|
50 |
-
*/
|
51 |
-
public $disable = [];
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Control's unit.
|
55 |
-
*
|
56 |
-
* @since 1.0.0
|
57 |
-
*
|
58 |
-
* @var string
|
59 |
-
*/
|
60 |
-
public $units = [
|
61 |
-
'px',
|
62 |
-
'%',
|
63 |
-
'em',
|
64 |
-
'rem',
|
65 |
-
];
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Control's global default unitt.
|
69 |
-
*
|
70 |
-
* @since 1.0.0
|
71 |
-
*
|
72 |
-
* @var string
|
73 |
-
*/
|
74 |
-
public static $default_unit = 'rem';
|
75 |
-
|
76 |
-
/**
|
77 |
-
* Refresh the parameters passed to the JavaScript via JSON.
|
78 |
-
*
|
79 |
-
* @since 1.0.0
|
80 |
-
*/
|
81 |
-
public function to_json() {
|
82 |
-
parent::to_json();
|
83 |
-
|
84 |
-
$this->json['exclude'] = $this->exclude;
|
85 |
-
$this->json['disable'] = $this->disable;
|
86 |
-
$this->json['units'] = $this->units;
|
87 |
-
$this->json['default_unit'] = self::$default_unit;
|
88 |
-
}
|
89 |
-
|
90 |
-
/**
|
91 |
-
* An Underscore (JS) template for control wrapper.
|
92 |
-
*
|
93 |
-
* Use to create the control template.
|
94 |
-
*
|
95 |
-
* @since 1.0.0
|
96 |
-
*/
|
97 |
-
protected function control_template() {
|
98 |
-
|
99 |
-
?>
|
100 |
-
<#
|
101 |
-
sides = [
|
102 |
-
'top',
|
103 |
-
'right',
|
104 |
-
'bottom',
|
105 |
-
'left'
|
106 |
-
]
|
107 |
-
properties = {
|
108 |
-
margin: {
|
109 |
-
title: '<?php esc_attr_e( 'Margin', 'jupiterx-core' ); ?>',
|
110 |
-
min: -1000,
|
111 |
-
},
|
112 |
-
padding: {
|
113 |
-
title: '<?php esc_attr_e( 'Padding', 'jupiterx-core' ); ?>',
|
114 |
-
min: 0,
|
115 |
-
}
|
116 |
-
}
|
117 |
-
units = data.units
|
118 |
-
selectorClass = _.isArray( units ) && 1 === _.size( units ) ? 'disabled' : ''
|
119 |
-
#>
|
120 |
-
<div class="jupiterx-control jupiterx-box-model-control">
|
121 |
-
<# _.each( properties, function ( props, key ) { #>
|
122 |
-
<# if ( data.exclude.indexOf( key ) < 0 ) {
|
123 |
-
unitValue = _.isEmpty( data.value[ key + '_unit' ] ) ? data.default_unit : data.value[ key + '_unit' ]
|
124 |
-
step = 'px' == unitValue ? 1 : .1 #>
|
125 |
-
<div class="jupiterx-box-model-control-property jupiterx-box-model-control-property-{{ key }}">
|
126 |
-
<span class="
|
127 |
-
<# _.each( sides, function ( side ) {
|
128 |
-
propertyName = key + '_' + side
|
129 |
-
value = ! _.isUndefined( data.value[ propertyName ] ) ? data.value[ propertyName ] : ''
|
130 |
-
disable = _.indexOf( data.disable, propertyName.replace( '_', '-' ) ) !== -1 ? 'disabled' : '' #>
|
131 |
-
<input class="jupiterx-box-model-control-input jupiterx-box-model-control-{{ side }}" min="{{ props.min }}" {{{ data.inputAttrs }}} type="text" value="{{ value }}" {{ disable }} step="{{ step }}" placeholder="-" {{{ data.link }}} data-setting-property-link="{{ propertyName }}" />
|
132 |
-
<# } ) #>
|
133 |
-
<# } #>
|
134 |
-
<# } ) #>
|
135 |
-
<# _.each( properties, function ( title, key ) { #>
|
136 |
-
<# if ( data.exclude.indexOf( key ) < 0 ) { #>
|
137 |
-
</div>
|
138 |
-
<# } #>
|
139 |
-
<# } ) #>
|
140 |
-
<div class="jupiterx-unit-selector-wrapper">
|
141 |
-
<# _.each( properties, function ( props, key ) { #>
|
142 |
-
<# if ( data.exclude.indexOf( key ) < 0 ) { #>
|
143 |
-
<# unitValue = _.isEmpty( data.value[ key + '_unit' ] ) ? data.default_unit : data.value[ key + '_unit' ] #>
|
144 |
-
<div class="jupiterx-control-units-container">
|
145 |
-
<input type="hidden" value="{{ unitValue }}" {{{ data.link }}} data-setting-property-link="{{key + '_unit'}}" />
|
146 |
-
<span class="jupiterx-unit-selector-label">{{key}}</span>
|
147 |
-
<ul class="jupiterx-control-unit-selector" data-inputs=".jupiterx-box-model-control-property-{{ key }} > input">
|
148 |
-
<li class="jupiterx-control-unit selected-unit {{ selectorClass }}">{{ unitValue }}</li>
|
149 |
-
<# _.each( units, function ( unit ) { #>
|
150 |
-
<li class="jupiterx-control-unit">{{ unit }}</li>
|
151 |
-
<# } ) #>
|
152 |
-
</ul>
|
153 |
-
</div>
|
154 |
-
<# } #>
|
155 |
-
<# } ) #>
|
156 |
-
</div>
|
157 |
-
</div>
|
158 |
-
<?php
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* Format CSS value from theme mod array value.
|
163 |
-
*
|
164 |
-
* @since 1.0.0
|
165 |
-
*
|
166 |
-
* @param array $value The field's value.
|
167 |
-
* @param array $args The field's arguments.
|
168 |
-
*
|
169 |
-
* @return array The formatted properties.
|
170 |
-
*/
|
171 |
-
public static function format_properties( $value, $args ) {
|
172 |
-
$args = array_merge( [ 'exclude' => [] ], $args );
|
173 |
-
|
174 |
-
$positions = [ 'top', 'right', 'bottom', 'left' ];
|
175 |
-
|
176 |
-
$vars = [];
|
177 |
-
|
178 |
-
if ( ! in_array( 'margin', $args['exclude'], true ) ) {
|
179 |
-
$margin_unit = isset( $value['margin_unit'] ) ? $value['margin_unit'] : self::$default_unit;
|
180 |
-
|
181 |
-
foreach ( $positions as $position ) {
|
182 |
-
// Accepts non-numeric value such as 'auto'.
|
183 |
-
if ( array_key_exists( 'margin_' . $position, $value ) ) {
|
184 |
-
$property_value = $value[ 'margin_' . $position ];
|
185 |
-
$unit = is_numeric( $property_value ) && 0 !== $property_value ? $margin_unit : '';
|
186 |
-
$position = jupiterx_get_direction( $position );
|
187 |
-
|
188 |
-
$vars[ 'margin-' . $position ] = $property_value . $unit;
|
189 |
-
}
|
190 |
-
}
|
191 |
-
}
|
192 |
-
|
193 |
-
if ( ! in_array( 'padding', $args['exclude'], true ) ) {
|
194 |
-
$padding_unit = isset( $value['padding_unit'] ) ? $value['padding_unit'] : self::$default_unit;
|
195 |
-
|
196 |
-
foreach ( $positions as $position ) {
|
197 |
-
// Does not accept any value that is not numeric.
|
198 |
-
if ( array_key_exists( 'padding_' . $position, $value ) && is_numeric( $value[ 'padding_' . $position ] ) ) {
|
199 |
-
$property_value = $value[ 'padding_' . $position ];
|
200 |
-
$unit = 0 !== $property_value ? $padding_unit : '';
|
201 |
-
$position = jupiterx_get_direction( $position );
|
202 |
-
|
203 |
-
$vars[ 'padding-' . $position ] = $property_value . $unit;
|
204 |
-
}
|
205 |
-
}
|
206 |
-
}
|
207 |
-
|
208 |
-
return $vars;
|
209 |
-
}
|
210 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handles box model control class.
|
4 |
+
*
|
5 |
+
* @package JupiterX\Framework\API\Customizer
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
*/
|
9 |
+
|
10 |
+
// Exit if accessed directly.
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Box model control class.
|
17 |
+
*
|
18 |
+
* @since 1.0.0
|
19 |
+
* @ignore
|
20 |
+
* @access private
|
21 |
+
*
|
22 |
+
* @package JupiterX\Framework\API\Customizer
|
23 |
+
*/
|
24 |
+
class JupiterX_Customizer_Control_Box_Model extends JupiterX_Customizer_Base_Control {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Control's type.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
*
|
31 |
+
* @var string
|
32 |
+
*/
|
33 |
+
public $type = 'jupiterx-box-model';
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Control's exclude box model parts.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
public $exclude = [];
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Control's disable box model parts.
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @var string
|
50 |
+
*/
|
51 |
+
public $disable = [];
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Control's unit.
|
55 |
+
*
|
56 |
+
* @since 1.0.0
|
57 |
+
*
|
58 |
+
* @var string
|
59 |
+
*/
|
60 |
+
public $units = [
|
61 |
+
'px',
|
62 |
+
'%',
|
63 |
+
'em',
|
64 |
+
'rem',
|
65 |
+
];
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Control's global default unitt.
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @var string
|
73 |
+
*/
|
74 |
+
public static $default_unit = 'rem';
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Refresh the parameters passed to the JavaScript via JSON.
|
78 |
+
*
|
79 |
+
* @since 1.0.0
|
80 |
+
*/
|
81 |
+
public function to_json() {
|
82 |
+
parent::to_json();
|
83 |
+
|
84 |
+
$this->json['exclude'] = $this->exclude;
|
85 |
+
$this->json['disable'] = $this->disable;
|
86 |
+
$this->json['units'] = $this->units;
|
87 |
+
$this->json['default_unit'] = self::$default_unit;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* An Underscore (JS) template for control wrapper.
|
92 |
+
*
|
93 |
+
* Use to create the control template.
|
94 |
+
*
|
95 |
+
* @since 1.0.0
|
96 |
+
*/
|
97 |
+
protected function control_template() {
|
98 |
+
|
99 |
+
?>
|
100 |
+
<#
|
101 |
+
sides = [
|
102 |
+
'top',
|
103 |
+
'right',
|
104 |
+
'bottom',
|
105 |
+
'left'
|
106 |
+
]
|
107 |
+
properties = {
|
108 |
+
margin: {
|
109 |
+
title: '<?php esc_attr_e( 'Margin', 'jupiterx-core' ); ?>',
|
110 |
+
min: -1000,
|
111 |
+
},
|
112 |
+
padding: {
|
113 |
+
title: '<?php esc_attr_e( 'Padding', 'jupiterx-core' ); ?>',
|
114 |
+
min: 0,
|
115 |
+
}
|
116 |
+
}
|
117 |
+
units = data.units
|
118 |
+
selectorClass = _.isArray( units ) && 1 === _.size( units ) ? 'disabled' : ''
|
119 |
+
#>
|
120 |
+
<div class="jupiterx-control jupiterx-box-model-control">
|
121 |
+
<# _.each( properties, function ( props, key ) { #>
|
122 |
+
<# if ( data.exclude.indexOf( key ) < 0 ) {
|
123 |
+
unitValue = _.isEmpty( data.value[ key + '_unit' ] ) ? data.default_unit : data.value[ key + '_unit' ]
|
124 |
+
step = 'px' == unitValue ? 1 : .1 #>
|
125 |
+
<div class="jupiterx-box-model-control-property jupiterx-box-model-control-property-{{ key }}">
|
126 |
+
<span class="jupite
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|