Version Description
Download this release
Release Info
Developer | artbees |
Plugin | Jupiter X Core |
Version | 1.10.0 |
Comparing to | |
See all releases |
Code changes from version 1.9.0 to 1.10.0
- includes/admin/options.php +62 -62
- includes/admin/tgmpa/tgmpa-plugin-list.php +185 -185
- includes/admin/update-plugins/class-update-plugins.php +102 -102
- includes/compiler/class-compiler.php +1018 -1019
- 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 +158 -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-export-import-content.php +1224 -1224
- 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 +98 -98
- includes/control-panel/includes/class-install-plugins.php +506 -506
- includes/control-panel/includes/class-install-template.php +1851 -1851
- 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 +70 -70
- includes/control-panel/views/image-sizes.php +64 -64
- includes/control-panel/views/install-plugins.php +56 -56
- includes/control-panel/views/install-templates.php +61 -61
- includes/control-panel/views/settings.php +103 -103
- includes/control-panel/views/system-status.php +0 -499
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,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 |
-
],
|
32 |
-
[
|
33 |
-
'name' => __( 'Jupiter Donut', 'jupiterx-core' ),
|
34 |
-
'slug' => 'jupiter-donut',
|
35 |
-
'required' => false,
|
36 |
-
'force_activation' => false,
|
37 |
-
'force_deactivation' => false,
|
38 |
-
'pro' => true,
|
39 |
-
'source' => 'external',
|
40 |
-
],
|
41 |
-
[
|
42 |
-
'name' => __( 'Jet Elements', 'jupiterx-core' ),
|
43 |
-
'slug' => 'jet-elements',
|
44 |
-
'required' => false,
|
45 |
-
'force_activation' => false,
|
46 |
-
'force_deactivation' => false,
|
47 |
-
'pro' => true,
|
48 |
-
'source' => 'external',
|
49 |
-
],
|
50 |
-
[
|
51 |
-
'name' => __( 'Jet Blog', 'jupiterx-core' ),
|
52 |
-
'slug' => 'jet-blog',
|
53 |
-
'required' => false,
|
54 |
-
'force_activation' => false,
|
55 |
-
'force_deactivation' => false,
|
56 |
-
'pro' => true,
|
57 |
-
'source' => 'external',
|
58 |
-
],
|
59 |
-
[
|
60 |
-
'name' => __( 'Jet Menu', 'jupiterx-core' ),
|
61 |
-
'slug' => 'jet-menu',
|
62 |
-
'required' => false,
|
63 |
-
'force_activation' => false,
|
64 |
-
'force_deactivation' => false,
|
65 |
-
'pro' => true,
|
66 |
-
'source' => 'external',
|
67 |
-
],
|
68 |
-
[
|
69 |
-
'name' => __( 'Jet Popup', 'jupiterx-core' ),
|
70 |
-
'slug' => 'jet-popup',
|
71 |
-
'required' => false,
|
72 |
-
'force_activation' => false,
|
73 |
-
'force_deactivation' => false,
|
74 |
-
'pro' => true,
|
75 |
-
'source' => 'external',
|
76 |
-
],
|
77 |
-
[
|
78 |
-
'name' => __( 'Jet Tabs', 'jupiterx-core' ),
|
79 |
-
'slug' => 'jet-tabs',
|
80 |
-
'required' => false,
|
81 |
-
'force_activation' => false,
|
82 |
-
'force_deactivation' => false,
|
83 |
-
'pro' => true,
|
84 |
-
'source' => 'external',
|
85 |
-
],
|
86 |
-
[
|
87 |
-
'name' => __( 'Jet WooBuilder', 'jupiterx-core' ),
|
88 |
-
'slug' => 'jet-woo-builder',
|
89 |
-
'required' => false,
|
90 |
-
'force_activation' => false,
|
91 |
-
'force_deactivation' => false,
|
92 |
-
'pro' => true,
|
93 |
-
'source' => 'external',
|
94 |
-
],
|
95 |
-
[
|
96 |
-
'name' => __( 'Jet Tricks', 'jupiterx-core' ),
|
97 |
-
'slug' => 'jet-tricks',
|
98 |
-
'required' => false,
|
99 |
-
'force_activation' => false,
|
100 |
-
'force_deactivation' => false,
|
101 |
-
'pro' => true,
|
102 |
-
'source' => 'external',
|
103 |
-
],
|
104 |
-
[
|
105 |
-
'name' => __( 'Jet Engine', 'jupiterx-core' ),
|
106 |
-
'slug' => 'jet-engine',
|
107 |
-
'required' => false,
|
108 |
-
'force_activation' => false,
|
109 |
-
'force_deactivation' => false,
|
110 |
-
'pro' => true,
|
111 |
-
'source' => 'external',
|
112 |
-
],
|
113 |
-
[
|
114 |
-
'name' => __( 'Jet SmartFilters', 'jupiterx-core' ),
|
115 |
-
'slug' => 'jet-smart-filters',
|
116 |
-
'required' => false,
|
117 |
-
'force_activation' => false,
|
118 |
-
'force_deactivation' => false,
|
119 |
-
'pro' => true,
|
120 |
-
'source' => 'external',
|
121 |
-
],
|
122 |
-
[
|
123 |
-
'name' => __( 'Advanced Custom Fields PRO', 'jupiterx-core' ),
|
124 |
-
'slug' => 'advanced-custom-fields-pro',
|
125 |
-
'required' => false,
|
126 |
-
'force_activation' => false,
|
127 |
-
'force_deactivation' => false,
|
128 |
-
'pro' => true,
|
129 |
-
'source' => 'external',
|
130 |
-
],
|
131 |
-
[
|
132 |
-
'name' => __( 'Slider Revolution', 'jupiterx-core' ),
|
133 |
-
'slug' => 'revslider',
|
134 |
-
'required' => false,
|
135 |
-
'force_activation' => false,
|
136 |
-
'force_deactivation' => false,
|
137 |
-
'pro' => true,
|
138 |
-
'source' => 'external',
|
139 |
-
],
|
140 |
-
[
|
141 |
-
'name' => __( 'Master Slider', 'jupiterx-core' ),
|
142 |
-
'slug' => 'masterslider',
|
143 |
-
'required' => false,
|
144 |
-
'force_activation' => false,
|
145 |
-
'force_deactivation' => false,
|
146 |
-
'pro' => true,
|
147 |
-
'source' => 'external',
|
148 |
-
],
|
149 |
-
[
|
150 |
-
'name' => __( 'Layer Slider', 'jupiterx-core' ),
|
151 |
-
'slug' => 'layerslider',
|
152 |
-
'required' => false,
|
153 |
-
'force_activation' => false,
|
154 |
-
'force_deactivation' => false,
|
155 |
-
'pro' => true,
|
156 |
-
'source' => 'external',
|
157 |
-
],
|
158 |
-
[
|
159 |
-
'name' => __( 'WPBakery Page Builder', 'jupiterx-core' ),
|
160 |
-
'slug' => 'raven',
|
161 |
-
'required' => false,
|
162 |
-
'force_activation' => false,
|
163 |
-
'force_deactivation' => false,
|
164 |
-
'pro' => true,
|
165 |
-
'source' => 'external',
|
166 |
-
],
|
167 |
-
[
|
168 |
-
'name' => __( 'Customizer Reset', 'jupiterx-core' ),
|
169 |
-
'slug' => 'customizer-reset-by-wpzoom',
|
170 |
-
'required' => false,
|
171 |
-
'force_activation' => false,
|
172 |
-
'force_deactivation' => false,
|
173 |
-
'pro' => false,
|
174 |
-
],
|
175 |
-
[
|
176 |
-
'name' => __( 'Customizer Export/Import', 'jupiterx-core' ),
|
177 |
-
'slug' => 'customizer-export-import',
|
178 |
-
'required' => false,
|
179 |
-
'force_activation' => false,
|
180 |
-
'force_deactivation' => false,
|
181 |
-
'pro' => false,
|
182 |
-
],
|
183 |
-
];
|
184 |
-
return array_merge( $pro_plugins, $plugins );
|
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 |
+
],
|
32 |
+
[
|
33 |
+
'name' => __( 'Jupiter Donut', 'jupiterx-core' ),
|
34 |
+
'slug' => 'jupiter-donut',
|
35 |
+
'required' => false,
|
36 |
+
'force_activation' => false,
|
37 |
+
'force_deactivation' => false,
|
38 |
+
'pro' => true,
|
39 |
+
'source' => 'external',
|
40 |
+
],
|
41 |
+
[
|
42 |
+
'name' => __( 'Jet Elements', 'jupiterx-core' ),
|
43 |
+
'slug' => 'jet-elements',
|
44 |
+
'required' => false,
|
45 |
+
'force_activation' => false,
|
46 |
+
'force_deactivation' => false,
|
47 |
+
'pro' => true,
|
48 |
+
'source' => 'external',
|
49 |
+
],
|
50 |
+
[
|
51 |
+
'name' => __( 'Jet Blog', 'jupiterx-core' ),
|
52 |
+
'slug' => 'jet-blog',
|
53 |
+
'required' => false,
|
54 |
+
'force_activation' => false,
|
55 |
+
'force_deactivation' => false,
|
56 |
+
'pro' => true,
|
57 |
+
'source' => 'external',
|
58 |
+
],
|
59 |
+
[
|
60 |
+
'name' => __( 'Jet Menu', 'jupiterx-core' ),
|
61 |
+
'slug' => 'jet-menu',
|
62 |
+
'required' => false,
|
63 |
+
'force_activation' => false,
|
64 |
+
'force_deactivation' => false,
|
65 |
+
'pro' => true,
|
66 |
+
'source' => 'external',
|
67 |
+
],
|
68 |
+
[
|
69 |
+
'name' => __( 'Jet Popup', 'jupiterx-core' ),
|
70 |
+
'slug' => 'jet-popup',
|
71 |
+
'required' => false,
|
72 |
+
'force_activation' => false,
|
73 |
+
'force_deactivation' => false,
|
74 |
+
'pro' => true,
|
75 |
+
'source' => 'external',
|
76 |
+
],
|
77 |
+
[
|
78 |
+
'name' => __( 'Jet Tabs', 'jupiterx-core' ),
|
79 |
+
'slug' => 'jet-tabs',
|
80 |
+
'required' => false,
|
81 |
+
'force_activation' => false,
|
82 |
+
'force_deactivation' => false,
|
83 |
+
'pro' => true,
|
84 |
+
'source' => 'external',
|
85 |
+
],
|
86 |
+
[
|
87 |
+
'name' => __( 'Jet WooBuilder', 'jupiterx-core' ),
|
88 |
+
'slug' => 'jet-woo-builder',
|
89 |
+
'required' => false,
|
90 |
+
'force_activation' => false,
|
91 |
+
'force_deactivation' => false,
|
92 |
+
'pro' => true,
|
93 |
+
'source' => 'external',
|
94 |
+
],
|
95 |
+
[
|
96 |
+
'name' => __( 'Jet Tricks', 'jupiterx-core' ),
|
97 |
+
'slug' => 'jet-tricks',
|
98 |
+
'required' => false,
|
99 |
+
'force_activation' => false,
|
100 |
+
'force_deactivation' => false,
|
101 |
+
'pro' => true,
|
102 |
+
'source' => 'external',
|
103 |
+
],
|
104 |
+
[
|
105 |
+
'name' => __( 'Jet Engine', 'jupiterx-core' ),
|
106 |
+
'slug' => 'jet-engine',
|
107 |
+
'required' => false,
|
108 |
+
'force_activation' => false,
|
109 |
+
'force_deactivation' => false,
|
110 |
+
'pro' => true,
|
111 |
+
'source' => 'external',
|
112 |
+
],
|
113 |
+
[
|
114 |
+
'name' => __( 'Jet SmartFilters', 'jupiterx-core' ),
|
115 |
+
'slug' => 'jet-smart-filters',
|
116 |
+
'required' => false,
|
117 |
+
'force_activation' => false,
|
118 |
+
'force_deactivation' => false,
|
119 |
+
'pro' => true,
|
120 |
+
'source' => 'external',
|
121 |
+
],
|
122 |
+
[
|
123 |
+
'name' => __( 'Advanced Custom Fields PRO', 'jupiterx-core' ),
|
124 |
+
'slug' => 'advanced-custom-fields-pro',
|
125 |
+
'required' => false,
|
126 |
+
'force_activation' => false,
|
127 |
+
'force_deactivation' => false,
|
128 |
+
'pro' => true,
|
129 |
+
'source' => 'external',
|
130 |
+
],
|
131 |
+
[
|
132 |
+
'name' => __( 'Slider Revolution', 'jupiterx-core' ),
|
133 |
+
'slug' => 'revslider',
|
134 |
+
'required' => false,
|
135 |
+
'force_activation' => false,
|
136 |
+
'force_deactivation' => false,
|
137 |
+
'pro' => true,
|
138 |
+
'source' => 'external',
|
139 |
+
],
|
140 |
+
[
|
141 |
+
'name' => __( 'Master Slider', 'jupiterx-core' ),
|
142 |
+
'slug' => 'masterslider',
|
143 |
+
'required' => false,
|
144 |
+
'force_activation' => false,
|
145 |
+
'force_deactivation' => false,
|
146 |
+
'pro' => true,
|
147 |
+
'source' => 'external',
|
148 |
+
],
|
149 |
+
[
|
150 |
+
'name' => __( 'Layer Slider', 'jupiterx-core' ),
|
151 |
+
'slug' => 'layerslider',
|
152 |
+
'required' => false,
|
153 |
+
'force_activation' => false,
|
154 |
+
'force_deactivation' => false,
|
155 |
+
'pro' => true,
|
156 |
+
'source' => 'external',
|
157 |
+
],
|
158 |
+
[
|
159 |
+
'name' => __( 'WPBakery Page Builder', 'jupiterx-core' ),
|
160 |
+
'slug' => 'raven',
|
161 |
+
'required' => false,
|
162 |
+
'force_activation' => false,
|
163 |
+
'force_deactivation' => false,
|
164 |
+
'pro' => true,
|
165 |
+
'source' => 'external',
|
166 |
+
],
|
167 |
+
[
|
168 |
+
'name' => __( 'Customizer Reset', 'jupiterx-core' ),
|
169 |
+
'slug' => 'customizer-reset-by-wpzoom',
|
170 |
+
'required' => false,
|
171 |
+
'force_activation' => false,
|
172 |
+
'force_deactivation' => false,
|
173 |
+
'pro' => false,
|
174 |
+
],
|
175 |
+
[
|
176 |
+
'name' => __( 'Customizer Export/Import', 'jupiterx-core' ),
|
177 |
+
'slug' => 'customizer-export-import',
|
178 |
+
'required' => false,
|
179 |
+
'force_activation' => false,
|
180 |
+
'force_deactivation' => false,
|
181 |
+
'pro' => false,
|
182 |
+
],
|
183 |
+
];
|
184 |
+
return array_merge( $pro_plugins, $plugins );
|
185 |
+
}
|
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,1019 +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 |
-
'
|
905 |
-
'
|
906 |
-
'
|
907 |
-
'
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
*
|
918 |
-
*
|
919 |
-
*
|
920 |
-
*
|
921 |
-
*
|
922 |
-
*
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
*
|
931 |
-
*
|
932 |
-
*
|
933 |
-
*
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
'
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
'
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
'
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
'
|
960 |
-
__( '
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
*
|
969 |
-
*
|
970 |
-
*
|
971 |
-
*
|
972 |
-
*
|
973 |
-
*
|
974 |
-
* @
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
'
|
981 |
-
'Compiler error',
|
982 |
-
|
983 |
-
|
984 |
-
'
|
985 |
-
|
986 |
-
|
987 |
-
'
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
'
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
*
|
1006 |
-
*
|
1007 |
-
*
|
1008 |
-
*
|
1009 |
-
*
|
1010 |
-
*
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
}
|
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,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 |
-
] );
|
28 |
-
} );
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Get started quick guide.
|
32 |
-
*
|
33 |
-
* @since 1.2.0
|
34 |
-
*/
|
35 |
-
add_action( 'jupiterx_control_panel_get_started', function() {
|
36 |
-
?>
|
37 |
-
<h6><?php esc_html_e( 'Get started:', 'jupiterx-core' ); ?></h6>
|
38 |
-
<iframe class="mb-4" width="400" height="225" src="https://www.youtube.com/embed/fnlzOHECEDo?modestbranding=1" frameborder="0" allowfullscreen></iframe>
|
39 |
-
<?php
|
40 |
-
} );
|
41 |
-
|
42 |
-
add_filter( 'jupiterx_control_panel_sections', 'jupiterx_add_control_panel_sections' );
|
43 |
-
/**
|
44 |
-
* Add sections to control panel.
|
45 |
-
*
|
46 |
-
* @since 1.9.0
|
47 |
-
*/
|
48 |
-
function jupiterx_add_control_panel_sections( $sections ) {
|
49 |
-
|
50 |
-
$sections['image_size'] = [
|
51 |
-
'title' => __( 'Image Sizes' , 'jupiterx-core' ),
|
52 |
-
'href' => 'image-sizes',
|
53 |
-
'condition' => defined( 'JUPITERX_CONTROL_PANEL_IMAGE_SIZES' ) && JUPITERX_CONTROL_PANEL_IMAGE_SIZES,
|
54 |
-
'order' => 40,
|
55 |
-
];
|
56 |
-
|
57 |
-
$sections['system_status'] = [
|
58 |
-
'title' => __( 'System Status' , 'jupiterx-core' ),
|
59 |
-
'href' => 'system-status',
|
60 |
-
'condition' => defined( 'JUPITERX_CONTROL_PANEL_SYSTEM_STATUS' ) && JUPITERX_CONTROL_PANEL_SYSTEM_STATUS,
|
61 |
-
'order' => 50,
|
62 |
-
];
|
63 |
-
|
64 |
-
$sections['settings'] = [
|
65 |
-
'title' => __( 'Settings' , 'jupiterx-core' ),
|
66 |
-
'href' => 'settings',
|
67 |
-
'condition' => defined( 'JUPITERX_CONTROL_PANEL_SETTINGS' ) && JUPITERX_CONTROL_PANEL_SETTINGS,
|
68 |
-
'order' => 70,
|
69 |
-
];
|
70 |
-
|
71 |
-
$sections['export_import'] = [
|
72 |
-
'title' => __( 'Export/Import' , 'jupiterx-core' ),
|
73 |
-
'href' => 'export-import',
|
74 |
-
'condition' => defined( 'JUPITERX_CONTROL_PANEL_EXPORT_IMPORT' ) && JUPITERX_CONTROL_PANEL_EXPORT_IMPORT,
|
75 |
-
'order' => 75,
|
76 |
-
];
|
77 |
-
|
78 |
-
return $sections;
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Core additional settings.
|
83 |
-
*
|
84 |
-
* @since 1.2.0
|
85 |
-
*/
|
86 |
-
add_action( 'jupiterx_control_panel_after_theme_settings', function() {
|
87 |
-
?>
|
88 |
-
<div class="form-group col-md-6">
|
89 |
-
<label for="jupiterx-cp-settings-svg-support">
|
90 |
-
<?php esc_html_e( 'SVG Support', 'jupiterx-core' ); ?>
|
91 |
-
</label>
|
92 |
-
<input type="hidden" name="jupiterx_svg_support" value="0">
|
93 |
-
<div class="jupiterx-switch">
|
94 |
-
<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' ); ?>>
|
95 |
-
<label for="jupiterx-cp-settings-svg-support"></label>
|
96 |
-
</div>
|
97 |
-
<small class="form-text text-muted">
|
98 |
-
<?php esc_html_e( 'Enable this option to upload SVG to WordPress Media Library.', 'jupiterx-core' ); ?>
|
99 |
-
</small>
|
100 |
-
</div>
|
101 |
-
<div class="col-md-12">
|
102 |
-
<hr />
|
103 |
-
</div>
|
104 |
-
<div class="form-group col-md-6">
|
105 |
-
<label for="jupiterx-cp-settings-google-analytics-id"><?php esc_html_e( 'Google Analytics ID', 'jupiterx-core' ); ?></label>
|
106 |
-
<?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' ) ); ?>
|
107 |
-
<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******-*">
|
108 |
-
</div>
|
109 |
-
<div class="form-group col-md-6">
|
110 |
-
<label for="jupiterx-cp-settings-google-analytics-anonymization"><?php esc_html_e( 'IP Anonymization', 'jupiterx-core' ); ?></label>
|
111 |
-
<input type="hidden" name="jupiterx_google_analytics_anonymization" value="0">
|
112 |
-
<div class="jupiterx-switch">
|
113 |
-
<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' : '' ); ?>>
|
114 |
-
<label for="jupiterx-cp-settings-google-analytics-anonymization"></label>
|
115 |
-
</div>
|
116 |
-
<small class="form-text text-muted"><?php esc_html_e( 'Enable IP Anonymization for Google Analytics.', 'jupiterx-core' ); ?></small>
|
117 |
-
</div>
|
118 |
-
<div class="form-group col-md-12">
|
119 |
-
<label for="jupiterx-cp-settings-adobe-project-id"><?php esc_html_e( 'Adobe Fonts Project ID', 'jupiterx-core' ); ?></label>
|
120 |
-
<?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' ) ); ?>
|
121 |
-
<?php jupiterx_pro_badge(); ?>
|
122 |
-
<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****">
|
123 |
-
</div>
|
124 |
-
<div class="col-md-12"><hr></div>
|
125 |
-
<div class="form-group col-md-6">
|
126 |
-
<label for="jupiterx-cp-settings-tracking-codes-after-head">
|
127 |
-
<?php /* translators: %s: html */ ?>
|
128 |
-
<?php printf( esc_html__( 'Tracking Codes After %s Tag', 'jupiterx-core' ), '<code><head></code>' ); ?>
|
129 |
-
<?php jupiterx_pro_badge(); ?>
|
130 |
-
</label>
|
131 |
-
<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>
|
132 |
-
</div>
|
133 |
-
<div class="form-group col-md-6">
|
134 |
-
<label for="jupiterx-cp-settings-tracking-codes-before-head">
|
135 |
-
<?php /* translators: %s: html */ ?>
|
136 |
-
<?php printf( esc_html__( 'Tracking Codes Before %s Tag', 'jupiterx-core' ), '<code></head></code>' ); ?>
|
137 |
-
<?php jupiterx_pro_badge(); ?>
|
138 |
-
</label>
|
139 |
-
<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>
|
140 |
-
</div>
|
141 |
-
<div class="form-group col-md-6">
|
142 |
-
<label for="jupiterx-cp-settings-tracking-codes-after-body">
|
143 |
-
<?php /* translators: %s: html */ ?>
|
144 |
-
<?php printf( esc_html__( 'Tracking Codes After %s Tag', 'jupiterx-core' ), '<code><body></code>' ); ?>
|
145 |
-
<?php jupiterx_pro_badge(); ?>
|
146 |
-
</label>
|
147 |
-
<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>
|
148 |
-
</div>
|
149 |
-
<div class="form-group col-md-6">
|
150 |
-
<label for="jupiterx-cp-settings-tracking-codes-before-body">
|
151 |
-
<?php /* translators: %s: html */ ?>
|
152 |
-
<?php printf( esc_html__( 'Tracking Codes Before %s Tag', 'jupiterx-core' ), '<code></body></code>' ); ?>
|
153 |
-
<?php jupiterx_pro_badge(); ?>
|
154 |
-
</label>
|
155 |
-
<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>
|
156 |
-
</div>
|
157 |
-
<?php
|
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 |
+
] );
|
28 |
+
} );
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Get started quick guide.
|
32 |
+
*
|
33 |
+
* @since 1.2.0
|
34 |
+
*/
|
35 |
+
add_action( 'jupiterx_control_panel_get_started', function() {
|
36 |
+
?>
|
37 |
+
<h6><?php esc_html_e( 'Get started:', 'jupiterx-core' ); ?></h6>
|
38 |
+
<iframe class="mb-4" width="400" height="225" src="https://www.youtube.com/embed/fnlzOHECEDo?modestbranding=1" frameborder="0" allowfullscreen></iframe>
|
39 |
+
<?php
|
40 |
+
} );
|
41 |
+
|
42 |
+
add_filter( 'jupiterx_control_panel_sections', 'jupiterx_add_control_panel_sections' );
|
43 |
+
/**
|
44 |
+
* Add sections to control panel.
|
45 |
+
*
|
46 |
+
* @since 1.9.0
|
47 |
+
*/
|
48 |
+
function jupiterx_add_control_panel_sections( $sections ) {
|
49 |
+
|
50 |
+
$sections['image_size'] = [
|
51 |
+
'title' => __( 'Image Sizes' , 'jupiterx-core' ),
|
52 |
+
'href' => 'image-sizes',
|
53 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_IMAGE_SIZES' ) && JUPITERX_CONTROL_PANEL_IMAGE_SIZES,
|
54 |
+
'order' => 40,
|
55 |
+
];
|
56 |
+
|
57 |
+
$sections['system_status'] = [
|
58 |
+
'title' => __( 'System Status' , 'jupiterx-core' ),
|
59 |
+
'href' => 'system-status',
|
60 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_SYSTEM_STATUS' ) && JUPITERX_CONTROL_PANEL_SYSTEM_STATUS,
|
61 |
+
'order' => 50,
|
62 |
+
];
|
63 |
+
|
64 |
+
$sections['settings'] = [
|
65 |
+
'title' => __( 'Settings' , 'jupiterx-core' ),
|
66 |
+
'href' => 'settings',
|
67 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_SETTINGS' ) && JUPITERX_CONTROL_PANEL_SETTINGS,
|
68 |
+
'order' => 70,
|
69 |
+
];
|
70 |
+
|
71 |
+
$sections['export_import'] = [
|
72 |
+
'title' => __( 'Export/Import' , 'jupiterx-core' ),
|
73 |
+
'href' => 'export-import',
|
74 |
+
'condition' => defined( 'JUPITERX_CONTROL_PANEL_EXPORT_IMPORT' ) && JUPITERX_CONTROL_PANEL_EXPORT_IMPORT,
|
75 |
+
'order' => 75,
|
76 |
+
];
|
77 |
+
|
78 |
+
return $sections;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Core additional settings.
|
83 |
+
*
|
84 |
+
* @since 1.2.0
|
85 |
+
*/
|
86 |
+
add_action( 'jupiterx_control_panel_after_theme_settings', function() {
|
87 |
+
?>
|
88 |
+
<div class="form-group col-md-6">
|
89 |
+
<label for="jupiterx-cp-settings-svg-support">
|
90 |
+
<?php esc_html_e( 'SVG Support', 'jupiterx-core' ); ?>
|
91 |
+
</label>
|
92 |
+
<input type="hidden" name="jupiterx_svg_support" value="0">
|
93 |
+
<div class="jupiterx-switch">
|
94 |
+
<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' ); ?>>
|
95 |
+
<label for="jupiterx-cp-settings-svg-support"></label>
|
96 |
+
</div>
|
97 |
+
<small class="form-text text-muted">
|
98 |
+
<?php esc_html_e( 'Enable this option to upload SVG to WordPress Media Library.', 'jupiterx-core' ); ?>
|
99 |
+
</small>
|
100 |
+
</div>
|
101 |
+
<div class="col-md-12">
|
102 |
+
<hr />
|
103 |
+
</div>
|
104 |
+
<div class="form-group col-md-6">
|
105 |
+
<label for="jupiterx-cp-settings-google-analytics-id"><?php esc_html_e( 'Google Analytics ID', 'jupiterx-core' ); ?></label>
|
106 |
+
<?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' ) ); ?>
|
107 |
+
<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******-*">
|
108 |
+
</div>
|
109 |
+
<div class="form-group col-md-6">
|
110 |
+
<label for="jupiterx-cp-settings-google-analytics-anonymization"><?php esc_html_e( 'IP Anonymization', 'jupiterx-core' ); ?></label>
|
111 |
+
<input type="hidden" name="jupiterx_google_analytics_anonymization" value="0">
|
112 |
+
<div class="jupiterx-switch">
|
113 |
+
<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' : '' ); ?>>
|
114 |
+
<label for="jupiterx-cp-settings-google-analytics-anonymization"></label>
|
115 |
+
</div>
|
116 |
+
<small class="form-text text-muted"><?php esc_html_e( 'Enable IP Anonymization for Google Analytics.', 'jupiterx-core' ); ?></small>
|
117 |
+
</div>
|
118 |
+
<div class="form-group col-md-12">
|
119 |
+
<label for="jupiterx-cp-settings-adobe-project-id"><?php esc_html_e( 'Adobe Fonts Project ID', 'jupiterx-core' ); ?></label>
|
120 |
+
<?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' ) ); ?>
|
121 |
+
<?php jupiterx_pro_badge(); ?>
|
122 |
+
<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****">
|
123 |
+
</div>
|
124 |
+
<div class="col-md-12"><hr></div>
|
125 |
+
<div class="form-group col-md-6">
|
126 |
+
<label for="jupiterx-cp-settings-tracking-codes-after-head">
|
127 |
+
<?php /* translators: %s: html */ ?>
|
128 |
+
<?php printf( esc_html__( 'Tracking Codes After %s Tag', 'jupiterx-core' ), '<code><head></code>' ); ?>
|
129 |
+
<?php jupiterx_pro_badge(); ?>
|
130 |
+
</label>
|
131 |
+
<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>
|
132 |
+
</div>
|
133 |
+
<div class="form-group col-md-6">
|
134 |
+
<label for="jupiterx-cp-settings-tracking-codes-before-head">
|
135 |
+
<?php /* translators: %s: html */ ?>
|
136 |
+
<?php printf( esc_html__( 'Tracking Codes Before %s Tag', 'jupiterx-core' ), '<code></head></code>' ); ?>
|
137 |
+
<?php jupiterx_pro_badge(); ?>
|
138 |
+
</label>
|
139 |
+
<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>
|
140 |
+
</div>
|
141 |
+
<div class="form-group col-md-6">
|
142 |
+
<label for="jupiterx-cp-settings-tracking-codes-after-body">
|
143 |
+
<?php /* translators: %s: html */ ?>
|
144 |
+
<?php printf( esc_html__( 'Tracking Codes After %s Tag', 'jupiterx-core' ), '<code><body></code>' ); ?>
|
145 |
+
<?php jupiterx_pro_badge(); ?>
|
146 |
+
</label>
|
147 |
+
<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>
|
148 |
+
</div>
|
149 |
+
<div class="form-group col-md-6">
|
150 |
+
<label for="jupiterx-cp-settings-tracking-codes-before-body">
|
151 |
+
<?php /* translators: %s: html */ ?>
|
152 |
+
<?php printf( esc_html__( 'Tracking Codes Before %s Tag', 'jupiterx-core' ), '<code></body></code>' ); ?>
|
153 |
+
<?php jupiterx_pro_badge(); ?>
|
154 |
+
</label>
|
155 |
+
<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>
|
156 |
+
</div>
|
157 |
+
<?php
|
158 |
+
} );
|
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-export-import-content.php
CHANGED
@@ -1,1224 +1,1224 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Export and Import API: JupiterX_Control_Panel_Export_Import base class
|
4 |
-
*
|
5 |
-
* @package JupiterX_Core\Control_Panel\Export_Import
|
6 |
-
* @since 1.0
|
7 |
-
*/
|
8 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Export_Import' ) ) {
|
9 |
-
/**
|
10 |
-
* Export/Import Site Content, Widgets, Settings.
|
11 |
-
*
|
12 |
-
* @author Artbees Team
|
13 |
-
* @since 1.0
|
14 |
-
* @SuppressWarnings(PHPMD.StaticAccess)
|
15 |
-
* @SuppressWarnings(PHPMD.ExcessiveClassComplexitys)
|
16 |
-
*/
|
17 |
-
class JupiterX_Control_Panel_Export_Import {
|
18 |
-
|
19 |
-
/**
|
20 |
-
* $jupiterx_filesystem instance.
|
21 |
-
*
|
22 |
-
* @since 1.0
|
23 |
-
* @var array
|
24 |
-
*/
|
25 |
-
private $jupiterx_filesystem;
|
26 |
-
|
27 |
-
|
28 |
-
/**
|
29 |
-
* $supported_plugins instance.
|
30 |
-
*
|
31 |
-
* @since 1.0
|
32 |
-
* @var array
|
33 |
-
*/
|
34 |
-
private $supported_plugins;
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Export and Import directory’s path and url.
|
38 |
-
*
|
39 |
-
* @since 1.0
|
40 |
-
* @var array
|
41 |
-
*/
|
42 |
-
private $folder = array();
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Constructor.
|
46 |
-
*
|
47 |
-
* @since 1.0
|
48 |
-
*/
|
49 |
-
public function __construct() {
|
50 |
-
|
51 |
-
add_filter( 'jupiterx_control_panel_pane_export_import', [ $this, 'view' ] );
|
52 |
-
|
53 |
-
$upload_dir = wp_upload_dir();
|
54 |
-
$this->folder['export_url'] = $upload_dir['baseurl'] . '/jupiterx/export';
|
55 |
-
$this->folder['export_dir'] = $upload_dir['basedir'] . '/jupiterx/export';
|
56 |
-
$this->folder['import_url'] = $upload_dir['baseurl'] . '/jupiterx/import';
|
57 |
-
$this->folder['import_dir'] = $upload_dir['basedir'] . '/jupiterx/import';
|
58 |
-
|
59 |
-
$this->supported_plugins = array(
|
60 |
-
'woocommerce',
|
61 |
-
'js_composer_theme',
|
62 |
-
'LayerSlider',
|
63 |
-
'masterslider',
|
64 |
-
'revslider',
|
65 |
-
'advanced-custom-fields-pro',
|
66 |
-
'advanced-custom-fields',
|
67 |
-
'jet-elements',
|
68 |
-
'jet-menu',
|
69 |
-
'jet-popup',
|
70 |
-
'jet-tabs',
|
71 |
-
'jet-woo-builder',
|
72 |
-
'jet-tricks',
|
73 |
-
'jet-engine',
|
74 |
-
'jet-smart-filters',
|
75 |
-
'raven',
|
76 |
-
'elementor',
|
77 |
-
'customizer-reset-by-wpzoom',
|
78 |
-
'customizer-export-import',
|
79 |
-
'jupiterx-core',
|
80 |
-
'jupiterx-pro',
|
81 |
-
'menu-icons',
|
82 |
-
);
|
83 |
-
|
84 |
-
add_action( 'wp_ajax_jupiterx_cp_export_import', array( $this, 'ajax_handler' ) );
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Export/Import HTML directory.
|
89 |
-
*
|
90 |
-
* @since 1.9.0
|
91 |
-
*
|
92 |
-
* @return string
|
93 |
-
*/
|
94 |
-
public function view() {
|
95 |
-
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/export-import-content.php';
|
96 |
-
}
|
97 |
-
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Map the requests to proper methods.
|
101 |
-
*
|
102 |
-
* @since 1.0
|
103 |
-
*/
|
104 |
-
public function ajax_handler() {
|
105 |
-
check_ajax_referer( 'jupiterx_control_panel', 'nonce' );
|
106 |
-
|
107 |
-
$type = filter_input( INPUT_POST, 'type' );
|
108 |
-
$step = filter_input( INPUT_POST, 'step' );
|
109 |
-
$attachment_id = filter_input( INPUT_POST, 'attachment_id' );
|
110 |
-
|
111 |
-
if ( empty( $type ) ) {
|
112 |
-
wp_send_json_error(
|
113 |
-
__( 'Type param is missing.', 'jupiterx-core' )
|
114 |
-
);
|
115 |
-
}
|
116 |
-
|
117 |
-
if ( empty( $step ) ) {
|
118 |
-
wp_send_json_error(
|
119 |
-
__( 'Step param is missing.', 'jupiterx-core' )
|
120 |
-
);
|
121 |
-
}
|
122 |
-
|
123 |
-
if ( 'Export' === $type ) {
|
124 |
-
$this->jupiterx_filesystem = new JupiterX_Filesystem(
|
125 |
-
array(
|
126 |
-
'context' => $this->folder['export_dir'],
|
127 |
-
)
|
128 |
-
);
|
129 |
-
return $this->export( $step );
|
130 |
-
}
|
131 |
-
|
132 |
-
if ( 'Import' === $type ) {
|
133 |
-
|
134 |
-
if ( empty( $attachment_id ) ) {
|
135 |
-
wp_send_json_error(
|
136 |
-
__( 'Attachment ID param is missing.', 'jupiterx-core' )
|
137 |
-
);
|
138 |
-
}
|
139 |
-
|
140 |
-
$this->jupiterx_filesystem = new JupiterX_Filesystem(
|
141 |
-
array(
|
142 |
-
'context' => $this->folder['import_dir'],
|
143 |
-
)
|
144 |
-
);
|
145 |
-
return $this->import( $step, $attachment_id );
|
146 |
-
}
|
147 |
-
|
148 |
-
wp_send_json_error(
|
149 |
-
sprintf( __( 'Type param (%s) is not valid.', 'jupiterx-core' ), $type )
|
150 |
-
);
|
151 |
-
}
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Run proper export method based on step.
|
155 |
-
*
|
156 |
-
* @since 1.0
|
157 |
-
* @param string $step The export step.
|
158 |
-
* @return void
|
159 |
-
*/
|
160 |
-
private function export( $step ) {
|
161 |
-
switch ( $step ) {
|
162 |
-
case 'Start':
|
163 |
-
$this->export_start();
|
164 |
-
break;
|
165 |
-
|
166 |
-
case 'Content':
|
167 |
-
$this->export_content();
|
168 |
-
break;
|
169 |
-
|
170 |
-
case 'Widgets':
|
171 |
-
$this->export_widgets();
|
172 |
-
break;
|
173 |
-
|
174 |
-
case 'Settings':
|
175 |
-
$this->export_settings();
|
176 |
-
break;
|
177 |
-
|
178 |
-
case 'End':
|
179 |
-
$this->export_end();
|
180 |
-
break;
|
181 |
-
|
182 |
-
case 'Discard':
|
183 |
-
$this->discard( $this->folder['export_dir'] );
|
184 |
-
break;
|
185 |
-
}
|
186 |
-
|
187 |
-
wp_send_json_error(
|
188 |
-
sprintf( __( 'Step param (%s) is not valid.', 'jupiterx-core' ), $step )
|
189 |
-
);
|
190 |
-
}
|
191 |
-
|
192 |
-
/**
|
193 |
-
* Start export process by cleaning the export directory.
|
194 |
-
*
|
195 |
-
* @throws Exception If can not clean export folder.
|
196 |
-
*
|
197 |
-
* @since 1.0
|
198 |
-
*/
|
199 |
-
private function export_start() {
|
200 |
-
try {
|
201 |
-
if ( $this->jupiterx_filesystem->rmdir( $this->folder['export_dir'], true ) ) {
|
202 |
-
return wp_send_json_success(
|
203 |
-
array(
|
204 |
-
'step' => 'Start',
|
205 |
-
)
|
206 |
-
);
|
207 |
-
}
|
208 |
-
|
209 |
-
throw new Exception( __( 'A problem occurred in cleaning export directory.', 'jupiterx-core' ) );
|
210 |
-
} catch ( Exception $e ) {
|
211 |
-
return wp_send_json_error( $e->getMessage() );
|
212 |
-
}
|
213 |
-
}
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Export content.
|
217 |
-
*
|
218 |
-
* @throws Exception If can not export Content.
|
219 |
-
*
|
220 |
-
* @since 1.0
|
221 |
-
*/
|
222 |
-
private function export_content() {
|
223 |
-
try {
|
224 |
-
require_once ABSPATH . 'wp-admin/includes/export.php';
|
225 |
-
|
226 |
-
ob_start();
|
227 |
-
export_wp();
|
228 |
-
$content = ob_get_clean();
|
229 |
-
ob_end_clean();
|
230 |
-
|
231 |
-
$file_name = 'theme_content.xml';
|
232 |
-
$file_path = $this->folder['export_dir'] . '/' . $file_name;
|
233 |
-
|
234 |
-
if ( ! $this->jupiterx_filesystem->put_contents( $file_path, $content ) ) {
|
235 |
-
throw new Exception( __( 'A problem occurred in exporting Content.', 'jupiterx-core' ) );
|
236 |
-
}
|
237 |
-
|
238 |
-
$this->export_plugins();
|
239 |
-
|
240 |
-
return wp_send_json_success(
|
241 |
-
array(
|
242 |
-
'step' => 'Content',
|
243 |
-
)
|
244 |
-
);
|
245 |
-
} catch ( Exception $e ) {
|
246 |
-
return wp_send_json_error( $e->getMessage() );
|
247 |
-
}
|
248 |
-
}
|
249 |
-
|
250 |
-
/**
|
251 |
-
* Export plugins content.
|
252 |
-
*
|
253 |
-
* @since 1.0.3
|
254 |
-
*/
|
255 |
-
public function export_plugins() {
|
256 |
-
$active_plugins = get_option( 'active_plugins' );
|
257 |
-
|
258 |
-
if ( is_multisite() ) {
|
259 |
-
$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins' ) );
|
260 |
-
}
|
261 |
-
|
262 |
-
foreach ( $active_plugins as $plugin ) {
|
263 |
-
$plugins_slug[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
264 |
-
}
|
265 |
-
|
266 |
-
$supported_plugins = array_intersect( $plugins_slug, $this->supported_plugins );
|
267 |
-
|
268 |
-
foreach ( $supported_plugins as $plugin ) {
|
269 |
-
if ( is_callable( [ $this, "export_{$plugin}_content" ] ) ) {
|
270 |
-
call_user_func( [ $this, "export_{$plugin}_content" ] );
|
271 |
-
}
|
272 |
-
}
|
273 |
-
}
|
274 |
-
|
275 |
-
/**
|
276 |
-
* Export Revolution Slider slides.
|
277 |
-
*
|
278 |
-
* @since 1.0.3
|
279 |
-
*/
|
280 |
-
public function export_revslider_content() {
|
281 |
-
if ( ! class_exists( 'RevSlider' ) ) {
|
282 |
-
return;
|
283 |
-
}
|
284 |
-
|
285 |
-
// Initialize Revolution Slider.
|
286 |
-
$revslider = new RevSlider();
|
287 |
-
|
288 |
-
$sliders = $revslider->getAllSliderAliases();
|
289 |
-
|
290 |
-
if ( empty( $sliders ) ) {
|
291 |
-
return;
|
292 |
-
}
|
293 |
-
|
294 |
-
// Create download url.
|
295 |
-
$base_arg = [
|
296 |
-
'action' => 'revslider_ajax_action',
|
297 |
-
'client_action' => 'export_slider',
|
298 |
-
'dummy' => 'false',
|
299 |
-
'nonce' => wp_create_nonce( 'revslider_actions' ),
|
300 |
-
];
|
301 |
-
|
302 |
-
$base_url = add_query_arg( $base_arg, admin_url( 'admin-ajax.php' ) );
|
303 |
-
|
304 |
-
$export_dir = "{$this->folder['export_dir']}/revslider/";
|
305 |
-
|
306 |
-
// Create and pass cookie.
|
307 |
-
$cookies = [];
|
308 |
-
|
309 |
-
foreach ( $_COOKIE as $name => $value ) {
|
310 |
-
$cookies[] = new WP_Http_Cookie( array( 'name' => $name, 'value' => $value ) );
|
311 |
-
}
|
312 |
-
|
313 |
-
$remote_args = [
|
314 |
-
'cookies' => $cookies,
|
315 |
-
];
|
316 |
-
|
317 |
-
// Go through each slides.
|
318 |
-
foreach ( $sliders as $slider_alias ) {
|
319 |
-
$revslider->initByAlias( $slider_alias );
|
320 |
-
|
321 |
-
$download_args = [
|
322 |
-
'sliderid' => $revslider->getID(),
|
323 |
-
];
|
324 |
-
|
325 |
-
$download_url = add_query_arg( $download_args, $base_url );
|
326 |
-
|
327 |
-
JupiterX_Control_Panel_Helpers::upload_from_url(
|
328 |
-
$download_url,
|
329 |
-
"{$slider_alias}.zip",
|
330 |
-
$export_dir,
|
331 |
-
$remote_args
|
332 |
-
);
|
333 |
-
}
|
334 |
-
}
|
335 |
-
|
336 |
-
public function availableWidgets() {
|
337 |
-
global $wp_registered_widget_controls;
|
338 |
-
$widget_controls = $wp_registered_widget_controls;
|
339 |
-
$available_widgets = array();
|
340 |
-
foreach ( $widget_controls as $widget ) {
|
341 |
-
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
|
342 |
-
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
343 |
-
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
344 |
-
}
|
345 |
-
}
|
346 |
-
|
347 |
-
return apply_filters( 'available_widgets', $available_widgets );
|
348 |
-
}
|
349 |
-
|
350 |
-
/**
|
351 |
-
* Export widgets.
|
352 |
-
*
|
353 |
-
* @throws Exception If can not export Widgets.
|
354 |
-
*
|
355 |
-
* @since 1.0
|
356 |
-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
357 |
-
*/
|
358 |
-
private function export_widgets() {
|
359 |
-
try {
|
360 |
-
$available_widgets = $this->availableWidgets();
|
361 |
-
|
362 |
-
// Get all widget instances for each widget.
|
363 |
-
$widget_instances = array();
|
364 |
-
|
365 |
-
// Loop widgets.
|
366 |
-
foreach ( $available_widgets as $widget_data ) {
|
367 |
-
// Get all instances for this ID base.
|
368 |
-
$instances = get_option( 'widget_' . $widget_data['id_base'] );
|
369 |
-
// Have instances.
|
370 |
-
if ( ! empty( $instances ) ) {
|
371 |
-
// Loop instances.
|
372 |
-
foreach ( $instances as $instance_id => $instance_data ) {
|
373 |
-
// Key is ID (not _multiwidget).
|
374 |
-
if ( is_numeric( $instance_id ) ) {
|
375 |
-
$unique_instance_id = $widget_data['id_base'] . '-' . $instance_id;
|
376 |
-
$widget_instances[ $unique_instance_id ] = $instance_data;
|
377 |
-
}
|
378 |
-
}
|
379 |
-
}
|
380 |
-
}
|
381 |
-
|
382 |
-
// Gather sidebars with their widget instances.
|
383 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
384 |
-
$sidebars_widget_ins = array();
|
385 |
-
foreach ( $sidebars_widgets as $sidebar_id => $widget_ids ) {
|
386 |
-
|
387 |
-
// Skip inactive widgets.
|
388 |
-
if ( 'wp_inactive_widgets' === $sidebar_id ) {
|
389 |
-
continue;
|
390 |
-
}
|
391 |
-
|
392 |
-
// Skip if no data or not an array (array_version).
|
393 |
-
if ( ! is_array( $widget_ids ) || empty( $widget_ids ) ) {
|
394 |
-
continue;
|
395 |
-
}
|
396 |
-
|
397 |
-
// Loop widget IDs for this sidebar.
|
398 |
-
foreach ( $widget_ids as $widget_id ) {
|
399 |
-
// Is there an instance for this widget ID?
|
400 |
-
if ( isset( $widget_instances[ $widget_id ] ) ) {
|
401 |
-
// Add to array.
|
402 |
-
$sidebars_widget_ins[ $sidebar_id ][ $widget_id ] = $widget_instances[ $widget_id ];
|
403 |
-
}
|
404 |
-
}
|
405 |
-
}
|
406 |
-
|
407 |
-
$content = wp_json_encode( $sidebars_widget_ins );
|
408 |
-
|
409 |
-
$file_name = 'widget_data.wie';
|
410 |
-
$file_path = $this->folder['export_dir'] . '/' . $file_name;
|
411 |
-
|
412 |
-
if ( $this->jupiterx_filesystem->put_contents( $file_path, $content ) ) {
|
413 |
-
return wp_send_json_success(
|
414 |
-
array(
|
415 |
-
'step' => 'Widgets',
|
416 |
-
)
|
417 |
-
);
|
418 |
-
}
|
419 |
-
|
420 |
-
throw new Exception( __( 'A problem occurred in exporting widgets.', 'jupiterx-core' ) );
|
421 |
-
} catch ( Exception $e ) {
|
422 |
-
return wp_send_json_error( $e->getMessage() );
|
423 |
-
} // End try().
|
424 |
-
}
|
425 |
-
|
426 |
-
|
427 |
-
/**
|
428 |
-
* An array of core options that shouldn't be imported.
|
429 |
-
*
|
430 |
-
* @since 1.0
|
431 |
-
* @access private
|
432 |
-
* @var array $core_options
|
433 |
-
*/
|
434 |
-
static private $core_options = array(
|
435 |
-
'blogname',
|
436 |
-
'blogdescription'
|
437 |
-
);
|
438 |
-
|
439 |
-
|
440 |
-
/**
|
441 |
-
* Export Settings.
|
442 |
-
*
|
443 |
-
* @throws Exception If can not export Settings.
|
444 |
-
*
|
445 |
-
* @since 1.0
|
446 |
-
*/
|
447 |
-
private function export_settings() {
|
448 |
-
try {
|
449 |
-
$data = [
|
450 |
-
'template' => get_template(),
|
451 |
-
'mods' => [],
|
452 |
-
'options' => [],
|
453 |
-
];
|
454 |
-
|
455 |
-
$data = $this->_export_settings_customizer_mods( $data );
|
456 |
-
|
457 |
-
$data = $this->_export_settings_customizer_options( $data );
|
458 |
-
|
459 |
-
$data = $this->_export_settings_plugins( $data );
|
460 |
-
|
461 |
-
$data = $this->_export_settings_options( $data );
|
462 |
-
|
463 |
-
// WP custom CSS.
|
464 |
-
if ( function_exists( 'wp_get_custom_css_post' ) ) {
|
465 |
-
$data['wp_css'] = wp_get_custom_css();
|
466 |
-
}
|
467 |
-
|
468 |
-
$file_name = 'settings.json';
|
469 |
-
$file_path = $this->folder['export_dir'] . '/' . $file_name;
|
470 |
-
|
471 |
-
if ( ! is_array( $data ) ) {
|
472 |
-
throw new Exception( __( 'All settings in Settings are set to default. Uncheck the Settings option or change one setting in Settings then export.', 'jupiterx-core' ) );
|
473 |
-
}
|
474 |
-
|
475 |
-
if ( ! $this->jupiterx_filesystem->put_contents( $file_path, wp_json_encode( $data ) ) ) {
|
476 |
-
throw new Exception( __( 'A problem occurred in exporting Settings.', 'jupiterx-core' ) );
|
477 |
-
}
|
478 |
-
|
479 |
-
return wp_send_json_success( [ 'step' => 'Settings' ] );
|
480 |
-
|
481 |
-
} catch ( Exception $e ) {
|
482 |
-
return wp_send_json_error( $e->getMessage() );
|
483 |
-
}
|
484 |
-
}
|
485 |
-
|
486 |
-
/**
|
487 |
-
* Export customizer mods.
|
488 |
-
*
|
489 |
-
* @since 1.0.4
|
490 |
-
*/
|
491 |
-
private function _export_settings_customizer_mods( $data ) {
|
492 |
-
$mods = get_theme_mods();
|
493 |
-
|
494 |
-
if ( ! empty( $mods ) ) {
|
495 |
-
unset( $mods['sidebars_widgets'] );
|
496 |
-
$data['mods'] = $mods;
|
497 |
-
}
|
498 |
-
|
499 |
-
return $data;
|
500 |
-
}
|
501 |
-
|
502 |
-
/**
|
503 |
-
* Export customizer options.
|
504 |
-
*
|
505 |
-
* @since 1.0.4
|
506 |
-
*/
|
507 |
-
private function _export_settings_customizer_options( $data ) {
|
508 |
-
require_once ABSPATH . 'wp-includes/class-wp-customize-manager.php';
|
509 |
-
|
510 |
-
$wp_customize = new WP_Customize_Manager();
|
511 |
-
$settings = $wp_customize->settings();
|
512 |
-
|
513 |
-
foreach ( $settings as $key => $setting ) {
|
514 |
-
if ( 'option' == $setting->type ) {
|
515 |
-
|
516 |
-
// Don't save widget data.
|
517 |
-
if ( stristr( $key, 'widget_' ) ) {
|
518 |
-
continue;
|
519 |
-
}
|
520 |
-
|
521 |
-
// Don't save sidebar data.
|
522 |
-
if ( stristr( $key, 'sidebars_' ) ) {
|
523 |
-
continue;
|
524 |
-
}
|
525 |
-
|
526 |
-
// Don't save core options.
|
527 |
-
if ( in_array( $key, self::$core_options ) ) {
|
528 |
-
continue;
|
529 |
-
}
|
530 |
-
|
531 |
-
$data['options'][ $key ] = $setting->value();
|
532 |
-
}
|
533 |
-
}
|
534 |
-
|
535 |
-
return $data;
|
536 |
-
}
|
537 |
-
|
538 |
-
/**
|
539 |
-
* Export active supported plugins.
|
540 |
-
*
|
541 |
-
* @since 1.0.4
|
542 |
-
*/
|
543 |
-
private function _export_settings_plugins( $data ) {
|
544 |
-
$all_active_plugins = get_option( 'active_plugins' );
|
545 |
-
|
546 |
-
foreach ( $all_active_plugins as $plugin ) {
|
547 |
-
$active_plugins[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
548 |
-
}
|
549 |
-
|
550 |
-
if ( is_multisite() ) {
|
551 |
-
$sitewide_all_active_plugins = get_site_option( 'active_sitewide_plugins' );
|
552 |
-
|
553 |
-
foreach ( $sitewide_all_active_plugins as $plugin => $id ) {
|
554 |
-
$active_plugins[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
555 |
-
}
|
556 |
-
}
|
557 |
-
|
558 |
-
$supported_active_plugins = array_intersect( $active_plugins, $this->supported_plugins );
|
559 |
-
|
560 |
-
foreach ( $supported_active_plugins as $plugins ) {
|
561 |
-
$data['options']['jupiterx_support_plugins'][] = $plugins;
|
562 |
-
}
|
563 |
-
|
564 |
-
return $data;
|
565 |
-
}
|
566 |
-
|
567 |
-
/**
|
568 |
-
* Export options.
|
569 |
-
*
|
570 |
-
* @since 1.0.4
|
571 |
-
*/
|
572 |
-
private function _export_settings_options( $data ) {
|
573 |
-
/**
|
574 |
-
* Extra options.
|
575 |
-
*
|
576 |
-
* Any option that can be exported & imported without modifications.
|
577 |
-
*/
|
578 |
-
$option_keys = apply_filters( 'jupiterx_extra_export_option_keys', [
|
579 |
-
'elementor_scheme_color',
|
580 |
-
'elementor_scheme_typography',
|
581 |
-
'elementor_scheme_color-picker',
|
582 |
-
'elementor_cpt_support',
|
583 |
-
'elementor_disable_color_schemes',
|
584 |
-
'elementor_disable_typography_schemes',
|
585 |
-
'elementor_default_generic_fonts',
|
586 |
-
'elementor_container_width',
|
587 |
-
'elementor_space_between_widgets',
|
588 |
-
'elementor_stretched_section_container',
|
589 |
-
'elementor_page_title_selector',
|
590 |
-
'elementor_viewport_lg',
|
591 |
-
'elementor_viewport_md',
|
592 |
-
'elementor_global_image_lightbox',
|
593 |
-
'elementor_lightbox_color',
|
594 |
-
'elementor_lightbox_ui_color',
|
595 |
-
'elementor_lightbox_ui_color_hover',
|
596 |
-
'elementor_enable_lightbox_in_editor',
|
597 |
-
'elementor_global_image_lightbox',
|
598 |
-
] );
|
599 |
-
|
600 |
-
foreach ( $option_keys as $option_key ) {
|
601 |
-
$option = get_option( $option_key, null );
|
602 |
-
|
603 |
-
if ( ! is_null( $option ) ) {
|
604 |
-
$data['options']['extra'][ $option_key ] = $option;
|
605 |
-
}
|
606 |
-
}
|
607 |
-
|
608 |
-
// Front page.
|
609 |
-
$page_on_front = get_option( 'page_on_front' );
|
610 |
-
|
611 |
-
if ( ! empty( $page_on_front ) ) {
|
612 |
-
$data['options']['page_on_front'] = get_the_title( $page_on_front );
|
613 |
-
}
|
614 |
-
|
615 |
-
// Menu locations.
|
616 |
-
$get_nav_locations = get_theme_mod( 'nav_menu_locations' );
|
617 |
-
|
618 |
-
foreach ( $get_nav_locations as $location => $id ) {
|
619 |
-
$get_term = get_term_by( 'id', $id, 'nav_menu' );
|
620 |
-
$data['options']['jupiterx_menu_locations'][ $location ] = $get_term->name;
|
621 |
-
}
|
622 |
-
|
623 |
-
// WooCommerce.
|
624 |
-
$woocommerce_shop_page_id = get_option( 'woocommerce_shop_page_id' );
|
625 |
-
|
626 |
-
if ( ! empty( $woocommerce_shop_page_id ) ) {
|
627 |
-
$data['options']['woocommerce_shop_page_id'] = get_the_title( $woocommerce_shop_page_id );
|
628 |
-
}
|
629 |
-
|
630 |
-
$woocommerce_cart_page_id = get_option( 'woocommerce_cart_page_id' );
|
631 |
-
|
632 |
-
if ( ! empty( $woocommerce_cart_page_id ) ) {
|
633 |
-
$data['options']['woocommerce_cart_page_id'] = get_the_title( $woocommerce_cart_page_id );
|
634 |
-
}
|
635 |
-
|
636 |
-
$woocommerce_checkout_page_id = get_option( 'woocommerce_checkout_page_id' );
|
637 |
-
|
638 |
-
if ( ! empty( $woocommerce_checkout_page_id ) ) {
|
639 |
-
$data['options']['woocommerce_checkout_page_id'] = get_the_title( $woocommerce_checkout_page_id );
|
640 |
-
}
|
641 |
-
|
642 |
-
$woocommerce_myaccount_page_id = get_option( 'woocommerce_myaccount_page_id' );
|
643 |
-
|
644 |
-
if ( ! empty( $woocommerce_checkout_page_id ) ) {
|
645 |
-
$data['options']['woocommerce_myaccount_page_id'] = get_the_title( $woocommerce_myaccount_page_id );
|
646 |
-
}
|
647 |
-
|
648 |
-
// Jet Menu.
|
649 |
-
$jet_menu_options = get_option( 'jet_menu_options' );
|
650 |
-
|
651 |
-
if ( ! empty( $jet_menu_options ) && in_array( 'jet-menu', $data['options']['jupiterx_support_plugins'], true ) ) {
|
652 |
-
$data['options']['jet_menu_options'] = $jet_menu_options;
|
653 |
-
}
|
654 |
-
|
655 |
-
return $data;
|
656 |
-
}
|
657 |
-
|
658 |
-
/**
|
659 |
-
* End export process by creating the zip file and download url.
|
660 |
-
*
|
661 |
-
* @since 1.0
|
662 |
-
*/
|
663 |
-
private function export_end() {
|
664 |
-
try {
|
665 |
-
$this->jupiterx_filesystem->zip_folder( $this->folder['export_dir'], "{$this->folder['export_dir']}/{$this->_prepare_directory_name()}.zip", $this->_prepare_directory_name() );
|
666 |
-
|
667 |
-
return wp_send_json_success(
|
668 |
-
array(
|
669 |
-
'step' => 'End',
|
670 |
-
'download_url' => $this->folder['export_url'] . '/' . $this->_prepare_directory_name() . '.zip',
|
671 |
-
)
|
672 |
-
);
|
673 |
-
|
674 |
-
} catch ( Exception $e ) {
|
675 |
-
return wp_send_json_error( $e->getMessage() );
|
676 |
-
}
|
677 |
-
}
|
678 |
-
|
679 |
-
/**
|
680 |
-
* Prepare the export zip file name.
|
681 |
-
*
|
682 |
-
* @since 1.0.0
|
683 |
-
*/
|
684 |
-
private function _prepare_directory_name() {
|
685 |
-
$site_title = ! empty( get_bloginfo( 'name' ) ) ? get_bloginfo( 'name' ) : 'package';
|
686 |
-
$form_data = jupiterx_post( 'data' );
|
687 |
-
|
688 |
-
if ( ! empty( $form_data['filename'] ) ) {
|
689 |
-
return sanitize_title( $form_data['filename'] );
|
690 |
-
}
|
691 |
-
|
692 |
-
return sanitize_title( $site_title ) . '-jupiterx';
|
693 |
-
}
|
694 |
-
|
695 |
-
/**
|
696 |
-
* Run proper import method based on step.
|
697 |
-
*
|
698 |
-
* @since 1.0
|
699 |
-
* @param string $step The import step.
|
700 |
-
* @param integer $attachment_id The uploaded zip file ID.
|
701 |
-
* @return void
|
702 |
-
*/
|
703 |
-
private function import( $step, $attachment_id ) {
|
704 |
-
switch ( $step ) {
|
705 |
-
case 'Start':
|
706 |
-
$this->import_start( $attachment_id );
|
707 |
-
break;
|
708 |
-
|
709 |
-
case 'Content':
|
710 |
-
$this->import_content();
|
711 |
-
break;
|
712 |
-
|
713 |
-
case 'Widgets':
|
714 |
-
$this->import_widgets();
|
715 |
-
break;
|
716 |
-
|
717 |
-
case 'Settings':
|
718 |
-
$this->import_settings();
|
719 |
-
break;
|
720 |
-
|
721 |
-
case 'End':
|
722 |
-
$this->import_end();
|
723 |
-
break;
|
724 |
-
|
725 |
-
case 'Discard':
|
726 |
-
$this->discard( $this->folder['import_dir'] );
|
727 |
-
break;
|
728 |
-
}
|
729 |
-
|
730 |
-
wp_send_json_error(
|
731 |
-
sprintf( __( 'Step param (%s) is not valid.', 'jupiterx-core' ), $step )
|
732 |
-
);
|
733 |
-
}
|
734 |
-
|
735 |
-
/**
|
736 |
-
* Start import process by cleaning import directory and
|
737 |
-
* unzipping file to directory Import directory.
|
738 |
-
*
|
739 |
-
* @since 1.0
|
740 |
-
* @param integer $attachment_id The uploaded zip file ID.
|
741 |
-
*/
|
742 |
-
private function import_start( $attachment_id ) {
|
743 |
-
try {
|
744 |
-
$this->jupiterx_filesystem->rmdir( $this->folder['import_dir'], true );
|
745 |
-
|
746 |
-
$this->jupiterx_filesystem->unzip_custom(
|
747 |
-
get_attached_file( $attachment_id ),
|
748 |
-
$this->folder['import_dir']
|
749 |
-
);
|
750 |
-
|
751 |
-
return wp_send_json_success(
|
752 |
-
array(
|
753 |
-
'step' => 'Start',
|
754 |
-
)
|
755 |
-
);
|
756 |
-
} catch ( Exception $e ) {
|
757 |
-
return wp_send_json_error( $e->getMessage() );
|
758 |
-
}
|
759 |
-
}
|
760 |
-
|
761 |
-
/**
|
762 |
-
* Import Content
|
763 |
-
*
|
764 |
-
* @throws Exception If required file is missing.
|
765 |
-
* @throws Exception If can not parse file..
|
766 |
-
*
|
767 |
-
* @since 1.0
|
768 |
-
*/
|
769 |
-
private function import_content() {
|
770 |
-
try {
|
771 |
-
$file_name = 'theme_content.xml';
|
772 |
-
$file = $this->_get_import_package_dir_path( $file_name );
|
773 |
-
$fetch_attachments = true;
|
774 |
-
|
775 |
-
if ( ! file_exists( $file ) ) {
|
776 |
-
throw new Exception(
|
777 |
-
sprintf( __( 'A required file (%s) is missing in the selected zip file.', 'jupiterx-core' ), $file_name )
|
778 |
-
);
|
779 |
-
}
|
780 |
-
|
781 |
-
// Include wordpress-importer class.
|
782 |
-
JupiterX_Control_Panel_Helpers::include_wordpress_importer();
|
783 |
-
|
784 |
-
$options = array(
|
785 |
-
'fetch_attachments' => filter_var( $fetch_attachments, FILTER_VALIDATE_BOOLEAN ),
|
786 |
-
'default_author' => get_current_user_id(),
|
787 |
-
);
|
788 |
-
|
789 |
-
// Create new instance for Importer.
|
790 |
-
$importer = new JupiterX_WXR_Importer( $options );
|
791 |
-
$logger = new JupiterX_Importer_Logger_ServerSentEvents();
|
792 |
-
$importer->set_logger( $logger );
|
793 |
-
|
794 |
-
$data = $importer->get_preliminary_information( $file );
|
795 |
-
|
796 |
-
if ( is_wp_error( $data ) ) {
|
797 |
-
throw new Exception(
|
798 |
-
sprintf( __( 'Error in parsing %s.', 'jupiterx-core' ), $file_name )
|
799 |
-
);
|
800 |
-
}
|
801 |
-
|
802 |
-
// Run import process.
|
803 |
-
ob_start();
|
804 |
-
$importer->import( $file );
|
805 |
-
ob_end_clean();
|
806 |
-
|
807 |
-
return wp_send_json_success(
|
808 |
-
array(
|
809 |
-
'step' => 'Content',
|
810 |
-
)
|
811 |
-
);
|
812 |
-
|
813 |
-
} catch ( Exception $e ) {
|
814 |
-
return wp_send_json_error( $e->getMessage() );
|
815 |
-
} // End try().
|
816 |
-
}
|
817 |
-
|
818 |
-
/**
|
819 |
-
* Import widgets' data.
|
820 |
-
*
|
821 |
-
* @throws Exception If can not read widget data.
|
822 |
-
*
|
823 |
-
* @since 5.7.0
|
824 |
-
* 6.0.4 Make it public.
|
825 |
-
* @param array $data Widgets' data.
|
826 |
-
* @return boolean
|
827 |
-
*/
|
828 |
-
public function import_widget_data( $data ) {
|
829 |
-
global $wp_registered_sidebars;
|
830 |
-
|
831 |
-
$available_widgets = $this->availableWidgets();
|
832 |
-
$widget_instances = array();
|
833 |
-
foreach ( $available_widgets as $widget_data ) {
|
834 |
-
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
835 |
-
}
|
836 |
-
if ( empty( $data ) || ! is_object( $data ) ) {
|
837 |
-
throw new Exception( 'Widget data could not be read. Please try a different file.' );
|
838 |
-
}
|
839 |
-
$results = array();
|
840 |
-
foreach ( $data as $sidebar_id => $widgets ) {
|
841 |
-
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
842 |
-
continue;
|
843 |
-
}
|
844 |
-
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
845 |
-
$sidebar_available = true;
|
846 |
-
$use_sidebar_id = $sidebar_id;
|
847 |
-
$sidebar_message_type = 'success';
|
848 |
-
$sidebar_message = '';
|
849 |
-
} else {
|
850 |
-
$sidebar_available = false;
|
851 |
-
$use_sidebar_id = 'wp_inactive_widgets';
|
852 |
-
$sidebar_message_type = 'error';
|
853 |
-
$sidebar_message = 'Sidebar does not exist in theme (using Inactive)';
|
854 |
-
}
|
855 |
-
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id;
|
856 |
-
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
857 |
-
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
858 |
-
$results[ $sidebar_id ]['widgets'] = array();
|
859 |
-
foreach ( $widgets as $widget_instance_id => $widget ) {
|
860 |
-
$fail = false;
|
861 |
-
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
862 |
-
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
863 |
-
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
864 |
-
$fail = true;
|
865 |
-
$widget_message_type = 'error';
|
866 |
-
$widget_message = 'Site does not support widget';
|
867 |
-
}
|
868 |
-
$widget = apply_filters( 'jupiterx_widget_settings', $widget );
|
869 |
-
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
870 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
871 |
-
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array();
|
872 |
-
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
873 |
-
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
874 |
-
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
875 |
-
$fail = true;
|
876 |
-
$widget_message_type = 'warning';
|
877 |
-
$widget_message = 'Widget already exists';
|
878 |
-
break;
|
879 |
-
}
|
880 |
-
}
|
881 |
-
}
|
882 |
-
if ( ! $fail ) {
|
883 |
-
$single_widget_instances = get_option( 'widget_' . $id_base );
|
884 |
-
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array(
|
885 |
-
'_multiwidget' => 1,
|
886 |
-
);
|
887 |
-
$single_widget_instances[] = (array) $widget;
|
888 |
-
end( $single_widget_instances );
|
889 |
-
$new_instance_id_number = key( $single_widget_instances );
|
890 |
-
if ( '0' === strval( $new_instance_id_number ) ) {
|
891 |
-
$new_instance_id_number = 1;
|
892 |
-
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
893 |
-
unset( $single_widget_instances[0] );
|
894 |
-
}
|
895 |
-
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
896 |
-
$multiwidget = $single_widget_instances['_multiwidget'];
|
897 |
-
unset( $single_widget_instances['_multiwidget'] );
|
898 |
-
$single_widget_instances['_multiwidget'] = $multiwidget;
|
899 |
-
}
|
900 |
-
update_option( 'widget_' . $id_base, $single_widget_instances );
|
901 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
902 |
-
$new_instance_id = $id_base . '-' . $new_instance_id_number;
|
903 |
-
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id;
|
904 |
-
update_option( 'sidebars_widgets', $sidebars_widgets );
|
905 |
-
if ( $sidebar_available ) {
|
906 |
-
$widget_message_type = 'success';
|
907 |
-
$widget_message = 'Imported';
|
908 |
-
} else {
|
909 |
-
$widget_message_type = 'warning';
|
910 |
-
$widget_message = 'Imported to Inactive';
|
911 |
-
}
|
912 |
-
}
|
913 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base;
|
914 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget->title ) ? $widget->title : '';
|
915 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
916 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
917 |
-
} // End foreach().
|
918 |
-
} // End foreach().
|
919 |
-
|
920 |
-
return true;
|
921 |
-
}
|
922 |
-
|
923 |
-
/**
|
924 |
-
* Import Widgets.
|
925 |
-
*
|
926 |
-
* @throws Exception If required file is missing.
|
927 |
-
* @throws Exception If can not import Widgets.
|
928 |
-
*
|
929 |
-
* @since 1.0
|
930 |
-
*/
|
931 |
-
private function import_widgets() {
|
932 |
-
try {
|
933 |
-
$file_name = 'widget_data.wie';
|
934 |
-
|
935 |
-
if ( ! file_exists( $this->_get_import_package_dir_path( $file_name ) ) ) {
|
936 |
-
throw new Exception(
|
937 |
-
sprintf( __( 'A required file (%s) is missing in the selected zip file.', 'jupiterx-core' ), $file_name )
|
938 |
-
);
|
939 |
-
}
|
940 |
-
|
941 |
-
$import_data = JupiterX_Control_Panel_Helpers::getFileBody(
|
942 |
-
$this->_get_import_package_dir_url( $file_name ),
|
943 |
-
$this->_get_import_package_dir_path( $file_name )
|
944 |
-
);
|
945 |
-
|
946 |
-
$data = json_decode( $import_data );
|
947 |
-
|
948 |
-
if ( ! $this->import_widget_data( $data ) ) {
|
949 |
-
throw new Exception( __( 'A problem occurred in importing Widgets.', 'jupiterx-core' ) );
|
950 |
-
}
|
951 |
-
|
952 |
-
return wp_send_json_success(
|
953 |
-
array(
|
954 |
-
'step' => 'Widgets',
|
955 |
-
)
|
956 |
-
);
|
957 |
-
|
958 |
-
} catch ( Exception $e ) {
|
959 |
-
return wp_send_json_error( $e->getMessage() );
|
960 |
-
}
|
961 |
-
}
|
962 |
-
|
963 |
-
/**
|
964 |
-
* Import Settings.
|
965 |
-
*
|
966 |
-
* @throws Exception If required file is missing.
|
967 |
-
* @throws Exception If can not import Settings.
|
968 |
-
*
|
969 |
-
* @since 1.0
|
970 |
-
*/
|
971 |
-
private function import_settings() {
|
972 |
-
try {
|
973 |
-
|
974 |
-
require_once ABSPATH . 'wp-includes/class-wp-customize-manager.php';
|
975 |
-
$wp_customize = new WP_Customize_Manager();
|
976 |
-
|
977 |
-
$file_name = 'settings.json';
|
978 |
-
|
979 |
-
if ( ! file_exists( $this->_get_import_package_dir_path( $file_name ) ) ) {
|
980 |
-
throw new Exception(
|
981 |
-
sprintf( __( '%s is missing in the selected zip file.', 'jupiterx-core' ), $file_name )
|
982 |
-
);
|
983 |
-
}
|
984 |
-
|
985 |
-
$import_data = JupiterX_Control_Panel_Helpers::getFileBody(
|
986 |
-
$this->_get_import_package_dir_url( $file_name ),
|
987 |
-
$this->_get_import_package_dir_path( $file_name )
|
988 |
-
);
|
989 |
-
|
990 |
-
$data = json_decode( $import_data, true );
|
991 |
-
|
992 |
-
// Data checks.
|
993 |
-
if ( 'array' != gettype( $data ) ) {
|
994 |
-
throw new Exception(
|
995 |
-
sprintf( __( 'Error importing settings! Please check that you uploaded (%s) a Settings export file.', 'jupiterx-core' ), $file_name )
|
996 |
-
);
|
997 |
-
}
|
998 |
-
if ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) {
|
999 |
-
throw new Exception(
|
1000 |
-
sprintf( __( 'Error importing settings! template Please check that you uploaded (%s) a Settings export file.', 'jupiterx-core' ), $file_name )
|
1001 |
-
);
|
1002 |
-
}
|
1003 |
-
|
1004 |
-
$data['mods'] = self::_import_images( $data['mods'] );
|
1005 |
-
|
1006 |
-
// Import custom options.
|
1007 |
-
// if ( isset( $data['options'] ) ) {
|
1008 |
-
|
1009 |
-
// foreach ( $data['options'] as $option_key => $option_value ) {
|
1010 |
-
|
1011 |
-
// $option = new JupiterX_Customizer_Option(
|
1012 |
-
// $wp_customize, $option_key, array(
|
1013 |
-
// 'default' => '',
|
1014 |
-
// 'type' => 'option',
|
1015 |
-
// 'capability' => 'edit_theme_options',
|
1016 |
-
// )
|
1017 |
-
// );
|
1018 |
-
|
1019 |
-
// $option->import( $option_value );
|
1020 |
-
// }
|
1021 |
-
// }
|
1022 |
-
|
1023 |
-
// If wp_css is set then import it.
|
1024 |
-
if ( function_exists( 'wp_update_custom_css_post' ) && isset( $data['wp_css'] ) && '' !== $data['wp_css'] ) {
|
1025 |
-
wp_update_custom_css_post( $data['wp_css'] );
|
1026 |
-
}
|
1027 |
-
|
1028 |
-
// Loop through the mods.
|
1029 |
-
foreach ( $data['mods'] as $key => $val ) {
|
1030 |
-
|
1031 |
-
// Save the mod.
|
1032 |
-
set_theme_mod( $key, $val );
|
1033 |
-
}
|
1034 |
-
|
1035 |
-
return wp_send_json_success(
|
1036 |
-
array(
|
1037 |
-
'step' => 'Settings',
|
1038 |
-
)
|
1039 |
-
);
|
1040 |
-
|
1041 |
-
} catch ( Exception $e ) {
|
1042 |
-
return wp_send_json_error( $e->getMessage() );
|
1043 |
-
}
|
1044 |
-
}
|
1045 |
-
|
1046 |
-
/**
|
1047 |
-
* End Import process by deleting Import directory and clearing theme cache.
|
1048 |
-
*
|
1049 |
-
* @since 1.0
|
1050 |
-
*/
|
1051 |
-
private function import_end() {
|
1052 |
-
try {
|
1053 |
-
|
1054 |
-
$this->jupiterx_filesystem->rmdir( $this->folder['import_dir'], true );
|
1055 |
-
|
1056 |
-
return wp_send_json_success(
|
1057 |
-
array(
|
1058 |
-
'step' => 'End',
|
1059 |
-
)
|
1060 |
-
);
|
1061 |
-
|
1062 |
-
} catch ( Exception $e ) {
|
1063 |
-
return wp_send_json_error( $e->getMessage() );
|
1064 |
-
}
|
1065 |
-
}
|
1066 |
-
|
1067 |
-
/**
|
1068 |
-
* Discard Export/Import process by deleting the the directory.
|
1069 |
-
*
|
1070 |
-
* @since 1.0
|
1071 |
-
* @param string $dir The Export/Import directory.
|
1072 |
-
*/
|
1073 |
-
private function discard( $dir ) {
|
1074 |
-
try {
|
1075 |
-
$this->jupiterx_filesystem->rmdir( $dir, true );
|
1076 |
-
|
1077 |
-
return wp_send_json_success(
|
1078 |
-
array(
|
1079 |
-
'step' => 'Discard',
|
1080 |
-
)
|
1081 |
-
);
|
1082 |
-
|
1083 |
-
} catch ( Exception $e ) {
|
1084 |
-
return wp_send_json_error( $e->getMessage() );
|
1085 |
-
}
|
1086 |
-
}
|
1087 |
-
|
1088 |
-
/**
|
1089 |
-
* Get import package directory name.
|
1090 |
-
*
|
1091 |
-
* @since 1.0
|
1092 |
-
*/
|
1093 |
-
private function _get_import_package_dir_name() {
|
1094 |
-
return end( @scandir( $this->folder['import_dir'] ) );
|
1095 |
-
}
|
1096 |
-
|
1097 |
-
/**
|
1098 |
-
* Get import package directory full path.
|
1099 |
-
*
|
1100 |
-
* @param array $$file_name The file name.
|
1101 |
-
*
|
1102 |
-
* @since 1.0
|
1103 |
-
*/
|
1104 |
-
private function _get_import_package_dir_path( $file_name ) {
|
1105 |
-
return $this->folder['import_dir'] . '/' . $this->_get_import_package_dir_name() . '/' . $file_name;
|
1106 |
-
}
|
1107 |
-
|
1108 |
-
/**
|
1109 |
-
* Get import package directory full url.
|
1110 |
-
*
|
1111 |
-
* @param array $file_name The file name.
|
1112 |
-
*
|
1113 |
-
* @since 1.0
|
1114 |
-
*/
|
1115 |
-
private function _get_import_package_dir_url( $file_name ) {
|
1116 |
-
return $this->folder['import_url'] . '/' . $this->_get_import_package_dir_name() . '/' . $file_name;
|
1117 |
-
}
|
1118 |
-
|
1119 |
-
/**
|
1120 |
-
* Imports images for settings saved as mods.
|
1121 |
-
*
|
1122 |
-
* @since 1.0
|
1123 |
-
* @access private
|
1124 |
-
* @param array $mods An array of customizer mods.
|
1125 |
-
* @return array The mods array with any new import data.
|
1126 |
-
*/
|
1127 |
-
static public function _import_images( $mods ) {
|
1128 |
-
foreach ( $mods as $key => $val ) {
|
1129 |
-
|
1130 |
-
if ( self::_is_image_url( $val ) ) {
|
1131 |
-
|
1132 |
-
$data = self::_sideload_image( $val );
|
1133 |
-
|
1134 |
-
if ( ! is_wp_error( $data ) ) {
|
1135 |
-
|
1136 |
-
$mods[ $key ] = $data->url;
|
1137 |
-
|
1138 |
-
// Handle header image controls.
|
1139 |
-
if ( isset( $mods[ $key . '_data' ] ) ) {
|
1140 |
-
$mods[ $key . '_data' ] = $data;
|
1141 |
-
update_post_meta( $data->attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
|
1142 |
-
}
|
1143 |
-
}
|
1144 |
-
}
|
1145 |
-
}
|
1146 |
-
|
1147 |
-
return $mods;
|
1148 |
-
}
|
1149 |
-
|
1150 |
-
/**
|
1151 |
-
* Taken from the core media_sideload_image function and
|
1152 |
-
* modified to return an array of data instead of html.
|
1153 |
-
*
|
1154 |
-
* @since 1.0
|
1155 |
-
* @access private
|
1156 |
-
* @param string $file The image file path.
|
1157 |
-
* @return array An array of image data.
|
1158 |
-
*/
|
1159 |
-
static private function _sideload_image( $file ) {
|
1160 |
-
$data = new stdClass();
|
1161 |
-
|
1162 |
-
if ( ! function_exists( 'media_handle_sideload' ) ) {
|
1163 |
-
require_once( ABSPATH . 'wp-admin/includes/media.php' );
|
1164 |
-
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
1165 |
-
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
1166 |
-
}
|
1167 |
-
if ( ! empty( $file ) ) {
|
1168 |
-
|
1169 |
-
// Set variables for storage, fix file filename for query strings.
|
1170 |
-
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
|
1171 |
-
$file_array = array();
|
1172 |
-
$file_array['name'] = basename( $matches[0] );
|
1173 |
-
|
1174 |
-
// Download file to temp location.
|
1175 |
-
$file_array['tmp_name'] = download_url( $file );
|
1176 |
-
|
1177 |
-
// If error storing temporarily, return the error.
|
1178 |
-
if ( is_wp_error( $file_array['tmp_name'] ) ) {
|
1179 |
-
return $file_array['tmp_name'];
|
1180 |
-
}
|
1181 |
-
|
1182 |
-
// Do the validation and storage stuff.
|
1183 |
-
$id = media_handle_sideload( $file_array, 0 );
|
1184 |
-
|
1185 |
-
// If error storing permanently, unlink.
|
1186 |
-
if ( is_wp_error( $id ) ) {
|
1187 |
-
@unlink( $file_array['tmp_name'] );
|
1188 |
-
return $id;
|
1189 |
-
}
|
1190 |
-
|
1191 |
-
// Build the object to return.
|
1192 |
-
$meta = wp_get_attachment_metadata( $id );
|
1193 |
-
$data->attachment_id = $id;
|
1194 |
-
$data->url = wp_get_attachment_url( $id );
|
1195 |
-
$data->thumbnail_url = wp_get_attachment_thumb_url( $id );
|
1196 |
-
$data->height = $meta['height'];
|
1197 |
-
$data->width = $meta['width'];
|
1198 |
-
}
|
1199 |
-
|
1200 |
-
return $data;
|
1201 |
-
}
|
1202 |
-
|
1203 |
-
/**
|
1204 |
-
* Checks to see whether a string is an image url or not.
|
1205 |
-
*
|
1206 |
-
* @since 1.0
|
1207 |
-
* @access private
|
1208 |
-
* @param string $string The string to check.
|
1209 |
-
* @return bool Whether the string is an image url or not.
|
1210 |
-
*/
|
1211 |
-
static private function _is_image_url( $string = '' ) {
|
1212 |
-
if ( is_string( $string ) ) {
|
1213 |
-
|
1214 |
-
if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
|
1215 |
-
return true;
|
1216 |
-
}
|
1217 |
-
}
|
1218 |
-
|
1219 |
-
return false;
|
1220 |
-
}
|
1221 |
-
}
|
1222 |
-
|
1223 |
-
new JupiterX_Control_Panel_Export_Import();
|
1224 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Export and Import API: JupiterX_Control_Panel_Export_Import base class
|
4 |
+
*
|
5 |
+
* @package JupiterX_Core\Control_Panel\Export_Import
|
6 |
+
* @since 1.0
|
7 |
+
*/
|
8 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Export_Import' ) ) {
|
9 |
+
/**
|
10 |
+
* Export/Import Site Content, Widgets, Settings.
|
11 |
+
*
|
12 |
+
* @author Artbees Team
|
13 |
+
* @since 1.0
|
14 |
+
* @SuppressWarnings(PHPMD.StaticAccess)
|
15 |
+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexitys)
|
16 |
+
*/
|
17 |
+
class JupiterX_Control_Panel_Export_Import {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* $jupiterx_filesystem instance.
|
21 |
+
*
|
22 |
+
* @since 1.0
|
23 |
+
* @var array
|
24 |
+
*/
|
25 |
+
private $jupiterx_filesystem;
|
26 |
+
|
27 |
+
|
28 |
+
/**
|
29 |
+
* $supported_plugins instance.
|
30 |
+
*
|
31 |
+
* @since 1.0
|
32 |
+
* @var array
|
33 |
+
*/
|
34 |
+
private $supported_plugins;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Export and Import directory’s path and url.
|
38 |
+
*
|
39 |
+
* @since 1.0
|
40 |
+
* @var array
|
41 |
+
*/
|
42 |
+
private $folder = array();
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Constructor.
|
46 |
+
*
|
47 |
+
* @since 1.0
|
48 |
+
*/
|
49 |
+
public function __construct() {
|
50 |
+
|
51 |
+
add_filter( 'jupiterx_control_panel_pane_export_import', [ $this, 'view' ] );
|
52 |
+
|
53 |
+
$upload_dir = wp_upload_dir();
|
54 |
+
$this->folder['export_url'] = $upload_dir['baseurl'] . '/jupiterx/export';
|
55 |
+
$this->folder['export_dir'] = $upload_dir['basedir'] . '/jupiterx/export';
|
56 |
+
$this->folder['import_url'] = $upload_dir['baseurl'] . '/jupiterx/import';
|
57 |
+
$this->folder['import_dir'] = $upload_dir['basedir'] . '/jupiterx/import';
|
58 |
+
|
59 |
+
$this->supported_plugins = array(
|
60 |
+
'woocommerce',
|
61 |
+
'js_composer_theme',
|
62 |
+
'LayerSlider',
|
63 |
+
'masterslider',
|
64 |
+
'revslider',
|
65 |
+
'advanced-custom-fields-pro',
|
66 |
+
'advanced-custom-fields',
|
67 |
+
'jet-elements',
|
68 |
+
'jet-menu',
|
69 |
+
'jet-popup',
|
70 |
+
'jet-tabs',
|
71 |
+
'jet-woo-builder',
|
72 |
+
'jet-tricks',
|
73 |
+
'jet-engine',
|
74 |
+
'jet-smart-filters',
|
75 |
+
'raven',
|
76 |
+
'elementor',
|
77 |
+
'customizer-reset-by-wpzoom',
|
78 |
+
'customizer-export-import',
|
79 |
+
'jupiterx-core',
|
80 |
+
'jupiterx-pro',
|
81 |
+
'menu-icons',
|
82 |
+
);
|
83 |
+
|
84 |
+
add_action( 'wp_ajax_jupiterx_cp_export_import', array( $this, 'ajax_handler' ) );
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Export/Import HTML directory.
|
89 |
+
*
|
90 |
+
* @since 1.9.0
|
91 |
+
*
|
92 |
+
* @return string
|
93 |
+
*/
|
94 |
+
public function view() {
|
95 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/export-import-content.php';
|
96 |
+
}
|
97 |
+
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Map the requests to proper methods.
|
101 |
+
*
|
102 |
+
* @since 1.0
|
103 |
+
*/
|
104 |
+
public function ajax_handler() {
|
105 |
+
check_ajax_referer( 'jupiterx_control_panel', 'nonce' );
|
106 |
+
|
107 |
+
$type = filter_input( INPUT_POST, 'type' );
|
108 |
+
$step = filter_input( INPUT_POST, 'step' );
|
109 |
+
$attachment_id = filter_input( INPUT_POST, 'attachment_id' );
|
110 |
+
|
111 |
+
if ( empty( $type ) ) {
|
112 |
+
wp_send_json_error(
|
113 |
+
__( 'Type param is missing.', 'jupiterx-core' )
|
114 |
+
);
|
115 |
+
}
|
116 |
+
|
117 |
+
if ( empty( $step ) ) {
|
118 |
+
wp_send_json_error(
|
119 |
+
__( 'Step param is missing.', 'jupiterx-core' )
|
120 |
+
);
|
121 |
+
}
|
122 |
+
|
123 |
+
if ( 'Export' === $type ) {
|
124 |
+
$this->jupiterx_filesystem = new JupiterX_Filesystem(
|
125 |
+
array(
|
126 |
+
'context' => $this->folder['export_dir'],
|
127 |
+
)
|
128 |
+
);
|
129 |
+
return $this->export( $step );
|
130 |
+
}
|
131 |
+
|
132 |
+
if ( 'Import' === $type ) {
|
133 |
+
|
134 |
+
if ( empty( $attachment_id ) ) {
|
135 |
+
wp_send_json_error(
|
136 |
+
__( 'Attachment ID param is missing.', 'jupiterx-core' )
|
137 |
+
);
|
138 |
+
}
|
139 |
+
|
140 |
+
$this->jupiterx_filesystem = new JupiterX_Filesystem(
|
141 |
+
array(
|
142 |
+
'context' => $this->folder['import_dir'],
|
143 |
+
)
|
144 |
+
);
|
145 |
+
return $this->import( $step, $attachment_id );
|
146 |
+
}
|
147 |
+
|
148 |
+
wp_send_json_error(
|
149 |
+
sprintf( __( 'Type param (%s) is not valid.', 'jupiterx-core' ), $type )
|
150 |
+
);
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Run proper export method based on step.
|
155 |
+
*
|
156 |
+
* @since 1.0
|
157 |
+
* @param string $step The export step.
|
158 |
+
* @return void
|
159 |
+
*/
|
160 |
+
private function export( $step ) {
|
161 |
+
switch ( $step ) {
|
162 |
+
case 'Start':
|
163 |
+
$this->export_start();
|
164 |
+
break;
|
165 |
+
|
166 |
+
case 'Content':
|
167 |
+
$this->export_content();
|
168 |
+
break;
|
169 |
+
|
170 |
+
case 'Widgets':
|
171 |
+
$this->export_widgets();
|
172 |
+
break;
|
173 |
+
|
174 |
+
case 'Settings':
|
175 |
+
$this->export_settings();
|
176 |
+
break;
|
177 |
+
|
178 |
+
case 'End':
|
179 |
+
$this->export_end();
|
180 |
+
break;
|
181 |
+
|
182 |
+
case 'Discard':
|
183 |
+
$this->discard( $this->folder['export_dir'] );
|
184 |
+
break;
|
185 |
+
}
|
186 |
+
|
187 |
+
wp_send_json_error(
|
188 |
+
sprintf( __( 'Step param (%s) is not valid.', 'jupiterx-core' ), $step )
|
189 |
+
);
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* Start export process by cleaning the export directory.
|
194 |
+
*
|
195 |
+
* @throws Exception If can not clean export folder.
|
196 |
+
*
|
197 |
+
* @since 1.0
|
198 |
+
*/
|
199 |
+
private function export_start() {
|
200 |
+
try {
|
201 |
+
if ( $this->jupiterx_filesystem->rmdir( $this->folder['export_dir'], true ) ) {
|
202 |
+
return wp_send_json_success(
|
203 |
+
array(
|
204 |
+
'step' => 'Start',
|
205 |
+
)
|
206 |
+
);
|
207 |
+
}
|
208 |
+
|
209 |
+
throw new Exception( __( 'A problem occurred in cleaning export directory.', 'jupiterx-core' ) );
|
210 |
+
} catch ( Exception $e ) {
|
211 |
+
return wp_send_json_error( $e->getMessage() );
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Export content.
|
217 |
+
*
|
218 |
+
* @throws Exception If can not export Content.
|
219 |
+
*
|
220 |
+
* @since 1.0
|
221 |
+
*/
|
222 |
+
private function export_content() {
|
223 |
+
try {
|
224 |
+
require_once ABSPATH . 'wp-admin/includes/export.php';
|
225 |
+
|
226 |
+
ob_start();
|
227 |
+
export_wp();
|
228 |
+
$content = ob_get_clean();
|
229 |
+
ob_end_clean();
|
230 |
+
|
231 |
+
$file_name = 'theme_content.xml';
|
232 |
+
$file_path = $this->folder['export_dir'] . '/' . $file_name;
|
233 |
+
|
234 |
+
if ( ! $this->jupiterx_filesystem->put_contents( $file_path, $content ) ) {
|
235 |
+
throw new Exception( __( 'A problem occurred in exporting Content.', 'jupiterx-core' ) );
|
236 |
+
}
|
237 |
+
|
238 |
+
$this->export_plugins();
|
239 |
+
|
240 |
+
return wp_send_json_success(
|
241 |
+
array(
|
242 |
+
'step' => 'Content',
|
243 |
+
)
|
244 |
+
);
|
245 |
+
} catch ( Exception $e ) {
|
246 |
+
return wp_send_json_error( $e->getMessage() );
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Export plugins content.
|
252 |
+
*
|
253 |
+
* @since 1.0.3
|
254 |
+
*/
|
255 |
+
public function export_plugins() {
|
256 |
+
$active_plugins = get_option( 'active_plugins' );
|
257 |
+
|
258 |
+
if ( is_multisite() ) {
|
259 |
+
$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins' ) );
|
260 |
+
}
|
261 |
+
|
262 |
+
foreach ( $active_plugins as $plugin ) {
|
263 |
+
$plugins_slug[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
264 |
+
}
|
265 |
+
|
266 |
+
$supported_plugins = array_intersect( $plugins_slug, $this->supported_plugins );
|
267 |
+
|
268 |
+
foreach ( $supported_plugins as $plugin ) {
|
269 |
+
if ( is_callable( [ $this, "export_{$plugin}_content" ] ) ) {
|
270 |
+
call_user_func( [ $this, "export_{$plugin}_content" ] );
|
271 |
+
}
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Export Revolution Slider slides.
|
277 |
+
*
|
278 |
+
* @since 1.0.3
|
279 |
+
*/
|
280 |
+
public function export_revslider_content() {
|
281 |
+
if ( ! class_exists( 'RevSlider' ) ) {
|
282 |
+
return;
|
283 |
+
}
|
284 |
+
|
285 |
+
// Initialize Revolution Slider.
|
286 |
+
$revslider = new RevSlider();
|
287 |
+
|
288 |
+
$sliders = $revslider->getAllSliderAliases();
|
289 |
+
|
290 |
+
if ( empty( $sliders ) ) {
|
291 |
+
return;
|
292 |
+
}
|
293 |
+
|
294 |
+
// Create download url.
|
295 |
+
$base_arg = [
|
296 |
+
'action' => 'revslider_ajax_action',
|
297 |
+
'client_action' => 'export_slider',
|
298 |
+
'dummy' => 'false',
|
299 |
+
'nonce' => wp_create_nonce( 'revslider_actions' ),
|
300 |
+
];
|
301 |
+
|
302 |
+
$base_url = add_query_arg( $base_arg, admin_url( 'admin-ajax.php' ) );
|
303 |
+
|
304 |
+
$export_dir = "{$this->folder['export_dir']}/revslider/";
|
305 |
+
|
306 |
+
// Create and pass cookie.
|
307 |
+
$cookies = [];
|
308 |
+
|
309 |
+
foreach ( $_COOKIE as $name => $value ) {
|
310 |
+
$cookies[] = new WP_Http_Cookie( array( 'name' => $name, 'value' => $value ) );
|
311 |
+
}
|
312 |
+
|
313 |
+
$remote_args = [
|
314 |
+
'cookies' => $cookies,
|
315 |
+
];
|
316 |
+
|
317 |
+
// Go through each slides.
|
318 |
+
foreach ( $sliders as $slider_alias ) {
|
319 |
+
$revslider->initByAlias( $slider_alias );
|
320 |
+
|
321 |
+
$download_args = [
|
322 |
+
'sliderid' => $revslider->getID(),
|
323 |
+
];
|
324 |
+
|
325 |
+
$download_url = add_query_arg( $download_args, $base_url );
|
326 |
+
|
327 |
+
JupiterX_Control_Panel_Helpers::upload_from_url(
|
328 |
+
$download_url,
|
329 |
+
"{$slider_alias}.zip",
|
330 |
+
$export_dir,
|
331 |
+
$remote_args
|
332 |
+
);
|
333 |
+
}
|
334 |
+
}
|
335 |
+
|
336 |
+
public function availableWidgets() {
|
337 |
+
global $wp_registered_widget_controls;
|
338 |
+
$widget_controls = $wp_registered_widget_controls;
|
339 |
+
$available_widgets = array();
|
340 |
+
foreach ( $widget_controls as $widget ) {
|
341 |
+
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
|
342 |
+
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
343 |
+
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
344 |
+
}
|
345 |
+
}
|
346 |
+
|
347 |
+
return apply_filters( 'available_widgets', $available_widgets );
|
348 |
+
}
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Export widgets.
|
352 |
+
*
|
353 |
+
* @throws Exception If can not export Widgets.
|
354 |
+
*
|
355 |
+
* @since 1.0
|
356 |
+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
357 |
+
*/
|
358 |
+
private function export_widgets() {
|
359 |
+
try {
|
360 |
+
$available_widgets = $this->availableWidgets();
|
361 |
+
|
362 |
+
// Get all widget instances for each widget.
|
363 |
+
$widget_instances = array();
|
364 |
+
|
365 |
+
// Loop widgets.
|
366 |
+
foreach ( $available_widgets as $widget_data ) {
|
367 |
+
// Get all instances for this ID base.
|
368 |
+
$instances = get_option( 'widget_' . $widget_data['id_base'] );
|
369 |
+
// Have instances.
|
370 |
+
if ( ! empty( $instances ) ) {
|
371 |
+
// Loop instances.
|
372 |
+
foreach ( $instances as $instance_id => $instance_data ) {
|
373 |
+
// Key is ID (not _multiwidget).
|
374 |
+
if ( is_numeric( $instance_id ) ) {
|
375 |
+
$unique_instance_id = $widget_data['id_base'] . '-' . $instance_id;
|
376 |
+
$widget_instances[ $unique_instance_id ] = $instance_data;
|
377 |
+
}
|
378 |
+
}
|
379 |
+
}
|
380 |
+
}
|
381 |
+
|
382 |
+
// Gather sidebars with their widget instances.
|
383 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
384 |
+
$sidebars_widget_ins = array();
|
385 |
+
foreach ( $sidebars_widgets as $sidebar_id => $widget_ids ) {
|
386 |
+
|
387 |
+
// Skip inactive widgets.
|
388 |
+
if ( 'wp_inactive_widgets' === $sidebar_id ) {
|
389 |
+
continue;
|
390 |
+
}
|
391 |
+
|
392 |
+
// Skip if no data or not an array (array_version).
|
393 |
+
if ( ! is_array( $widget_ids ) || empty( $widget_ids ) ) {
|
394 |
+
continue;
|
395 |
+
}
|
396 |
+
|
397 |
+
// Loop widget IDs for this sidebar.
|
398 |
+
foreach ( $widget_ids as $widget_id ) {
|
399 |
+
// Is there an instance for this widget ID?
|
400 |
+
if ( isset( $widget_instances[ $widget_id ] ) ) {
|
401 |
+
// Add to array.
|
402 |
+
$sidebars_widget_ins[ $sidebar_id ][ $widget_id ] = $widget_instances[ $widget_id ];
|
403 |
+
}
|
404 |
+
}
|
405 |
+
}
|
406 |
+
|
407 |
+
$content = wp_json_encode( $sidebars_widget_ins );
|
408 |
+
|
409 |
+
$file_name = 'widget_data.wie';
|
410 |
+
$file_path = $this->folder['export_dir'] . '/' . $file_name;
|
411 |
+
|
412 |
+
if ( $this->jupiterx_filesystem->put_contents( $file_path, $content ) ) {
|
413 |
+
return wp_send_json_success(
|
414 |
+
array(
|
415 |
+
'step' => 'Widgets',
|
416 |
+
)
|
417 |
+
);
|
418 |
+
}
|
419 |
+
|
420 |
+
throw new Exception( __( 'A problem occurred in exporting widgets.', 'jupiterx-core' ) );
|
421 |
+
} catch ( Exception $e ) {
|
422 |
+
return wp_send_json_error( $e->getMessage() );
|
423 |
+
} // End try().
|
424 |
+
}
|
425 |
+
|
426 |
+
|
427 |
+
/**
|
428 |
+
* An array of core options that shouldn't be imported.
|
429 |
+
*
|
430 |
+
* @since 1.0
|
431 |
+
* @access private
|
432 |
+
* @var array $core_options
|
433 |
+
*/
|
434 |
+
static private $core_options = array(
|
435 |
+
'blogname',
|
436 |
+
'blogdescription'
|
437 |
+
);
|
438 |
+
|
439 |
+
|
440 |
+
/**
|
441 |
+
* Export Settings.
|
442 |
+
*
|
443 |
+
* @throws Exception If can not export Settings.
|
444 |
+
*
|
445 |
+
* @since 1.0
|
446 |
+
*/
|
447 |
+
private function export_settings() {
|
448 |
+
try {
|
449 |
+
$data = [
|
450 |
+
'template' => get_template(),
|
451 |
+
'mods' => [],
|
452 |
+
'options' => [],
|
453 |
+
];
|
454 |
+
|
455 |
+
$data = $this->_export_settings_customizer_mods( $data );
|
456 |
+
|
457 |
+
$data = $this->_export_settings_customizer_options( $data );
|
458 |
+
|
459 |
+
$data = $this->_export_settings_plugins( $data );
|
460 |
+
|
461 |
+
$data = $this->_export_settings_options( $data );
|
462 |
+
|
463 |
+
// WP custom CSS.
|
464 |
+
if ( function_exists( 'wp_get_custom_css_post' ) ) {
|
465 |
+
$data['wp_css'] = wp_get_custom_css();
|
466 |
+
}
|
467 |
+
|
468 |
+
$file_name = 'settings.json';
|
469 |
+
$file_path = $this->folder['export_dir'] . '/' . $file_name;
|
470 |
+
|
471 |
+
if ( ! is_array( $data ) ) {
|
472 |
+
throw new Exception( __( 'All settings in Settings are set to default. Uncheck the Settings option or change one setting in Settings then export.', 'jupiterx-core' ) );
|
473 |
+
}
|
474 |
+
|
475 |
+
if ( ! $this->jupiterx_filesystem->put_contents( $file_path, wp_json_encode( $data ) ) ) {
|
476 |
+
throw new Exception( __( 'A problem occurred in exporting Settings.', 'jupiterx-core' ) );
|
477 |
+
}
|
478 |
+
|
479 |
+
return wp_send_json_success( [ 'step' => 'Settings' ] );
|
480 |
+
|
481 |
+
} catch ( Exception $e ) {
|
482 |
+
return wp_send_json_error( $e->getMessage() );
|
483 |
+
}
|
484 |
+
}
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Export customizer mods.
|
488 |
+
*
|
489 |
+
* @since 1.0.4
|
490 |
+
*/
|
491 |
+
private function _export_settings_customizer_mods( $data ) {
|
492 |
+
$mods = get_theme_mods();
|
493 |
+
|
494 |
+
if ( ! empty( $mods ) ) {
|
495 |
+
unset( $mods['sidebars_widgets'] );
|
496 |
+
$data['mods'] = $mods;
|
497 |
+
}
|
498 |
+
|
499 |
+
return $data;
|
500 |
+
}
|
501 |
+
|
502 |
+
/**
|
503 |
+
* Export customizer options.
|
504 |
+
*
|
505 |
+
* @since 1.0.4
|
506 |
+
*/
|
507 |
+
private function _export_settings_customizer_options( $data ) {
|
508 |
+
require_once ABSPATH . 'wp-includes/class-wp-customize-manager.php';
|
509 |
+
|
510 |
+
$wp_customize = new WP_Customize_Manager();
|
511 |
+
$settings = $wp_customize->settings();
|
512 |
+
|
513 |
+
foreach ( $settings as $key => $setting ) {
|
514 |
+
if ( 'option' == $setting->type ) {
|
515 |
+
|
516 |
+
// Don't save widget data.
|
517 |
+
if ( stristr( $key, 'widget_' ) ) {
|
518 |
+
continue;
|
519 |
+
}
|
520 |
+
|
521 |
+
// Don't save sidebar data.
|
522 |
+
if ( stristr( $key, 'sidebars_' ) ) {
|
523 |
+
continue;
|
524 |
+
}
|
525 |
+
|
526 |
+
// Don't save core options.
|
527 |
+
if ( in_array( $key, self::$core_options ) ) {
|
528 |
+
continue;
|
529 |
+
}
|
530 |
+
|
531 |
+
$data['options'][ $key ] = $setting->value();
|
532 |
+
}
|
533 |
+
}
|
534 |
+
|
535 |
+
return $data;
|
536 |
+
}
|
537 |
+
|
538 |
+
/**
|
539 |
+
* Export active supported plugins.
|
540 |
+
*
|
541 |
+
* @since 1.0.4
|
542 |
+
*/
|
543 |
+
private function _export_settings_plugins( $data ) {
|
544 |
+
$all_active_plugins = get_option( 'active_plugins' );
|
545 |
+
|
546 |
+
foreach ( $all_active_plugins as $plugin ) {
|
547 |
+
$active_plugins[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
548 |
+
}
|
549 |
+
|
550 |
+
if ( is_multisite() ) {
|
551 |
+
$sitewide_all_active_plugins = get_site_option( 'active_sitewide_plugins' );
|
552 |
+
|
553 |
+
foreach ( $sitewide_all_active_plugins as $plugin => $id ) {
|
554 |
+
$active_plugins[] = substr( $plugin, 0, strrpos( $plugin, '/' ) );
|
555 |
+
}
|
556 |
+
}
|
557 |
+
|
558 |
+
$supported_active_plugins = array_intersect( $active_plugins, $this->supported_plugins );
|
559 |
+
|
560 |
+
foreach ( $supported_active_plugins as $plugins ) {
|
561 |
+
$data['options']['jupiterx_support_plugins'][] = $plugins;
|
562 |
+
}
|
563 |
+
|
564 |
+
return $data;
|
565 |
+
}
|
566 |
+
|
567 |
+
/**
|
568 |
+
* Export options.
|
569 |
+
*
|
570 |
+
* @since 1.0.4
|
571 |
+
*/
|
572 |
+
private function _export_settings_options( $data ) {
|
573 |
+
/**
|
574 |
+
* Extra options.
|
575 |
+
*
|
576 |
+
* Any option that can be exported & imported without modifications.
|
577 |
+
*/
|
578 |
+
$option_keys = apply_filters( 'jupiterx_extra_export_option_keys', [
|
579 |
+
'elementor_scheme_color',
|
580 |
+
'elementor_scheme_typography',
|
581 |
+
'elementor_scheme_color-picker',
|
582 |
+
'elementor_cpt_support',
|
583 |
+
'elementor_disable_color_schemes',
|
584 |
+
'elementor_disable_typography_schemes',
|
585 |
+
'elementor_default_generic_fonts',
|
586 |
+
'elementor_container_width',
|
587 |
+
'elementor_space_between_widgets',
|
588 |
+
'elementor_stretched_section_container',
|
589 |
+
'elementor_page_title_selector',
|
590 |
+
'elementor_viewport_lg',
|
591 |
+
'elementor_viewport_md',
|
592 |
+
'elementor_global_image_lightbox',
|
593 |
+
'elementor_lightbox_color',
|
594 |
+
'elementor_lightbox_ui_color',
|
595 |
+
'elementor_lightbox_ui_color_hover',
|
596 |
+
'elementor_enable_lightbox_in_editor',
|
597 |
+
'elementor_global_image_lightbox',
|
598 |
+
] );
|
599 |
+
|
600 |
+
foreach ( $option_keys as $option_key ) {
|
601 |
+
$option = get_option( $option_key, null );
|
602 |
+
|
603 |
+
if ( ! is_null( $option ) ) {
|
604 |
+
$data['options']['extra'][ $option_key ] = $option;
|
605 |
+
}
|
606 |
+
}
|
607 |
+
|
608 |
+
// Front page.
|
609 |
+
$page_on_front = get_option( 'page_on_front' );
|
610 |
+
|
611 |
+
if ( ! empty( $page_on_front ) ) {
|
612 |
+
$data['options']['page_on_front'] = get_the_title( $page_on_front );
|
613 |
+
}
|
614 |
+
|
615 |
+
// Menu locations.
|
616 |
+
$get_nav_locations = get_theme_mod( 'nav_menu_locations' );
|
617 |
+
|
618 |
+
foreach ( $get_nav_locations as $location => $id ) {
|
619 |
+
$get_term = get_term_by( 'id', $id, 'nav_menu' );
|
620 |
+
$data['options']['jupiterx_menu_locations'][ $location ] = $get_term->name;
|
621 |
+
}
|
622 |
+
|
623 |
+
// WooCommerce.
|
624 |
+
$woocommerce_shop_page_id = get_option( 'woocommerce_shop_page_id' );
|
625 |
+
|
626 |
+
if ( ! empty( $woocommerce_shop_page_id ) ) {
|
627 |
+
$data['options']['woocommerce_shop_page_id'] = get_the_title( $woocommerce_shop_page_id );
|
628 |
+
}
|
629 |
+
|
630 |
+
$woocommerce_cart_page_id = get_option( 'woocommerce_cart_page_id' );
|
631 |
+
|
632 |
+
if ( ! empty( $woocommerce_cart_page_id ) ) {
|
633 |
+
$data['options']['woocommerce_cart_page_id'] = get_the_title( $woocommerce_cart_page_id );
|
634 |
+
}
|
635 |
+
|
636 |
+
$woocommerce_checkout_page_id = get_option( 'woocommerce_checkout_page_id' );
|
637 |
+
|
638 |
+
if ( ! empty( $woocommerce_checkout_page_id ) ) {
|
639 |
+
$data['options']['woocommerce_checkout_page_id'] = get_the_title( $woocommerce_checkout_page_id );
|
640 |
+
}
|
641 |
+
|
642 |
+
$woocommerce_myaccount_page_id = get_option( 'woocommerce_myaccount_page_id' );
|
643 |
+
|
644 |
+
if ( ! empty( $woocommerce_checkout_page_id ) ) {
|
645 |
+
$data['options']['woocommerce_myaccount_page_id'] = get_the_title( $woocommerce_myaccount_page_id );
|
646 |
+
}
|
647 |
+
|
648 |
+
// Jet Menu.
|
649 |
+
$jet_menu_options = get_option( 'jet_menu_options' );
|
650 |
+
|
651 |
+
if ( ! empty( $jet_menu_options ) && in_array( 'jet-menu', $data['options']['jupiterx_support_plugins'], true ) ) {
|
652 |
+
$data['options']['jet_menu_options'] = $jet_menu_options;
|
653 |
+
}
|
654 |
+
|
655 |
+
return $data;
|
656 |
+
}
|
657 |
+
|
658 |
+
/**
|
659 |
+
* End export process by creating the zip file and download url.
|
660 |
+
*
|
661 |
+
* @since 1.0
|
662 |
+
*/
|
663 |
+
private function export_end() {
|
664 |
+
try {
|
665 |
+
$this->jupiterx_filesystem->zip_folder( $this->folder['export_dir'], "{$this->folder['export_dir']}/{$this->_prepare_directory_name()}.zip", $this->_prepare_directory_name() );
|
666 |
+
|
667 |
+
return wp_send_json_success(
|
668 |
+
array(
|
669 |
+
'step' => 'End',
|
670 |
+
'download_url' => $this->folder['export_url'] . '/' . $this->_prepare_directory_name() . '.zip',
|
671 |
+
)
|
672 |
+
);
|
673 |
+
|
674 |
+
} catch ( Exception $e ) {
|
675 |
+
return wp_send_json_error( $e->getMessage() );
|
676 |
+
}
|
677 |
+
}
|
678 |
+
|
679 |
+
/**
|
680 |
+
* Prepare the export zip file name.
|
681 |
+
*
|
682 |
+
* @since 1.0.0
|
683 |
+
*/
|
684 |
+
private function _prepare_directory_name() {
|
685 |
+
$site_title = ! empty( get_bloginfo( 'name' ) ) ? get_bloginfo( 'name' ) : 'package';
|
686 |
+
$form_data = jupiterx_post( 'data' );
|
687 |
+
|
688 |
+
if ( ! empty( $form_data['filename'] ) ) {
|
689 |
+
return sanitize_title( $form_data['filename'] );
|
690 |
+
}
|
691 |
+
|
692 |
+
return sanitize_title( $site_title ) . '-jupiterx';
|
693 |
+
}
|
694 |
+
|
695 |
+
/**
|
696 |
+
* Run proper import method based on step.
|
697 |
+
*
|
698 |
+
* @since 1.0
|
699 |
+
* @param string $step The import step.
|
700 |
+
* @param integer $attachment_id The uploaded zip file ID.
|
701 |
+
* @return void
|
702 |
+
*/
|
703 |
+
private function import( $step, $attachment_id ) {
|
704 |
+
switch ( $step ) {
|
705 |
+
case 'Start':
|
706 |
+
$this->import_start( $attachment_id );
|
707 |
+
break;
|
708 |
+
|
709 |
+
case 'Content':
|
710 |
+
$this->import_content();
|
711 |
+
break;
|
712 |
+
|
713 |
+
case 'Widgets':
|
714 |
+
$this->import_widgets();
|
715 |
+
break;
|
716 |
+
|
717 |
+
case 'Settings':
|
718 |
+
$this->import_settings();
|
719 |
+
break;
|
720 |
+
|
721 |
+
case 'End':
|
722 |
+
$this->import_end();
|
723 |
+
break;
|
724 |
+
|
725 |
+
case 'Discard':
|
726 |
+
$this->discard( $this->folder['import_dir'] );
|
727 |
+
break;
|
728 |
+
}
|
729 |
+
|
730 |
+
wp_send_json_error(
|
731 |
+
sprintf( __( 'Step param (%s) is not valid.', 'jupiterx-core' ), $step )
|
732 |
+
);
|
733 |
+
}
|
734 |
+
|
735 |
+
/**
|
736 |
+
* Start import process by cleaning import directory and
|
737 |
+
* unzipping file to directory Import directory.
|
738 |
+
*
|
739 |
+
* @since 1.0
|
740 |
+
* @param integer $attachment_id The uploaded zip file ID.
|
741 |
+
*/
|
742 |
+
private function import_start( $attachment_id ) {
|
743 |
+
try {
|
744 |
+
$this->jupiterx_filesystem->rmdir( $this->folder['import_dir'], true );
|
745 |
+
|
746 |
+
$this->jupiterx_filesystem->unzip_custom(
|
747 |
+
get_attached_file( $attachment_id ),
|
748 |
+
$this->folder['import_dir']
|
749 |
+
);
|
750 |
+
|
751 |
+
return wp_send_json_success(
|
752 |
+
array(
|
753 |
+
'step' => 'Start',
|
754 |
+
)
|
755 |
+
);
|
756 |
+
} catch ( Exception $e ) {
|
757 |
+
return wp_send_json_error( $e->getMessage() );
|
758 |
+
}
|
759 |
+
}
|
760 |
+
|
761 |
+
/**
|
762 |
+
* Import Content
|
763 |
+
*
|
764 |
+
* @throws Exception If required file is missing.
|
765 |
+
* @throws Exception If can not parse file..
|
766 |
+
*
|
767 |
+
* @since 1.0
|
768 |
+
*/
|
769 |
+
private function import_content() {
|
770 |
+
try {
|
771 |
+
$file_name = 'theme_content.xml';
|
772 |
+
$file = $this->_get_import_package_dir_path( $file_name );
|
773 |
+
$fetch_attachments = true;
|
774 |
+
|
775 |
+
if ( ! file_exists( $file ) ) {
|
776 |
+
throw new Exception(
|
777 |
+
sprintf( __( 'A required file (%s) is missing in the selected zip file.', 'jupiterx-core' ), $file_name )
|
778 |
+
);
|
779 |
+
}
|
780 |
+
|
781 |
+
// Include wordpress-importer class.
|
782 |
+
JupiterX_Control_Panel_Helpers::include_wordpress_importer();
|
783 |
+
|
784 |
+
$options = array(
|
785 |
+
'fetch_attachments' => filter_var( $fetch_attachments, FILTER_VALIDATE_BOOLEAN ),
|
786 |
+
'default_author' => get_current_user_id(),
|
787 |
+
);
|
788 |
+
|
789 |
+
// Create new instance for Importer.
|
790 |
+
$importer = new JupiterX_WXR_Importer( $options );
|
791 |
+
$logger = new JupiterX_Importer_Logger_ServerSentEvents();
|
792 |
+
$importer->set_logger( $logger );
|
793 |
+
|
794 |
+
$data = $importer->get_preliminary_information( $file );
|
795 |
+
|
796 |
+
if ( is_wp_error( $data ) ) {
|
797 |
+
throw new Exception(
|
798 |
+
sprintf( __( 'Error in parsing %s.', 'jupiterx-core' ), $file_name )
|
799 |
+
);
|
800 |
+
}
|
801 |
+
|
802 |
+
// Run import process.
|
803 |
+
ob_start();
|
804 |
+
$importer->import( $file );
|
805 |
+
ob_end_clean();
|
806 |
+
|
807 |
+
return wp_send_json_success(
|
808 |
+
array(
|
809 |
+
'step' => 'Content',
|
810 |
+
)
|
811 |
+
);
|
812 |
+
|
813 |
+
} catch ( Exception $e ) {
|
814 |
+
return wp_send_json_error( $e->getMessage() );
|
815 |
+
} // End try().
|
816 |
+
}
|
817 |
+
|
818 |
+
/**
|
819 |
+
* Import widgets' data.
|
820 |
+
*
|
821 |
+
* @throws Exception If can not read widget data.
|
822 |
+
*
|
823 |
+
* @since 5.7.0
|
824 |
+
* 6.0.4 Make it public.
|
825 |
+
* @param array $data Widgets' data.
|
826 |
+
* @return boolean
|
827 |
+
*/
|
828 |
+
public function import_widget_data( $data ) {
|
829 |
+
global $wp_registered_sidebars;
|
830 |
+
|
831 |
+
$available_widgets = $this->availableWidgets();
|
832 |
+
$widget_instances = array();
|
833 |
+
foreach ( $available_widgets as $widget_data ) {
|
834 |
+
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
835 |
+
}
|
836 |
+
if ( empty( $data ) || ! is_object( $data ) ) {
|
837 |
+
throw new Exception( 'Widget data could not be read. Please try a different file.' );
|
838 |
+
}
|
839 |
+
$results = array();
|
840 |
+
foreach ( $data as $sidebar_id => $widgets ) {
|
841 |
+
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
842 |
+
continue;
|
843 |
+
}
|
844 |
+
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
845 |
+
$sidebar_available = true;
|
846 |
+
$use_sidebar_id = $sidebar_id;
|
847 |
+
$sidebar_message_type = 'success';
|
848 |
+
$sidebar_message = '';
|
849 |
+
} else {
|
850 |
+
$sidebar_available = false;
|
851 |
+
$use_sidebar_id = 'wp_inactive_widgets';
|
852 |
+
$sidebar_message_type = 'error';
|
853 |
+
$sidebar_message = 'Sidebar does not exist in theme (using Inactive)';
|
854 |
+
}
|
855 |
+
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id;
|
856 |
+
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
857 |
+
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
858 |
+
$results[ $sidebar_id ]['widgets'] = array();
|
859 |
+
foreach ( $widgets as $widget_instance_id => $widget ) {
|
860 |
+
$fail = false;
|
861 |
+
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
862 |
+
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
863 |
+
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
864 |
+
$fail = true;
|
865 |
+
$widget_message_type = 'error';
|
866 |
+
$widget_message = 'Site does not support widget';
|
867 |
+
}
|
868 |
+
$widget = apply_filters( 'jupiterx_widget_settings', $widget );
|
869 |
+
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
870 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
871 |
+
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array();
|
872 |
+
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
873 |
+
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
874 |
+
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
875 |
+
$fail = true;
|
876 |
+
$widget_message_type = 'warning';
|
877 |
+
$widget_message = 'Widget already exists';
|
878 |
+
break;
|
879 |
+
}
|
880 |
+
}
|
881 |
+
}
|
882 |
+
if ( ! $fail ) {
|
883 |
+
$single_widget_instances = get_option( 'widget_' . $id_base );
|
884 |
+
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array(
|
885 |
+
'_multiwidget' => 1,
|
886 |
+
);
|
887 |
+
$single_widget_instances[] = (array) $widget;
|
888 |
+
end( $single_widget_instances );
|
889 |
+
$new_instance_id_number = key( $single_widget_instances );
|
890 |
+
if ( '0' === strval( $new_instance_id_number ) ) {
|
891 |
+
$new_instance_id_number = 1;
|
892 |
+
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
893 |
+
unset( $single_widget_instances[0] );
|
894 |
+
}
|
895 |
+
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
896 |
+
$multiwidget = $single_widget_instances['_multiwidget'];
|
897 |
+
unset( $single_widget_instances['_multiwidget'] );
|
898 |
+
$single_widget_instances['_multiwidget'] = $multiwidget;
|
899 |
+
}
|
900 |
+
update_option( 'widget_' . $id_base, $single_widget_instances );
|
901 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
902 |
+
$new_instance_id = $id_base . '-' . $new_instance_id_number;
|
903 |
+
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id;
|
904 |
+
update_option( 'sidebars_widgets', $sidebars_widgets );
|
905 |
+
if ( $sidebar_available ) {
|
906 |
+
$widget_message_type = 'success';
|
907 |
+
$widget_message = 'Imported';
|
908 |
+
} else {
|
909 |
+
$widget_message_type = 'warning';
|
910 |
+
$widget_message = 'Imported to Inactive';
|
911 |
+
}
|
912 |
+
}
|
913 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base;
|
914 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget->title ) ? $widget->title : '';
|
915 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
916 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
917 |
+
} // End foreach().
|
918 |
+
} // End foreach().
|
919 |
+
|
920 |
+
return true;
|
921 |
+
}
|
922 |
+
|
923 |
+
/**
|
924 |
+
* Import Widgets.
|
925 |
+
*
|
926 |
+
* @throws Exception If required file is missing.
|
927 |
+
* @throws Exception If can not import Widgets.
|
928 |
+
*
|
929 |
+
* @since 1.0
|
930 |
+
*/
|
931 |
+
private function import_widgets() {
|
932 |
+
try {
|
933 |
+
$file_name = 'widget_data.wie';
|
934 |
+
|
935 |
+
if ( ! file_exists( $this->_get_import_package_dir_path( $file_name ) ) ) {
|
936 |
+
throw new Exception(
|
937 |
+
sprintf( __( 'A required file (%s) is missing in the selected zip file.', 'jupiterx-core' ), $file_name )
|
938 |
+
);
|
939 |
+
}
|
940 |
+
|
941 |
+
$import_data = JupiterX_Control_Panel_Helpers::getFileBody(
|
942 |
+
$this->_get_import_package_dir_url( $file_name ),
|
943 |
+
$this->_get_import_package_dir_path( $file_name )
|
944 |
+
);
|
945 |
+
|
946 |
+
$data = json_decode( $import_data );
|
947 |
+
|
948 |
+
if ( ! $this->import_widget_data( $data ) ) {
|
949 |
+
throw new Exception( __( 'A problem occurred in importing Widgets.', 'jupiterx-core' ) );
|
950 |
+
}
|
951 |
+
|
952 |
+
return wp_send_json_success(
|
953 |
+
array(
|
954 |
+
'step' => 'Widgets',
|
955 |
+
)
|
956 |
+
);
|
957 |
+
|
958 |
+
} catch ( Exception $e ) {
|
959 |
+
return wp_send_json_error( $e->getMessage() );
|
960 |
+
}
|
961 |
+
}
|
962 |
+
|
963 |
+
/**
|
964 |
+
* Import Settings.
|
965 |
+
*
|
966 |
+
* @throws Exception If required file is missing.
|
967 |
+
* @throws Exception If can not import Settings.
|
968 |
+
*
|
969 |
+
* @since 1.0
|
970 |
+
*/
|
971 |
+
private function import_settings() {
|
972 |
+
try {
|
973 |
+
|
974 |
+
require_once ABSPATH . 'wp-includes/class-wp-customize-manager.php';
|
975 |
+
$wp_customize = new WP_Customize_Manager();
|
976 |
+
|
977 |
+
$file_name = 'settings.json';
|
978 |
+
|
979 |
+
if ( ! file_exists( $this->_get_import_package_dir_path( $file_name ) ) ) {
|
980 |
+
throw new Exception(
|
981 |
+
sprintf( __( '%s is missing in the selected zip file.', 'jupiterx-core' ), $file_name )
|
982 |
+
);
|
983 |
+
}
|
984 |
+
|
985 |
+
$import_data = JupiterX_Control_Panel_Helpers::getFileBody(
|
986 |
+
$this->_get_import_package_dir_url( $file_name ),
|
987 |
+
$this->_get_import_package_dir_path( $file_name )
|
988 |
+
);
|
989 |
+
|
990 |
+
$data = json_decode( $import_data, true );
|
991 |
+
|
992 |
+
// Data checks.
|
993 |
+
if ( 'array' != gettype( $data ) ) {
|
994 |
+
throw new Exception(
|
995 |
+
sprintf( __( 'Error importing settings! Please check that you uploaded (%s) a Settings export file.', 'jupiterx-core' ), $file_name )
|
996 |
+
);
|
997 |
+
}
|
998 |
+
if ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) {
|
999 |
+
throw new Exception(
|
1000 |
+
sprintf( __( 'Error importing settings! template Please check that you uploaded (%s) a Settings export file.', 'jupiterx-core' ), $file_name )
|
1001 |
+
);
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
$data['mods'] = self::_import_images( $data['mods'] );
|
1005 |
+
|
1006 |
+
// Import custom options.
|
1007 |
+
// if ( isset( $data['options'] ) ) {
|
1008 |
+
|
1009 |
+
// foreach ( $data['options'] as $option_key => $option_value ) {
|
1010 |
+
|
1011 |
+
// $option = new JupiterX_Customizer_Option(
|
1012 |
+
// $wp_customize, $option_key, array(
|
1013 |
+
// 'default' => '',
|
1014 |
+
// 'type' => 'option',
|
1015 |
+
// 'capability' => 'edit_theme_options',
|
1016 |
+
// )
|
1017 |
+
// );
|
1018 |
+
|
1019 |
+
// $option->import( $option_value );
|
1020 |
+
// }
|
1021 |
+
// }
|
1022 |
+
|
1023 |
+
// If wp_css is set then import it.
|
1024 |
+
if ( function_exists( 'wp_update_custom_css_post' ) && isset( $data['wp_css'] ) && '' !== $data['wp_css'] ) {
|
1025 |
+
wp_update_custom_css_post( $data['wp_css'] );
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
// Loop through the mods.
|
1029 |
+
foreach ( $data['mods'] as $key => $val ) {
|
1030 |
+
|
1031 |
+
// Save the mod.
|
1032 |
+
set_theme_mod( $key, $val );
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
return wp_send_json_success(
|
1036 |
+
array(
|
1037 |
+
'step' => 'Settings',
|
1038 |
+
)
|
1039 |
+
);
|
1040 |
+
|
1041 |
+
} catch ( Exception $e ) {
|
1042 |
+
return wp_send_json_error( $e->getMessage() );
|
1043 |
+
}
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
/**
|
1047 |
+
* End Import process by deleting Import directory and clearing theme cache.
|
1048 |
+
*
|
1049 |
+
* @since 1.0
|
1050 |
+
*/
|
1051 |
+
private function import_end() {
|
1052 |
+
try {
|
1053 |
+
|
1054 |
+
$this->jupiterx_filesystem->rmdir( $this->folder['import_dir'], true );
|
1055 |
+
|
1056 |
+
return wp_send_json_success(
|
1057 |
+
array(
|
1058 |
+
'step' => 'End',
|
1059 |
+
)
|
1060 |
+
);
|
1061 |
+
|
1062 |
+
} catch ( Exception $e ) {
|
1063 |
+
return wp_send_json_error( $e->getMessage() );
|
1064 |
+
}
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
/**
|
1068 |
+
* Discard Export/Import process by deleting the the directory.
|
1069 |
+
*
|
1070 |
+
* @since 1.0
|
1071 |
+
* @param string $dir The Export/Import directory.
|
1072 |
+
*/
|
1073 |
+
private function discard( $dir ) {
|
1074 |
+
try {
|
1075 |
+
$this->jupiterx_filesystem->rmdir( $dir, true );
|
1076 |
+
|
1077 |
+
return wp_send_json_success(
|
1078 |
+
array(
|
1079 |
+
'step' => 'Discard',
|
1080 |
+
)
|
1081 |
+
);
|
1082 |
+
|
1083 |
+
} catch ( Exception $e ) {
|
1084 |
+
return wp_send_json_error( $e->getMessage() );
|
1085 |
+
}
|
1086 |
+
}
|
1087 |
+
|
1088 |
+
/**
|
1089 |
+
* Get import package directory name.
|
1090 |
+
*
|
1091 |
+
* @since 1.0
|
1092 |
+
*/
|
1093 |
+
private function _get_import_package_dir_name() {
|
1094 |
+
return end( @scandir( $this->folder['import_dir'] ) );
|
1095 |
+
}
|
1096 |
+
|
1097 |
+
/**
|
1098 |
+
* Get import package directory full path.
|
1099 |
+
*
|
1100 |
+
* @param array $$file_name The file name.
|
1101 |
+
*
|
1102 |
+
* @since 1.0
|
1103 |
+
*/
|
1104 |
+
private function _get_import_package_dir_path( $file_name ) {
|
1105 |
+
return $this->folder['import_dir'] . '/' . $this->_get_import_package_dir_name() . '/' . $file_name;
|
1106 |
+
}
|
1107 |
+
|
1108 |
+
/**
|
1109 |
+
* Get import package directory full url.
|
1110 |
+
*
|
1111 |
+
* @param array $file_name The file name.
|
1112 |
+
*
|
1113 |
+
* @since 1.0
|
1114 |
+
*/
|
1115 |
+
private function _get_import_package_dir_url( $file_name ) {
|
1116 |
+
return $this->folder['import_url'] . '/' . $this->_get_import_package_dir_name() . '/' . $file_name;
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
/**
|
1120 |
+
* Imports images for settings saved as mods.
|
1121 |
+
*
|
1122 |
+
* @since 1.0
|
1123 |
+
* @access private
|
1124 |
+
* @param array $mods An array of customizer mods.
|
1125 |
+
* @return array The mods array with any new import data.
|
1126 |
+
*/
|
1127 |
+
static public function _import_images( $mods ) {
|
1128 |
+
foreach ( $mods as $key => $val ) {
|
1129 |
+
|
1130 |
+
if ( self::_is_image_url( $val ) ) {
|
1131 |
+
|
1132 |
+
$data = self::_sideload_image( $val );
|
1133 |
+
|
1134 |
+
if ( ! is_wp_error( $data ) ) {
|
1135 |
+
|
1136 |
+
$mods[ $key ] = $data->url;
|
1137 |
+
|
1138 |
+
// Handle header image controls.
|
1139 |
+
if ( isset( $mods[ $key . '_data' ] ) ) {
|
1140 |
+
$mods[ $key . '_data' ] = $data;
|
1141 |
+
update_post_meta( $data->attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
|
1142 |
+
}
|
1143 |
+
}
|
1144 |
+
}
|
1145 |
+
}
|
1146 |
+
|
1147 |
+
return $mods;
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
/**
|
1151 |
+
* Taken from the core media_sideload_image function and
|
1152 |
+
* modified to return an array of data instead of html.
|
1153 |
+
*
|
1154 |
+
* @since 1.0
|
1155 |
+
* @access private
|
1156 |
+
* @param string $file The image file path.
|
1157 |
+
* @return array An array of image data.
|
1158 |
+
*/
|
1159 |
+
static private function _sideload_image( $file ) {
|
1160 |
+
$data = new stdClass();
|
1161 |
+
|
1162 |
+
if ( ! function_exists( 'media_handle_sideload' ) ) {
|
1163 |
+
require_once( ABSPATH . 'wp-admin/includes/media.php' );
|
1164 |
+
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
1165 |
+
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
1166 |
+
}
|
1167 |
+
if ( ! empty( $file ) ) {
|
1168 |
+
|
1169 |
+
// Set variables for storage, fix file filename for query strings.
|
1170 |
+
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
|
1171 |
+
$file_array = array();
|
1172 |
+
$file_array['name'] = basename( $matches[0] );
|
1173 |
+
|
1174 |
+
// Download file to temp location.
|
1175 |
+
$file_array['tmp_name'] = download_url( $file );
|
1176 |
+
|
1177 |
+
// If error storing temporarily, return the error.
|
1178 |
+
if ( is_wp_error( $file_array['tmp_name'] ) ) {
|
1179 |
+
return $file_array['tmp_name'];
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
// Do the validation and storage stuff.
|
1183 |
+
$id = media_handle_sideload( $file_array, 0 );
|
1184 |
+
|
1185 |
+
// If error storing permanently, unlink.
|
1186 |
+
if ( is_wp_error( $id ) ) {
|
1187 |
+
@unlink( $file_array['tmp_name'] );
|
1188 |
+
return $id;
|
1189 |
+
}
|
1190 |
+
|
1191 |
+
// Build the object to return.
|
1192 |
+
$meta = wp_get_attachment_metadata( $id );
|
1193 |
+
$data->attachment_id = $id;
|
1194 |
+
$data->url = wp_get_attachment_url( $id );
|
1195 |
+
$data->thumbnail_url = wp_get_attachment_thumb_url( $id );
|
1196 |
+
$data->height = $meta['height'];
|
1197 |
+
$data->width = $meta['width'];
|
1198 |
+
}
|
1199 |
+
|
1200 |
+
return $data;
|
1201 |
+
}
|
1202 |
+
|
1203 |
+
/**
|
1204 |
+
* Checks to see whether a string is an image url or not.
|
1205 |
+
*
|
1206 |
+
* @since 1.0
|
1207 |
+
* @access private
|
1208 |
+
* @param string $string The string to check.
|
1209 |
+
* @return bool Whether the string is an image url or not.
|
1210 |
+
*/
|
1211 |
+
static private function _is_image_url( $string = '' ) {
|
1212 |
+
if ( is_string( $string ) ) {
|
1213 |
+
|
1214 |
+
if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
|
1215 |
+
return true;
|
1216 |
+
}
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
return false;
|
1220 |
+
}
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
new JupiterX_Control_Panel_Export_Import();
|
1224 |
+
}
|
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,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 |
-
* Return list of the stored image sizes.
|
21 |
-
*
|
22 |
-
* If empty, it will return default sample size.
|
23 |
-
*
|
24 |
-
* @since 1.2.0
|
25 |
-
*
|
26 |
-
* @return array
|
27 |
-
*/
|
28 |
-
public static function get_available_image_sizes() {
|
29 |
-
$options = get_option( JUPITERX_IMAGE_SIZE_OPTION );
|
30 |
-
|
31 |
-
if ( empty( $options ) ) {
|
32 |
-
$options = [
|
33 |
-
[
|
34 |
-
'size_w' => 500,
|
35 |
-
'size_h' => 500,
|
36 |
-
'size_n' => 'Image Size 500x500',
|
37 |
-
'size_c' => 'on',
|
38 |
-
],
|
39 |
-
];
|
40 |
-
}
|
41 |
-
|
42 |
-
return $options;
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Class constructor.
|
47 |
-
*
|
48 |
-
* @since 1.2.0
|
49 |
-
*/
|
50 |
-
public function __construct() {
|
51 |
-
add_filter( 'jupiterx_control_panel_pane_image_sizes', [ $this, 'view' ] );
|
52 |
-
add_action( 'wp_ajax_jupiterx_save_image_sizes', [ $this, 'save_image_size' ] );
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Image sizes HTML directory.
|
57 |
-
*
|
58 |
-
* @since 1.2.0
|
59 |
-
*
|
60 |
-
* @return string
|
61 |
-
*/
|
62 |
-
public function view() {
|
63 |
-
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/image-sizes.php';
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Process image sizes data passed via admin-ajax.php and store it in wp_options table.
|
68 |
-
*
|
69 |
-
* @since 1.2.0
|
70 |
-
*/
|
71 |
-
public function save_image_size() {
|
72 |
-
check_ajax_referer( 'ajax-image-sizes-options', 'security' );
|
73 |
-
|
74 |
-
$options = [];
|
75 |
-
|
76 |
-
if ( empty( $_POST['options'] ) ) {
|
77 |
-
wp_send_json_error( esc_html__( 'Options are not valid.', 'jupiterx-core' ) );
|
78 |
-
}
|
79 |
-
|
80 |
-
// phpcs:disable
|
81 |
-
$options = array_map( 'sanitize_text_field', $_POST['options'] );
|
82 |
-
// phpcs:enable
|
83 |
-
|
84 |
-
$options_array = [];
|
85 |
-
|
86 |
-
foreach ( $options as $sizes ) {
|
87 |
-
parse_str( $sizes, $output );
|
88 |
-
$options_array[] = $output;
|
89 |
-
}
|
90 |
-
|
91 |
-
update_option( JUPITERX_IMAGE_SIZE_OPTION, $options_array );
|
92 |
-
|
93 |
-
wp_die( 1 );
|
94 |
-
}
|
95 |
-
}
|
96 |
-
}
|
97 |
-
|
98 |
-
new JupiterX_Control_Panel_Image_Sizes();
|
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 |
+
* Return list of the stored image sizes.
|
21 |
+
*
|
22 |
+
* If empty, it will return default sample size.
|
23 |
+
*
|
24 |
+
* @since 1.2.0
|
25 |
+
*
|
26 |
+
* @return array
|
27 |
+
*/
|
28 |
+
public static function get_available_image_sizes() {
|
29 |
+
$options = get_option( JUPITERX_IMAGE_SIZE_OPTION );
|
30 |
+
|
31 |
+
if ( empty( $options ) ) {
|
32 |
+
$options = [
|
33 |
+
[
|
34 |
+
'size_w' => 500,
|
35 |
+
'size_h' => 500,
|
36 |
+
'size_n' => 'Image Size 500x500',
|
37 |
+
'size_c' => 'on',
|
38 |
+
],
|
39 |
+
];
|
40 |
+
}
|
41 |
+
|
42 |
+
return $options;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Class constructor.
|
47 |
+
*
|
48 |
+
* @since 1.2.0
|
49 |
+
*/
|
50 |
+
public function __construct() {
|
51 |
+
add_filter( 'jupiterx_control_panel_pane_image_sizes', [ $this, 'view' ] );
|
52 |
+
add_action( 'wp_ajax_jupiterx_save_image_sizes', [ $this, 'save_image_size' ] );
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Image sizes HTML directory.
|
57 |
+
*
|
58 |
+
* @since 1.2.0
|
59 |
+
*
|
60 |
+
* @return string
|
61 |
+
*/
|
62 |
+
public function view() {
|
63 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/image-sizes.php';
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Process image sizes data passed via admin-ajax.php and store it in wp_options table.
|
68 |
+
*
|
69 |
+
* @since 1.2.0
|
70 |
+
*/
|
71 |
+
public function save_image_size() {
|
72 |
+
check_ajax_referer( 'ajax-image-sizes-options', 'security' );
|
73 |
+
|
74 |
+
$options = [];
|
75 |
+
|
76 |
+
if ( empty( $_POST['options'] ) ) {
|
77 |
+
wp_send_json_error( esc_html__( 'Options are not valid.', 'jupiterx-core' ) );
|
78 |
+
}
|
79 |
+
|
80 |
+
// phpcs:disable
|
81 |
+
$options = array_map( 'sanitize_text_field', $_POST['options'] );
|
82 |
+
// phpcs:enable
|
83 |
+
|
84 |
+
$options_array = [];
|
85 |
+
|
86 |
+
foreach ( $options as $sizes ) {
|
87 |
+
parse_str( $sizes, $output );
|
88 |
+
$options_array[] = $output;
|
89 |
+
}
|
90 |
+
|
91 |
+
update_option( JUPITERX_IMAGE_SIZE_OPTION, $options_array );
|
92 |
+
|
93 |
+
wp_die( 1 );
|
94 |
+
}
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
new JupiterX_Control_Panel_Image_Sizes();
|
includes/control-panel/includes/class-install-plugins.php
CHANGED
@@ -1,506 +1,506 @@
|
|
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( 'init', [ $this, 'cache' ] );
|
35 |
-
|
36 |
-
add_action( 'wp_ajax_abb_get_plugins', [ $this, 'get_plugins_for_frontend' ] );
|
37 |
-
add_action( 'wp_ajax_abb_deactivate_plugin', [ $this, 'deactivate' ] );
|
38 |
-
add_action( 'wp_ajax_abb_update_plugin_checker', [ $this, 'plugin_conflict_checker' ] );
|
39 |
-
}
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Load view from Jupiter X Core plugin.
|
43 |
-
*
|
44 |
-
* @since 1.9.0
|
45 |
-
*/
|
46 |
-
public function view() {
|
47 |
-
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/install-plugins.php';
|
48 |
-
}
|
49 |
-
|
50 |
-
/**
|
51 |
-
* Get class instance.
|
52 |
-
*
|
53 |
-
* @since 1.9.0
|
54 |
-
*/
|
55 |
-
public static function get_instance() {
|
56 |
-
if ( ! self::$instance ) {
|
57 |
-
self::$instance = new self;
|
58 |
-
}
|
59 |
-
|
60 |
-
return self::$instance;
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Send a json list of plugins and their data and activation limit status for front-end usage.
|
65 |
-
*
|
66 |
-
* @since 1.9.0
|
67 |
-
*/
|
68 |
-
public function get_plugins_for_frontend() {
|
69 |
-
$plugins = $this->get_all_plugins();
|
70 |
-
|
71 |
-
$plugins = $this->update_plugins_status( $plugins );
|
72 |
-
|
73 |
-
ksort( $plugins );
|
74 |
-
|
75 |
-
$limit = $this->plugins_threshold();
|
76 |
-
|
77 |
-
return wp_send_json( [ 'plugins' => $plugins, 'limit' => $limit ] );
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Get full list of plugins.
|
82 |
-
* 12h cache.
|
83 |
-
*
|
84 |
-
* @since 1.9.0
|
85 |
-
*/
|
86 |
-
public function get_all_plugins() {
|
87 |
-
$plugins = get_transient( 'jupiterx_list_of_plugins' );
|
88 |
-
|
89 |
-
if ( ! $plugins ) {
|
90 |
-
$plugins = $this->get_free_plugins() + $this->get_pro_plugins();
|
91 |
-
set_transient( 'jupiterx_list_of_plugins' , $plugins, 12 * HOUR_IN_SECONDS );
|
92 |
-
}
|
93 |
-
|
94 |
-
return $plugins;
|
95 |
-
}
|
96 |
-
|
97 |
-
/**
|
98 |
-
* Get list of pro plugins from Artbees API.
|
99 |
-
*
|
100 |
-
* @since 1.9.0
|
101 |
-
*/
|
102 |
-
public function get_pro_plugins() {
|
103 |
-
return $this->get_plugins_from_api( [ 'slug', 'basename', 'version', 'name', 'desc', 'more_link', 'img_url', 'required', 'pro', 'is_callable' ] );
|
104 |
-
}
|
105 |
-
|
106 |
-
/**
|
107 |
-
* Filter tgmpa plugins to extract list of free plugins.
|
108 |
-
*
|
109 |
-
* @since 1.9.0
|
110 |
-
*/
|
111 |
-
public function get_free_plugins_raw() {
|
112 |
-
return array_filter(
|
113 |
-
$this->tgmpa->plugins,
|
114 |
-
function( $plugin_info, $plugin ) {
|
115 |
-
return 'repo' === $plugin_info['source'];
|
116 |
-
},
|
117 |
-
ARRAY_FILTER_USE_BOTH
|
118 |
-
);
|
119 |
-
}
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Get list of free plugins.
|
123 |
-
* List gets update to add needed info like icon and version from WordPress repo.
|
124 |
-
*
|
125 |
-
* @since 1.9.0
|
126 |
-
*/
|
127 |
-
public function get_free_plugins() {
|
128 |
-
|
129 |
-
$plugins = $this->get_free_plugins_raw();
|
130 |
-
|
131 |
-
foreach ( $plugins as $plugin => $plugin_info ) {
|
132 |
-
$wp_plugin_info = $this->get_plugin_info_from_wp( $plugin, [ 'icons' => true, 'short_description' => true ] );
|
133 |
-
|
134 |
-
$plugins[ $plugin ]['version'] = $wp_plugin_info->version;
|
135 |
-
$plugins[ $plugin ]['desc'] = $wp_plugin_info->short_description;
|
136 |
-
$plugins[ $plugin ]['img_url'] = isset( $wp_plugin_info->icons['1x'] ) ? $wp_plugin_info->icons['1x'] : $wp_plugin_info->icons['default'];
|
137 |
-
}
|
138 |
-
|
139 |
-
return $plugins;
|
140 |
-
}
|
141 |
-
|
142 |
-
/**
|
143 |
-
* Get a list of slugs of free plugins.
|
144 |
-
*
|
145 |
-
* @since 1.9.0
|
146 |
-
*/
|
147 |
-
public function get_free_plugins_slug() {
|
148 |
-
$free_plugins = $this->get_free_plugins();
|
149 |
-
|
150 |
-
return array_column( $plugins, 'slug' );
|
151 |
-
}
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Get detail of given plugin from WordPress repo.
|
155 |
-
* Used to get version, icon and plugin description.
|
156 |
-
*
|
157 |
-
* @since 1.9.0
|
158 |
-
*
|
159 |
-
* @param string $plugin_slug Plugin slug from plugin header.
|
160 |
-
* @param array $fields Needed extra information.
|
161 |
-
*/
|
162 |
-
public function get_plugin_info_from_wp( $plugin_slug = '', $fields = [] ) {
|
163 |
-
|
164 |
-
if ( empty( $plugin_slug ) ) {
|
165 |
-
return;
|
166 |
-
}
|
167 |
-
|
168 |
-
if ( ! function_exists( 'plugins_api' ) ) {
|
169 |
-
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
|
170 |
-
}
|
171 |
-
|
172 |
-
$default_fields = [
|
173 |
-
'short_description' => false,
|
174 |
-
'description' => false,
|
175 |
-
'sections' => false,
|
176 |
-
'tested' => false,
|
177 |
-
'requires' => false,
|
178 |
-
'rating' => false,
|
179 |
-
'downloaded' => false,
|
180 |
-
'downloadlink' => false,
|
181 |
-
'last_updated' => false,
|
182 |
-
'added' => false,
|
183 |
-
'tags' => false,
|
184 |
-
'compatibility' => false,
|
185 |
-
'homepage' => false,
|
186 |
-
'versions' => false,
|
187 |
-
'donate_link' => false,
|
188 |
-
'reviews' => false,
|
189 |
-
'banners' => false,
|
190 |
-
'icons' => false,
|
191 |
-
'active_installs' => false,
|
192 |
-
'group' => false,
|
193 |
-
'contributors' => false,
|
194 |
-
];
|
195 |
-
|
196 |
-
$fields = wp_parse_args( $fields, $default_fields );
|
197 |
-
|
198 |
-
// @todo Set cache.
|
199 |
-
$plugin_info = plugins_api(
|
200 |
-
'plugin_information',
|
201 |
-
[
|
202 |
-
'slug' => $plugin_slug,
|
203 |
-
'fields' => $fields,
|
204 |
-
]
|
205 |
-
);
|
206 |
-
|
207 |
-
if ( is_wp_error( $plugin_info ) ) {
|
208 |
-
return [];
|
209 |
-
}
|
210 |
-
|
211 |
-
return $plugin_info;
|
212 |
-
}
|
213 |
-
|
214 |
-
/**
|
215 |
-
* Get custom list of plugins from Artbees API.
|
216 |
-
*
|
217 |
-
* @param array $fields Needed information.
|
218 |
-
*/
|
219 |
-
public function get_plugins_from_api( $fields = [] ) {
|
220 |
-
|
221 |
-
$plugin_info = [];
|
222 |
-
|
223 |
-
$free_plugins = array_column( $this->get_free_plugins(), 'slug' );
|
224 |
-
|
225 |
-
$response = wp_remote_get(
|
226 |
-
$this->api_url . 'tools/plugin-custom-list',
|
227 |
-
[
|
228 |
-
'sslverify' => false,
|
229 |
-
'headers' =>
|
230 |
-
[
|
231 |
-
'domain' => $_SERVER['SERVER_NAME'],
|
232 |
-
'theme-name' => $this->theme_name,
|
233 |
-
'list-of-attr' => wp_json_encode( $fields ),
|
234 |
-
'from' => 0,
|
235 |
-
'count' => 0,
|
236 |
-
],
|
237 |
-
]
|
238 |
-
);
|
239 |
-
|
240 |
-
$plugins = json_decode( wp_remote_retrieve_body( $response ), true );
|
241 |
-
$plugins = $plugins['data'];
|
242 |
-
|
243 |
-
$plugins = array_filter(
|
244 |
-
$plugins,
|
245 |
-
function( $v, $k ) use ( $free_plugins ) {
|
246 |
-
return ! in_array( $v['slug'], $free_plugins, true );
|
247 |
-
},
|
248 |
-
ARRAY_FILTER_USE_BOTH
|
249 |
-
);
|
250 |
-
|
251 |
-
$corrected_plugins_list = [];
|
252 |
-
|
253 |
-
foreach ( $plugins as $key => $plugin ) {
|
254 |
-
$corrected_plugins_list[ $plugin['slug'] ] = $plugin;
|
255 |
-
}
|
256 |
-
|
257 |
-
return $corrected_plugins_list;
|
258 |
-
}
|
259 |
-
|
260 |
-
/**
|
261 |
-
* Check number of activated plugins in two different groups.
|
262 |
-
*
|
263 |
-
* @since 1.9.0
|
264 |
-
*
|
265 |
-
* @return bool $threshold Wether we are meeting threshold or not.
|
266 |
-
*/
|
267 |
-
public function plugins_threshold() {
|
268 |
-
|
269 |
-
$plugins = get_option('active_plugins');
|
270 |
-
$threshold = [];
|
271 |
-
|
272 |
-
if ( count( $plugins ) >= 20 ) {
|
273 |
-
$threshold[] = 'num';
|
274 |
-
}
|
275 |
-
|
276 |
-
$sliders = [
|
277 |
-
'LayerSlider/layerslider.php',
|
278 |
-
'masterslider/masterslider.php',
|
279 |
-
'revslider/revslider.php',
|
280 |
-
];
|
281 |
-
|
282 |
-
if ( count( array_intersect( $plugins, $sliders ) ) >= 1 ) {
|
283 |
-
$threshold[] = 'sliders';
|
284 |
-
}
|
285 |
-
|
286 |
-
$jet_plugins = [
|
287 |
-
'jet-blog/jet-blog.php',
|
288 |
-
'jet-elements/jet-elements.php',
|
289 |
-
'jet-engine/jet-engine.php',
|
290 |
-
'jet-menu/jet-menu.php',
|
291 |
-
'jet-popup/jet-popup.php',
|
292 |
-
'jet-smart-filters/jet-smart-filters.php',
|
293 |
-
'jet-tabs/jet-tabs.php',
|
294 |
-
'jet-tricks/jet-tricks.php',
|
295 |
-
'jet-woo-builder/jet-woo-builder.php',
|
296 |
-
];
|
297 |
-
|
298 |
-
if ( count( array_intersect( $plugins, $jet_plugins ) ) >= 4 ) {
|
299 |
-
$threshold[] = 'jet-plugins';
|
300 |
-
}
|
301 |
-
|
302 |
-
return implode( $threshold, ',' );
|
303 |
-
}
|
304 |
-
|
305 |
-
/**
|
306 |
-
* Delete plugin information transient to load updated one.
|
307 |
-
* Usage: add force-check=1 to the URL of control panel.
|
308 |
-
*
|
309 |
-
* @since 1.9.0
|
310 |
-
*/
|
311 |
-
public function cache() {
|
312 |
-
if ( jupiterx_get( 'force-check', false ) ) {
|
313 |
-
delete_transient( 'jupiterx_list_of_plugins' );
|
314 |
-
}
|
315 |
-
}
|
316 |
-
|
317 |
-
/**
|
318 |
-
* Update plugin information to add activation, installation and update status to plugin data.
|
319 |
-
* URL used to add activation/installation URL using TGMPA.
|
320 |
-
*
|
321 |
-
* @since 1.9.0
|
322 |
-
*
|
323 |
-
* @param array $plugins List of plugins.
|
324 |
-
*/
|
325 |
-
public function update_plugins_status( $plugins = [] ) {
|
326 |
-
|
327 |
-
foreach ( $plugins as $slug => $plugin ) {
|
328 |
-
|
329 |
-
if ( ! isset( $plugins[ $slug ]['basename'] ) || empty( $plugins[ $slug ]['basename'] ) ) {
|
330 |
-
$plugins[ $slug ]['basename'] = $this->find_plugin_path( $slug );
|
331 |
-
}
|
332 |
-
|
333 |
-
$plugins[ $slug ]['update_needed'] = false;
|
334 |
-
$plugins[ $slug ]['installed'] = false;
|
335 |
-
$plugins[ $slug ]['active'] = false;
|
336 |
-
$plugins[ $slug ]['network_active'] = false;
|
337 |
-
$plugins[ $slug ]['install_disabled'] = false;
|
338 |
-
|
339 |
-
if ( is_plugin_active_for_network( $plugins[ $slug ]['basename'] ) ) {
|
340 |
-
if ( ! current_user_can( 'manage_network_plugins' ) ) {
|
341 |
-
unset( $plugins[ $slug ] );
|
342 |
-
continue;
|
343 |
-
}
|
344 |
-
|
345 |
-
$plugins[ $slug ]['network_active'] = true;
|
346 |
-
}
|
347 |
-
|
348 |
-
if ( $this->tgmpa->does_plugin_have_update( $slug ) ) {
|
349 |
-
$plugins[ $slug ]['update_needed'] = true;
|
350 |
-
$plugins[ $slug ]['update_url'] = $this->get_tgmpa_action_url( $slug, 'update' );
|
351 |
-
}
|
352 |
-
|
353 |
-
if ( $this->tgmpa->is_plugin_active( $slug ) ) {
|
354 |
-
$plugins[ $slug ]['active'] = true;
|
355 |
-
$plugins[ $slug ]['installed'] = true;
|
356 |
-
} elseif ( $this->tgmpa->is_plugin_installed( $slug ) ) {
|
357 |
-
$plugins[ $slug ]['installed'] = true;
|
358 |
-
}
|
359 |
-
|
360 |
-
if ( ! jupiterx_is_pro() && 'true' === $plugins[ $slug ]['pro'] && ! $plugins[ $slug ]['installed'] ) {
|
361 |
-
$plugins[ $slug ]['pro'] = true;
|
362 |
-
} else {
|
363 |
-
unset( $plugins[ $slug ]['pro'] );
|
364 |
-
}
|
365 |
-
|
366 |
-
if ( ! $plugins[ $slug ]['installed'] && ( is_multisite() && ! current_user_can( 'manage_network_plugins' ) ) ) {
|
367 |
-
$plugins[ $slug ]['install_disabled'] = true;
|
368 |
-
}
|
369 |
-
|
370 |
-
if ( ! $plugins[ $slug ]['installed'] && ! $plugins[ $slug ]['install_disabled'] ) {
|
371 |
-
$plugins[ $slug ]['url'] = $this->get_tgmpa_action_url( $slug, 'install' );
|
372 |
-
} elseif ( $plugins[ $slug ]['installed'] && ! $plugins[ $slug ]['active'] ) {
|
373 |
-
$plugins[ $slug ]['url'] = $this->get_tgmpa_action_url( $slug, 'activate' );
|
374 |
-
}
|
375 |
-
|
376 |
-
if ( $plugins[ $slug ]['installed'] ) {
|
377 |
-
$plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $this->find_plugin_path( $slug ) );
|
378 |
-
$plugins[ $slug ]['version'] = $plugin_data['Version'];
|
379 |
-
}
|
380 |
-
|
381 |
-
}
|
382 |
-
|
383 |
-
return $plugins;
|
384 |
-
}
|
385 |
-
|
386 |
-
/**
|
387 |
-
* Get plugin basename by plugin slug.
|
388 |
-
* Works only for installed plugins.
|
389 |
-
*
|
390 |
-
* @since 1.9.0
|
391 |
-
*
|
392 |
-
* @param string $plugin_slug
|
393 |
-
*/
|
394 |
-
public function find_plugin_path( $plugin_slug = '' ) {
|
395 |
-
|
396 |
-
$plugins = get_plugins();
|
397 |
-
foreach ( $plugins as $plugin_address => $plugin_data ) {
|
398 |
-
|
399 |
-
// Extract slug from address
|
400 |
-
if ( strlen( $plugin_address ) == basename( $plugin_address ) ) {
|
401 |
-
$slug = strtolower( str_replace( '.php', '', $plugin_address ) );
|
402 |
-
} else {
|
403 |
-
$slug = strtolower( str_replace( '/' . basename( $plugin_address ), '', $plugin_address ) );
|
404 |
-
}
|
405 |
-
// Check if slug exists
|
406 |
-
if ( strtolower( $plugin_slug ) == $slug ) {
|
407 |
-
return $plugin_address;
|
408 |
-
}
|
409 |
-
}
|
410 |
-
|
411 |
-
return false;
|
412 |
-
}
|
413 |
-
|
414 |
-
/**
|
415 |
-
* Get installation/activation URL of a plugin using TGMPA.
|
416 |
-
*
|
417 |
-
* @since 1.9.0
|
418 |
-
*
|
419 |
-
* @param string $slug Plugin slug.
|
420 |
-
* @param string $action install/activate
|
421 |
-
*/
|
422 |
-
public function get_tgmpa_action_url( $slug = '', $action = '' ) {
|
423 |
-
if ( ! in_array( $action, [ 'install', 'activate', 'update' ], true ) ) {
|
424 |
-
wp_send_json_error( [ 'message' => esc_html__( 'Action is not valid.', 'jupiterx-core' ) ] );
|
425 |
-
}
|
426 |
-
|
427 |
-
$nonce_url = wp_nonce_url(
|
428 |
-
add_query_arg(
|
429 |
-
[
|
430 |
-
'plugin' => urlencode( $slug ),
|
431 |
-
'tgmpa-' . $action => $action . '-plugin',
|
432 |
-
],
|
433 |
-
admin_url( 'themes.php?page=tgmpa-install-plugins' )
|
434 |
-
),
|
435 |
-
'tgmpa-' . $action,
|
436 |
-
'tgmpa-nonce'
|
437 |
-
);
|
438 |
-
|
439 |
-
return $nonce_url;
|
440 |
-
}
|
441 |
-
|
442 |
-
/**
|
443 |
-
* Deactivate plugin using native WordPress functionalities.
|
444 |
-
*
|
445 |
-
* @since 1.9.0
|
446 |
-
*/
|
447 |
-
public function deactivate() {
|
448 |
-
if ( ! isset( $_POST['slug'] ) ) {
|
449 |
-
wp_send_json_error( [ 'message' => esc_html__( 'Can\'t deactivate plugin', 'jupiterx-core' ) ] );
|
450 |
-
}
|
451 |
-
|
452 |
-
$plugin = $this->find_plugin_path( sanitize_text_field( $_POST['slug'] ) );
|
453 |
-
|
454 |
-
if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
|
455 |
-
wp_send_json_error( esc_html__( 'Sorry, you are not allowed to deactivate this plugin.', 'jupiterx-core' ) );
|
456 |
-
}
|
457 |
-
|
458 |
-
deactivate_plugins( $plugin );
|
459 |
-
|
460 |
-
wp_send_json_success( esc_html__( 'Deactivated Successfully.', 'jupiterx-core' ) );
|
461 |
-
}
|
462 |
-
|
463 |
-
/**
|
464 |
-
* Check for possible conflicts with Themes & Plugins for a specific plugin.
|
465 |
-
*
|
466 |
-
* @since 1.9.0
|
467 |
-
*
|
468 |
-
* @return void
|
469 |
-
*/
|
470 |
-
public function plugin_conflict_checker() {
|
471 |
-
if ( ! function_exists( 'get_plugins' ) ) {
|
472 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
473 |
-
}
|
474 |
-
|
475 |
-
$plugin_data = wp_unslash( $_POST['plugin'] );
|
476 |
-
|
477 |
-
if ( empty( $plugin_data ) ) {
|
478 |
-
wp_json_send_error( __( 'Plugin data is missing', 'jupiterx' ) );
|
479 |
-
}
|
480 |
-
|
481 |
-
if ( 'wp-repo' === $plugin_data['version'] ) {
|
482 |
-
$wp_updated_plugins = get_site_transient('update_plugins');
|
483 |
-
|
484 |
-
if (
|
485 |
-
empty( $wp_updated_plugins ) &&
|
486 |
-
empty( $wp_updated_plugins->response[ $plugin_data['basename'] ] )
|
487 |
-
) {
|
488 |
-
wp_send_json_success();
|
489 |
-
}
|
490 |
-
|
491 |
-
$plugin_data['version'] = $wp_updated_plugins
|
492 |
-
->response[ $plugin_data['basename'] ]
|
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( 'init', [ $this, 'cache' ] );
|
35 |
+
|
36 |
+
add_action( 'wp_ajax_abb_get_plugins', [ $this, 'get_plugins_for_frontend' ] );
|
37 |
+
add_action( 'wp_ajax_abb_deactivate_plugin', [ $this, 'deactivate' ] );
|
38 |
+
add_action( 'wp_ajax_abb_update_plugin_checker', [ $this, 'plugin_conflict_checker' ] );
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Load view from Jupiter X Core plugin.
|
43 |
+
*
|
44 |
+
* @since 1.9.0
|
45 |
+
*/
|
46 |
+
public function view() {
|
47 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/install-plugins.php';
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Get class instance.
|
52 |
+
*
|
53 |
+
* @since 1.9.0
|
54 |
+
*/
|
55 |
+
public static function get_instance() {
|
56 |
+
if ( ! self::$instance ) {
|
57 |
+
self::$instance = new self;
|
58 |
+
}
|
59 |
+
|
60 |
+
return self::$instance;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Send a json list of plugins and their data and activation limit status for front-end usage.
|
65 |
+
*
|
66 |
+
* @since 1.9.0
|
67 |
+
*/
|
68 |
+
public function get_plugins_for_frontend() {
|
69 |
+
$plugins = $this->get_all_plugins();
|
70 |
+
|
71 |
+
$plugins = $this->update_plugins_status( $plugins );
|
72 |
+
|
73 |
+
ksort( $plugins );
|
74 |
+
|
75 |
+
$limit = $this->plugins_threshold();
|
76 |
+
|
77 |
+
return wp_send_json( [ 'plugins' => $plugins, 'limit' => $limit ] );
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Get full list of plugins.
|
82 |
+
* 12h cache.
|
83 |
+
*
|
84 |
+
* @since 1.9.0
|
85 |
+
*/
|
86 |
+
public function get_all_plugins() {
|
87 |
+
$plugins = get_transient( 'jupiterx_list_of_plugins' );
|
88 |
+
|
89 |
+
if ( ! $plugins ) {
|
90 |
+
$plugins = $this->get_free_plugins() + $this->get_pro_plugins();
|
91 |
+
set_transient( 'jupiterx_list_of_plugins' , $plugins, 12 * HOUR_IN_SECONDS );
|
92 |
+
}
|
93 |
+
|
94 |
+
return $plugins;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Get list of pro plugins from Artbees API.
|
99 |
+
*
|
100 |
+
* @since 1.9.0
|
101 |
+
*/
|
102 |
+
public function get_pro_plugins() {
|
103 |
+
return $this->get_plugins_from_api( [ 'slug', 'basename', 'version', 'name', 'desc', 'more_link', 'img_url', 'required', 'pro', 'is_callable' ] );
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Filter tgmpa plugins to extract list of free plugins.
|
108 |
+
*
|
109 |
+
* @since 1.9.0
|
110 |
+
*/
|
111 |
+
public function get_free_plugins_raw() {
|
112 |
+
return array_filter(
|
113 |
+
$this->tgmpa->plugins,
|
114 |
+
function( $plugin_info, $plugin ) {
|
115 |
+
return 'repo' === $plugin_info['source'];
|
116 |
+
},
|
117 |
+
ARRAY_FILTER_USE_BOTH
|
118 |
+
);
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Get list of free plugins.
|
123 |
+
* List gets update to add needed info like icon and version from WordPress repo.
|
124 |
+
*
|
125 |
+
* @since 1.9.0
|
126 |
+
*/
|
127 |
+
public function get_free_plugins() {
|
128 |
+
|
129 |
+
$plugins = $this->get_free_plugins_raw();
|
130 |
+
|
131 |
+
foreach ( $plugins as $plugin => $plugin_info ) {
|
132 |
+
$wp_plugin_info = $this->get_plugin_info_from_wp( $plugin, [ 'icons' => true, 'short_description' => true ] );
|
133 |
+
|
134 |
+
$plugins[ $plugin ]['version'] = $wp_plugin_info->version;
|
135 |
+
$plugins[ $plugin ]['desc'] = $wp_plugin_info->short_description;
|
136 |
+
$plugins[ $plugin ]['img_url'] = isset( $wp_plugin_info->icons['1x'] ) ? $wp_plugin_info->icons['1x'] : $wp_plugin_info->icons['default'];
|
137 |
+
}
|
138 |
+
|
139 |
+
return $plugins;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Get a list of slugs of free plugins.
|
144 |
+
*
|
145 |
+
* @since 1.9.0
|
146 |
+
*/
|
147 |
+
public function get_free_plugins_slug() {
|
148 |
+
$free_plugins = $this->get_free_plugins();
|
149 |
+
|
150 |
+
return array_column( $plugins, 'slug' );
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Get detail of given plugin from WordPress repo.
|
155 |
+
* Used to get version, icon and plugin description.
|
156 |
+
*
|
157 |
+
* @since 1.9.0
|
158 |
+
*
|
159 |
+
* @param string $plugin_slug Plugin slug from plugin header.
|
160 |
+
* @param array $fields Needed extra information.
|
161 |
+
*/
|
162 |
+
public function get_plugin_info_from_wp( $plugin_slug = '', $fields = [] ) {
|
163 |
+
|
164 |
+
if ( empty( $plugin_slug ) ) {
|
165 |
+
return;
|
166 |
+
}
|
167 |
+
|
168 |
+
if ( ! function_exists( 'plugins_api' ) ) {
|
169 |
+
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
|
170 |
+
}
|
171 |
+
|
172 |
+
$default_fields = [
|
173 |
+
'short_description' => false,
|
174 |
+
'description' => false,
|
175 |
+
'sections' => false,
|
176 |
+
'tested' => false,
|
177 |
+
'requires' => false,
|
178 |
+
'rating' => false,
|
179 |
+
'downloaded' => false,
|
180 |
+
'downloadlink' => false,
|
181 |
+
'last_updated' => false,
|
182 |
+
'added' => false,
|
183 |
+
'tags' => false,
|
184 |
+
'compatibility' => false,
|
185 |
+
'homepage' => false,
|
186 |
+
'versions' => false,
|
187 |
+
'donate_link' => false,
|
188 |
+
'reviews' => false,
|
189 |
+
'banners' => false,
|
190 |
+
'icons' => false,
|
191 |
+
'active_installs' => false,
|
192 |
+
'group' => false,
|
193 |
+
'contributors' => false,
|
194 |
+
];
|
195 |
+
|
196 |
+
$fields = wp_parse_args( $fields, $default_fields );
|
197 |
+
|
198 |
+
// @todo Set cache.
|
199 |
+
$plugin_info = plugins_api(
|
200 |
+
'plugin_information',
|
201 |
+
[
|
202 |
+
'slug' => $plugin_slug,
|
203 |
+
'fields' => $fields,
|
204 |
+
]
|
205 |
+
);
|
206 |
+
|
207 |
+
if ( is_wp_error( $plugin_info ) ) {
|
208 |
+
return [];
|
209 |
+
}
|
210 |
+
|
211 |
+
return $plugin_info;
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Get custom list of plugins from Artbees API.
|
216 |
+
*
|
217 |
+
* @param array $fields Needed information.
|
218 |
+
*/
|
219 |
+
public function get_plugins_from_api( $fields = [] ) {
|
220 |
+
|
221 |
+
$plugin_info = [];
|
222 |
+
|
223 |
+
$free_plugins = array_column( $this->get_free_plugins(), 'slug' );
|
224 |
+
|
225 |
+
$response = wp_remote_get(
|
226 |
+
$this->api_url . 'tools/plugin-custom-list',
|
227 |
+
[
|
228 |
+
'sslverify' => false,
|
229 |
+
'headers' =>
|
230 |
+
[
|
231 |
+
'domain' => $_SERVER['SERVER_NAME'],
|
232 |
+
'theme-name' => $this->theme_name,
|
233 |
+
'list-of-attr' => wp_json_encode( $fields ),
|
234 |
+
'from' => 0,
|
235 |
+
'count' => 0,
|
236 |
+
],
|
237 |
+
]
|
238 |
+
);
|
239 |
+
|
240 |
+
$plugins = json_decode( wp_remote_retrieve_body( $response ), true );
|
241 |
+
$plugins = $plugins['data'];
|
242 |
+
|
243 |
+
$plugins = array_filter(
|
244 |
+
$plugins,
|
245 |
+
function( $v, $k ) use ( $free_plugins ) {
|
246 |
+
return ! in_array( $v['slug'], $free_plugins, true );
|
247 |
+
},
|
248 |
+
ARRAY_FILTER_USE_BOTH
|
249 |
+
);
|
250 |
+
|
251 |
+
$corrected_plugins_list = [];
|
252 |
+
|
253 |
+
foreach ( $plugins as $key => $plugin ) {
|
254 |
+
$corrected_plugins_list[ $plugin['slug'] ] = $plugin;
|
255 |
+
}
|
256 |
+
|
257 |
+
return $corrected_plugins_list;
|
258 |
+
}
|
259 |
+
|
260 |
+
/**
|
261 |
+
* Check number of activated plugins in two different groups.
|
262 |
+
*
|
263 |
+
* @since 1.9.0
|
264 |
+
*
|
265 |
+
* @return bool $threshold Wether we are meeting threshold or not.
|
266 |
+
*/
|
267 |
+
public function plugins_threshold() {
|
268 |
+
|
269 |
+
$plugins = get_option('active_plugins');
|
270 |
+
$threshold = [];
|
271 |
+
|
272 |
+
if ( count( $plugins ) >= 20 ) {
|
273 |
+
$threshold[] = 'num';
|
274 |
+
}
|
275 |
+
|
276 |
+
$sliders = [
|
277 |
+
'LayerSlider/layerslider.php',
|
278 |
+
'masterslider/masterslider.php',
|
279 |
+
'revslider/revslider.php',
|
280 |
+
];
|
281 |
+
|
282 |
+
if ( count( array_intersect( $plugins, $sliders ) ) >= 1 ) {
|
283 |
+
$threshold[] = 'sliders';
|
284 |
+
}
|
285 |
+
|
286 |
+
$jet_plugins = [
|
287 |
+
'jet-blog/jet-blog.php',
|
288 |
+
'jet-elements/jet-elements.php',
|
289 |
+
'jet-engine/jet-engine.php',
|
290 |
+
'jet-menu/jet-menu.php',
|
291 |
+
'jet-popup/jet-popup.php',
|
292 |
+
'jet-smart-filters/jet-smart-filters.php',
|
293 |
+
'jet-tabs/jet-tabs.php',
|
294 |
+
'jet-tricks/jet-tricks.php',
|
295 |
+
'jet-woo-builder/jet-woo-builder.php',
|
296 |
+
];
|
297 |
+
|
298 |
+
if ( count( array_intersect( $plugins, $jet_plugins ) ) >= 4 ) {
|
299 |
+
$threshold[] = 'jet-plugins';
|
300 |
+
}
|
301 |
+
|
302 |
+
return implode( $threshold, ',' );
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Delete plugin information transient to load updated one.
|
307 |
+
* Usage: add force-check=1 to the URL of control panel.
|
308 |
+
*
|
309 |
+
* @since 1.9.0
|
310 |
+
*/
|
311 |
+
public function cache() {
|
312 |
+
if ( jupiterx_get( 'force-check', false ) ) {
|
313 |
+
delete_transient( 'jupiterx_list_of_plugins' );
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Update plugin information to add activation, installation and update status to plugin data.
|
319 |
+
* URL used to add activation/installation URL using TGMPA.
|
320 |
+
*
|
321 |
+
* @since 1.9.0
|
322 |
+
*
|
323 |
+
* @param array $plugins List of plugins.
|
324 |
+
*/
|
325 |
+
public function update_plugins_status( $plugins = [] ) {
|
326 |
+
|
327 |
+
foreach ( $plugins as $slug => $plugin ) {
|
328 |
+
|
329 |
+
if ( ! isset( $plugins[ $slug ]['basename'] ) || empty( $plugins[ $slug ]['basename'] ) ) {
|
330 |
+
$plugins[ $slug ]['basename'] = $this->find_plugin_path( $slug );
|
331 |
+
}
|
332 |
+
|
333 |
+
$plugins[ $slug ]['update_needed'] = false;
|
334 |
+
$plugins[ $slug ]['installed'] = false;
|
335 |
+
$plugins[ $slug ]['active'] = false;
|
336 |
+
$plugins[ $slug ]['network_active'] = false;
|
337 |
+
$plugins[ $slug ]['install_disabled'] = false;
|
338 |
+
|
339 |
+
if ( is_plugin_active_for_network( $plugins[ $slug ]['basename'] ) ) {
|
340 |
+
if ( ! current_user_can( 'manage_network_plugins' ) ) {
|
341 |
+
unset( $plugins[ $slug ] );
|
342 |
+
continue;
|
343 |
+
}
|
344 |
+
|
345 |
+
$plugins[ $slug ]['network_active'] = true;
|
346 |
+
}
|
347 |
+
|
348 |
+
if ( $this->tgmpa->does_plugin_have_update( $slug ) ) {
|
349 |
+
$plugins[ $slug ]['update_needed'] = true;
|
350 |
+
$plugins[ $slug ]['update_url'] = $this->get_tgmpa_action_url( $slug, 'update' );
|
351 |
+
}
|
352 |
+
|
353 |
+
if ( $this->tgmpa->is_plugin_active( $slug ) ) {
|
354 |
+
$plugins[ $slug ]['active'] = true;
|
355 |
+
$plugins[ $slug ]['installed'] = true;
|
356 |
+
} elseif ( $this->tgmpa->is_plugin_installed( $slug ) ) {
|
357 |
+
$plugins[ $slug ]['installed'] = true;
|
358 |
+
}
|
359 |
+
|
360 |
+
if ( ! jupiterx_is_pro() && 'true' === $plugins[ $slug ]['pro'] && ! $plugins[ $slug ]['installed'] ) {
|
361 |
+
$plugins[ $slug ]['pro'] = true;
|
362 |
+
} else {
|
363 |
+
unset( $plugins[ $slug ]['pro'] );
|
364 |
+
}
|
365 |
+
|
366 |
+
if ( ! $plugins[ $slug ]['installed'] && ( is_multisite() && ! current_user_can( 'manage_network_plugins' ) ) ) {
|
367 |
+
$plugins[ $slug ]['install_disabled'] = true;
|
368 |
+
}
|
369 |
+
|
370 |
+
if ( ! $plugins[ $slug ]['installed'] && ! $plugins[ $slug ]['install_disabled'] ) {
|
371 |
+
$plugins[ $slug ]['url'] = $this->get_tgmpa_action_url( $slug, 'install' );
|
372 |
+
} elseif ( $plugins[ $slug ]['installed'] && ! $plugins[ $slug ]['active'] ) {
|
373 |
+
$plugins[ $slug ]['url'] = $this->get_tgmpa_action_url( $slug, 'activate' );
|
374 |
+
}
|
375 |
+
|
376 |
+
if ( $plugins[ $slug ]['installed'] ) {
|
377 |
+
$plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $this->find_plugin_path( $slug ) );
|
378 |
+
$plugins[ $slug ]['version'] = $plugin_data['Version'];
|
379 |
+
}
|
380 |
+
|
381 |
+
}
|
382 |
+
|
383 |
+
return $plugins;
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Get plugin basename by plugin slug.
|
388 |
+
* Works only for installed plugins.
|
389 |
+
*
|
390 |
+
* @since 1.9.0
|
391 |
+
*
|
392 |
+
* @param string $plugin_slug
|
393 |
+
*/
|
394 |
+
public function find_plugin_path( $plugin_slug = '' ) {
|
395 |
+
|
396 |
+
$plugins = get_plugins();
|
397 |
+
foreach ( $plugins as $plugin_address => $plugin_data ) {
|
398 |
+
|
399 |
+
// Extract slug from address
|
400 |
+
if ( strlen( $plugin_address ) == basename( $plugin_address ) ) {
|
401 |
+
$slug = strtolower( str_replace( '.php', '', $plugin_address ) );
|
402 |
+
} else {
|
403 |
+
$slug = strtolower( str_replace( '/' . basename( $plugin_address ), '', $plugin_address ) );
|
404 |
+
}
|
405 |
+
// Check if slug exists
|
406 |
+
if ( strtolower( $plugin_slug ) == $slug ) {
|
407 |
+
return $plugin_address;
|
408 |
+
}
|
409 |
+
}
|
410 |
+
|
411 |
+
return false;
|
412 |
+
}
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Get installation/activation URL of a plugin using TGMPA.
|
416 |
+
*
|
417 |
+
* @since 1.9.0
|
418 |
+
*
|
419 |
+
* @param string $slug Plugin slug.
|
420 |
+
* @param string $action install/activate
|
421 |
+
*/
|
422 |
+
public function get_tgmpa_action_url( $slug = '', $action = '' ) {
|
423 |
+
if ( ! in_array( $action, [ 'install', 'activate', 'update' ], true ) ) {
|
424 |
+
wp_send_json_error( [ 'message' => esc_html__( 'Action is not valid.', 'jupiterx-core' ) ] );
|
425 |
+
}
|
426 |
+
|
427 |
+
$nonce_url = wp_nonce_url(
|
428 |
+
add_query_arg(
|
429 |
+
[
|
430 |
+
'plugin' => urlencode( $slug ),
|
431 |
+
'tgmpa-' . $action => $action . '-plugin',
|
432 |
+
],
|
433 |
+
admin_url( 'themes.php?page=tgmpa-install-plugins' )
|
434 |
+
),
|
435 |
+
'tgmpa-' . $action,
|
436 |
+
'tgmpa-nonce'
|
437 |
+
);
|
438 |
+
|
439 |
+
return $nonce_url;
|
440 |
+
}
|
441 |
+
|
442 |
+
/**
|
443 |
+
* Deactivate plugin using native WordPress functionalities.
|
444 |
+
*
|
445 |
+
* @since 1.9.0
|
446 |
+
*/
|
447 |
+
public function deactivate() {
|
448 |
+
if ( ! isset( $_POST['slug'] ) ) {
|
449 |
+
wp_send_json_error( [ 'message' => esc_html__( 'Can\'t deactivate plugin', 'jupiterx-core' ) ] );
|
450 |
+
}
|
451 |
+
|
452 |
+
$plugin = $this->find_plugin_path( sanitize_text_field( $_POST['slug'] ) );
|
453 |
+
|
454 |
+
if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
|
455 |
+
wp_send_json_error( esc_html__( 'Sorry, you are not allowed to deactivate this plugin.', 'jupiterx-core' ) );
|
456 |
+
}
|
457 |
+
|
458 |
+
deactivate_plugins( $plugin );
|
459 |
+
|
460 |
+
wp_send_json_success( esc_html__( 'Deactivated Successfully.', 'jupiterx-core' ) );
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* Check for possible conflicts with Themes & Plugins for a specific plugin.
|
465 |
+
*
|
466 |
+
* @since 1.9.0
|
467 |
+
*
|
468 |
+
* @return void
|
469 |
+
*/
|
470 |
+
public function plugin_conflict_checker() {
|
471 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
472 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
473 |
+
}
|
474 |
+
|
475 |
+
$plugin_data = wp_unslash( $_POST['plugin'] );
|
476 |
+
|
477 |
+
if ( empty( $plugin_data ) ) {
|
478 |
+
wp_json_send_error( __( 'Plugin data is missing', 'jupiterx' ) );
|
479 |
+
}
|
480 |
+
|
481 |
+
if ( 'wp-repo' === $plugin_data['version'] ) {
|
482 |
+
$wp_updated_plugins = get_site_transient('update_plugins');
|
483 |
+
|
484 |
+
if (
|
485 |
+
empty( $wp_updated_plugins ) &&
|
486 |
+
empty( $wp_updated_plugins->response[ $plugin_data['basename'] ] )
|
487 |
+
) {
|
488 |
+
wp_send_json_success();
|
489 |
+
}
|
490 |
+
|
491 |
+
$plugin_data['version'] = $wp_updated_plugins
|
492 |
+
->response[ $plugin_data['basename'] ]
|
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();
|
includes/control-panel/includes/class-install-template.php
CHANGED
@@ -1,1851 +1,1851 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This class is responsible manage all jupiter templates
|
4 |
-
* it will communicate with artbees API and get list of templates , install them or remove them.
|
5 |
-
*
|
6 |
-
* @author Artbees <info@artbees.net>
|
7 |
-
* @copyright Artbees LTD (c)
|
8 |
-
*
|
9 |
-
* @link https://artbees.net
|
10 |
-
* @since 1.0
|
11 |
-
* @version 1.0
|
12 |
-
*/
|
13 |
-
if ( ! class_exists( 'JupiterX_Control_Panel_Install_Template' ) ) {
|
14 |
-
class JupiterX_Control_Panel_Install_Template {
|
15 |
-
|
16 |
-
|
17 |
-
private $layer_slider_slug = 'layerslider';
|
18 |
-
|
19 |
-
private $theme_name;
|
20 |
-
|
21 |
-
public function setThemeName( $theme_name ) {
|
22 |
-
$this->theme_name = $theme_name;
|
23 |
-
}
|
24 |
-
|
25 |
-
public function getThemeName() {
|
26 |
-
return $this->theme_name;
|
27 |
-
}
|
28 |
-
|
29 |
-
private $api_url;
|
30 |
-
|
31 |
-
public function setApiURL( $api_url ) {
|
32 |
-
$this->api_url = $api_url;
|
33 |
-
}
|
34 |
-
|
35 |
-
public function getApiURL() {
|
36 |
-
return $this->api_url;
|
37 |
-
}
|
38 |
-
|
39 |
-
private $template_id;
|
40 |
-
|
41 |
-
public function setTemplateID( $template_id ) {
|
42 |
-
$this->template_id = $template_id;
|
43 |
-
}
|
44 |
-
|
45 |
-
public function getTemplateID() {
|
46 |
-
return intval( $this->template_id );
|
47 |
-
}
|
48 |
-
|
49 |
-
private $template_name;
|
50 |
-
|
51 |
-
public function setTemplateName( $template_name ) {
|
52 |
-
$this->template_name = $template_name;
|
53 |
-
}
|
54 |
-
|
55 |
-
public function getTemplateName() {
|
56 |
-
return strtolower( $this->template_name );
|
57 |
-
}
|
58 |
-
|
59 |
-
private $template_file_name;
|
60 |
-
|
61 |
-
public function setTemplateFileName( $template_file_name ) {
|
62 |
-
$this->template_file_name = $template_file_name;
|
63 |
-
}
|
64 |
-
|
65 |
-
public function getTemplateFileName() {
|
66 |
-
return $this->template_file_name;
|
67 |
-
}
|
68 |
-
|
69 |
-
private $template_remote_address;
|
70 |
-
|
71 |
-
public function setTemplateRemoteAddress( $template_remote_address ) {
|
72 |
-
$this->template_remote_address = $template_remote_address;
|
73 |
-
}
|
74 |
-
|
75 |
-
public function getTemplateRemoteAddress() {
|
76 |
-
return $this->template_remote_address;
|
77 |
-
}
|
78 |
-
|
79 |
-
private $template_content_file_name;
|
80 |
-
|
81 |
-
public function setTemplateContentFileName( $template_content_file_name ) {
|
82 |
-
$this->template_content_file_name = $template_content_file_name;
|
83 |
-
}
|
84 |
-
|
85 |
-
public function getTemplateContentFileName() {
|
86 |
-
return $this->template_content_file_name;
|
87 |
-
}
|
88 |
-
|
89 |
-
private $widget_file_name;
|
90 |
-
|
91 |
-
public function setWidgetFileName( $widget_file_name ) {
|
92 |
-
$this->widget_file_name = $widget_file_name;
|
93 |
-
}
|
94 |
-
|
95 |
-
public function getWidgetFileName() {
|
96 |
-
return $this->widget_file_name;
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Settings filename.
|
101 |
-
*
|
102 |
-
* @since 1.0
|
103 |
-
* @var string
|
104 |
-
*/
|
105 |
-
private $settings_file_name;
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Set Settings filename.
|
109 |
-
*
|
110 |
-
* @since 1.0
|
111 |
-
* @param string $settings_file_name Settings filename.
|
112 |
-
*/
|
113 |
-
public function set_settings_file_name( $settings_file_name ) {
|
114 |
-
$this->settings_file_name = $settings_file_name;
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Get Settings filename.
|
119 |
-
*
|
120 |
-
* @since 1.0
|
121 |
-
* @return string Settings filename.
|
122 |
-
*/
|
123 |
-
public function get_settings_file_name() {
|
124 |
-
return $this->settings_file_name;
|
125 |
-
}
|
126 |
-
|
127 |
-
private $upload_dir;
|
128 |
-
|
129 |
-
public function setUploadDir( $upload_dir ) {
|
130 |
-
$this->upload_dir = $upload_dir;
|
131 |
-
}
|
132 |
-
|
133 |
-
public function getUploadDir() {
|
134 |
-
return $this->upload_dir;
|
135 |
-
}
|
136 |
-
|
137 |
-
private $base_path;
|
138 |
-
|
139 |
-
public function setBasePath( $base_path ) {
|
140 |
-
$this->base_path = $base_path;
|
141 |
-
}
|
142 |
-
|
143 |
-
public function getBasePath() {
|
144 |
-
return $this->base_path;
|
145 |
-
}
|
146 |
-
|
147 |
-
private $base_url;
|
148 |
-
|
149 |
-
public function setBaseUrl( $base_url ) {
|
150 |
-
$this->base_url = $base_url;
|
151 |
-
}
|
152 |
-
|
153 |
-
public function getBaseUrl() {
|
154 |
-
return $this->base_url;
|
155 |
-
}
|
156 |
-
|
157 |
-
private $message;
|
158 |
-
|
159 |
-
public function setMessage( $message ) {
|
160 |
-
$this->message = $message;
|
161 |
-
}
|
162 |
-
|
163 |
-
public function getMessage() {
|
164 |
-
return $this->message;
|
165 |
-
}
|
166 |
-
|
167 |
-
/**
|
168 |
-
* Construct.
|
169 |
-
*
|
170 |
-
* @param bool $system_text_env if you want to create an instance of this method for phpunit it should be true
|
171 |
-
*/
|
172 |
-
public function __construct() {
|
173 |
-
|
174 |
-
add_filter( 'jupiterx_control_panel_pane_install_templates', [ $this, 'view' ] );
|
175 |
-
|
176 |
-
// Get TGMPA.
|
177 |
-
if ( class_exists( 'TGM_Plugin_Activation' ) ) {
|
178 |
-
$this->tgmpa = isset( $GLOBALS['tgmpa'] ) ? $GLOBALS['tgmpa'] : TGM_Plugin_Activation::get_instance();
|
179 |
-
}
|
180 |
-
|
181 |
-
$menu_items_access = get_site_option( 'menu_items' );
|
182 |
-
|
183 |
-
@set_time_limit( 0 );
|
184 |
-
|
185 |
-
$this->setThemeName( 'jupiterx' );
|
186 |
-
|
187 |
-
$this->setApiURL( 'https://artbees.net/api/v2/' );
|
188 |
-
|
189 |
-
$this->setUploadDir( wp_upload_dir() );
|
190 |
-
$this->setBasePath( $this->getUploadDir()['basedir'] . '/jupiterx_templates/' );
|
191 |
-
$this->setBaseUrl( $this->getUploadDir()['baseurl'] . '/jupiterx_templates/' );
|
192 |
-
|
193 |
-
$this->setTemplateContentFileName( 'theme_content.xml' );
|
194 |
-
$this->setWidgetFileName( 'widget_data.wie' );
|
195 |
-
$this->set_settings_file_name( 'settings.json' );
|
196 |
-
global $wpdb;
|
197 |
-
|
198 |
-
if ( ! defined( 'JupiterX_LOAD_IMPORTERS' ) ) {
|
199 |
-
define( 'JupiterX_LOAD_IMPORTERS', true );
|
200 |
-
}
|
201 |
-
|
202 |
-
add_filter( 'tgmpa_load', '__return_true', 10, 1 );
|
203 |
-
|
204 |
-
add_action( 'wp_ajax_abb_template_lazy_load', array( &$this, 'loadTemplatesFromApi' ) );
|
205 |
-
add_action( 'wp_ajax_abb_install_template_procedure', array( &$this, 'install_template_procedure' ) );
|
206 |
-
|
207 |
-
// Action only for importing theme content with Server-Sent Event.
|
208 |
-
add_action( 'wp_ajax_abb_install_template_sse', array( &$this, 'import_theme_content_sse' ) );
|
209 |
-
|
210 |
-
add_action( 'wp_ajax_abb_get_templates_categories', array( &$this, 'getTemplateCategoryListFromApi' ) );
|
211 |
-
add_action( 'wp_ajax_abb_restore_latest_db', array( &$this, 'restoreLatestDB' ) );
|
212 |
-
add_action( 'wp_ajax_abb_is_restore_db', array( &$this, 'isRestoreDB' ) );
|
213 |
-
|
214 |
-
add_action( 'wp_ajax_abb_uninstall_template', array( &$this, 'uninstallTemplate' ) );
|
215 |
-
add_action( 'wp_ajax_abb_get_template_psd_link', array( &$this, 'get_template_psd_link' ) );
|
216 |
-
}
|
217 |
-
|
218 |
-
/**
|
219 |
-
* Settings HTML path.
|
220 |
-
*
|
221 |
-
* @since 1.4.0
|
222 |
-
*
|
223 |
-
* @return string
|
224 |
-
*/
|
225 |
-
public function view() {
|
226 |
-
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/install-templates.php';
|
227 |
-
}
|
228 |
-
|
229 |
-
public function install_template_procedure() {
|
230 |
-
$template_id = ( isset( $_POST['template_id'] ) ? intval( $_POST['template_id'] ) : 0 );
|
231 |
-
$this->setTemplateID( $template_id );
|
232 |
-
$template_name = ( isset( $_POST['template_name'] ) ? sanitize_text_field( $_POST['template_name'] ) : null );
|
233 |
-
$import_media = ( isset( $_POST['import_media'] ) ? sanitize_text_field( $_POST['import_media'] ) : false );
|
234 |
-
$type = ( isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : null );
|
235 |
-
$partial_import = ( isset( $_POST['partial_import'] ) ? filter_var( $_POST['partial_import'], FILTER_VALIDATE_BOOLEAN ) : false );
|
236 |
-
|
237 |
-
if ( is_null( $template_name ) || is_null( $type ) ) {
|
238 |
-
$this->message( 'System problem at installing , please contact support', false );
|
239 |
-
return false;
|
240 |
-
}
|
241 |
-
|
242 |
-
switch ( $type ) {
|
243 |
-
case 'preparation':
|
244 |
-
$this->preparation( $template_name );
|
245 |
-
break;
|
246 |
-
case 'backup_db':
|
247 |
-
$this->backupDB();
|
248 |
-
break;
|
249 |
-
case 'backup_media_records':
|
250 |
-
$this->backup_media_records();
|
251 |
-
break;
|
252 |
-
case 'restore_media_records':
|
253 |
-
$this->restore_media_records();
|
254 |
-
break;
|
255 |
-
case 'reset_db':
|
256 |
-
$this->resetDB();
|
257 |
-
break;
|
258 |
-
case 'upload':
|
259 |
-
$this->uploadTemplateToServer( $template_name );
|
260 |
-
break;
|
261 |
-
case 'unzip':
|
262 |
-
$this->unzipTemplateInServer( $template_name );
|
263 |
-
break;
|
264 |
-
case 'validate':
|
265 |
-
$this->validateTemplateFiles( $template_name );
|
266 |
-
break;
|
267 |
-
case 'install_plugins':
|
268 |
-
$this->installRequiredPlugins( $template_name );
|
269 |
-
break;
|
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;
|
276 |
-
case 'setup_pages':
|
277 |
-
$this->setUpPages( $template_name );
|
278 |
-
break;
|
279 |
-
case 'plugins_content':
|
280 |
-
$this->import_plugins_content( $template_name );
|
281 |
-
break;
|
282 |
-
case 'settings':
|
283 |
-
$this->import_settings( $template_name );
|
284 |
-
break;
|
285 |
-
case 'menu_locations':
|
286 |
-
$this->importMenuLocations( $template_name );
|
287 |
-
break;
|
288 |
-
case 'theme_widget':
|
289 |
-
$this->importThemeWidgets( $template_name );
|
290 |
-
break;
|
291 |
-
case 'finalize':
|
292 |
-
$this->finalizeImporting( $template_name, $partial_import );
|
293 |
-
break;
|
294 |
-
}
|
295 |
-
}
|
296 |
-
public function reinitializeData( $template_name ) {
|
297 |
-
try {
|
298 |
-
if ( empty( $template_name ) ) {
|
299 |
-
throw new Exception( 'Choose template first' );
|
300 |
-
}
|
301 |
-
$this->setTemplateName( $template_name );
|
302 |
-
if (
|
303 |
-
file_exists( $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() ) ) == false ||
|
304 |
-
file_exists( $this->getAssetsAddress( 'widget_path', $this->getTemplateName() ) ) == false ||
|
305 |
-
file_exists( $this->getAssetsAddress( 'settings_path', $this->getTemplateName() ) ) == false
|
306 |
-
) {
|
307 |
-
throw new Exception( "Some template assets are missing Template Name : $template_name, Contact support." );
|
308 |
-
} else {
|
309 |
-
return true;
|
310 |
-
}
|
311 |
-
} catch ( Exception $e ) {
|
312 |
-
$this->message( $e->getMessage(), false );
|
313 |
-
return false;
|
314 |
-
}
|
315 |
-
}
|
316 |
-
|
317 |
-
/**
|
318 |
-
* Reinitilize Template file is exist or not for SEE request.
|
319 |
-
*
|
320 |
-
* @since 1.0
|
321 |
-
*
|
322 |
-
* @throws Exception If template name empty.
|
323 |
-
* @throws Exception If template file is not exist.
|
324 |
-
*
|
325 |
-
* @param string $template_name The template name will be imported.
|
326 |
-
* @param string $template_id The template ID will be imported.
|
327 |
-
* @return boolean File status.
|
328 |
-
*/
|
329 |
-
public function reinitialize_data_sse( $template_name, $template_id ) {
|
330 |
-
try {
|
331 |
-
|
332 |
-
// Check template name and ID.
|
333 |
-
if ( empty( $template_name ) || empty( $template_id ) ) {
|
334 |
-
throw new Exception( 'Choose template first!' );
|
335 |
-
}
|
336 |
-
|
337 |
-
$this->setTemplateName( $template_name );
|
338 |
-
$this->setTemplateID( $template_id );
|
339 |
-
|
340 |
-
// Check template file exist or not.
|
341 |
-
if ( false === file_exists( $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() ) ) ) {
|
342 |
-
throw new Exception( 'Template content does not exist - Contact support.' );
|
343 |
-
}
|
344 |
-
|
345 |
-
return true;
|
346 |
-
} catch ( Exception $e ) {
|
347 |
-
$this->message_sse( $e->getMessage(), true );
|
348 |
-
exit;
|
349 |
-
}
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Method that is resposible to pass plugin list to UI base on lazy load condition.
|
354 |
-
*
|
355 |
-
* @param str $_POST[from] from number.
|
356 |
-
* @param str $_POST[count] how many.
|
357 |
-
*
|
358 |
-
* @return bool will return boolean status of action , all message is setted to $this->message()
|
359 |
-
*/
|
360 |
-
public function loadTemplatesFromApi() {
|
361 |
-
try {
|
362 |
-
$from = ( isset( $_POST['from'] ) ? intval( $_POST['from'] ) : null );
|
363 |
-
$count = ( isset( $_POST['count'] ) ? intval( $_POST['count'] ) : null );
|
364 |
-
$template_id = ( isset( $_POST['template_id'] ) ? intval( $_POST['template_id'] ) : 0 );
|
365 |
-
$template_name = ( isset( $_POST['template_name'] ) ? sanitize_text_field( $_POST['template_name'] ) : null );
|
366 |
-
$template_category = ( isset( $_POST['template_category'] ) ? sanitize_text_field( $_POST['template_category'] ) : null );
|
367 |
-
|
368 |
-
if ( is_null( $from ) || is_null( $count ) ) {
|
369 |
-
throw new Exception( 'System problem , please contact support', 1001 );
|
370 |
-
return false;
|
371 |
-
}
|
372 |
-
$getTemplateListArgs = [
|
373 |
-
'pagination_start' => $from,
|
374 |
-
'pagination_count' => $count,
|
375 |
-
'template_category' => $template_category,
|
376 |
-
'template_name' => $template_name,
|
377 |
-
'template_id' => $template_id,
|
378 |
-
];
|
379 |
-
$list_of_templates = $this->getTemplateListFromApi( $getTemplateListArgs );
|
380 |
-
|
381 |
-
if ( ! is_array( $list_of_templates ) ) {
|
382 |
-
throw new Exception( 'Template list is not what we expected' );
|
383 |
-
}
|
384 |
-
|
385 |
-
if ( jupiterx_is_pro() ) {
|
386 |
-
foreach ( $list_of_templates as $index => $template ) {
|
387 |
-
$list_of_templates[ $index ]->free_template = '1';
|
388 |
-
}
|
389 |
-
}
|
390 |
-
|
391 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
392 |
-
$backups = $db_manager->is_restore_db();
|
393 |
-
$this->message(
|
394 |
-
'Successfull', true, array(
|
395 |
-
'templates' => $list_of_templates,
|
396 |
-
'backups' => $backups,
|
397 |
-
)
|
398 |
-
);
|
399 |
-
return true;
|
400 |
-
|
401 |
-
} catch ( Exception $e ) {
|
402 |
-
$this->message( $e->getMessage(), false );
|
403 |
-
return false;
|
404 |
-
}
|
405 |
-
}
|
406 |
-
public function preparation( $template_name ) {
|
407 |
-
try {
|
408 |
-
$this->message( 'All is ready.', true );
|
409 |
-
return true;
|
410 |
-
} catch ( Exception $e ) {
|
411 |
-
$this->message( $e->getMessage(), false );
|
412 |
-
return false;
|
413 |
-
}
|
414 |
-
}
|
415 |
-
public function backupDB() {
|
416 |
-
try {
|
417 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
418 |
-
$dm_response = $db_manager->backup_db();
|
419 |
-
if ( false == $dm_response ) {
|
420 |
-
throw new Exception( $db_manager->get_error_message() );
|
421 |
-
}
|
422 |
-
|
423 |
-
$this->message( 'Backup created.', true );
|
424 |
-
return true;
|
425 |
-
|
426 |
-
} catch ( Exception $e ) {
|
427 |
-
$this->message( $e->getMessage(), false );
|
428 |
-
return false;
|
429 |
-
}
|
430 |
-
}
|
431 |
-
public function backup_media_records() {
|
432 |
-
try {
|
433 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
434 |
-
|
435 |
-
$dm_response = $db_manager->backup_media_records();
|
436 |
-
|
437 |
-
if ( false == $dm_response ) {
|
438 |
-
throw new Exception( $db_manager->get_error_message() );
|
439 |
-
}
|
440 |
-
$this->message( 'Media records backup created.', true );
|
441 |
-
return true;
|
442 |
-
|
443 |
-
} catch ( Exception $e ) {
|
444 |
-
$this->message( $e->getMessage(), false );
|
445 |
-
return false;
|
446 |
-
}
|
447 |
-
}
|
448 |
-
public function restore_media_records() {
|
449 |
-
try {
|
450 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
451 |
-
|
452 |
-
$dm_response = $db_manager->restore_media_records();
|
453 |
-
|
454 |
-
if ( false == $dm_response ) {
|
455 |
-
throw new Exception( $db_manager->get_error_message() );
|
456 |
-
}
|
457 |
-
$this->message( 'Media records restored successfully', true );
|
458 |
-
return true;
|
459 |
-
|
460 |
-
} catch ( Exception $e ) {
|
461 |
-
$this->message( $e->getMessage(), false );
|
462 |
-
return false;
|
463 |
-
}
|
464 |
-
}
|
465 |
-
public function isRestoreDB() {
|
466 |
-
try {
|
467 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
468 |
-
$result = $db_manager->is_restore_db();
|
469 |
-
if ( is_array( $result ) ) {
|
470 |
-
$this->message( 'Successfull', true, $result );
|
471 |
-
return true;
|
472 |
-
} else {
|
473 |
-
throw new Exception( 'Result is not what we expected' );
|
474 |
-
}
|
475 |
-
} catch ( Exception $e ) {
|
476 |
-
$this->message( $e->getMessage(), false );
|
477 |
-
return false;
|
478 |
-
}
|
479 |
-
}
|
480 |
-
public function restoreLatestDB() {
|
481 |
-
try {
|
482 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
483 |
-
$return = $db_manager->restore_latest_db();
|
484 |
-
if ( false == $return ) {
|
485 |
-
throw new Exception( $db_manager->get_error_message() );
|
486 |
-
}
|
487 |
-
JupiterX_Control_Panel_Helpers::prevent_cache_plugins();
|
488 |
-
$this->message( 'Restore completed!', true );
|
489 |
-
return true;
|
490 |
-
} catch ( Exception $e ) {
|
491 |
-
$this->message( $e->getMessage(), false );
|
492 |
-
return false;
|
493 |
-
}
|
494 |
-
}
|
495 |
-
public function resetDB() {
|
496 |
-
try {
|
497 |
-
$tables = array(
|
498 |
-
'comments',
|
499 |
-
'commentmeta',
|
500 |
-
'links',
|
501 |
-
'postmeta',
|
502 |
-
'posts',
|
503 |
-
'term_relationships',
|
504 |
-
'termmeta',
|
505 |
-
'terms',
|
506 |
-
'term_taxonomy',
|
507 |
-
);
|
508 |
-
|
509 |
-
include_once ABSPATH . 'wp-admin/includes/plugin.php';
|
510 |
-
if ( jupiterx_is_callable( 'SitePress' ) ) {
|
511 |
-
$tables[] = 'icl_translations';
|
512 |
-
}
|
513 |
-
|
514 |
-
$this->resetWordpressDatabase( $tables, array(), false );
|
515 |
-
$this->message( 'Database reseted', true );
|
516 |
-
|
517 |
-
return true;
|
518 |
-
} catch ( Exception $e ) {
|
519 |
-
$this->message( $e->getMessage(), false );
|
520 |
-
|
521 |
-
return false;
|
522 |
-
}
|
523 |
-
}
|
524 |
-
public function uploadTemplateToServer( $template_name ) {
|
525 |
-
try {
|
526 |
-
$this->setTemplateName( $template_name );
|
527 |
-
$getTemplateName = $this->getTemplateName();
|
528 |
-
if ( empty( $getTemplateName ) ) {
|
529 |
-
throw new Exception( 'Choose one template first' );
|
530 |
-
}
|
531 |
-
$url = $this->getTemplateDownloadLink( $this->getTemplateName(), 'download' );
|
532 |
-
$template_file_name = $this->getTemplateDownloadLink( $this->getTemplateName(), 'filename' );
|
533 |
-
$this->setTemplateRemoteAddress( $url );
|
534 |
-
if ( filter_var( $url, FILTER_VALIDATE_URL ) === false ) {
|
535 |
-
throw new Exception( 'Template source URL is not validate' );
|
536 |
-
}
|
537 |
-
JupiterX_Control_Panel_Helpers::upload_from_url( $this->getTemplateRemoteAddress(), $template_file_name, $this->getBasePath() );
|
538 |
-
$this->message( 'Uploaded to server', true );
|
539 |
-
return true;
|
540 |
-
} catch ( Exception $e ) {
|
541 |
-
$this->message( $e->getMessage(), false );
|
542 |
-
return false;
|
543 |
-
}
|
544 |
-
}
|
545 |
-
public function unzipTemplateInServer( $template_name ) {
|
546 |
-
try {
|
547 |
-
$this->setTemplateName( $template_name );
|
548 |
-
$getTemplateName = $this->getTemplateName();
|
549 |
-
if ( empty( $getTemplateName ) ) {
|
550 |
-
throw new Exception( 'Choose one template first' );
|
551 |
-
}
|
552 |
-
|
553 |
-
$response = $this->getTemplateDownloadLink( $this->getTemplateName(), 'filename' );
|
554 |
-
|
555 |
-
$this->setTemplateFileName( $response );
|
556 |
-
|
557 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
558 |
-
array(
|
559 |
-
'context' => $this->getBasePath(),
|
560 |
-
)
|
561 |
-
);
|
562 |
-
|
563 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
564 |
-
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
565 |
-
return false;
|
566 |
-
}
|
567 |
-
|
568 |
-
if ( ! $jupiterx_filesystem->exists( $this->getBasePath() . $this->getTemplateName() ) ) {
|
569 |
-
JupiterX_Control_Panel_Helpers::un_zip( $this->getBasePath() . $this->getTemplateFileName(), $this->getBasePath() );
|
570 |
-
} else {
|
571 |
-
if ( $jupiterx_filesystem->rmdir( $this->getBasePath() . $this->getTemplateName(), true ) ) {
|
572 |
-
JupiterX_Control_Panel_Helpers::un_zip( $this->getBasePath() . $this->getTemplateFileName(), $this->getBasePath() );
|
573 |
-
}
|
574 |
-
}
|
575 |
-
|
576 |
-
$jupiterx_filesystem->delete( $this->getBasePath() . $this->getTemplateFileName() );
|
577 |
-
|
578 |
-
$this->message( 'Completed', true );
|
579 |
-
|
580 |
-
return true;
|
581 |
-
} catch ( Exception $e ) {
|
582 |
-
$this->message( $e->getMessage(), false );
|
583 |
-
|
584 |
-
return false;
|
585 |
-
}
|
586 |
-
}
|
587 |
-
public function validateTemplateFiles( $template_name ) {
|
588 |
-
try {
|
589 |
-
if ( empty( $template_name ) ) {
|
590 |
-
throw new Exception( 'Choose template first' );
|
591 |
-
}
|
592 |
-
|
593 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
594 |
-
array(
|
595 |
-
'context' => $this->getBasePath(),
|
596 |
-
)
|
597 |
-
);
|
598 |
-
|
599 |
-
if ( $jupiterx_filesystem->get_error_code() ) {
|
600 |
-
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
601 |
-
return false;
|
602 |
-
}
|
603 |
-
|
604 |
-
$this->setTemplateName( $template_name );
|
605 |
-
if (
|
606 |
-
$jupiterx_filesystem->exists( $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() ) ) == false ||
|
607 |
-
$jupiterx_filesystem->exists( $this->getAssetsAddress( 'widget_path', $this->getTemplateName() ) ) == false ||
|
608 |
-
$jupiterx_filesystem->exists( $this->getAssetsAddress( 'settings_path', $this->getTemplateName() ) ) == false
|
609 |
-
) {
|
610 |
-
throw new Exception( "Some template assets are missing Template Name : $template_name, Contact support." );
|
611 |
-
} else {
|
612 |
-
$this->message( 'Completed', true );
|
613 |
-
return true;
|
614 |
-
}
|
615 |
-
} catch ( Exception $e ) {
|
616 |
-
$this->message( $e->getMessage(), false );
|
617 |
-
|
618 |
-
return false;
|
619 |
-
}
|
620 |
-
}
|
621 |
-
|
622 |
-
public function installRequiredPlugins( $template_name ) {
|
623 |
-
|
624 |
-
$plugin_install_access = is_multisite() ? is_super_admin() : ( current_user_can( 'install_themes' ) && current_user_can( 'activate_plugins' ) );
|
625 |
-
$single_site_message = 'You are not allowed to install a new plugin or template because your user role does not have required permissions.';
|
626 |
-
$multi_site_message = 'Template installation is only allowed for user with Super Admin role. Please contact your website\'s administrator. <a target="_blank" href="https://themes.artbees.net/docs/installing-a-template/">Learn More</a>';
|
627 |
-
|
628 |
-
if ( ! $plugin_install_access ) {
|
629 |
-
$message = $single_site_message;
|
630 |
-
if ( is_multisite() ) {
|
631 |
-
$message = $multi_site_message;
|
632 |
-
}
|
633 |
-
$this->message( $message, false );
|
634 |
-
}
|
635 |
-
|
636 |
-
$template_settings = $this->getSettingsData( $template_name );
|
637 |
-
$actions = [];
|
638 |
-
$plugins_to_install = [];
|
639 |
-
$tgmpa_url = $this->tgmpa->get_tgmpa_url();
|
640 |
-
$template_plugins = $template_settings['options']['jupiterx_support_plugins'];
|
641 |
-
|
642 |
-
$template_plugins = array_diff( $template_plugins, ['jupiterx-pro', 'advanced-custom-fields-pro'] );
|
643 |
-
|
644 |
-
$template_plugins[] = 'advanced-custom-fields';
|
645 |
-
|
646 |
-
foreach ( $template_plugins as $slug ) {
|
647 |
-
|
648 |
-
if ( ! $this->tgmpa->is_plugin_active( $slug ) || false !== $this->tgmpa->does_plugin_have_update( $slug ) ) {
|
649 |
-
if ( ! $this->tgmpa->is_plugin_installed( $slug ) ) {
|
650 |
-
$plugins_to_install[] = $slug;
|
651 |
-
}
|
652 |
-
}
|
653 |
-
}
|
654 |
-
|
655 |
-
if ( ! empty( $plugins_to_install ) ) {
|
656 |
-
$actions['install'] = [
|
657 |
-
'url' => $tgmpa_url,
|
658 |
-
'plugin' => $plugins_to_install,
|
659 |
-
'tgmpa-page' => $this->tgmpa->menu,
|
660 |
-
'plugin_status' => 'all',
|
661 |
-
'_wpnonce' => wp_create_nonce( 'bulk-plugins' ),
|
662 |
-
'action' => 'tgmpa-bulk-install',
|
663 |
-
'action2' => - 1,
|
664 |
-
'message' => esc_html__( 'Installing', 'jupiterx-core' ),
|
665 |
-
];
|
666 |
-
}
|
667 |
-
|
668 |
-
$actions['url'] = $tgmpa_url;
|
669 |
-
$actions['status'] = true;
|
670 |
-
|
671 |
-
wp_send_json( $actions );
|
672 |
-
}
|
673 |
-
|
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 |
-
$actions['activate'] = [
|
686 |
-
'url' => $tgmpa_url,
|
687 |
-
'plugin' => $template_plugins,
|
688 |
-
'tgmpa-page' => $this->tgmpa->menu,
|
689 |
-
'plugin_status' => 'all',
|
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( $actions );
|
700 |
-
}
|
701 |
-
|
702 |
-
|
703 |
-
/**
|
704 |
-
* Import plugins content.
|
705 |
-
*
|
706 |
-
* @since 1.0.3
|
707 |
-
*/
|
708 |
-
public function import_plugins_content( $template_name ) {
|
709 |
-
|
710 |
-
try {
|
711 |
-
$this->setTemplateName( $template_name );
|
712 |
-
// Get template settings.
|
713 |
-
$settings = $this->getSettingsData( $this->getTemplateName() );
|
714 |
-
|
715 |
-
// Supported plugins list.
|
716 |
-
$supported_plugins = $settings['options']['jupiterx_support_plugins'];
|
717 |
-
|
718 |
-
// Run plugins importer.
|
719 |
-
foreach ( $supported_plugins as $plugin ) {
|
720 |
-
if ( is_callable( [ $this, "import_{$plugin}_content" ] ) ) {
|
721 |
-
call_user_func( [ $this, "import_{$plugin}_content" ] );
|
722 |
-
}
|
723 |
-
}
|
724 |
-
|
725 |
-
$this->message( esc_html__( 'Data of plugins have imported.', 'jupiterx-core' ), true );
|
726 |
-
|
727 |
-
return true;
|
728 |
-
} catch ( Exception $e ) {
|
729 |
-
$this->message( $e->getMessage(), false );
|
730 |
-
return false;
|
731 |
-
}
|
732 |
-
|
733 |
-
}
|
734 |
-
|
735 |
-
/**
|
736 |
-
* Import Revolution Slider content.
|
737 |
-
*
|
738 |
-
* @since 1.0.3
|
739 |
-
*/
|
740 |
-
public function import_revslider_content() {
|
741 |
-
if ( ! class_exists( 'RevSlider' ) ) {
|
742 |
-
return;
|
743 |
-
}
|
744 |
-
|
745 |
-
$filesystem = new JupiterX_Filesystem( [
|
746 |
-
'context' => $this->getBasePath(),
|
747 |
-
] );
|
748 |
-
|
749 |
-
$revslider_folder = $this->getBasePath() . sanitize_title( $this->getTemplateName() ) . '/revslider';
|
750 |
-
|
751 |
-
// Check extracted template if `revslider` folder exists inside.
|
752 |
-
if ( ! $filesystem->exists( $revslider_folder ) ) {
|
753 |
-
return;
|
754 |
-
}
|
755 |
-
|
756 |
-
$revslider = new RevSlider();
|
757 |
-
|
758 |
-
$sliders = glob( $revslider_folder . '/*.zip' );
|
759 |
-
|
760 |
-
if ( empty( $sliders ) ) {
|
761 |
-
return;
|
762 |
-
}
|
763 |
-
|
764 |
-
global $wpdb;
|
765 |
-
|
766 |
-
$tables = [
|
767 |
-
'revslider_css',
|
768 |
-
'revslider_layer_animations',
|
769 |
-
'revslider_navigations',
|
770 |
-
'revslider_sliders',
|
771 |
-
'revslider_slides',
|
772 |
-
'revslider_static_slides',
|
773 |
-
];
|
774 |
-
|
775 |
-
// Truncate tables.
|
776 |
-
foreach ( $tables as $table ) {
|
777 |
-
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}{$table}" );
|
778 |
-
}
|
779 |
-
|
780 |
-
// Import sliders.
|
781 |
-
foreach ( $sliders as $slide ) {
|
782 |
-
/**
|
783 |
-
* Start import slider.
|
784 |
-
*
|
785 |
-
* @param boolean Update animation.
|
786 |
-
* @param boolean Deprecated static param.
|
787 |
-
* @param mixed Slider file path.
|
788 |
-
* @param boolean Template slide.
|
789 |
-
* @param boolean Single slide.
|
790 |
-
* @param boolean Update navigation.
|
791 |
-
*/
|
792 |
-
$revslider->importSliderFromPost( true, true, $slide, false, false, true );
|
793 |
-
}
|
794 |
-
}
|
795 |
-
|
796 |
-
/**
|
797 |
-
* Import theme content via Server-Sent Events request.
|
798 |
-
*
|
799 |
-
*
|
800 |
-
* @throws Exception If template data is empty.
|
801 |
-
* @throws Exception If preliminary data is empty.
|
802 |
-
*/
|
803 |
-
public function import_theme_content_sse() {
|
804 |
-
try {
|
805 |
-
/*
|
806 |
-
* Filter data input from GET method. Eventsource doesn't allow us to use
|
807 |
-
* POST method.
|
808 |
-
*/
|
809 |
-
$template_name = '';
|
810 |
-
if ( ! empty( $_GET['template_name'] ) ) {
|
811 |
-
// WPCS: XSS ok, CSRF ok.
|
812 |
-
$template_name = sanitize_text_field( $_GET['template_name'] );
|
813 |
-
}
|
814 |
-
|
815 |
-
$template_id = '';
|
816 |
-
if ( ! empty( $_GET['template_id'] ) ) {
|
817 |
-
// WPCS: XSS ok, CSRF ok.
|
818 |
-
$template_id = sanitize_text_field( $_GET['template_id'] );
|
819 |
-
}
|
820 |
-
|
821 |
-
$fetch_attachments = 'false';
|
822 |
-
if ( ! empty( $_GET['fetch_attachments'] ) ) {
|
823 |
-
// WPCS: XSS ok, CSRF ok.
|
824 |
-
$fetch_attachments = sanitize_text_field( $_GET['fetch_attachments'] );
|
825 |
-
} elseif ( ! empty( $_GET['import_media'] ) ) {
|
826 |
-
$fetch_attachments = sanitize_text_field( $_GET['import_media'] );
|
827 |
-
}
|
828 |
-
|
829 |
-
$partial_import = false;
|
830 |
-
if ( ! empty( $_GET['partial_import'] ) ) {
|
831 |
-
// phpcs:ignore
|
832 |
-
$partial_import = filter_var( $_GET['partial_import'], FILTER_VALIDATE_BOOLEAN );
|
833 |
-
}
|
834 |
-
|
835 |
-
// Include wordpress-importer class.
|
836 |
-
JupiterX_Control_Panel_Helpers::include_wordpress_importer();
|
837 |
-
$this->reinitialize_data_sse( $template_name, $template_id );
|
838 |
-
|
839 |
-
// Set importer options as an array.
|
840 |
-
$options = array(
|
841 |
-
'fetch_attachments' => filter_var( $fetch_attachments, FILTER_VALIDATE_BOOLEAN ),
|
842 |
-
'default_author' => get_current_user_id(),
|
843 |
-
);
|
844 |
-
|
845 |
-
// Create new instance for Importer.
|
846 |
-
$importer = new JupiterX_Importer( $options, $partial_import );
|
847 |
-
$logger = new JupiterX_Importer_Logger_ServerSentEvents();
|
848 |
-
$importer->set_logger( $logger );
|
849 |
-
|
850 |
-
// Get preliminary information.
|
851 |
-
$file = $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() );
|
852 |
-
$pre_data = $importer->get_preliminary_information( $file );
|
853 |
-
if ( is_wp_error( $pre_data ) ) {
|
854 |
-
throw new Exception( $pre_data->get_error_message() );
|
855 |
-
}
|
856 |
-
|
857 |
-
// @codingStandardsIgnoreStart
|
858 |
-
// Turn off PHP output compression, allow us to print the log.
|
859 |
-
$previous = error_reporting(error_reporting() ^ E_WARNING);
|
860 |
-
|
861 |
-
// Configuration disabled for theme check plugin.
|
862 |
-
// ini_set('output_buffering', 'off');
|
863 |
-
// ini_set('zlib.output_compression', false);
|
864 |
-
|
865 |
-
error_reporting($previous);
|
866 |
-
// @codingStandardsIgnoreEnd
|
867 |
-
|
868 |
-
if ( $GLOBALS['is_nginx'] ) {
|
869 |
-
// Setting this header instructs Nginx to disable fastcgi_buffering
|
870 |
-
// and disable gzip for this request.
|
871 |
-
header( 'X-Accel-Buffering: no' );
|
872 |
-
header( 'Content-Encoding: none' );
|
873 |
-
}
|
874 |
-
|
875 |
-
// Start the event stream here to record all the logs.
|
876 |
-
header( 'Content-Type: text/event-stream' );
|
877 |
-
header( 'Cache-Control: no-cache' );
|
878 |
-
|
879 |
-
// Time to run the import!
|
880 |
-
set_time_limit( 0 );
|
881 |
-
|
882 |
-
// Ensure we're not buffered.
|
883 |
-
wp_ob_end_flush_all();
|
884 |
-
flush();
|
885 |
-
|
886 |
-
// Run import process.
|
887 |
-
$process = $importer->import( $file );
|
888 |
-
|
889 |
-
// Setup complete response.
|
890 |
-
$complete = array(
|
891 |
-
'status' => true, // The process is complete no matter success or not.
|
892 |
-
'error' => false, // Message error if any.
|
893 |
-
'data' => null, // Compatibility with current Ajax.
|
894 |
-
'message' => 'Template contents were imported.',
|
895 |
-
);
|
896 |
-
|
897 |
-
// Check if the request is error, then set the message.
|
898 |
-
if ( is_wp_error( $process ) ) {
|
899 |
-
$complete['error'] = $process->get_error_message();
|
900 |
-
}
|
901 |
-
|
902 |
-
$this->message_sse( $complete );
|
903 |
-
exit;
|
904 |
-
|
905 |
-
} catch ( Exception $e ) {
|
906 |
-
$this->message_sse( $e->getMessage(), true );
|
907 |
-
exit;
|
908 |
-
}
|
909 |
-
}
|
910 |
-
|
911 |
-
/**
|
912 |
-
* Get settings.json data.
|
913 |
-
*
|
914 |
-
*/
|
915 |
-
public function getSettingsData( $template_name ) {
|
916 |
-
|
917 |
-
$this->setTemplateName( $template_name );
|
918 |
-
$settings_url = $this->getAssetsAddress( 'settings_url', $this->getTemplateName() );
|
919 |
-
$settings_path = $this->getAssetsAddress( 'settings_path', $this->getTemplateName() );
|
920 |
-
$response = JupiterX_Control_Panel_Helpers::getFileBody( $settings_url, $settings_path );
|
921 |
-
|
922 |
-
return json_decode( $response, true );
|
923 |
-
}
|
924 |
-
|
925 |
-
/**
|
926 |
-
* Send a Server-Sent Events message.
|
927 |
-
*
|
928 |
-
*
|
929 |
-
* @param mixed $message Data to be JSON-encoded and sent in the message.
|
930 |
-
* @param boolean $need_header Send response along with the header.
|
931 |
-
*/
|
932 |
-
public function message_sse( $message, $need_header = false ) {
|
933 |
-
// Add header to start event stream only if needed.
|
934 |
-
if ( $need_header ) {
|
935 |
-
// Start the event stream.
|
936 |
-
header( 'Content-Type: text/event-stream' );
|
937 |
-
header( 'Cache-Control: no-cache' );
|
938 |
-
}
|
939 |
-
|
940 |
-
// Convert any message data as an array.
|
941 |
-
if ( ! is_array( $message ) ) {
|
942 |
-
$message = array(
|
943 |
-
'message' => $message,
|
944 |
-
);
|
945 |
-
}
|
946 |
-
|
947 |
-
// Set message event and pass the data.
|
948 |
-
echo "event: message\n";
|
949 |
-
echo 'data: ' . wp_json_encode( $message ) . "\n\n";
|
950 |
-
|
951 |
-
flush();
|
952 |
-
}
|
953 |
-
|
954 |
-
public function importThemeContent( $template_name, $fetch_attachments = false, $partial_import = false ) {
|
955 |
-
try {
|
956 |
-
|
957 |
-
// Include wordpress-importer class.
|
958 |
-
JupiterX_Control_Panel_Helpers::include_wordpress_importer();
|
959 |
-
$this->reinitializeData( $template_name );
|
960 |
-
// Set importer options as an array.
|
961 |
-
$options = array(
|
962 |
-
'fetch_attachments' => filter_var( $fetch_attachments, FILTER_VALIDATE_BOOLEAN ),
|
963 |
-
'default_author' => get_current_user_id(),
|
964 |
-
);
|
965 |
-
|
966 |
-
// Create new instance for Importer.
|
967 |
-
$importer = new JupiterX_WXR_Importer( $options, $partial_import );
|
968 |
-
$logger = new JupiterX_Importer_Logger_ServerSentEvents();
|
969 |
-
$importer->set_logger( $logger );
|
970 |
-
|
971 |
-
// Get preliminary information.
|
972 |
-
$file = $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() );
|
973 |
-
$data = $importer->get_preliminary_information( $file );
|
974 |
-
if ( is_wp_error( $data ) ) {
|
975 |
-
$this->message( 'Error in parsing theme_content.xml!', false );
|
976 |
-
return false;
|
977 |
-
}
|
978 |
-
|
979 |
-
// Time to run the import!
|
980 |
-
set_time_limit( 0 );
|
981 |
-
|
982 |
-
// Run import process.
|
983 |
-
ob_start();
|
984 |
-
$importer->import( $file );
|
985 |
-
ob_end_clean();
|
986 |
-
|
987 |
-
$this->message( 'Template contents were imported.', true );
|
988 |
-
return true;
|
989 |
-
|
990 |
-
} catch ( Exception $e ) {
|
991 |
-
$this->message( $e->getMessage(), false );
|
992 |
-
return false;
|
993 |
-
}
|
994 |
-
}
|
995 |
-
public function importMenuLocations( $template_name ) {
|
996 |
-
try {
|
997 |
-
$settings = $this->getSettingsData( $template_name );
|
998 |
-
|
999 |
-
$nav_menus = wp_get_nav_menus();
|
1000 |
-
|
1001 |
-
if ( ! isset( $settings['options']['jupiterx_menu_locations'] ) || empty( $settings['options']['jupiterx_menu_locations'] ) || empty( $nav_menus ) ) {
|
1002 |
-
$this->message( 'There were no menu locations to import.', true );
|
1003 |
-
}
|
1004 |
-
|
1005 |
-
$menu_locations = $settings['options']['jupiterx_menu_locations'];
|
1006 |
-
|
1007 |
-
$locations = [];
|
1008 |
-
|
1009 |
-
foreach ( $nav_menus as $menu ) {
|
1010 |
-
if ( in_array( $menu->name, $menu_locations, true ) ) {
|
1011 |
-
$location_key = array_search( $menu->name, $menu_locations, true );
|
1012 |
-
$locations[ $location_key ] = $menu->term_id;
|
1013 |
-
}
|
1014 |
-
}
|
1015 |
-
|
1016 |
-
set_theme_mod( 'nav_menu_locations', $locations );
|
1017 |
-
|
1018 |
-
$this->message( 'Navigation locations is configured.', true, [ $locations ] );
|
1019 |
-
|
1020 |
-
return true;
|
1021 |
-
} catch ( Exception $e ) {
|
1022 |
-
$this->message( $e->getMessage(), false );
|
1023 |
-
|
1024 |
-
return false;
|
1025 |
-
} // End try().
|
1026 |
-
}
|
1027 |
-
|
1028 |
-
public function setUpPages( $template_name ) {
|
1029 |
-
try {
|
1030 |
-
$package_data = $this->getSettingsData( $template_name );
|
1031 |
-
|
1032 |
-
// Set homepage.
|
1033 |
-
if(isset($package_data['options']['page_on_front'])) {
|
1034 |
-
$homepage_title = $package_data['options']['page_on_front'];
|
1035 |
-
if ( ! empty( $homepage_title ) ) {
|
1036 |
-
$homepage = get_page_by_title( $homepage_title );
|
1037 |
-
}
|
1038 |
-
if ( ! empty( $homepage->ID ) ) {
|
1039 |
-
update_option( 'page_on_front', $homepage->ID );
|
1040 |
-
update_option( 'show_on_front', 'page' );
|
1041 |
-
}
|
1042 |
-
}
|
1043 |
-
|
1044 |
-
// Set shop page.
|
1045 |
-
if(isset($package_data['options']['woocommerce_shop_page_id'])) {
|
1046 |
-
$shop_title = $package_data['options']['woocommerce_shop_page_id'];
|
1047 |
-
if ( ! empty( $shop_title ) ) {
|
1048 |
-
$shop_page = get_page_by_title( $shop_title );
|
1049 |
-
}
|
1050 |
-
if ( ! empty( $shop_page->ID ) ) {
|
1051 |
-
update_option( 'woocommerce_shop_page_id', $shop_page->ID );
|
1052 |
-
}
|
1053 |
-
}
|
1054 |
-
|
1055 |
-
// Set cart page.
|
1056 |
-
if(isset($package_data['options']['woocommerce_cart_page_id'])) {
|
1057 |
-
$cart_title = $package_data['options']['woocommerce_cart_page_id'];
|
1058 |
-
if ( ! empty( $cart_title ) ) {
|
1059 |
-
$cart_page = get_page_by_title( $cart_title );
|
1060 |
-
}
|
1061 |
-
if ( ! empty( $cart_page->ID ) ) {
|
1062 |
-
update_option( 'woocommerce_cart_page_id', $cart_page->ID );
|
1063 |
-
}
|
1064 |
-
}
|
1065 |
-
|
1066 |
-
// Set Checkout page.
|
1067 |
-
if(isset($package_data['options']['woocommerce_checkout_page_id'])) {
|
1068 |
-
$checkout_title = $package_data['options']['woocommerce_checkout_page_id'];
|
1069 |
-
if ( ! empty( $checkout_title ) ) {
|
1070 |
-
$checkout_page = get_page_by_title( $checkout_title );
|
1071 |
-
}
|
1072 |
-
if ( ! empty( $checkout_page->ID ) ) {
|
1073 |
-
update_option( 'woocommerce_checkout_page_id', $checkout_page->ID );
|
1074 |
-
}
|
1075 |
-
}
|
1076 |
-
|
1077 |
-
// Set My Account page.
|
1078 |
-
if ( isset( $package_data['options']['woocommerce_myaccount_page_id'] ) ) {
|
1079 |
-
$myaccount_title = $package_data['options']['woocommerce_myaccount_page_id'];
|
1080 |
-
|
1081 |
-
if ( ! empty( $myaccount_title ) ) {
|
1082 |
-
$myaccount_page = get_page_by_title( $myaccount_title );
|
1083 |
-
}
|
1084 |
-
|
1085 |
-
if ( ! empty( $myaccount_page->ID ) ) {
|
1086 |
-
update_option( 'woocommerce_myaccount_page_id', $myaccount_page->ID );
|
1087 |
-
}
|
1088 |
-
}
|
1089 |
-
|
1090 |
-
$this->message( 'pages are configured.', true );
|
1091 |
-
|
1092 |
-
return true;
|
1093 |
-
} catch ( Exception $e ) {
|
1094 |
-
$this->message( $e->getMessage(), false );
|
1095 |
-
|
1096 |
-
return false;
|
1097 |
-
} // End try().
|
1098 |
-
}
|
1099 |
-
/**
|
1100 |
-
* Import Settings options.
|
1101 |
-
*
|
1102 |
-
* @param string $template_name Name of template.
|
1103 |
-
* @return mixed
|
1104 |
-
* @throws Exception When Settings file is empty.
|
1105 |
-
*/
|
1106 |
-
public function import_settings( $template_name ) {
|
1107 |
-
try {
|
1108 |
-
$this->reinitializeData( $template_name );
|
1109 |
-
$data = $this->getSettingsData( $template_name );
|
1110 |
-
|
1111 |
-
// Data checks.
|
1112 |
-
if ( 'array' != gettype( $data ) ) {
|
1113 |
-
throw new Exception(
|
1114 |
-
sprintf( esc_html__( 'Error importing settings! Please check that you uploaded (%s) a settings export file.', 'jupiterx-core' ), $file_name )
|
1115 |
-
);
|
1116 |
-
}
|
1117 |
-
if ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) {
|
1118 |
-
throw new Exception(
|
1119 |
-
sprintf( esc_html__( 'Error importing settings! template Please check that you uploaded (%s) a settings export file.', 'jupiterx-core' ), $file_name )
|
1120 |
-
);
|
1121 |
-
}
|
1122 |
-
|
1123 |
-
// Clear theme mods.
|
1124 |
-
remove_theme_mods();
|
1125 |
-
|
1126 |
-
$data['mods'] = JupiterX_Control_Panel_Export_Import::_import_images( $data['mods'] );
|
1127 |
-
|
1128 |
-
// If wp_css is set then import it.
|
1129 |
-
if ( function_exists( 'wp_update_custom_css_post' ) && isset( $data['wp_css'] ) && '' !== $data['wp_css'] ) {
|
1130 |
-
wp_update_custom_css_post( $data['wp_css'] );
|
1131 |
-
}
|
1132 |
-
|
1133 |
-
// Exclude nav menu locations in this process.
|
1134 |
-
if ( isset( $data['mods']['nav_menu_locations'] ) ) {
|
1135 |
-
unset( $data['mods']['nav_menu_locations'] );
|
1136 |
-
}
|
1137 |
-
|
1138 |
-
// Loop through the mods.
|
1139 |
-
foreach ( $data['mods'] as $key => $val ) {
|
1140 |
-
set_theme_mod( $key, $val );
|
1141 |
-
}
|
1142 |
-
|
1143 |
-
// Set Jet Menu options.
|
1144 |
-
if ( isset( $data['options']['jet_menu_options'] ) ) {
|
1145 |
-
update_option( 'jet_menu_options', $data['options']['jet_menu_options'] );
|
1146 |
-
}
|
1147 |
-
|
1148 |
-
// Set Jet Popup options.
|
1149 |
-
if ( isset( $data['options']['jet_popup_conditions'] ) ) {
|
1150 |
-
update_option( 'jet_popup_conditions', $data['options']['jet_popup_conditions'] );
|
1151 |
-
}
|
1152 |
-
|
1153 |
-
// Set Jupiter X custom siderbars option.
|
1154 |
-
if ( isset( $data['options']['jupiterx_custom_sidebars'] ) ) {
|
1155 |
-
jupiterx_update_option( 'custom_sidebars', $data['options']['jupiterx_custom_sidebars'] );
|
1156 |
-
}
|
1157 |
-
|
1158 |
-
// Set extra options.
|
1159 |
-
if ( ! empty( $data['options']['extra'] ) ) {
|
1160 |
-
foreach( $data['options']['extra'] as $key => $val ) {
|
1161 |
-
if ( 'elementor_cpt_support' === $key && ! is_array( $val ) ) {
|
1162 |
-
continue;
|
1163 |
-
}
|
1164 |
-
|
1165 |
-
if ( 'elementor_global_image_lightbox' === $key && is_bool( $val ) ) {
|
1166 |
-
continue;
|
1167 |
-
}
|
1168 |
-
|
1169 |
-
update_option( $key, $val );
|
1170 |
-
}
|
1171 |
-
}
|
1172 |
-
|
1173 |
-
$this->message( 'Settings are imported.', true );
|
1174 |
-
return true;
|
1175 |
-
|
1176 |
-
} catch ( Exception $e ) {
|
1177 |
-
$this->message( $e->getMessage(), false );
|
1178 |
-
|
1179 |
-
return false;
|
1180 |
-
}
|
1181 |
-
}
|
1182 |
-
public function importThemeWidgets( $template_name ) {
|
1183 |
-
$this->reinitializeData( $template_name );
|
1184 |
-
try {
|
1185 |
-
$data = JupiterX_Control_Panel_Helpers::getFileBody(
|
1186 |
-
$this->getAssetsAddress( 'widget_url', $this->getTemplateName() ),
|
1187 |
-
$this->getAssetsAddress( 'widget_path', $this->getTemplateName() )
|
1188 |
-
);
|
1189 |
-
$data = json_decode( $data, true );
|
1190 |
-
$this->import_widget_data( $data );
|
1191 |
-
|
1192 |
-
$this->message( 'Widgets are imported.', true );
|
1193 |
-
|
1194 |
-
return true;
|
1195 |
-
} catch ( Exception $e ) {
|
1196 |
-
$this->message( $e->getMessage(), false );
|
1197 |
-
|
1198 |
-
return false;
|
1199 |
-
}
|
1200 |
-
}
|
1201 |
-
public function finalizeImporting( $template_name, $partial_import = false ) {
|
1202 |
-
$this->reinitializeData( $template_name );
|
1203 |
-
$template_name = sanitize_title( $template_name );
|
1204 |
-
// Check if it had something to import.
|
1205 |
-
try {
|
1206 |
-
|
1207 |
-
if ( ! $this->cleanInstallFiles( $template_name ) ) {
|
1208 |
-
throw new Exception( 'Can not remove installation source files' );
|
1209 |
-
return false;
|
1210 |
-
}
|
1211 |
-
|
1212 |
-
if ( ! $partial_import ) {
|
1213 |
-
jupiterx_update_option( 'template_installed', $this->getTemplateName() );
|
1214 |
-
jupiterx_update_option( 'template_installed_id', $this->getTemplateID() );
|
1215 |
-
}
|
1216 |
-
|
1217 |
-
jupiterx_core_flush_cache();
|
1218 |
-
|
1219 |
-
$this->message( 'Data imported successfully', true );
|
1220 |
-
return true;
|
1221 |
-
|
1222 |
-
} catch ( Exception $e ) {
|
1223 |
-
$this->message( $e->getMessage(), false );
|
1224 |
-
|
1225 |
-
return false;
|
1226 |
-
}
|
1227 |
-
}
|
1228 |
-
|
1229 |
-
/**
|
1230 |
-
* Set default value Raven nav menus recursively.
|
1231 |
-
*
|
1232 |
-
* @access public
|
1233 |
-
* @since 1.4.0
|
1234 |
-
*
|
1235 |
-
* @param array $element Template element.
|
1236 |
-
* @param array $list Raven menu default list.
|
1237 |
-
* @return void
|
1238 |
-
*/
|
1239 |
-
public function set_default_raven_menu_list( &$element, $list )
|
1240 |
-
{
|
1241 |
-
if (
|
1242 |
-
isset( $element['elType'] ) &&
|
1243 |
-
$element['elType'] === 'widget' &&
|
1244 |
-
isset( $element['widgetType'] ) &&
|
1245 |
-
$element['widgetType'] === 'raven-nav-menu' &&
|
1246 |
-
! isset( $element['settings']['list'] )
|
1247 |
-
) {
|
1248 |
-
$element['settings']['list'] = $list;
|
1249 |
-
return;
|
1250 |
-
}
|
1251 |
-
|
1252 |
-
foreach( $element['elements'] as &$inner_element ) {
|
1253 |
-
$this->set_default_raven_menu_list( $inner_element, $list );
|
1254 |
-
}
|
1255 |
-
}
|
1256 |
-
|
1257 |
-
/**
|
1258 |
-
* Clean install files
|
1259 |
-
*
|
1260 |
-
* @param $template_name
|
1261 |
-
* @author Artbees Team
|
1262 |
-
* @return bool
|
1263 |
-
*/
|
1264 |
-
private function cleanInstallFiles( $template_name ) {
|
1265 |
-
$jupiterx_filesystem = new JupiterX_Filesystem(
|
1266 |
-
array(
|
1267 |
-
'context' => $this->getBasePath(),
|
1268 |
-
)
|
1269 |
-
);
|
1270 |
-
|
1271 |
-
// Deleting Template Source Folder.
|
1272 |
-
$template_path = $this->getBasePath() . sanitize_title( $template_name );
|
1273 |
-
if ( $jupiterx_filesystem->exists( $template_path ) && $jupiterx_filesystem->is_dir( $template_path ) && ! $jupiterx_filesystem->delete( $template_path, true ) ) {
|
1274 |
-
return false;
|
1275 |
-
}
|
1276 |
-
|
1277 |
-
// Deleting Template Source Zip file.
|
1278 |
-
$template_zip = $template_path . '.zip';
|
1279 |
-
if ( $jupiterx_filesystem->exists( $template_zip ) && $jupiterx_filesystem->is_file( $template_zip ) && ! $jupiterx_filesystem->delete( $template_zip ) ) {
|
1280 |
-
return false;
|
1281 |
-
}
|
1282 |
-
|
1283 |
-
return true;
|
1284 |
-
}
|
1285 |
-
public function uninstallTemplate() {
|
1286 |
-
try {
|
1287 |
-
$tables = array(
|
1288 |
-
'comments',
|
1289 |
-
'commentmeta',
|
1290 |
-
'links',
|
1291 |
-
'options',
|
1292 |
-
'postmeta',
|
1293 |
-
'posts',
|
1294 |
-
'term_relationships',
|
1295 |
-
'termmeta',
|
1296 |
-
'terms',
|
1297 |
-
'term_taxonomy',
|
1298 |
-
);
|
1299 |
-
|
1300 |
-
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
1301 |
-
|
1302 |
-
$db_manager->backup_media_records();
|
1303 |
-
|
1304 |
-
$reset = $this->resetWordpressDatabase( $tables, array(), true );
|
1305 |
-
|
1306 |
-
$db_manager->restore_media_records();
|
1307 |
-
|
1308 |
-
if ( ! $reset ) {
|
1309 |
-
throw new Exception( 'Failed to uninstall template. Please try again.' );
|
1310 |
-
}
|
1311 |
-
|
1312 |
-
$this->message( 'Template uninstall success.', true );
|
1313 |
-
return true;
|
1314 |
-
} catch ( Exception $e ) {
|
1315 |
-
$this->message( $e->getMessage(), false );
|
1316 |
-
|
1317 |
-
return false;
|
1318 |
-
}
|
1319 |
-
}
|
1320 |
-
public function availableWidgets() {
|
1321 |
-
global $wp_registered_widget_controls;
|
1322 |
-
$widget_controls = $wp_registered_widget_controls;
|
1323 |
-
$available_widgets = array();
|
1324 |
-
foreach ( $widget_controls as $widget ) {
|
1325 |
-
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
|
1326 |
-
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
1327 |
-
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
1328 |
-
}
|
1329 |
-
}
|
1330 |
-
|
1331 |
-
return apply_filters( 'available_widgets', $available_widgets );
|
1332 |
-
}
|
1333 |
-
|
1334 |
-
/**
|
1335 |
-
* Import widgets' data.
|
1336 |
-
*
|
1337 |
-
* @throws Exception If can not read widget data.
|
1338 |
-
*
|
1339 |
-
* @param array $data Widgets' data.
|
1340 |
-
* @return boolean
|
1341 |
-
*/
|
1342 |
-
public function import_widget_data( $data ) {
|
1343 |
-
global $wp_registered_sidebars;
|
1344 |
-
|
1345 |
-
$available_widgets = $this->availableWidgets();
|
1346 |
-
$widget_instances = array();
|
1347 |
-
foreach ( $available_widgets as $widget_data ) {
|
1348 |
-
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
1349 |
-
}
|
1350 |
-
if ( empty( $data ) || ! is_array( $data ) ) {
|
1351 |
-
throw new Exception( 'Widget data could not be read. Please try a different file.' );
|
1352 |
-
}
|
1353 |
-
$results = array();
|
1354 |
-
foreach ( $data as $sidebar_id => $widgets ) {
|
1355 |
-
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
1356 |
-
continue;
|
1357 |
-
}
|
1358 |
-
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
1359 |
-
$sidebar_available = true;
|
1360 |
-
$use_sidebar_id = $sidebar_id;
|
1361 |
-
$sidebar_message_type = 'success';
|
1362 |
-
$sidebar_message = '';
|
1363 |
-
} else {
|
1364 |
-
$sidebar_available = false;
|
1365 |
-
$use_sidebar_id = 'wp_inactive_widgets';
|
1366 |
-
$sidebar_message_type = 'error';
|
1367 |
-
$sidebar_message = 'Sidebar does not exist in theme (using Inactive)';
|
1368 |
-
}
|
1369 |
-
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id;
|
1370 |
-
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
1371 |
-
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
1372 |
-
$results[ $sidebar_id ]['widgets'] = array();
|
1373 |
-
foreach ( $widgets as $widget_instance_id => $widget ) {
|
1374 |
-
$fail = false;
|
1375 |
-
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
1376 |
-
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
1377 |
-
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
1378 |
-
$fail = true;
|
1379 |
-
$widget_message_type = 'error';
|
1380 |
-
$widget_message = 'Site does not support widget';
|
1381 |
-
}
|
1382 |
-
$widget = apply_filters( 'jupiterx_widget_settings', $widget );
|
1383 |
-
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
1384 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
1385 |
-
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array();
|
1386 |
-
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
1387 |
-
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
1388 |
-
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
1389 |
-
$fail = true;
|
1390 |
-
$widget_message_type = 'warning';
|
1391 |
-
$widget_message = 'Widget already exists';
|
1392 |
-
break;
|
1393 |
-
}
|
1394 |
-
}
|
1395 |
-
}
|
1396 |
-
if ( ! $fail ) {
|
1397 |
-
$single_widget_instances = get_option( 'widget_' . $id_base );
|
1398 |
-
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array(
|
1399 |
-
'_multiwidget' => 1,
|
1400 |
-
);
|
1401 |
-
$single_widget_instances[] = (array) $widget;
|
1402 |
-
end( $single_widget_instances );
|
1403 |
-
$new_instance_id_number = key( $single_widget_instances );
|
1404 |
-
if ( '0' === strval( $new_instance_id_number ) ) {
|
1405 |
-
$new_instance_id_number = 1;
|
1406 |
-
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
1407 |
-
unset( $single_widget_instances[0] );
|
1408 |
-
}
|
1409 |
-
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
1410 |
-
$multiwidget = $single_widget_instances['_multiwidget'];
|
1411 |
-
unset( $single_widget_instances['_multiwidget'] );
|
1412 |
-
$single_widget_instances['_multiwidget'] = $multiwidget;
|
1413 |
-
}
|
1414 |
-
update_option( 'widget_' . $id_base, $single_widget_instances );
|
1415 |
-
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
1416 |
-
$new_instance_id = $id_base . '-' . $new_instance_id_number;
|
1417 |
-
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id;
|
1418 |
-
update_option( 'sidebars_widgets', $sidebars_widgets );
|
1419 |
-
if ( $sidebar_available ) {
|
1420 |
-
$widget_message_type = 'success';
|
1421 |
-
$widget_message = 'Imported';
|
1422 |
-
} else {
|
1423 |
-
$widget_message_type = 'warning';
|
1424 |
-
$widget_message = 'Imported to Inactive';
|
1425 |
-
}
|
1426 |
-
}
|
1427 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base;
|
1428 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget->title ) ? $widget->title : '';
|
1429 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
1430 |
-
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
1431 |
-
} // End foreach().
|
1432 |
-
} // End foreach().
|
1433 |
-
|
1434 |
-
return true;
|
1435 |
-
}
|
1436 |
-
/**
|
1437 |
-
* It will empty all or custom database tables of WordPress and install WordPress again if needed.
|
1438 |
-
*
|
1439 |
-
* @param array $table which table need to be empty ? example : array('user' , 'usermeta')
|
1440 |
-
* table names should be without any prefix
|
1441 |
-
* @param bool $install_needed if WordPress need to be installed after reseting database
|
1442 |
-
* it should be false or true
|
1443 |
-
*
|
1444 |
-
* @return bool return if everything looks good and throwing errors on problems
|
1445 |
-
*/
|
1446 |
-
public function resetWordpressDatabase( $tables = array(), $exclude_tables = array(), $install_needed = false ) {
|
1447 |
-
global $wpdb, $reactivate_wp_reset_additional, $current_user;
|
1448 |
-
|
1449 |
-
if ( $install_needed ) {
|
1450 |
-
|
1451 |
-
require_once ABSPATH . '/wp-admin/includes/upgrade.php';
|
1452 |
-
|
1453 |
-
$new_options = array();
|
1454 |
-
|
1455 |
-
$old_options = array(
|
1456 |
-
'active_plugins',
|
1457 |
-
);
|
1458 |
-
|
1459 |
-
$blogname = get_option( 'blogname' );
|
1460 |
-
$blog_public = get_option( 'blog_public' );
|
1461 |
-
$site_url = site_url();
|
1462 |
-
$current_theme = wp_get_theme();
|
1463 |
-
|
1464 |
-
foreach ( $old_options as $old_option_key ) {
|
1465 |
-
$new_options[ $old_option_key ] = get_option( $old_option_key );
|
1466 |
-
}
|
1467 |
-
|
1468 |
-
$keep_options = [
|
1469 |
-
'api_key',
|
1470 |
-
'api_access_token',
|
1471 |
-
'envato_purchase_code_5177775',
|
1472 |
-
'setup_wizard_current_page',
|
1473 |
-
'setup_wizard_hide_notice',
|
1474 |
-
];
|
1475 |
-
|
1476 |
-
$jupiterx_options = get_option( 'jupiterx', [] );
|
1477 |
-
|
1478 |
-
$new_options['jupiterx'] = array_intersect_key( $jupiterx_options, array_flip( $keep_options ) );
|
1479 |
-
|
1480 |
-
if ( 'admin' != $current_user->user_login ) {
|
1481 |
-
$user = get_user_by( 'login', 'admin' );
|
1482 |
-
}
|
1483 |
-
|
1484 |
-
if ( empty( $user->user_level ) || $user->user_level < 10 ) {
|
1485 |
-
$user = $current_user;
|
1486 |
-
$session_tokens = get_user_meta( $user->ID, 'session_tokens', true );
|
1487 |
-
}
|
1488 |
-
|
1489 |
-
// Check if we need all the tables or specific table.
|
1490 |
-
if ( is_array( $tables ) && count( $tables ) > 0 ) {
|
1491 |
-
array_walk(
|
1492 |
-
$tables, function ( &$value, $key ) use ( $wpdb ) {
|
1493 |
-
$value = $wpdb->prefix . $value;
|
1494 |
-
}
|
1495 |
-
);
|
1496 |
-
} else {
|
1497 |
-
$prefix = str_replace( '_', '\_', $wpdb->prefix );
|
1498 |
-
$tables = $wpdb->get_col( "SHOW TABLES LIKE '{$prefix}%'" );
|
1499 |
-
}
|
1500 |
-
|
1501 |
-
// exclude table if its valued.
|
1502 |
-
if ( is_array( $exclude_tables ) && count( $exclude_tables ) > 0 ) {
|
1503 |
-
array_walk(
|
1504 |
-
$exclude_tables, function ( &$ex_value, $key ) use ( $wpdb ) {
|
1505 |
-
$ex_value = $wpdb->prefix . $ex_value;
|
1506 |
-
}
|
1507 |
-
);
|
1508 |
-
$tables = array_diff( $tables, $exclude_tables );
|
1509 |
-
}
|
1510 |
-
// Removing data from WordPress tables.
|
1511 |
-
foreach ( $tables as $table ) {
|
1512 |
-
$wpdb->query( "DROP TABLE $table" );
|
1513 |
-
}
|
1514 |
-
|
1515 |
-
$result = wp_install( $blogname, $user->user_login, $user->user_email, $blog_public );
|
1516 |
-
switch_theme( $current_theme->get_stylesheet() );
|
1517 |
-
|
1518 |
-
/* GoDaddy Patch => GD have a problem of cleaning siteurl option value after reseting database */
|
1519 |
-
if ( site_url() == '' ) {
|
1520 |
-
$wpdb->update(
|
1521 |
-
$wpdb->options, array(
|
1522 |
-
'option_value' => $site_url,
|
1523 |
-
),array(
|
1524 |
-
'option_name' => 'siteurl',
|
1525 |
-
)
|
1526 |
-
);
|
1527 |
-
}
|
1528 |
-
extract( $result, EXTR_SKIP );
|
1529 |
-
|
1530 |
-
$query = $wpdb->prepare( "UPDATE $wpdb->users SET user_pass = %s, user_activation_key = '' WHERE ID = %d", $user->user_pass, $user_id );
|
1531 |
-
$wpdb->query( $query );
|
1532 |
-
|
1533 |
-
$get_user_meta = function_exists( 'get_user_meta' ) ? 'get_user_meta' : 'get_usermeta';
|
1534 |
-
$update_user_meta = function_exists( 'update_user_meta' ) ? 'update_user_meta' : 'update_usermeta';
|
1535 |
-
|
1536 |
-
if ( $get_user_meta($user_id, 'default_password_nag') ) {
|
1537 |
-
$update_user_meta($user_id, 'default_password_nag', false);
|
1538 |
-
}
|
1539 |
-
|
1540 |
-
if ( $get_user_meta($user_id, $wpdb->prefix . 'default_password_nag') ) {
|
1541 |
-
$update_user_meta($user_id, $wpdb->prefix . 'default_password_nag', false);
|
1542 |
-
}
|
1543 |
-
|
1544 |
-
wp_clear_auth_cookie();
|
1545 |
-
wp_set_current_user( $user_id, $user->user_login );
|
1546 |
-
if ( $session_tokens ) {
|
1547 |
-
delete_user_meta( $user->ID, 'session_tokens' );
|
1548 |
-
update_user_meta( $user->ID, 'session_tokens', $session_tokens );
|
1549 |
-
}
|
1550 |
-
|
1551 |
-
wp_set_auth_cookie( $user_id, true );
|
1552 |
-
do_action( 'wp_login', $user->user_login, $user );
|
1553 |
-
|
1554 |
-
if ( $new_options ) {
|
1555 |
-
foreach ( $new_options as $key => $value ) {
|
1556 |
-
update_option( $key, $value );
|
1557 |
-
}
|
1558 |
-
}
|
1559 |
-
return true;
|
1560 |
-
} else {
|
1561 |
-
|
1562 |
-
$jupiterx_temp_installed = jupiterx_get_option( 'template_installed' );
|
1563 |
-
|
1564 |
-
if ( $jupiterx_temp_installed ) {
|
1565 |
-
|
1566 |
-
// Delete option data for page_on_front.
|
1567 |
-
if ( get_option( 'page_on_front' ) ) {
|
1568 |
-
delete_option( 'page_on_front' );
|
1569 |
-
}
|
1570 |
-
|
1571 |
-
// Delete option data for show_on_front.
|
1572 |
-
if ( get_option( 'show_on_front' ) ) {
|
1573 |
-
delete_option( 'show_on_front' );
|
1574 |
-
}
|
1575 |
-
|
1576 |
-
// Delete option data for woocommerce_shop_page_id.
|
1577 |
-
if ( get_option( 'woocommerce_shop_page_id' ) ) {
|
1578 |
-
delete_option( 'woocommerce_shop_page_id' );
|
1579 |
-
}
|
1580 |
-
|
1581 |
-
// Delete widgets.
|
1582 |
-
$wpdb->query( "DELETE FROM {$wpdb->prefix}options WHERE option_name LIKE '%widget%';" );
|
1583 |
-
|
1584 |
-
}// End if().
|
1585 |
-
|
1586 |
-
// truncate tables.
|
1587 |
-
foreach ( $tables as $table ) {
|
1588 |
-
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}{$table}" );
|
1589 |
-
}
|
1590 |
-
|
1591 |
-
return true;
|
1592 |
-
}// End if().
|
1593 |
-
}
|
1594 |
-
|
1595 |
-
private function setResponseForApiTemplateList( $url, $configs ) {
|
1596 |
-
$headers = array(
|
1597 |
-
'theme-name' => $this->getThemeName(),
|
1598 |
-
'pagination-start' => isset( $configs['pagination_start'] ) ? $configs['pagination_start'] : 0,
|
1599 |
-
'pagination-count' => isset( $configs['pagination_count'] ) ? $configs['pagination_count'] : 1,
|
1600 |
-
);
|
1601 |
-
|
1602 |
-
if ( isset( $configs['template_id'] ) && is_null( $configs['template_id'] ) == false ) {
|
1603 |
-
$headers['template-id'] = $configs['template_id'];
|
1604 |
-
}
|
1605 |
-
|
1606 |
-
if ( isset( $configs['template_name'] ) && is_null( $configs['template_name'] ) == false ) {
|
1607 |
-
$headers['template-name'] = $configs['template_name'];
|
1608 |
-
}
|
1609 |
-
|
1610 |
-
if ( isset( $configs['template_category'] ) && is_null( $configs['template_category'] ) == false ) {
|
1611 |
-
$headers['template-category'] = $configs['template_category'];
|
1612 |
-
}
|
1613 |
-
|
1614 |
-
return $this->wp_remote_get( $url, $headers );
|
1615 |
-
}
|
1616 |
-
/**
|
1617 |
-
* This method is resposible to get template list from api and create download link if template need to extract from WordPress repo.
|
1618 |
-
*
|
1619 |
-
* @param str $template_name if template name is valued it will return array of information about the this template.
|
1620 |
-
* but if template is valued as false it will return all templates information
|
1621 |
-
*
|
1622 |
-
* @return array will return array of templates
|
1623 |
-
*/
|
1624 |
-
public function getTemplateListFromApi( $configs ) {
|
1625 |
-
if ( ! is_array( $configs ) ) {
|
1626 |
-
$configs = array();
|
1627 |
-
}
|
1628 |
-
$url = $this->getApiURL() . 'theme/templates';
|
1629 |
-
$response = $this->setResponseForApiTemplateList( $url, $configs );
|
1630 |
-
if ( false == isset( $response->bool ) || false == $response->bool ) {
|
1631 |
-
throw new Exception( $response->message );
|
1632 |
-
}
|
1633 |
-
return $response->data;
|
1634 |
-
}
|
1635 |
-
public function getTemplateDownloadLink( $template_name = '', $type = 'download' ) {
|
1636 |
-
$url = $this->getApiURL() . 'theme/download-template';
|
1637 |
-
$response = $this->wp_remote_get( $url, array(
|
1638 |
-
'template-name' => $template_name,
|
1639 |
-
'type' => $type,
|
1640 |
-
) );
|
1641 |
-
|
1642 |
-
if ( false == isset( $response->bool ) || false == $response->bool ) {
|
1643 |
-
throw new Exception( $response->message );
|
1644 |
-
}
|
1645 |
-
|
1646 |
-
/**
|
1647 |
-
* Filters the template download url.
|
1648 |
-
*
|
1649 |
-
* @param string $response->data Download url.
|
1650 |
-
*/
|
1651 |
-
return apply_filters( 'jupiterx_template_download_url', $response->data, $type );
|
1652 |
-
}
|
1653 |
-
|
1654 |
-
/**
|
1655 |
-
* Gets psd file download link.
|
1656 |
-
*
|
1657 |
-
*/
|
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,
|
1665 |
-
)
|
1666 |
-
);
|
1667 |
-
return true;
|
1668 |
-
} catch ( Exception $e ) {
|
1669 |
-
$this->message( $e->getMessage(), false );
|
1670 |
-
return false;
|
1671 |
-
} // End try().
|
1672 |
-
}
|
1673 |
-
|
1674 |
-
/**
|
1675 |
-
* This method is resposible to get templates categories list from api
|
1676 |
-
*
|
1677 |
-
* @param str $template_name if template name is valued it will return array of information about the this template.
|
1678 |
-
* but if template is valued as false it will return all templates information.
|
1679 |
-
*
|
1680 |
-
* @return array will return array of plugins.
|
1681 |
-
*/
|
1682 |
-
public function getTemplateCategoryListFromApi() {
|
1683 |
-
try {
|
1684 |
-
$url = $this->getApiURL() . 'theme/template-categories';
|
1685 |
-
$response = $this->wp_remote_get( $url );
|
1686 |
-
if ( false == isset( $response->bool ) || false == $response->bool ) {
|
1687 |
-
throw new Exception( $response->message );
|
1688 |
-
}
|
1689 |
-
$this->message( 'Successfull', true, $response->data );
|
1690 |
-
return true;
|
1691 |
-
} catch ( Exception $e ) {
|
1692 |
-
$this->message( $e->getMessage(), false );
|
1693 |
-
return false;
|
1694 |
-
}
|
1695 |
-
}
|
1696 |
-
/**
|
1697 |
-
* We need to make assets addresses dynamic and fully proccess.
|
1698 |
-
* in one method for future development
|
1699 |
-
* it will get the type of address and will return full address in string
|
1700 |
-
* example :
|
1701 |
-
* for (options_url) type , it will return something like this
|
1702 |
-
* (http://localhost/jupiter/wp-content/uploads/jupiterx_templates/dia/options.txt).
|
1703 |
-
*
|
1704 |
-
* For (options_path) type , it will return something like this.
|
1705 |
-
* (/usr/apache/www/wp-content/uploads/jupiterx_templates/dia/options.txt)
|
1706 |
-
*
|
1707 |
-
* @param str $which_one Which address do you need.
|
1708 |
-
* @param str $template_name such as.
|
1709 |
-
*/
|
1710 |
-
public function getAssetsAddress( $which_one, $template_name ) {
|
1711 |
-
$template_name = sanitize_title( $template_name );
|
1712 |
-
switch ( $which_one ) {
|
1713 |
-
case 'template_content_url':
|
1714 |
-
return $this->getBaseUrl() . $template_name . '/' . $this->getTemplateContentFileName();
|
1715 |
-
break;
|
1716 |
-
case 'template_content_path':
|
1717 |
-
return $this->getBasePath() . $template_name . '/' . $this->getTemplateContentFileName();
|
1718 |
-
break;
|
1719 |
-
case 'widget_url':
|
1720 |
-
return $this->getBaseUrl() . $template_name . '/' . $this->getWidgetFileName();
|
1721 |
-
break;
|
1722 |
-
case 'widget_path':
|
1723 |
-
return $this->getBasePath() . $template_name . '/' . $this->getWidgetFileName();
|
1724 |
-
break;
|
1725 |
-
case 'settings_url':
|
1726 |
-
return $this->getBaseUrl() . $template_name . '/' . $this->get_settings_file_name();
|
1727 |
-
break;
|
1728 |
-
case 'settings_path':
|
1729 |
-
return $this->getBasePath() . $template_name . '/' . $this->get_settings_file_name();
|
1730 |
-
break;
|
1731 |
-
default:
|
1732 |
-
throw new Exception( 'File name you are looking for is not introduced.' );
|
1733 |
-
|
1734 |
-
return false;
|
1735 |
-
break;
|
1736 |
-
}
|
1737 |
-
}
|
1738 |
-
|
1739 |
-
public function find_plugin_path( $plugin_slug ) {
|
1740 |
-
$plugins = get_plugins();
|
1741 |
-
foreach ( $plugins as $plugin_address => $plugin_data ) {
|
1742 |
-
|
1743 |
-
// Extract slug from address
|
1744 |
-
if ( strlen( $plugin_address ) == basename( $plugin_address ) ) {
|
1745 |
-
$slug = strtolower( str_replace( '.php', '', $plugin_address ) );
|
1746 |
-
} else {
|
1747 |
-
$slug = strtolower( str_replace( '/' . basename( $plugin_address ), '', $plugin_address ) );
|
1748 |
-
}
|
1749 |
-
// Check if slug exists
|
1750 |
-
if ( strtolower( $plugin_slug ) == $slug ) {
|
1751 |
-
return $plugin_address;
|
1752 |
-
}
|
1753 |
-
}
|
1754 |
-
return false;
|
1755 |
-
}
|
1756 |
-
|
1757 |
-
public function importLayerSliderContent( $content_path ) {
|
1758 |
-
global $wpdb;
|
1759 |
-
$ls_path = $this->find_plugin_path( $this->layer_slider_slug );
|
1760 |
-
|
1761 |
-
if ( $ls_path == false ) {
|
1762 |
-
throw new Exception( 'LayerSlider is not installed , install it first' );
|
1763 |
-
return false;
|
1764 |
-
}
|
1765 |
-
|
1766 |
-
if ( defined( LS_PLUGIN_VERSION ) ) {
|
1767 |
-
throw new Exception( 'LayerSlider is installed but not activated , activate it first' );
|
1768 |
-
return false;
|
1769 |
-
}
|
1770 |
-
// Empty layerslider table first.
|
1771 |
-
$table = $wpdb->prefix . 'layerslider';
|
1772 |
-
$wpdb->query( "TRUNCATE TABLE $table" );
|
1773 |
-
|
1774 |
-
// Try to import configs.
|
1775 |
-
$ls_plugin_root_path = pathinfo( $plugin->get_plugins_dir() . $ls_path );
|
1776 |
-
include $ls_plugin_root_path['dirname'] . '/classes/class.ls.importutil.php';
|
1777 |
-
new LS_ImportUtil( $content_path );
|
1778 |
-
return true;
|
1779 |
-
}
|
1780 |
-
|
1781 |
-
/**
|
1782 |
-
* Reusable wrapper method for WP remote getter.
|
1783 |
-
*
|
1784 |
-
* Method only returns response body.
|
1785 |
-
*/
|
1786 |
-
public function wp_remote_get( $url = '', $headers = [] ) {
|
1787 |
-
$required_headers = [
|
1788 |
-
'api-key' => jupiterx_get_option( 'api_key' ),
|
1789 |
-
'domain' => esc_url_raw( $_SERVER['SERVER_NAME'] ),
|
1790 |
-
];
|
1791 |
-
|
1792 |
-
// Combined headers.
|
1793 |
-
$headers = array_merge( $headers, $required_headers );
|
1794 |
-
|
1795 |
-
$response = json_decode( wp_remote_retrieve_body( wp_remote_get( $url, [
|
1796 |
-
'sslverify' => false,
|
1797 |
-
'headers' => $headers,
|
1798 |
-
] ) ) );
|
1799 |
-
|
1800 |
-
return $response;
|
1801 |
-
}
|
1802 |
-
|
1803 |
-
/**
|
1804 |
-
* This method is resposible to manage all the classes messages.
|
1805 |
-
*/
|
1806 |
-
public function message( $message, $status, $data = null ) {
|
1807 |
-
$response = [
|
1808 |
-
'message' => jupiterx_logic_message_helper( 'template-management', $message ),
|
1809 |
-
'status' => $status,
|
1810 |
-
'data' => $data,
|
1811 |
-
];
|
1812 |
-
|
1813 |
-
wp_send_json( $response );
|
1814 |
-
}
|
1815 |
-
}
|
1816 |
-
}
|
1817 |
-
|
1818 |
-
if ( ! function_exists( 'jupiterx_disable_woocommerce' ) ) {
|
1819 |
-
/* Disable woocommerce redirection */
|
1820 |
-
add_action( 'admin_init', 'jupiterx_disable_woocommerce', 5 );
|
1821 |
-
/**
|
1822 |
-
* Disable Woocommerce redirect for template install
|
1823 |
-
*
|
1824 |
-
*/
|
1825 |
-
function jupiterx_disable_woocommerce() {
|
1826 |
-
delete_transient( '_wc_activation_redirect' );
|
1827 |
-
add_filter(
|
1828 |
-
'woocommerce_prevent_automatic_wizard_redirect', function () {
|
1829 |
-
return true;
|
1830 |
-
}
|
1831 |
-
);
|
1832 |
-
}
|
1833 |
-
}
|
1834 |
-
|
1835 |
-
|
1836 |
-
add_filter(
|
1837 |
-
'pre_transient__wc_activation_redirect', function () {
|
1838 |
-
return 0;
|
1839 |
-
}
|
1840 |
-
);
|
1841 |
-
|
1842 |
-
add_filter(
|
1843 |
-
'pre_transient__vc_page_welcome_redirect', function () {
|
1844 |
-
return 0;
|
1845 |
-
}
|
1846 |
-
);
|
1847 |
-
|
1848 |
-
global $abb_phpunit;
|
1849 |
-
if ( empty( $abb_phpunit ) || $abb_phpunit == false ) {
|
1850 |
-
new JupiterX_Control_Panel_Install_Template();
|
1851 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class is responsible manage all jupiter templates
|
4 |
+
* it will communicate with artbees API and get list of templates , install them or remove them.
|
5 |
+
*
|
6 |
+
* @author Artbees <info@artbees.net>
|
7 |
+
* @copyright Artbees LTD (c)
|
8 |
+
*
|
9 |
+
* @link https://artbees.net
|
10 |
+
* @since 1.0
|
11 |
+
* @version 1.0
|
12 |
+
*/
|
13 |
+
if ( ! class_exists( 'JupiterX_Control_Panel_Install_Template' ) ) {
|
14 |
+
class JupiterX_Control_Panel_Install_Template {
|
15 |
+
|
16 |
+
|
17 |
+
private $layer_slider_slug = 'layerslider';
|
18 |
+
|
19 |
+
private $theme_name;
|
20 |
+
|
21 |
+
public function setThemeName( $theme_name ) {
|
22 |
+
$this->theme_name = $theme_name;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function getThemeName() {
|
26 |
+
return $this->theme_name;
|
27 |
+
}
|
28 |
+
|
29 |
+
private $api_url;
|
30 |
+
|
31 |
+
public function setApiURL( $api_url ) {
|
32 |
+
$this->api_url = $api_url;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function getApiURL() {
|
36 |
+
return $this->api_url;
|
37 |
+
}
|
38 |
+
|
39 |
+
private $template_id;
|
40 |
+
|
41 |
+
public function setTemplateID( $template_id ) {
|
42 |
+
$this->template_id = $template_id;
|
43 |
+
}
|
44 |
+
|
45 |
+
public function getTemplateID() {
|
46 |
+
return intval( $this->template_id );
|
47 |
+
}
|
48 |
+
|
49 |
+
private $template_name;
|
50 |
+
|
51 |
+
public function setTemplateName( $template_name ) {
|
52 |
+
$this->template_name = $template_name;
|
53 |
+
}
|
54 |
+
|
55 |
+
public function getTemplateName() {
|
56 |
+
return strtolower( $this->template_name );
|
57 |
+
}
|
58 |
+
|
59 |
+
private $template_file_name;
|
60 |
+
|
61 |
+
public function setTemplateFileName( $template_file_name ) {
|
62 |
+
$this->template_file_name = $template_file_name;
|
63 |
+
}
|
64 |
+
|
65 |
+
public function getTemplateFileName() {
|
66 |
+
return $this->template_file_name;
|
67 |
+
}
|
68 |
+
|
69 |
+
private $template_remote_address;
|
70 |
+
|
71 |
+
public function setTemplateRemoteAddress( $template_remote_address ) {
|
72 |
+
$this->template_remote_address = $template_remote_address;
|
73 |
+
}
|
74 |
+
|
75 |
+
public function getTemplateRemoteAddress() {
|
76 |
+
return $this->template_remote_address;
|
77 |
+
}
|
78 |
+
|
79 |
+
private $template_content_file_name;
|
80 |
+
|
81 |
+
public function setTemplateContentFileName( $template_content_file_name ) {
|
82 |
+
$this->template_content_file_name = $template_content_file_name;
|
83 |
+
}
|
84 |
+
|
85 |
+
public function getTemplateContentFileName() {
|
86 |
+
return $this->template_content_file_name;
|
87 |
+
}
|
88 |
+
|
89 |
+
private $widget_file_name;
|
90 |
+
|
91 |
+
public function setWidgetFileName( $widget_file_name ) {
|
92 |
+
$this->widget_file_name = $widget_file_name;
|
93 |
+
}
|
94 |
+
|
95 |
+
public function getWidgetFileName() {
|
96 |
+
return $this->widget_file_name;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Settings filename.
|
101 |
+
*
|
102 |
+
* @since 1.0
|
103 |
+
* @var string
|
104 |
+
*/
|
105 |
+
private $settings_file_name;
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Set Settings filename.
|
109 |
+
*
|
110 |
+
* @since 1.0
|
111 |
+
* @param string $settings_file_name Settings filename.
|
112 |
+
*/
|
113 |
+
public function set_settings_file_name( $settings_file_name ) {
|
114 |
+
$this->settings_file_name = $settings_file_name;
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Get Settings filename.
|
119 |
+
*
|
120 |
+
* @since 1.0
|
121 |
+
* @return string Settings filename.
|
122 |
+
*/
|
123 |
+
public function get_settings_file_name() {
|
124 |
+
return $this->settings_file_name;
|
125 |
+
}
|
126 |
+
|
127 |
+
private $upload_dir;
|
128 |
+
|
129 |
+
public function setUploadDir( $upload_dir ) {
|
130 |
+
$this->upload_dir = $upload_dir;
|
131 |
+
}
|
132 |
+
|
133 |
+
public function getUploadDir() {
|
134 |
+
return $this->upload_dir;
|
135 |
+
}
|
136 |
+
|
137 |
+
private $base_path;
|
138 |
+
|
139 |
+
public function setBasePath( $base_path ) {
|
140 |
+
$this->base_path = $base_path;
|
141 |
+
}
|
142 |
+
|
143 |
+
public function getBasePath() {
|
144 |
+
return $this->base_path;
|
145 |
+
}
|
146 |
+
|
147 |
+
private $base_url;
|
148 |
+
|
149 |
+
public function setBaseUrl( $base_url ) {
|
150 |
+
$this->base_url = $base_url;
|
151 |
+
}
|
152 |
+
|
153 |
+
public function getBaseUrl() {
|
154 |
+
return $this->base_url;
|
155 |
+
}
|
156 |
+
|
157 |
+
private $message;
|
158 |
+
|
159 |
+
public function setMessage( $message ) {
|
160 |
+
$this->message = $message;
|
161 |
+
}
|
162 |
+
|
163 |
+
public function getMessage() {
|
164 |
+
return $this->message;
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Construct.
|
169 |
+
*
|
170 |
+
* @param bool $system_text_env if you want to create an instance of this method for phpunit it should be true
|
171 |
+
*/
|
172 |
+
public function __construct() {
|
173 |
+
|
174 |
+
add_filter( 'jupiterx_control_panel_pane_install_templates', [ $this, 'view' ] );
|
175 |
+
|
176 |
+
// Get TGMPA.
|
177 |
+
if ( class_exists( 'TGM_Plugin_Activation' ) ) {
|
178 |
+
$this->tgmpa = isset( $GLOBALS['tgmpa'] ) ? $GLOBALS['tgmpa'] : TGM_Plugin_Activation::get_instance();
|
179 |
+
}
|
180 |
+
|
181 |
+
$menu_items_access = get_site_option( 'menu_items' );
|
182 |
+
|
183 |
+
@set_time_limit( 0 );
|
184 |
+
|
185 |
+
$this->setThemeName( 'jupiterx' );
|
186 |
+
|
187 |
+
$this->setApiURL( 'https://artbees.net/api/v2/' );
|
188 |
+
|
189 |
+
$this->setUploadDir( wp_upload_dir() );
|
190 |
+
$this->setBasePath( $this->getUploadDir()['basedir'] . '/jupiterx_templates/' );
|
191 |
+
$this->setBaseUrl( $this->getUploadDir()['baseurl'] . '/jupiterx_templates/' );
|
192 |
+
|
193 |
+
$this->setTemplateContentFileName( 'theme_content.xml' );
|
194 |
+
$this->setWidgetFileName( 'widget_data.wie' );
|
195 |
+
$this->set_settings_file_name( 'settings.json' );
|
196 |
+
global $wpdb;
|
197 |
+
|
198 |
+
if ( ! defined( 'JupiterX_LOAD_IMPORTERS' ) ) {
|
199 |
+
define( 'JupiterX_LOAD_IMPORTERS', true );
|
200 |
+
}
|
201 |
+
|
202 |
+
add_filter( 'tgmpa_load', '__return_true', 10, 1 );
|
203 |
+
|
204 |
+
add_action( 'wp_ajax_abb_template_lazy_load', array( &$this, 'loadTemplatesFromApi' ) );
|
205 |
+
add_action( 'wp_ajax_abb_install_template_procedure', array( &$this, 'install_template_procedure' ) );
|
206 |
+
|
207 |
+
// Action only for importing theme content with Server-Sent Event.
|
208 |
+
add_action( 'wp_ajax_abb_install_template_sse', array( &$this, 'import_theme_content_sse' ) );
|
209 |
+
|
210 |
+
add_action( 'wp_ajax_abb_get_templates_categories', array( &$this, 'getTemplateCategoryListFromApi' ) );
|
211 |
+
add_action( 'wp_ajax_abb_restore_latest_db', array( &$this, 'restoreLatestDB' ) );
|
212 |
+
add_action( 'wp_ajax_abb_is_restore_db', array( &$this, 'isRestoreDB' ) );
|
213 |
+
|
214 |
+
add_action( 'wp_ajax_abb_uninstall_template', array( &$this, 'uninstallTemplate' ) );
|
215 |
+
add_action( 'wp_ajax_abb_get_template_psd_link', array( &$this, 'get_template_psd_link' ) );
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Settings HTML path.
|
220 |
+
*
|
221 |
+
* @since 1.4.0
|
222 |
+
*
|
223 |
+
* @return string
|
224 |
+
*/
|
225 |
+
public function view() {
|
226 |
+
return jupiterx_core()->plugin_dir() . 'includes/control-panel/views/install-templates.php';
|
227 |
+
}
|
228 |
+
|
229 |
+
public function install_template_procedure() {
|
230 |
+
$template_id = ( isset( $_POST['template_id'] ) ? intval( $_POST['template_id'] ) : 0 );
|
231 |
+
$this->setTemplateID( $template_id );
|
232 |
+
$template_name = ( isset( $_POST['template_name'] ) ? sanitize_text_field( $_POST['template_name'] ) : null );
|
233 |
+
$import_media = ( isset( $_POST['import_media'] ) ? sanitize_text_field( $_POST['import_media'] ) : false );
|
234 |
+
$type = ( isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : null );
|
235 |
+
$partial_import = ( isset( $_POST['partial_import'] ) ? filter_var( $_POST['partial_import'], FILTER_VALIDATE_BOOLEAN ) : false );
|
236 |
+
|
237 |
+
if ( is_null( $template_name ) || is_null( $type ) ) {
|
238 |
+
$this->message( 'System problem at installing , please contact support', false );
|
239 |
+
return false;
|
240 |
+
}
|
241 |
+
|
242 |
+
switch ( $type ) {
|
243 |
+
case 'preparation':
|
244 |
+
$this->preparation( $template_name );
|
245 |
+
break;
|
246 |
+
case 'backup_db':
|
247 |
+
$this->backupDB();
|
248 |
+
break;
|
249 |
+
case 'backup_media_records':
|
250 |
+
$this->backup_media_records();
|
251 |
+
break;
|
252 |
+
case 'restore_media_records':
|
253 |
+
$this->restore_media_records();
|
254 |
+
break;
|
255 |
+
case 'reset_db':
|
256 |
+
$this->resetDB();
|
257 |
+
break;
|
258 |
+
case 'upload':
|
259 |
+
$this->uploadTemplateToServer( $template_name );
|
260 |
+
break;
|
261 |
+
case 'unzip':
|
262 |
+
$this->unzipTemplateInServer( $template_name );
|
263 |
+
break;
|
264 |
+
case 'validate':
|
265 |
+
$this->validateTemplateFiles( $template_name );
|
266 |
+
break;
|
267 |
+
case 'install_plugins':
|
268 |
+
$this->installRequiredPlugins( $template_name );
|
269 |
+
break;
|
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;
|
276 |
+
case 'setup_pages':
|
277 |
+
$this->setUpPages( $template_name );
|
278 |
+
break;
|
279 |
+
case 'plugins_content':
|
280 |
+
$this->import_plugins_content( $template_name );
|
281 |
+
break;
|
282 |
+
case 'settings':
|
283 |
+
$this->import_settings( $template_name );
|
284 |
+
break;
|
285 |
+
case 'menu_locations':
|
286 |
+
$this->importMenuLocations( $template_name );
|
287 |
+
break;
|
288 |
+
case 'theme_widget':
|
289 |
+
$this->importThemeWidgets( $template_name );
|
290 |
+
break;
|
291 |
+
case 'finalize':
|
292 |
+
$this->finalizeImporting( $template_name, $partial_import );
|
293 |
+
break;
|
294 |
+
}
|
295 |
+
}
|
296 |
+
public function reinitializeData( $template_name ) {
|
297 |
+
try {
|
298 |
+
if ( empty( $template_name ) ) {
|
299 |
+
throw new Exception( 'Choose template first' );
|
300 |
+
}
|
301 |
+
$this->setTemplateName( $template_name );
|
302 |
+
if (
|
303 |
+
file_exists( $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() ) ) == false ||
|
304 |
+
file_exists( $this->getAssetsAddress( 'widget_path', $this->getTemplateName() ) ) == false ||
|
305 |
+
file_exists( $this->getAssetsAddress( 'settings_path', $this->getTemplateName() ) ) == false
|
306 |
+
) {
|
307 |
+
throw new Exception( "Some template assets are missing Template Name : $template_name, Contact support." );
|
308 |
+
} else {
|
309 |
+
return true;
|
310 |
+
}
|
311 |
+
} catch ( Exception $e ) {
|
312 |
+
$this->message( $e->getMessage(), false );
|
313 |
+
return false;
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Reinitilize Template file is exist or not for SEE request.
|
319 |
+
*
|
320 |
+
* @since 1.0
|
321 |
+
*
|
322 |
+
* @throws Exception If template name empty.
|
323 |
+
* @throws Exception If template file is not exist.
|
324 |
+
*
|
325 |
+
* @param string $template_name The template name will be imported.
|
326 |
+
* @param string $template_id The template ID will be imported.
|
327 |
+
* @return boolean File status.
|
328 |
+
*/
|
329 |
+
public function reinitialize_data_sse( $template_name, $template_id ) {
|
330 |
+
try {
|
331 |
+
|
332 |
+
// Check template name and ID.
|
333 |
+
if ( empty( $template_name ) || empty( $template_id ) ) {
|
334 |
+
throw new Exception( 'Choose template first!' );
|
335 |
+
}
|
336 |
+
|
337 |
+
$this->setTemplateName( $template_name );
|
338 |
+
$this->setTemplateID( $template_id );
|
339 |
+
|
340 |
+
// Check template file exist or not.
|
341 |
+
if ( false === file_exists( $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() ) ) ) {
|
342 |
+
throw new Exception( 'Template content does not exist - Contact support.' );
|
343 |
+
}
|
344 |
+
|
345 |
+
return true;
|
346 |
+
} catch ( Exception $e ) {
|
347 |
+
$this->message_sse( $e->getMessage(), true );
|
348 |
+
exit;
|
349 |
+
}
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Method that is resposible to pass plugin list to UI base on lazy load condition.
|
354 |
+
*
|
355 |
+
* @param str $_POST[from] from number.
|
356 |
+
* @param str $_POST[count] how many.
|
357 |
+
*
|
358 |
+
* @return bool will return boolean status of action , all message is setted to $this->message()
|
359 |
+
*/
|
360 |
+
public function loadTemplatesFromApi() {
|
361 |
+
try {
|
362 |
+
$from = ( isset( $_POST['from'] ) ? intval( $_POST['from'] ) : null );
|
363 |
+
$count = ( isset( $_POST['count'] ) ? intval( $_POST['count'] ) : null );
|
364 |
+
$template_id = ( isset( $_POST['template_id'] ) ? intval( $_POST['template_id'] ) : 0 );
|
365 |
+
$template_name = ( isset( $_POST['template_name'] ) ? sanitize_text_field( $_POST['template_name'] ) : null );
|
366 |
+
$template_category = ( isset( $_POST['template_category'] ) ? sanitize_text_field( $_POST['template_category'] ) : null );
|
367 |
+
|
368 |
+
if ( is_null( $from ) || is_null( $count ) ) {
|
369 |
+
throw new Exception( 'System problem , please contact support', 1001 );
|
370 |
+
return false;
|
371 |
+
}
|
372 |
+
$getTemplateListArgs = [
|
373 |
+
'pagination_start' => $from,
|
374 |
+
'pagination_count' => $count,
|
375 |
+
'template_category' => $template_category,
|
376 |
+
'template_name' => $template_name,
|
377 |
+
'template_id' => $template_id,
|
378 |
+
];
|
379 |
+
$list_of_templates = $this->getTemplateListFromApi( $getTemplateListArgs );
|
380 |
+
|
381 |
+
if ( ! is_array( $list_of_templates ) ) {
|
382 |
+
throw new Exception( 'Template list is not what we expected' );
|
383 |
+
}
|
384 |
+
|
385 |
+
if ( jupiterx_is_pro() ) {
|
386 |
+
foreach ( $list_of_templates as $index => $template ) {
|
387 |
+
$list_of_templates[ $index ]->free_template = '1';
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
392 |
+
$backups = $db_manager->is_restore_db();
|
393 |
+
$this->message(
|
394 |
+
'Successfull', true, array(
|
395 |
+
'templates' => $list_of_templates,
|
396 |
+
'backups' => $backups,
|
397 |
+
)
|
398 |
+
);
|
399 |
+
return true;
|
400 |
+
|
401 |
+
} catch ( Exception $e ) {
|
402 |
+
$this->message( $e->getMessage(), false );
|
403 |
+
return false;
|
404 |
+
}
|
405 |
+
}
|
406 |
+
public function preparation( $template_name ) {
|
407 |
+
try {
|
408 |
+
$this->message( 'All is ready.', true );
|
409 |
+
return true;
|
410 |
+
} catch ( Exception $e ) {
|
411 |
+
$this->message( $e->getMessage(), false );
|
412 |
+
return false;
|
413 |
+
}
|
414 |
+
}
|
415 |
+
public function backupDB() {
|
416 |
+
try {
|
417 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
418 |
+
$dm_response = $db_manager->backup_db();
|
419 |
+
if ( false == $dm_response ) {
|
420 |
+
throw new Exception( $db_manager->get_error_message() );
|
421 |
+
}
|
422 |
+
|
423 |
+
$this->message( 'Backup created.', true );
|
424 |
+
return true;
|
425 |
+
|
426 |
+
} catch ( Exception $e ) {
|
427 |
+
$this->message( $e->getMessage(), false );
|
428 |
+
return false;
|
429 |
+
}
|
430 |
+
}
|
431 |
+
public function backup_media_records() {
|
432 |
+
try {
|
433 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
434 |
+
|
435 |
+
$dm_response = $db_manager->backup_media_records();
|
436 |
+
|
437 |
+
if ( false == $dm_response ) {
|
438 |
+
throw new Exception( $db_manager->get_error_message() );
|
439 |
+
}
|
440 |
+
$this->message( 'Media records backup created.', true );
|
441 |
+
return true;
|
442 |
+
|
443 |
+
} catch ( Exception $e ) {
|
444 |
+
$this->message( $e->getMessage(), false );
|
445 |
+
return false;
|
446 |
+
}
|
447 |
+
}
|
448 |
+
public function restore_media_records() {
|
449 |
+
try {
|
450 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
451 |
+
|
452 |
+
$dm_response = $db_manager->restore_media_records();
|
453 |
+
|
454 |
+
if ( false == $dm_response ) {
|
455 |
+
throw new Exception( $db_manager->get_error_message() );
|
456 |
+
}
|
457 |
+
$this->message( 'Media records restored successfully', true );
|
458 |
+
return true;
|
459 |
+
|
460 |
+
} catch ( Exception $e ) {
|
461 |
+
$this->message( $e->getMessage(), false );
|
462 |
+
return false;
|
463 |
+
}
|
464 |
+
}
|
465 |
+
public function isRestoreDB() {
|
466 |
+
try {
|
467 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
468 |
+
$result = $db_manager->is_restore_db();
|
469 |
+
if ( is_array( $result ) ) {
|
470 |
+
$this->message( 'Successfull', true, $result );
|
471 |
+
return true;
|
472 |
+
} else {
|
473 |
+
throw new Exception( 'Result is not what we expected' );
|
474 |
+
}
|
475 |
+
} catch ( Exception $e ) {
|
476 |
+
$this->message( $e->getMessage(), false );
|
477 |
+
return false;
|
478 |
+
}
|
479 |
+
}
|
480 |
+
public function restoreLatestDB() {
|
481 |
+
try {
|
482 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
483 |
+
$return = $db_manager->restore_latest_db();
|
484 |
+
if ( false == $return ) {
|
485 |
+
throw new Exception( $db_manager->get_error_message() );
|
486 |
+
}
|
487 |
+
JupiterX_Control_Panel_Helpers::prevent_cache_plugins();
|
488 |
+
$this->message( 'Restore completed!', true );
|
489 |
+
return true;
|
490 |
+
} catch ( Exception $e ) {
|
491 |
+
$this->message( $e->getMessage(), false );
|
492 |
+
return false;
|
493 |
+
}
|
494 |
+
}
|
495 |
+
public function resetDB() {
|
496 |
+
try {
|
497 |
+
$tables = array(
|
498 |
+
'comments',
|
499 |
+
'commentmeta',
|
500 |
+
'links',
|
501 |
+
'postmeta',
|
502 |
+
'posts',
|
503 |
+
'term_relationships',
|
504 |
+
'termmeta',
|
505 |
+
'terms',
|
506 |
+
'term_taxonomy',
|
507 |
+
);
|
508 |
+
|
509 |
+
include_once ABSPATH . 'wp-admin/includes/plugin.php';
|
510 |
+
if ( jupiterx_is_callable( 'SitePress' ) ) {
|
511 |
+
$tables[] = 'icl_translations';
|
512 |
+
}
|
513 |
+
|
514 |
+
$this->resetWordpressDatabase( $tables, array(), false );
|
515 |
+
$this->message( 'Database reseted', true );
|
516 |
+
|
517 |
+
return true;
|
518 |
+
} catch ( Exception $e ) {
|
519 |
+
$this->message( $e->getMessage(), false );
|
520 |
+
|
521 |
+
return false;
|
522 |
+
}
|
523 |
+
}
|
524 |
+
public function uploadTemplateToServer( $template_name ) {
|
525 |
+
try {
|
526 |
+
$this->setTemplateName( $template_name );
|
527 |
+
$getTemplateName = $this->getTemplateName();
|
528 |
+
if ( empty( $getTemplateName ) ) {
|
529 |
+
throw new Exception( 'Choose one template first' );
|
530 |
+
}
|
531 |
+
$url = $this->getTemplateDownloadLink( $this->getTemplateName(), 'download' );
|
532 |
+
$template_file_name = $this->getTemplateDownloadLink( $this->getTemplateName(), 'filename' );
|
533 |
+
$this->setTemplateRemoteAddress( $url );
|
534 |
+
if ( filter_var( $url, FILTER_VALIDATE_URL ) === false ) {
|
535 |
+
throw new Exception( 'Template source URL is not validate' );
|
536 |
+
}
|
537 |
+
JupiterX_Control_Panel_Helpers::upload_from_url( $this->getTemplateRemoteAddress(), $template_file_name, $this->getBasePath() );
|
538 |
+
$this->message( 'Uploaded to server', true );
|
539 |
+
return true;
|
540 |
+
} catch ( Exception $e ) {
|
541 |
+
$this->message( $e->getMessage(), false );
|
542 |
+
return false;
|
543 |
+
}
|
544 |
+
}
|
545 |
+
public function unzipTemplateInServer( $template_name ) {
|
546 |
+
try {
|
547 |
+
$this->setTemplateName( $template_name );
|
548 |
+
$getTemplateName = $this->getTemplateName();
|
549 |
+
if ( empty( $getTemplateName ) ) {
|
550 |
+
throw new Exception( 'Choose one template first' );
|
551 |
+
}
|
552 |
+
|
553 |
+
$response = $this->getTemplateDownloadLink( $this->getTemplateName(), 'filename' );
|
554 |
+
|
555 |
+
$this->setTemplateFileName( $response );
|
556 |
+
|
557 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
558 |
+
array(
|
559 |
+
'context' => $this->getBasePath(),
|
560 |
+
)
|
561 |
+
);
|
562 |
+
|
563 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
564 |
+
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
565 |
+
return false;
|
566 |
+
}
|
567 |
+
|
568 |
+
if ( ! $jupiterx_filesystem->exists( $this->getBasePath() . $this->getTemplateName() ) ) {
|
569 |
+
JupiterX_Control_Panel_Helpers::un_zip( $this->getBasePath() . $this->getTemplateFileName(), $this->getBasePath() );
|
570 |
+
} else {
|
571 |
+
if ( $jupiterx_filesystem->rmdir( $this->getBasePath() . $this->getTemplateName(), true ) ) {
|
572 |
+
JupiterX_Control_Panel_Helpers::un_zip( $this->getBasePath() . $this->getTemplateFileName(), $this->getBasePath() );
|
573 |
+
}
|
574 |
+
}
|
575 |
+
|
576 |
+
$jupiterx_filesystem->delete( $this->getBasePath() . $this->getTemplateFileName() );
|
577 |
+
|
578 |
+
$this->message( 'Completed', true );
|
579 |
+
|
580 |
+
return true;
|
581 |
+
} catch ( Exception $e ) {
|
582 |
+
$this->message( $e->getMessage(), false );
|
583 |
+
|
584 |
+
return false;
|
585 |
+
}
|
586 |
+
}
|
587 |
+
public function validateTemplateFiles( $template_name ) {
|
588 |
+
try {
|
589 |
+
if ( empty( $template_name ) ) {
|
590 |
+
throw new Exception( 'Choose template first' );
|
591 |
+
}
|
592 |
+
|
593 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
594 |
+
array(
|
595 |
+
'context' => $this->getBasePath(),
|
596 |
+
)
|
597 |
+
);
|
598 |
+
|
599 |
+
if ( $jupiterx_filesystem->get_error_code() ) {
|
600 |
+
throw new Exception( $jupiterx_filesystem->get_error_message() );
|
601 |
+
return false;
|
602 |
+
}
|
603 |
+
|
604 |
+
$this->setTemplateName( $template_name );
|
605 |
+
if (
|
606 |
+
$jupiterx_filesystem->exists( $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() ) ) == false ||
|
607 |
+
$jupiterx_filesystem->exists( $this->getAssetsAddress( 'widget_path', $this->getTemplateName() ) ) == false ||
|
608 |
+
$jupiterx_filesystem->exists( $this->getAssetsAddress( 'settings_path', $this->getTemplateName() ) ) == false
|
609 |
+
) {
|
610 |
+
throw new Exception( "Some template assets are missing Template Name : $template_name, Contact support." );
|
611 |
+
} else {
|
612 |
+
$this->message( 'Completed', true );
|
613 |
+
return true;
|
614 |
+
}
|
615 |
+
} catch ( Exception $e ) {
|
616 |
+
$this->message( $e->getMessage(), false );
|
617 |
+
|
618 |
+
return false;
|
619 |
+
}
|
620 |
+
}
|
621 |
+
|
622 |
+
public function installRequiredPlugins( $template_name ) {
|
623 |
+
|
624 |
+
$plugin_install_access = is_multisite() ? is_super_admin() : ( current_user_can( 'install_themes' ) && current_user_can( 'activate_plugins' ) );
|
625 |
+
$single_site_message = 'You are not allowed to install a new plugin or template because your user role does not have required permissions.';
|
626 |
+
$multi_site_message = 'Template installation is only allowed for user with Super Admin role. Please contact your website\'s administrator. <a target="_blank" href="https://themes.artbees.net/docs/installing-a-template/">Learn More</a>';
|
627 |
+
|
628 |
+
if ( ! $plugin_install_access ) {
|
629 |
+
$message = $single_site_message;
|
630 |
+
if ( is_multisite() ) {
|
631 |
+
$message = $multi_site_message;
|
632 |
+
}
|
633 |
+
$this->message( $message, false );
|
634 |
+
}
|
635 |
+
|
636 |
+
$template_settings = $this->getSettingsData( $template_name );
|
637 |
+
$actions = [];
|
638 |
+
$plugins_to_install = [];
|
639 |
+
$tgmpa_url = $this->tgmpa->get_tgmpa_url();
|
640 |
+
$template_plugins = $template_settings['options']['jupiterx_support_plugins'];
|
641 |
+
|
642 |
+
$template_plugins = array_diff( $template_plugins, ['jupiterx-pro', 'advanced-custom-fields-pro'] );
|
643 |
+
|
644 |
+
$template_plugins[] = 'advanced-custom-fields';
|
645 |
+
|
646 |
+
foreach ( $template_plugins as $slug ) {
|
647 |
+
|
648 |
+
if ( ! $this->tgmpa->is_plugin_active( $slug ) || false !== $this->tgmpa->does_plugin_have_update( $slug ) ) {
|
649 |
+
if ( ! $this->tgmpa->is_plugin_installed( $slug ) ) {
|
650 |
+
$plugins_to_install[] = $slug;
|
651 |
+
}
|
652 |
+
}
|
653 |
+
}
|
654 |
+
|
655 |
+
if ( ! empty( $plugins_to_install ) ) {
|
656 |
+
$actions['install'] = [
|
657 |
+
'url' => $tgmpa_url,
|
658 |
+
'plugin' => $plugins_to_install,
|
659 |
+
'tgmpa-page' => $this->tgmpa->menu,
|
660 |
+
'plugin_status' => 'all',
|
661 |
+
'_wpnonce' => wp_create_nonce( 'bulk-plugins' ),
|
662 |
+
'action' => 'tgmpa-bulk-install',
|
663 |
+
'action2' => - 1,
|
664 |
+
'message' => esc_html__( 'Installing', 'jupiterx-core' ),
|
665 |
+
];
|
666 |
+
}
|
667 |
+
|
668 |
+
$actions['url'] = $tgmpa_url;
|
669 |
+
$actions['status'] = true;
|
670 |
+
|
671 |
+
wp_send_json( $actions );
|
672 |
+
}
|
673 |
+
|
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 |
+
$actions['activate'] = [
|
686 |
+
'url' => $tgmpa_url,
|
687 |
+
'plugin' => $template_plugins,
|
688 |
+
'tgmpa-page' => $this->tgmpa->menu,
|
689 |
+
'plugin_status' => 'all',
|
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( $actions );
|
700 |
+
}
|
701 |
+
|
702 |
+
|
703 |
+
/**
|
704 |
+
* Import plugins content.
|
705 |
+
*
|
706 |
+
* @since 1.0.3
|
707 |
+
*/
|
708 |
+
public function import_plugins_content( $template_name ) {
|
709 |
+
|
710 |
+
try {
|
711 |
+
$this->setTemplateName( $template_name );
|
712 |
+
// Get template settings.
|
713 |
+
$settings = $this->getSettingsData( $this->getTemplateName() );
|
714 |
+
|
715 |
+
// Supported plugins list.
|
716 |
+
$supported_plugins = $settings['options']['jupiterx_support_plugins'];
|
717 |
+
|
718 |
+
// Run plugins importer.
|
719 |
+
foreach ( $supported_plugins as $plugin ) {
|
720 |
+
if ( is_callable( [ $this, "import_{$plugin}_content" ] ) ) {
|
721 |
+
call_user_func( [ $this, "import_{$plugin}_content" ] );
|
722 |
+
}
|
723 |
+
}
|
724 |
+
|
725 |
+
$this->message( esc_html__( 'Data of plugins have imported.', 'jupiterx-core' ), true );
|
726 |
+
|
727 |
+
return true;
|
728 |
+
} catch ( Exception $e ) {
|
729 |
+
$this->message( $e->getMessage(), false );
|
730 |
+
return false;
|
731 |
+
}
|
732 |
+
|
733 |
+
}
|
734 |
+
|
735 |
+
/**
|
736 |
+
* Import Revolution Slider content.
|
737 |
+
*
|
738 |
+
* @since 1.0.3
|
739 |
+
*/
|
740 |
+
public function import_revslider_content() {
|
741 |
+
if ( ! class_exists( 'RevSlider' ) ) {
|
742 |
+
return;
|
743 |
+
}
|
744 |
+
|
745 |
+
$filesystem = new JupiterX_Filesystem( [
|
746 |
+
'context' => $this->getBasePath(),
|
747 |
+
] );
|
748 |
+
|
749 |
+
$revslider_folder = $this->getBasePath() . sanitize_title( $this->getTemplateName() ) . '/revslider';
|
750 |
+
|
751 |
+
// Check extracted template if `revslider` folder exists inside.
|
752 |
+
if ( ! $filesystem->exists( $revslider_folder ) ) {
|
753 |
+
return;
|
754 |
+
}
|
755 |
+
|
756 |
+
$revslider = new RevSlider();
|
757 |
+
|
758 |
+
$sliders = glob( $revslider_folder . '/*.zip' );
|
759 |
+
|
760 |
+
if ( empty( $sliders ) ) {
|
761 |
+
return;
|
762 |
+
}
|
763 |
+
|
764 |
+
global $wpdb;
|
765 |
+
|
766 |
+
$tables = [
|
767 |
+
'revslider_css',
|
768 |
+
'revslider_layer_animations',
|
769 |
+
'revslider_navigations',
|
770 |
+
'revslider_sliders',
|
771 |
+
'revslider_slides',
|
772 |
+
'revslider_static_slides',
|
773 |
+
];
|
774 |
+
|
775 |
+
// Truncate tables.
|
776 |
+
foreach ( $tables as $table ) {
|
777 |
+
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}{$table}" );
|
778 |
+
}
|
779 |
+
|
780 |
+
// Import sliders.
|
781 |
+
foreach ( $sliders as $slide ) {
|
782 |
+
/**
|
783 |
+
* Start import slider.
|
784 |
+
*
|
785 |
+
* @param boolean Update animation.
|
786 |
+
* @param boolean Deprecated static param.
|
787 |
+
* @param mixed Slider file path.
|
788 |
+
* @param boolean Template slide.
|
789 |
+
* @param boolean Single slide.
|
790 |
+
* @param boolean Update navigation.
|
791 |
+
*/
|
792 |
+
$revslider->importSliderFromPost( true, true, $slide, false, false, true );
|
793 |
+
}
|
794 |
+
}
|
795 |
+
|
796 |
+
/**
|
797 |
+
* Import theme content via Server-Sent Events request.
|
798 |
+
*
|
799 |
+
*
|
800 |
+
* @throws Exception If template data is empty.
|
801 |
+
* @throws Exception If preliminary data is empty.
|
802 |
+
*/
|
803 |
+
public function import_theme_content_sse() {
|
804 |
+
try {
|
805 |
+
/*
|
806 |
+
* Filter data input from GET method. Eventsource doesn't allow us to use
|
807 |
+
* POST method.
|
808 |
+
*/
|
809 |
+
$template_name = '';
|
810 |
+
if ( ! empty( $_GET['template_name'] ) ) {
|
811 |
+
// WPCS: XSS ok, CSRF ok.
|
812 |
+
$template_name = sanitize_text_field( $_GET['template_name'] );
|
813 |
+
}
|
814 |
+
|
815 |
+
$template_id = '';
|
816 |
+
if ( ! empty( $_GET['template_id'] ) ) {
|
817 |
+
// WPCS: XSS ok, CSRF ok.
|
818 |
+
$template_id = sanitize_text_field( $_GET['template_id'] );
|
819 |
+
}
|
820 |
+
|
821 |
+
$fetch_attachments = 'false';
|
822 |
+
if ( ! empty( $_GET['fetch_attachments'] ) ) {
|
823 |
+
// WPCS: XSS ok, CSRF ok.
|
824 |
+
$fetch_attachments = sanitize_text_field( $_GET['fetch_attachments'] );
|
825 |
+
} elseif ( ! empty( $_GET['import_media'] ) ) {
|
826 |
+
$fetch_attachments = sanitize_text_field( $_GET['import_media'] );
|
827 |
+
}
|
828 |
+
|
829 |
+
$partial_import = false;
|
830 |
+
if ( ! empty( $_GET['partial_import'] ) ) {
|
831 |
+
// phpcs:ignore
|
832 |
+
$partial_import = filter_var( $_GET['partial_import'], FILTER_VALIDATE_BOOLEAN );
|
833 |
+
}
|
834 |
+
|
835 |
+
// Include wordpress-importer class.
|
836 |
+
JupiterX_Control_Panel_Helpers::include_wordpress_importer();
|
837 |
+
$this->reinitialize_data_sse( $template_name, $template_id );
|
838 |
+
|
839 |
+
// Set importer options as an array.
|
840 |
+
$options = array(
|
841 |
+
'fetch_attachments' => filter_var( $fetch_attachments, FILTER_VALIDATE_BOOLEAN ),
|
842 |
+
'default_author' => get_current_user_id(),
|
843 |
+
);
|
844 |
+
|
845 |
+
// Create new instance for Importer.
|
846 |
+
$importer = new JupiterX_Importer( $options, $partial_import );
|
847 |
+
$logger = new JupiterX_Importer_Logger_ServerSentEvents();
|
848 |
+
$importer->set_logger( $logger );
|
849 |
+
|
850 |
+
// Get preliminary information.
|
851 |
+
$file = $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() );
|
852 |
+
$pre_data = $importer->get_preliminary_information( $file );
|
853 |
+
if ( is_wp_error( $pre_data ) ) {
|
854 |
+
throw new Exception( $pre_data->get_error_message() );
|
855 |
+
}
|
856 |
+
|
857 |
+
// @codingStandardsIgnoreStart
|
858 |
+
// Turn off PHP output compression, allow us to print the log.
|
859 |
+
$previous = error_reporting(error_reporting() ^ E_WARNING);
|
860 |
+
|
861 |
+
// Configuration disabled for theme check plugin.
|
862 |
+
// ini_set('output_buffering', 'off');
|
863 |
+
// ini_set('zlib.output_compression', false);
|
864 |
+
|
865 |
+
error_reporting($previous);
|
866 |
+
// @codingStandardsIgnoreEnd
|
867 |
+
|
868 |
+
if ( $GLOBALS['is_nginx'] ) {
|
869 |
+
// Setting this header instructs Nginx to disable fastcgi_buffering
|
870 |
+
// and disable gzip for this request.
|
871 |
+
header( 'X-Accel-Buffering: no' );
|
872 |
+
header( 'Content-Encoding: none' );
|
873 |
+
}
|
874 |
+
|
875 |
+
// Start the event stream here to record all the logs.
|
876 |
+
header( 'Content-Type: text/event-stream' );
|
877 |
+
header( 'Cache-Control: no-cache' );
|
878 |
+
|
879 |
+
// Time to run the import!
|
880 |
+
set_time_limit( 0 );
|
881 |
+
|
882 |
+
// Ensure we're not buffered.
|
883 |
+
wp_ob_end_flush_all();
|
884 |
+
flush();
|
885 |
+
|
886 |
+
// Run import process.
|
887 |
+
$process = $importer->import( $file );
|
888 |
+
|
889 |
+
// Setup complete response.
|
890 |
+
$complete = array(
|
891 |
+
'status' => true, // The process is complete no matter success or not.
|
892 |
+
'error' => false, // Message error if any.
|
893 |
+
'data' => null, // Compatibility with current Ajax.
|
894 |
+
'message' => 'Template contents were imported.',
|
895 |
+
);
|
896 |
+
|
897 |
+
// Check if the request is error, then set the message.
|
898 |
+
if ( is_wp_error( $process ) ) {
|
899 |
+
$complete['error'] = $process->get_error_message();
|
900 |
+
}
|
901 |
+
|
902 |
+
$this->message_sse( $complete );
|
903 |
+
exit;
|
904 |
+
|
905 |
+
} catch ( Exception $e ) {
|
906 |
+
$this->message_sse( $e->getMessage(), true );
|
907 |
+
exit;
|
908 |
+
}
|
909 |
+
}
|
910 |
+
|
911 |
+
/**
|
912 |
+
* Get settings.json data.
|
913 |
+
*
|
914 |
+
*/
|
915 |
+
public function getSettingsData( $template_name ) {
|
916 |
+
|
917 |
+
$this->setTemplateName( $template_name );
|
918 |
+
$settings_url = $this->getAssetsAddress( 'settings_url', $this->getTemplateName() );
|
919 |
+
$settings_path = $this->getAssetsAddress( 'settings_path', $this->getTemplateName() );
|
920 |
+
$response = JupiterX_Control_Panel_Helpers::getFileBody( $settings_url, $settings_path );
|
921 |
+
|
922 |
+
return json_decode( $response, true );
|
923 |
+
}
|
924 |
+
|
925 |
+
/**
|
926 |
+
* Send a Server-Sent Events message.
|
927 |
+
*
|
928 |
+
*
|
929 |
+
* @param mixed $message Data to be JSON-encoded and sent in the message.
|
930 |
+
* @param boolean $need_header Send response along with the header.
|
931 |
+
*/
|
932 |
+
public function message_sse( $message, $need_header = false ) {
|
933 |
+
// Add header to start event stream only if needed.
|
934 |
+
if ( $need_header ) {
|
935 |
+
// Start the event stream.
|
936 |
+
header( 'Content-Type: text/event-stream' );
|
937 |
+
header( 'Cache-Control: no-cache' );
|
938 |
+
}
|
939 |
+
|
940 |
+
// Convert any message data as an array.
|
941 |
+
if ( ! is_array( $message ) ) {
|
942 |
+
$message = array(
|
943 |
+
'message' => $message,
|
944 |
+
);
|
945 |
+
}
|
946 |
+
|
947 |
+
// Set message event and pass the data.
|
948 |
+
echo "event: message\n";
|
949 |
+
echo 'data: ' . wp_json_encode( $message ) . "\n\n";
|
950 |
+
|
951 |
+
flush();
|
952 |
+
}
|
953 |
+
|
954 |
+
public function importThemeContent( $template_name, $fetch_attachments = false, $partial_import = false ) {
|
955 |
+
try {
|
956 |
+
|
957 |
+
// Include wordpress-importer class.
|
958 |
+
JupiterX_Control_Panel_Helpers::include_wordpress_importer();
|
959 |
+
$this->reinitializeData( $template_name );
|
960 |
+
// Set importer options as an array.
|
961 |
+
$options = array(
|
962 |
+
'fetch_attachments' => filter_var( $fetch_attachments, FILTER_VALIDATE_BOOLEAN ),
|
963 |
+
'default_author' => get_current_user_id(),
|
964 |
+
);
|
965 |
+
|
966 |
+
// Create new instance for Importer.
|
967 |
+
$importer = new JupiterX_WXR_Importer( $options, $partial_import );
|
968 |
+
$logger = new JupiterX_Importer_Logger_ServerSentEvents();
|
969 |
+
$importer->set_logger( $logger );
|
970 |
+
|
971 |
+
// Get preliminary information.
|
972 |
+
$file = $this->getAssetsAddress( 'template_content_path', $this->getTemplateName() );
|
973 |
+
$data = $importer->get_preliminary_information( $file );
|
974 |
+
if ( is_wp_error( $data ) ) {
|
975 |
+
$this->message( 'Error in parsing theme_content.xml!', false );
|
976 |
+
return false;
|
977 |
+
}
|
978 |
+
|
979 |
+
// Time to run the import!
|
980 |
+
set_time_limit( 0 );
|
981 |
+
|
982 |
+
// Run import process.
|
983 |
+
ob_start();
|
984 |
+
$importer->import( $file );
|
985 |
+
ob_end_clean();
|
986 |
+
|
987 |
+
$this->message( 'Template contents were imported.', true );
|
988 |
+
return true;
|
989 |
+
|
990 |
+
} catch ( Exception $e ) {
|
991 |
+
$this->message( $e->getMessage(), false );
|
992 |
+
return false;
|
993 |
+
}
|
994 |
+
}
|
995 |
+
public function importMenuLocations( $template_name ) {
|
996 |
+
try {
|
997 |
+
$settings = $this->getSettingsData( $template_name );
|
998 |
+
|
999 |
+
$nav_menus = wp_get_nav_menus();
|
1000 |
+
|
1001 |
+
if ( ! isset( $settings['options']['jupiterx_menu_locations'] ) || empty( $settings['options']['jupiterx_menu_locations'] ) || empty( $nav_menus ) ) {
|
1002 |
+
$this->message( 'There were no menu locations to import.', true );
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
$menu_locations = $settings['options']['jupiterx_menu_locations'];
|
1006 |
+
|
1007 |
+
$locations = [];
|
1008 |
+
|
1009 |
+
foreach ( $nav_menus as $menu ) {
|
1010 |
+
if ( in_array( $menu->name, $menu_locations, true ) ) {
|
1011 |
+
$location_key = array_search( $menu->name, $menu_locations, true );
|
1012 |
+
$locations[ $location_key ] = $menu->term_id;
|
1013 |
+
}
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
set_theme_mod( 'nav_menu_locations', $locations );
|
1017 |
+
|
1018 |
+
$this->message( 'Navigation locations is configured.', true, [ $locations ] );
|
1019 |
+
|
1020 |
+
return true;
|
1021 |
+
} catch ( Exception $e ) {
|
1022 |
+
$this->message( $e->getMessage(), false );
|
1023 |
+
|
1024 |
+
return false;
|
1025 |
+
} // End try().
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
public function setUpPages( $template_name ) {
|
1029 |
+
try {
|
1030 |
+
$package_data = $this->getSettingsData( $template_name );
|
1031 |
+
|
1032 |
+
// Set homepage.
|
1033 |
+
if(isset($package_data['options']['page_on_front'])) {
|
1034 |
+
$homepage_title = $package_data['options']['page_on_front'];
|
1035 |
+
if ( ! empty( $homepage_title ) ) {
|
1036 |
+
$homepage = get_page_by_title( $homepage_title );
|
1037 |
+
}
|
1038 |
+
if ( ! empty( $homepage->ID ) ) {
|
1039 |
+
update_option( 'page_on_front', $homepage->ID );
|
1040 |
+
update_option( 'show_on_front', 'page' );
|
1041 |
+
}
|
1042 |
+
}
|
1043 |
+
|
1044 |
+
// Set shop page.
|
1045 |
+
if(isset($package_data['options']['woocommerce_shop_page_id'])) {
|
1046 |
+
$shop_title = $package_data['options']['woocommerce_shop_page_id'];
|
1047 |
+
if ( ! empty( $shop_title ) ) {
|
1048 |
+
$shop_page = get_page_by_title( $shop_title );
|
1049 |
+
}
|
1050 |
+
if ( ! empty( $shop_page->ID ) ) {
|
1051 |
+
update_option( 'woocommerce_shop_page_id', $shop_page->ID );
|
1052 |
+
}
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
// Set cart page.
|
1056 |
+
if(isset($package_data['options']['woocommerce_cart_page_id'])) {
|
1057 |
+
$cart_title = $package_data['options']['woocommerce_cart_page_id'];
|
1058 |
+
if ( ! empty( $cart_title ) ) {
|
1059 |
+
$cart_page = get_page_by_title( $cart_title );
|
1060 |
+
}
|
1061 |
+
if ( ! empty( $cart_page->ID ) ) {
|
1062 |
+
update_option( 'woocommerce_cart_page_id', $cart_page->ID );
|
1063 |
+
}
|
1064 |
+
}
|
1065 |
+
|
1066 |
+
// Set Checkout page.
|
1067 |
+
if(isset($package_data['options']['woocommerce_checkout_page_id'])) {
|
1068 |
+
$checkout_title = $package_data['options']['woocommerce_checkout_page_id'];
|
1069 |
+
if ( ! empty( $checkout_title ) ) {
|
1070 |
+
$checkout_page = get_page_by_title( $checkout_title );
|
1071 |
+
}
|
1072 |
+
if ( ! empty( $checkout_page->ID ) ) {
|
1073 |
+
update_option( 'woocommerce_checkout_page_id', $checkout_page->ID );
|
1074 |
+
}
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
// Set My Account page.
|
1078 |
+
if ( isset( $package_data['options']['woocommerce_myaccount_page_id'] ) ) {
|
1079 |
+
$myaccount_title = $package_data['options']['woocommerce_myaccount_page_id'];
|
1080 |
+
|
1081 |
+
if ( ! empty( $myaccount_title ) ) {
|
1082 |
+
$myaccount_page = get_page_by_title( $myaccount_title );
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
if ( ! empty( $myaccount_page->ID ) ) {
|
1086 |
+
update_option( 'woocommerce_myaccount_page_id', $myaccount_page->ID );
|
1087 |
+
}
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
$this->message( 'pages are configured.', true );
|
1091 |
+
|
1092 |
+
return true;
|
1093 |
+
} catch ( Exception $e ) {
|
1094 |
+
$this->message( $e->getMessage(), false );
|
1095 |
+
|
1096 |
+
return false;
|
1097 |
+
} // End try().
|
1098 |
+
}
|
1099 |
+
/**
|
1100 |
+
* Import Settings options.
|
1101 |
+
*
|
1102 |
+
* @param string $template_name Name of template.
|
1103 |
+
* @return mixed
|
1104 |
+
* @throws Exception When Settings file is empty.
|
1105 |
+
*/
|
1106 |
+
public function import_settings( $template_name ) {
|
1107 |
+
try {
|
1108 |
+
$this->reinitializeData( $template_name );
|
1109 |
+
$data = $this->getSettingsData( $template_name );
|
1110 |
+
|
1111 |
+
// Data checks.
|
1112 |
+
if ( 'array' != gettype( $data ) ) {
|
1113 |
+
throw new Exception(
|
1114 |
+
sprintf( esc_html__( 'Error importing settings! Please check that you uploaded (%s) a settings export file.', 'jupiterx-core' ), $file_name )
|
1115 |
+
);
|
1116 |
+
}
|
1117 |
+
if ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) {
|
1118 |
+
throw new Exception(
|
1119 |
+
sprintf( esc_html__( 'Error importing settings! template Please check that you uploaded (%s) a settings export file.', 'jupiterx-core' ), $file_name )
|
1120 |
+
);
|
1121 |
+
}
|
1122 |
+
|
1123 |
+
// Clear theme mods.
|
1124 |
+
remove_theme_mods();
|
1125 |
+
|
1126 |
+
$data['mods'] = JupiterX_Control_Panel_Export_Import::_import_images( $data['mods'] );
|
1127 |
+
|
1128 |
+
// If wp_css is set then import it.
|
1129 |
+
if ( function_exists( 'wp_update_custom_css_post' ) && isset( $data['wp_css'] ) && '' !== $data['wp_css'] ) {
|
1130 |
+
wp_update_custom_css_post( $data['wp_css'] );
|
1131 |
+
}
|
1132 |
+
|
1133 |
+
// Exclude nav menu locations in this process.
|
1134 |
+
if ( isset( $data['mods']['nav_menu_locations'] ) ) {
|
1135 |
+
unset( $data['mods']['nav_menu_locations'] );
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
// Loop through the mods.
|
1139 |
+
foreach ( $data['mods'] as $key => $val ) {
|
1140 |
+
set_theme_mod( $key, $val );
|
1141 |
+
}
|
1142 |
+
|
1143 |
+
// Set Jet Menu options.
|
1144 |
+
if ( isset( $data['options']['jet_menu_options'] ) ) {
|
1145 |
+
update_option( 'jet_menu_options', $data['options']['jet_menu_options'] );
|
1146 |
+
}
|
1147 |
+
|
1148 |
+
// Set Jet Popup options.
|
1149 |
+
if ( isset( $data['options']['jet_popup_conditions'] ) ) {
|
1150 |
+
update_option( 'jet_popup_conditions', $data['options']['jet_popup_conditions'] );
|
1151 |
+
}
|
1152 |
+
|
1153 |
+
// Set Jupiter X custom siderbars option.
|
1154 |
+
if ( isset( $data['options']['jupiterx_custom_sidebars'] ) ) {
|
1155 |
+
jupiterx_update_option( 'custom_sidebars', $data['options']['jupiterx_custom_sidebars'] );
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
// Set extra options.
|
1159 |
+
if ( ! empty( $data['options']['extra'] ) ) {
|
1160 |
+
foreach( $data['options']['extra'] as $key => $val ) {
|
1161 |
+
if ( 'elementor_cpt_support' === $key && ! is_array( $val ) ) {
|
1162 |
+
continue;
|
1163 |
+
}
|
1164 |
+
|
1165 |
+
if ( 'elementor_global_image_lightbox' === $key && is_bool( $val ) ) {
|
1166 |
+
continue;
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
update_option( $key, $val );
|
1170 |
+
}
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
$this->message( 'Settings are imported.', true );
|
1174 |
+
return true;
|
1175 |
+
|
1176 |
+
} catch ( Exception $e ) {
|
1177 |
+
$this->message( $e->getMessage(), false );
|
1178 |
+
|
1179 |
+
return false;
|
1180 |
+
}
|
1181 |
+
}
|
1182 |
+
public function importThemeWidgets( $template_name ) {
|
1183 |
+
$this->reinitializeData( $template_name );
|
1184 |
+
try {
|
1185 |
+
$data = JupiterX_Control_Panel_Helpers::getFileBody(
|
1186 |
+
$this->getAssetsAddress( 'widget_url', $this->getTemplateName() ),
|
1187 |
+
$this->getAssetsAddress( 'widget_path', $this->getTemplateName() )
|
1188 |
+
);
|
1189 |
+
$data = json_decode( $data, true );
|
1190 |
+
$this->import_widget_data( $data );
|
1191 |
+
|
1192 |
+
$this->message( 'Widgets are imported.', true );
|
1193 |
+
|
1194 |
+
return true;
|
1195 |
+
} catch ( Exception $e ) {
|
1196 |
+
$this->message( $e->getMessage(), false );
|
1197 |
+
|
1198 |
+
return false;
|
1199 |
+
}
|
1200 |
+
}
|
1201 |
+
public function finalizeImporting( $template_name, $partial_import = false ) {
|
1202 |
+
$this->reinitializeData( $template_name );
|
1203 |
+
$template_name = sanitize_title( $template_name );
|
1204 |
+
// Check if it had something to import.
|
1205 |
+
try {
|
1206 |
+
|
1207 |
+
if ( ! $this->cleanInstallFiles( $template_name ) ) {
|
1208 |
+
throw new Exception( 'Can not remove installation source files' );
|
1209 |
+
return false;
|
1210 |
+
}
|
1211 |
+
|
1212 |
+
if ( ! $partial_import ) {
|
1213 |
+
jupiterx_update_option( 'template_installed', $this->getTemplateName() );
|
1214 |
+
jupiterx_update_option( 'template_installed_id', $this->getTemplateID() );
|
1215 |
+
}
|
1216 |
+
|
1217 |
+
jupiterx_core_flush_cache();
|
1218 |
+
|
1219 |
+
$this->message( 'Data imported successfully', true );
|
1220 |
+
return true;
|
1221 |
+
|
1222 |
+
} catch ( Exception $e ) {
|
1223 |
+
$this->message( $e->getMessage(), false );
|
1224 |
+
|
1225 |
+
return false;
|
1226 |
+
}
|
1227 |
+
}
|
1228 |
+
|
1229 |
+
/**
|
1230 |
+
* Set default value Raven nav menus recursively.
|
1231 |
+
*
|
1232 |
+
* @access public
|
1233 |
+
* @since 1.4.0
|
1234 |
+
*
|
1235 |
+
* @param array $element Template element.
|
1236 |
+
* @param array $list Raven menu default list.
|
1237 |
+
* @return void
|
1238 |
+
*/
|
1239 |
+
public function set_default_raven_menu_list( &$element, $list )
|
1240 |
+
{
|
1241 |
+
if (
|
1242 |
+
isset( $element['elType'] ) &&
|
1243 |
+
$element['elType'] === 'widget' &&
|
1244 |
+
isset( $element['widgetType'] ) &&
|
1245 |
+
$element['widgetType'] === 'raven-nav-menu' &&
|
1246 |
+
! isset( $element['settings']['list'] )
|
1247 |
+
) {
|
1248 |
+
$element['settings']['list'] = $list;
|
1249 |
+
return;
|
1250 |
+
}
|
1251 |
+
|
1252 |
+
foreach( $element['elements'] as &$inner_element ) {
|
1253 |
+
$this->set_default_raven_menu_list( $inner_element, $list );
|
1254 |
+
}
|
1255 |
+
}
|
1256 |
+
|
1257 |
+
/**
|
1258 |
+
* Clean install files
|
1259 |
+
*
|
1260 |
+
* @param $template_name
|
1261 |
+
* @author Artbees Team
|
1262 |
+
* @return bool
|
1263 |
+
*/
|
1264 |
+
private function cleanInstallFiles( $template_name ) {
|
1265 |
+
$jupiterx_filesystem = new JupiterX_Filesystem(
|
1266 |
+
array(
|
1267 |
+
'context' => $this->getBasePath(),
|
1268 |
+
)
|
1269 |
+
);
|
1270 |
+
|
1271 |
+
// Deleting Template Source Folder.
|
1272 |
+
$template_path = $this->getBasePath() . sanitize_title( $template_name );
|
1273 |
+
if ( $jupiterx_filesystem->exists( $template_path ) && $jupiterx_filesystem->is_dir( $template_path ) && ! $jupiterx_filesystem->delete( $template_path, true ) ) {
|
1274 |
+
return false;
|
1275 |
+
}
|
1276 |
+
|
1277 |
+
// Deleting Template Source Zip file.
|
1278 |
+
$template_zip = $template_path . '.zip';
|
1279 |
+
if ( $jupiterx_filesystem->exists( $template_zip ) && $jupiterx_filesystem->is_file( $template_zip ) && ! $jupiterx_filesystem->delete( $template_zip ) ) {
|
1280 |
+
return false;
|
1281 |
+
}
|
1282 |
+
|
1283 |
+
return true;
|
1284 |
+
}
|
1285 |
+
public function uninstallTemplate() {
|
1286 |
+
try {
|
1287 |
+
$tables = array(
|
1288 |
+
'comments',
|
1289 |
+
'commentmeta',
|
1290 |
+
'links',
|
1291 |
+
'options',
|
1292 |
+
'postmeta',
|
1293 |
+
'posts',
|
1294 |
+
'term_relationships',
|
1295 |
+
'termmeta',
|
1296 |
+
'terms',
|
1297 |
+
'term_taxonomy',
|
1298 |
+
);
|
1299 |
+
|
1300 |
+
$db_manager = new JupiterX_Control_Panel_Database_Manager();
|
1301 |
+
|
1302 |
+
$db_manager->backup_media_records();
|
1303 |
+
|
1304 |
+
$reset = $this->resetWordpressDatabase( $tables, array(), true );
|
1305 |
+
|
1306 |
+
$db_manager->restore_media_records();
|
1307 |
+
|
1308 |
+
if ( ! $reset ) {
|
1309 |
+
throw new Exception( 'Failed to uninstall template. Please try again.' );
|
1310 |
+
}
|
1311 |
+
|
1312 |
+
$this->message( 'Template uninstall success.', true );
|
1313 |
+
return true;
|
1314 |
+
} catch ( Exception $e ) {
|
1315 |
+
$this->message( $e->getMessage(), false );
|
1316 |
+
|
1317 |
+
return false;
|
1318 |
+
}
|
1319 |
+
}
|
1320 |
+
public function availableWidgets() {
|
1321 |
+
global $wp_registered_widget_controls;
|
1322 |
+
$widget_controls = $wp_registered_widget_controls;
|
1323 |
+
$available_widgets = array();
|
1324 |
+
foreach ( $widget_controls as $widget ) {
|
1325 |
+
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
|
1326 |
+
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
1327 |
+
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
1328 |
+
}
|
1329 |
+
}
|
1330 |
+
|
1331 |
+
return apply_filters( 'available_widgets', $available_widgets );
|
1332 |
+
}
|
1333 |
+
|
1334 |
+
/**
|
1335 |
+
* Import widgets' data.
|
1336 |
+
*
|
1337 |
+
* @throws Exception If can not read widget data.
|
1338 |
+
*
|
1339 |
+
* @param array $data Widgets' data.
|
1340 |
+
* @return boolean
|
1341 |
+
*/
|
1342 |
+
public function import_widget_data( $data ) {
|
1343 |
+
global $wp_registered_sidebars;
|
1344 |
+
|
1345 |
+
$available_widgets = $this->availableWidgets();
|
1346 |
+
$widget_instances = array();
|
1347 |
+
foreach ( $available_widgets as $widget_data ) {
|
1348 |
+
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
1349 |
+
}
|
1350 |
+
if ( empty( $data ) || ! is_array( $data ) ) {
|
1351 |
+
throw new Exception( 'Widget data could not be read. Please try a different file.' );
|
1352 |
+
}
|
1353 |
+
$results = array();
|
1354 |
+
foreach ( $data as $sidebar_id => $widgets ) {
|
1355 |
+
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
1356 |
+
continue;
|
1357 |
+
}
|
1358 |
+
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
1359 |
+
$sidebar_available = true;
|
1360 |
+
$use_sidebar_id = $sidebar_id;
|
1361 |
+
$sidebar_message_type = 'success';
|
1362 |
+
$sidebar_message = '';
|
1363 |
+
} else {
|
1364 |
+
$sidebar_available = false;
|
1365 |
+
$use_sidebar_id = 'wp_inactive_widgets';
|
1366 |
+
$sidebar_message_type = 'error';
|
1367 |
+
$sidebar_message = 'Sidebar does not exist in theme (using Inactive)';
|
1368 |
+
}
|
1369 |
+
$results[ $sidebar_id ]['name'] = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id;
|
1370 |
+
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
1371 |
+
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
1372 |
+
$results[ $sidebar_id ]['widgets'] = array();
|
1373 |
+
foreach ( $widgets as $widget_instance_id => $widget ) {
|
1374 |
+
$fail = false;
|
1375 |
+
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
1376 |
+
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
1377 |
+
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
1378 |
+
$fail = true;
|
1379 |
+
$widget_message_type = 'error';
|
1380 |
+
$widget_message = 'Site does not support widget';
|
1381 |
+
}
|
1382 |
+
$widget = apply_filters( 'jupiterx_widget_settings', $widget );
|
1383 |
+
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
1384 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
1385 |
+
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array();
|
1386 |
+
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
1387 |
+
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
1388 |
+
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
1389 |
+
$fail = true;
|
1390 |
+
$widget_message_type = 'warning';
|
1391 |
+
$widget_message = 'Widget already exists';
|
1392 |
+
break;
|
1393 |
+
}
|
1394 |
+
}
|
1395 |
+
}
|
1396 |
+
if ( ! $fail ) {
|
1397 |
+
$single_widget_instances = get_option( 'widget_' . $id_base );
|
1398 |
+
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array(
|
1399 |
+
'_multiwidget' => 1,
|
1400 |
+
);
|
1401 |
+
$single_widget_instances[] = (array) $widget;
|
1402 |
+
end( $single_widget_instances );
|
1403 |
+
$new_instance_id_number = key( $single_widget_instances );
|
1404 |
+
if ( '0' === strval( $new_instance_id_number ) ) {
|
1405 |
+
$new_instance_id_number = 1;
|
1406 |
+
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
1407 |
+
unset( $single_widget_instances[0] );
|
1408 |
+
}
|
1409 |
+
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
1410 |
+
$multiwidget = $single_widget_instances['_multiwidget'];
|
1411 |
+
unset( $single_widget_instances['_multiwidget'] );
|
1412 |
+
$single_widget_instances['_multiwidget'] = $multiwidget;
|
1413 |
+
}
|
1414 |
+
update_option( 'widget_' . $id_base, $single_widget_instances );
|
1415 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
1416 |
+
$new_instance_id = $id_base . '-' . $new_instance_id_number;
|
1417 |
+
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id;
|
1418 |
+
update_option( 'sidebars_widgets', $sidebars_widgets );
|
1419 |
+
if ( $sidebar_available ) {
|
1420 |
+
$widget_message_type = 'success';
|
1421 |
+
$widget_message = 'Imported';
|
1422 |
+
} else {
|
1423 |
+
$widget_message_type = 'warning';
|
1424 |
+
$widget_message = 'Imported to Inactive';
|
1425 |
+
}
|
1426 |
+
}
|
1427 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name'] = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base;
|
1428 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget->title ) ? $widget->title : '';
|
1429 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
1430 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
1431 |
+
} // End foreach().
|
1432 |
+
} // End foreach().
|
1433 |
+
|
1434 |
+
return true;
|
1435 |
+
}
|
1436 |
+
/**
|
1437 |
+
* It will empty all or custom database tables of WordPress and install WordPress again if needed.
|
1438 |
+
*
|
1439 |
+
* @param array $table which table need to be empty ? example : array('user' , 'usermeta')
|
1440 |
+
* table names should be without any prefix
|
1441 |
+
* @param bool $install_needed if WordPress need to be installed after reseting database
|
1442 |
+
* it should be false or true
|
1443 |
+
*
|
1444 |
+
* @return bool return if everything looks good and throwing errors on problems
|
1445 |
+
*/
|
1446 |
+
public function resetWordpressDatabase( $tables = array(), $exclude_tables = array(), $install_needed = false ) {
|
1447 |
+
global $wpdb, $reactivate_wp_reset_additional, $current_user;
|
1448 |
+
|
1449 |
+
if ( $install_needed ) {
|
1450 |
+
|
1451 |
+
require_once ABSPATH . '/wp-admin/includes/upgrade.php';
|
1452 |
+
|
1453 |
+
$new_options = array();
|
1454 |
+
|
1455 |
+
$old_options = array(
|
1456 |
+
'active_plugins',
|
1457 |
+
);
|
1458 |
+
|
1459 |
+
$blogname = get_option( 'blogname' );
|
1460 |
+
$blog_public = get_option( 'blog_public' );
|
1461 |
+
$site_url = site_url();
|
1462 |
+
$current_theme = wp_get_theme();
|
1463 |
+
|
1464 |
+
foreach ( $old_options as $old_option_key ) {
|
1465 |
+
$new_options[ $old_option_key ] = get_option( $old_option_key );
|
1466 |
+
}
|
1467 |
+
|
1468 |
+
$keep_options = [
|
1469 |
+
'api_key',
|
1470 |
+
'api_access_token',
|
1471 |
+
'envato_purchase_code_5177775',
|
1472 |
+
'setup_wizard_current_page',
|
1473 |
+
'setup_wizard_hide_notice',
|
1474 |
+
];
|
1475 |
+
|
1476 |
+
$jupiterx_options = get_option( 'jupiterx', [] );
|
1477 |
+
|
1478 |
+
$new_options['jupiterx'] = array_intersect_key( $jupiterx_options, array_flip( $keep_options ) );
|
1479 |
+
|
1480 |
+
if ( 'admin' != $current_user->user_login ) {
|
1481 |
+
$user = get_user_by( 'login', 'admin' );
|
1482 |
+
}
|
1483 |
+
|
1484 |
+
if ( empty( $user->user_level ) || $user->user_level < 10 ) {
|
1485 |
+
$user = $current_user;
|
1486 |
+
$session_tokens = get_user_meta( $user->ID, 'session_tokens', true );
|
1487 |
+
}
|
1488 |
+
|
1489 |
+
// Check if we need all the tables or specific table.
|
1490 |
+
if ( is_array( $tables ) && count( $tables ) > 0 ) {
|
1491 |
+
array_walk(
|
1492 |
+
$tables, function ( &$value, $key ) use ( $wpdb ) {
|
1493 |
+
$value = $wpdb->prefix . $value;
|
1494 |
+
}
|
1495 |
+
);
|
1496 |
+
} else {
|
1497 |
+
$prefix = str_replace( '_', '\_', $wpdb->prefix );
|
1498 |
+
$tables = $wpdb->get_col( "SHOW TABLES LIKE '{$prefix}%'" );
|
1499 |
+
}
|
1500 |
+
|
1501 |
+
// exclude table if its valued.
|
1502 |
+
if ( is_array( $exclude_tables ) && count( $exclude_tables ) > 0 ) {
|
1503 |
+
array_walk(
|
1504 |
+
$exclude_tables, function ( &$ex_value, $key ) use ( $wpdb ) {
|
1505 |
+
$ex_value = $wpdb->prefix . $ex_value;
|
1506 |
+
}
|
1507 |
+
);
|
1508 |
+
$tables = array_diff( $tables, $exclude_tables );
|
1509 |
+
}
|
1510 |
+
// Removing data from WordPress tables.
|
1511 |
+
foreach ( $tables as $table ) {
|
1512 |
+
$wpdb->query( "DROP TABLE $table" );
|
1513 |
+
}
|
1514 |
+
|
1515 |
+
$result = wp_install( $blogname, $user->user_login, $user->user_email, $blog_public );
|
1516 |
+
switch_theme( $current_theme->get_stylesheet() );
|
1517 |
+
|
1518 |
+
/* GoDaddy Patch => GD have a problem of cleaning siteurl option value after reseting database */
|
1519 |
+
if ( site_url() == '' ) {
|
1520 |
+
$wpdb->update(
|
1521 |
+
$wpdb->options, array(
|
1522 |
+
'option_value' => $site_url,
|
1523 |
+
),array(
|
1524 |
+
'option_name' => 'siteurl',
|
1525 |
+
)
|
1526 |
+
);
|
1527 |
+
}
|
1528 |
+
extract( $result, EXTR_SKIP );
|
1529 |
+
|
1530 |
+
$query = $wpdb->prepare( "UPDATE $wpdb->users SET user_pass = %s, user_activation_key = '' WHERE ID = %d", $user->user_pass, $user_id );
|
1531 |
+
$wpdb->query( $query );
|
1532 |
+
|
1533 |
+
$get_user_meta = function_exists( 'get_user_meta' ) ? 'get_user_meta' : 'get_usermeta';
|
1534 |
+
$update_user_meta = function_exists( 'update_user_meta' ) ? 'update_user_meta' : 'update_usermeta';
|
1535 |
+
|
1536 |
+
if ( $get_user_meta($user_id, 'default_password_nag') ) {
|
1537 |
+
$update_user_meta($user_id, 'default_password_nag', false);
|
1538 |
+
}
|
1539 |
+
|
1540 |
+
if ( $get_user_meta($user_id, $wpdb->prefix . 'default_password_nag') ) {
|
1541 |
+
$update_user_meta($user_id, $wpdb->prefix . 'default_password_nag', false);
|
1542 |
+
}
|
1543 |
+
|
1544 |
+
wp_clear_auth_cookie();
|
1545 |
+
wp_set_current_user( $user_id, $user->user_login );
|
1546 |
+
if ( $session_tokens ) {
|
1547 |
+
delete_user_meta( $user->ID, 'session_tokens' );
|
1548 |
+
update_user_meta( $user->ID, 'session_tokens', $session_tokens );
|
1549 |
+
}
|
1550 |
+
|
1551 |
+
wp_set_auth_cookie( $user_id, true );
|
1552 |
+
do_action( 'wp_login', $user->user_login, $user );
|
1553 |
+
|
1554 |
+
if ( $new_options ) {
|
1555 |
+
foreach ( $new_options as $key => $value ) {
|
1556 |
+
update_option( $key, $value );
|
1557 |
+
}
|
1558 |
+
}
|
1559 |
+
return true;
|
1560 |
+
} else {
|
1561 |
+
|
1562 |
+
$jupiterx_temp_installed = jupiterx_get_option( 'template_installed' );
|
1563 |
+
|
1564 |
+
if ( $jupiterx_temp_installed ) {
|
1565 |
+
|
1566 |
+
// Delete option data for page_on_front.
|
1567 |
+
if ( get_option( 'page_on_front' ) ) {
|
1568 |
+
delete_option( 'page_on_front' );
|
1569 |
+
}
|
1570 |
+
|
1571 |
+
// Delete option data for show_on_front.
|
1572 |
+
if ( get_option( 'show_on_front' ) ) {
|
1573 |
+
delete_option( 'show_on_front' );
|
1574 |
+
}
|
1575 |
+
|
1576 |
+
// Delete option data for woocommerce_shop_page_id.
|
1577 |
+
if ( get_option( 'woocommerce_shop_page_id' ) ) {
|
1578 |
+
delete_option( 'woocommerce_shop_page_id' );
|
1579 |
+
}
|
1580 |
+
|
1581 |
+
// Delete widgets.
|
1582 |
+
$wpdb->query( "DELETE FROM {$wpdb->prefix}options WHERE option_name LIKE '%widget%';" );
|
1583 |
+
|
1584 |
+
}// End if().
|
1585 |
+
|
1586 |
+
// truncate tables.
|
1587 |
+
foreach ( $tables as $table ) {
|
1588 |
+
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}{$table}" );
|
1589 |
+
}
|
1590 |
+
|
1591 |
+
return true;
|
1592 |
+
}// End if().
|
1593 |
+
}
|
1594 |
+
|
1595 |
+
private function setResponseForApiTemplateList( $url, $configs ) {
|
1596 |
+
$headers = array(
|
1597 |
+
'theme-name' => $this->getThemeName(),
|
1598 |
+
'pagination-start' => isset( $configs['pagination_start'] ) ? $configs['pagination_start'] : 0,
|
1599 |
+
'pagination-count' => isset( $configs['pagination_count'] ) ? $configs['pagination_count'] : 1,
|
1600 |
+
);
|
1601 |
+
|
1602 |
+
if ( isset( $configs['template_id'] ) && is_null( $configs['template_id'] ) == false ) {
|
1603 |
+
$headers['template-id'] = $configs['template_id'];
|
1604 |
+
}
|
1605 |
+
|
1606 |
+
if ( isset( $configs['template_name'] ) && is_null( $configs['template_name'] ) == false ) {
|
1607 |
+
$headers['template-name'] = $configs['template_name'];
|
1608 |
+
}
|
1609 |
+
|
1610 |
+
if ( isset( $configs['template_category'] ) && is_null( $configs['template_category'] ) == false ) {
|
1611 |
+
$headers['template-category'] = $configs['template_category'];
|
1612 |
+
}
|
1613 |
+
|
1614 |
+
return $this->wp_remote_get( $url, $headers );
|
1615 |
+
}
|
1616 |
+
/**
|
1617 |
+
* This method is resposible to get template list from api and create download link if template need to extract from WordPress repo.
|
1618 |
+
*
|
1619 |
+
* @param str $template_name if template name is valued it will return array of information about the this template.
|
1620 |
+
* but if template is valued as false it will return all templates information
|
1621 |
+
*
|
1622 |
+
* @return array will return array of templates
|
1623 |
+
*/
|
1624 |
+
public function getTemplateListFromApi( $configs ) {
|
1625 |
+
if ( ! is_array( $configs ) ) {
|
1626 |
+
$configs = array();
|
1627 |
+
}
|
1628 |
+
$url = $this->getApiURL() . 'theme/templates';
|
1629 |
+
$response = $this->setResponseForApiTemplateList( $url, $configs );
|
1630 |
+
if ( false == isset( $response->bool ) || false == $response->bool ) {
|
1631 |
+
throw new Exception( $response->message );
|
1632 |
+
}
|
1633 |
+
return $response->data;
|
1634 |
+
}
|
1635 |
+
public function getTemplateDownloadLink( $template_name = '', $type = 'download' ) {
|
1636 |
+
$url = $this->getApiURL() . 'theme/download-template';
|
1637 |
+
$response = $this->wp_remote_get( $url, array(
|
1638 |
+
'template-name' => $template_name,
|
1639 |
+
'type' => $type,
|
1640 |
+
) );
|
1641 |
+
|
1642 |
+
if ( false == isset( $response->bool ) || false == $response->bool ) {
|
1643 |
+
throw new Exception( $response->message );
|
1644 |
+
}
|
1645 |
+
|
1646 |
+
/**
|
1647 |
+
* Filters the template download url.
|
1648 |
+
*
|
1649 |
+
* @param string $response->data Download url.
|
1650 |
+
*/
|
1651 |
+
return apply_filters( 'jupiterx_template_download_url', $response->data, $type );
|
1652 |
+
}
|
1653 |
+
|
1654 |
+
/**
|
1655 |
+
* Gets psd file download link.
|
1656 |
+
*
|
1657 |
+
*/
|
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,
|
1665 |
+
)
|
1666 |
+
);
|
1667 |
+
return true;
|
1668 |
+
} catch ( Exception $e ) {
|
1669 |
+
$this->message( $e->getMessage(), false );
|
1670 |
+
return false;
|
1671 |
+
} // End try().
|
1672 |
+
}
|
1673 |
+
|
1674 |
+
/**
|
1675 |
+
* This method is resposible to get templates categories list from api
|
1676 |
+
*
|
1677 |
+
* @param str $template_name if template name is valued it will return array of information about the this template.
|
1678 |
+
* but if template is valued as false it will return all templates information.
|
1679 |
+
*
|
1680 |
+
* @return array will return array of plugins.
|
1681 |
+
*/
|
1682 |
+
public function getTemplateCategoryListFromApi() {
|
1683 |
+
try {
|
1684 |
+
$url = $this->getApiURL() . 'theme/template-categories';
|
1685 |
+
$response = $this->wp_remote_get( $url );
|
1686 |
+
if ( false == isset( $response->bool ) || false == $response->bool ) {
|
1687 |
+
throw new Exception( $response->message );
|
1688 |
+
}
|
1689 |
+
$this->message( 'Successfull', true, $response->data );
|
1690 |
+
return true;
|
1691 |
+
} catch ( Exception $e ) {
|
1692 |
+
$this->message( $e->getMessage(), false );
|
1693 |
+
return false;
|
1694 |
+
}
|
1695 |
+
}
|
1696 |
+
/**
|
1697 |
+
* We need to make assets addresses dynamic and fully proccess.
|
1698 |
+
* in one method for future development
|
1699 |
+
* it will get the type of address and will return full address in string
|
1700 |
+
* example :
|
1701 |
+
* for (options_url) type , it will return something like this
|
1702 |
+
* (http://localhost/jupiter/wp-content/uploads/jupiterx_templates/dia/options.txt).
|
1703 |
+
*
|
1704 |
+
* For (options_path) type , it will return something like this.
|
1705 |
+
* (/usr/apache/www/wp-content/uploads/jupiterx_templates/dia/options.txt)
|
1706 |
+
*
|
1707 |
+
* @param str $which_one Which address do you need.
|
1708 |
+
* @param str $template_name such as.
|
1709 |
+
*/
|
1710 |
+
public function getAssetsAddress( $which_one, $template_name ) {
|
1711 |
+
$template_name = sanitize_title( $template_name );
|
1712 |
+
switch ( $which_one ) {
|
1713 |
+
case 'template_content_url':
|
1714 |
+
return $this->getBaseUrl() . $template_name . '/' . $this->getTemplateContentFileName();
|
1715 |
+
break;
|
1716 |
+
case 'template_content_path':
|
1717 |
+
return $this->getBasePath() . $template_name . '/' . $this->getTemplateContentFileName();
|
1718 |
+
break;
|
1719 |
+
case 'widget_url':
|
1720 |
+
return $this->getBaseUrl() . $template_name . '/' . $this->getWidgetFileName();
|
1721 |
+
break;
|
1722 |
+
case 'widget_path':
|
1723 |
+
return $this->getBasePath() . $template_name . '/' . $this->getWidgetFileName();
|
1724 |
+
break;
|
1725 |
+
case 'settings_url':
|
1726 |
+
return $this->getBaseUrl() . $template_name . '/' . $this->get_settings_file_name();
|
1727 |
+
break;
|
1728 |
+
case 'settings_path':
|
1729 |
+
return $this->getBasePath() . $template_name . '/' . $this->get_settings_file_name();
|
1730 |
+
break;
|
1731 |
+
default:
|
1732 |
+
throw new Exception( 'File name you are looking for is not introduced.' );
|
1733 |
+
|
1734 |
+
return false;
|
1735 |
+
break;
|
1736 |
+
}
|
1737 |
+
}
|
1738 |
+
|
1739 |
+
public function find_plugin_path( $plugin_slug ) {
|
1740 |
+
$plugins = get_plugins();
|
1741 |
+
foreach ( $plugins as $plugin_address => $plugin_data ) {
|
1742 |
+
|
1743 |
+
// Extract slug from address
|
1744 |
+
if ( strlen( $plugin_address ) == basename( $plugin_address ) ) {
|
1745 |
+
$slug = strtolower( str_replace( '.php', '', $plugin_address ) );
|
1746 |
+
} else {
|
1747 |
+
$slug = strtolower( str_replace( '/' . basename( $plugin_address ), '', $plugin_address ) );
|
1748 |
+
}
|
1749 |
+
// Check if slug exists
|
1750 |
+
if ( strtolower( $plugin_slug ) == $slug ) {
|
1751 |
+
return $plugin_address;
|
1752 |
+
}
|
1753 |
+
}
|
1754 |
+
return false;
|
1755 |
+
}
|
1756 |
+
|
1757 |
+
public function importLayerSliderContent( $content_path ) {
|
1758 |
+
global $wpdb;
|
1759 |
+
$ls_path = $this->find_plugin_path( $this->layer_slider_slug );
|
1760 |
+
|
1761 |
+
if ( $ls_path == false ) {
|
1762 |
+
throw new Exception( 'LayerSlider is not installed , install it first' );
|
1763 |
+
return false;
|
1764 |
+
}
|
1765 |
+
|
1766 |
+
if ( defined( LS_PLUGIN_VERSION ) ) {
|
1767 |
+
throw new Exception( 'LayerSlider is installed but not activated , activate it first' );
|
1768 |
+
return false;
|
1769 |
+
}
|
1770 |
+
// Empty layerslider table first.
|
1771 |
+
$table = $wpdb->prefix . 'layerslider';
|
1772 |
+
$wpdb->query( "TRUNCATE TABLE $table" );
|
1773 |
+
|
1774 |
+
// Try to import configs.
|
1775 |
+
$ls_plugin_root_path = pathinfo( $plugin->get_plugins_dir() . $ls_path );
|
1776 |
+
include $ls_plugin_root_path['dirname'] . '/classes/class.ls.importutil.php';
|
1777 |
+
new LS_ImportUtil( $content_path );
|
1778 |
+
return true;
|
1779 |
+
}
|
1780 |
+
|
1781 |
+
/**
|
1782 |
+
* Reusable wrapper method for WP remote getter.
|
1783 |
+
*
|
1784 |
+
* Method only returns response body.
|
1785 |
+
*/
|
1786 |
+
public function wp_remote_get( $url = '', $headers = [] ) {
|
1787 |
+
$required_headers = [
|
1788 |
+
'api-key' => jupiterx_get_option( 'api_key' ),
|
1789 |
+
'domain' => esc_url_raw( $_SERVER['SERVER_NAME'] ),
|
1790 |
+
];
|
1791 |
+
|
1792 |
+
// Combined headers.
|
1793 |
+
$headers = array_merge( $headers, $required_headers );
|
1794 |
+
|
1795 |
+
$response = json_decode( wp_remote_retrieve_body( wp_remote_get( $url, [
|
1796 |
+
'sslverify' => false,
|
1797 |
+
'headers' => $headers,
|
1798 |
+
] ) ) );
|
1799 |
+
|
1800 |
+
return $response;
|
1801 |
+
}
|
1802 |
+
|
1803 |
+
/**
|
1804 |
+
* This method is resposible to manage all the classes messages.
|
1805 |
+
*/
|
1806 |
+
public function message( $message, $status, $data = null ) {
|
1807 |
+
$response = [
|
1808 |
+
'message' => jupiterx_logic_message_helper( 'template-management', $message ),
|
1809 |
+
'status' => $status,
|
1810 |
+
'data' => $data,
|
1811 |
+
];
|
1812 |
+
|
1813 |
+
wp_send_json( $response );
|
1814 |
+
}
|
1815 |
+
}
|
1816 |
+
}
|
1817 |
+
|
1818 |
+
if ( ! function_exists( 'jupiterx_disable_woocommerce' ) ) {
|
1819 |
+
/* Disable woocommerce redirection */
|
1820 |
+
add_action( 'admin_init', 'jupiterx_disable_woocommerce', 5 );
|
1821 |
+
/**
|
1822 |
+
* Disable Woocommerce redirect for template install
|
1823 |
+
*
|
1824 |
+
*/
|
1825 |
+
function jupiterx_disable_woocommerce() {
|
1826 |
+
delete_transient( '_wc_activation_redirect' );
|
1827 |
+
add_filter(
|
1828 |
+
'woocommerce_prevent_automatic_wizard_redirect', function () {
|
1829 |
+
return true;
|
1830 |
+
}
|
1831 |
+
);
|
1832 |
+
}
|
1833 |
+
}
|
1834 |
+
|
1835 |
+
|
1836 |
+
add_filter(
|
1837 |
+
'pre_transient__wc_activation_redirect', function () {
|
1838 |
+
return 0;
|
1839 |
+
}
|
1840 |
+
);
|
1841 |
+
|
1842 |
+
add_filter(
|
1843 |
+
'pre_transient__vc_page_welcome_redirect', function () {
|
1844 |
+
return 0;
|
1845 |
+
}
|
1846 |
+
);
|
1847 |
+
|
1848 |
+
global $abb_phpunit;
|
1849 |
+
if ( empty( $abb_phpunit ) || $abb_phpunit == false ) {
|
1850 |
+
new JupiterX_Control_Panel_Install_Template();
|
1851 |
+
}
|
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,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>
|
39 |
-
<hr style="margin: 0;">
|
40 |
-
<div class="jupiterx-card-body">
|
41 |
-
<button class="btn btn-primary jupiterx-cp-export-btn" type="submit">
|
42 |
-
<?php esc_html_e( 'Export', 'jupiterx-core' ); ?>
|
43 |
-
</button>
|
44 |
-
</div>
|
45 |
-
</form>
|
46 |
-
</div>
|
47 |
-
<h3><?php esc_html_e( 'Import', 'jupiterx-core' ); ?></h3>
|
48 |
-
<div class="jupiterx-cp-import-wrap jupiterx-card">
|
49 |
-
<div class="jupiterx-card-body">
|
50 |
-
<div class="jupiterx-upload-wrap w-75">
|
51 |
-
<div class="input-group">
|
52 |
-
<input class="jupiterx-form-control" placeholder="Select a Zip file" type="text">
|
53 |
-
<div class="input-group-append">
|
54 |
-
<a class="btn btn-secondary jupiterx-cp-import-upload-btn" href="#">
|
55 |
-
<?php esc_html_e( 'Upload', 'jupiterx-core' ); ?>
|
56 |
-
</a>
|
57 |
-
</div>
|
58 |
-
</input>
|
59 |
-
</div>
|
60 |
-
</div>
|
61 |
-
</div>
|
62 |
-
<hr style="margin: 0;">
|
63 |
-
<div class="jupiterx-card-body">
|
64 |
-
<button class="btn btn-primary jupiterx-cp-import-btn" type="submit">
|
65 |
-
<?php esc_html_e( 'Import', 'jupiterx-core' ); ?>
|
66 |
-
</button>
|
67 |
-
</div>
|
68 |
-
|
69 |
-
</div>
|
70 |
-
</div>
|
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>
|
39 |
+
<hr style="margin: 0;">
|
40 |
+
<div class="jupiterx-card-body">
|
41 |
+
<button class="btn btn-primary jupiterx-cp-export-btn" type="submit">
|
42 |
+
<?php esc_html_e( 'Export', 'jupiterx-core' ); ?>
|
43 |
+
</button>
|
44 |
+
</div>
|
45 |
+
</form>
|
46 |
+
</div>
|
47 |
+
<h3><?php esc_html_e( 'Import', 'jupiterx-core' ); ?></h3>
|
48 |
+
<div class="jupiterx-cp-import-wrap jupiterx-card">
|
49 |
+
<div class="jupiterx-card-body">
|
50 |
+
<div class="jupiterx-upload-wrap w-75">
|
51 |
+
<div class="input-group">
|
52 |
+
<input class="jupiterx-form-control" placeholder="Select a Zip file" type="text">
|
53 |
+
<div class="input-group-append">
|
54 |
+
<a class="btn btn-secondary jupiterx-cp-import-upload-btn" href="#">
|
55 |
+
<?php esc_html_e( 'Upload', 'jupiterx-core' ); ?>
|
56 |
+
</a>
|
57 |
+
</div>
|
58 |
+
</input>
|
59 |
+
</div>
|
60 |
+
</div>
|
61 |
+
</div>
|
62 |
+
<hr style="margin: 0;">
|
63 |
+
<div class="jupiterx-card-body">
|
64 |
+
<button class="btn btn-primary jupiterx-cp-import-btn" type="submit">
|
65 |
+
<?php esc_html_e( 'Import', 'jupiterx-core' ); ?>
|
66 |
+
</button>
|
67 |
+
</div>
|
68 |
+
|
69 |
+
</div>
|
70 |
+
</div>
|
includes/control-panel/views/image-sizes.php
CHANGED
@@ -1,64 +1,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 |
-
</div>
|
53 |
-
</div>
|
54 |
-
</div>
|
55 |
-
<?php
|
56 |
-
endif;
|
57 |
-
endforeach;
|
58 |
-
?>
|
59 |
-
</div>
|
60 |
-
<div class="clearfix"></div>
|
61 |
-
</div>
|
62 |
-
<?php wp_nonce_field( 'ajax-image-sizes-options', 'security' ); ?>
|
63 |
-
</div>
|
64 |
-
</div>
|
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 |
+
</div>
|
53 |
+
</div>
|
54 |
+
</div>
|
55 |
+
<?php
|
56 |
+
endif;
|
57 |
+
endforeach;
|
58 |
+
?>
|
59 |
+
</div>
|
60 |
+
<div class="clearfix"></div>
|
61 |
+
</div>
|
62 |
+
<?php wp_nonce_field( 'ajax-image-sizes-options', 'security' ); ?>
|
63 |
+
</div>
|
64 |
+
</div>
|
includes/control-panel/views/install-plugins.php
CHANGED
@@ -1,56 +1,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 if ( ! is_multisite() ) : ?>
|
46 |
-
<button type="button" class="btn btn-outline-secondary" data-filter="update" disabled><?php esc_html_e( 'Update available', 'jupiterx' ); ?></button>
|
47 |
-
<?php endif; ?>
|
48 |
-
</div>
|
49 |
-
</div>
|
50 |
-
<div id="js__jupiterx-plugins" class="d-flex">
|
51 |
-
<svg class="jupiterx-spinner" width="50px" height="50px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
52 |
-
<circle class="jupiterx-spinner-path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
53 |
-
</svg>
|
54 |
-
</div>
|
55 |
-
</div>
|
56 |
-
</div>
|
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 if ( ! is_multisite() ) : ?>
|
46 |
+
<button type="button" class="btn btn-outline-secondary" data-filter="update" disabled><?php esc_html_e( 'Update available', 'jupiterx' ); ?></button>
|
47 |
+
<?php endif; ?>
|
48 |
+
</div>
|
49 |
+
</div>
|
50 |
+
<div id="js__jupiterx-plugins" class="d-flex">
|
51 |
+
<svg class="jupiterx-spinner" width="50px" height="50px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
52 |
+
<circle class="jupiterx-spinner-path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
53 |
+
</svg>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
</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,103 @@
|
|
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 if ( ! empty( $post_types ) ) : ?>
|
51 |
-
<?php foreach ( $post_types as $id => $post_type ) : ?>
|
52 |
-
<?php echo '<div class="custom-control custom-checkbox">'; ?>
|
53 |
-
<?php echo '<input type="checkbox" class="custom-control-input" name="jupiterx_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 ) . '">'; ?>
|
54 |
-
<?php echo '<label class="custom-control-label" for="jupiterx_post_type_' . esc_attr( $post_type->name ) . '">' . $post_type->label . '</label>'; ?>
|
55 |
-
<?php echo '</div>'; ?>
|
56 |
-
<?php endforeach; ?>
|
57 |
-
<?php else : ?>
|
58 |
-
<div class="jupiterx-settings-no-post-type">
|
59 |
-
<i class="jupiterx-icon-info-circle"></i><?php esc_html_e( 'No custom post type was found.', 'jupiterx-core' ); ?>
|
60 |
-
</div>
|
61 |
-
<?php endif; ?>
|
62 |
-
</div>
|
63 |
-
<?php do_action( 'jupiterx_control_panel_settings_white_label' ); ?>
|
64 |
-
<?php if ( jupiterx_is_premium() && class_exists( 'Jupiter_Donut' ) ) : ?>
|
65 |
-
<div class="col-md-12"><hr></div>
|
66 |
-
<h5 class="col-md-12 mb-3">Donut Plugin</h5>
|
67 |
-
<div class="form-group col-md-6">
|
68 |
-
<label for="jupiterx-cp-settings-donut-twitter-consumer-key"><?php esc_html_e( 'Twitter Consumer Key', 'jupiterx-core' ); ?></label>
|
69 |
-
<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">
|
70 |
-
</div>
|
71 |
-
<div class="form-group col-md-6">
|
72 |
-
<label for="jupiterx-cp-settings-donut-twitter-consumer-secret"><?php esc_html_e( 'Twitter Consumer Secret', 'jupiterx-core' ); ?></label>
|
73 |
-
<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">
|
74 |
-
</div>
|
75 |
-
<div class="form-group col-md-6">
|
76 |
-
<label for="jupiterx-cp-settings-donut-twitter-access-token"><?php esc_html_e( 'Twitter Access Token', 'jupiterx-core' ); ?></label>
|
77 |
-
<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">
|
78 |
-
</div>
|
79 |
-
<div class="form-group col-md-6">
|
80 |
-
<label for="jupiterx-cp-settings-donut-twitter-access-token-secret"><?php esc_html_e( 'Twitter Access Token Secret', 'jupiterx-core' ); ?></label>
|
81 |
-
<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">
|
82 |
-
</div>
|
83 |
-
<div class="form-group col-md-6">
|
84 |
-
<label for="jupiterx-cp-settings-donut-mailchimp-api-key"><?php esc_html_e( 'MailChimp API Key', 'jupiterx-core' ); ?></label>
|
85 |
-
<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">
|
86 |
-
</div>
|
87 |
-
<div class="form-group col-md-6">
|
88 |
-
<label for="jupiterx-cp-settings-donut-mailchimp-list-id"><?php esc_html_e( 'Mailchimp List ID', 'jupiterx-core' ); ?></label>
|
89 |
-
<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">
|
90 |
-
</div>
|
91 |
-
<div class="form-group col-md-6">
|
92 |
-
<label for="jupiterx-cp-settings-donut-google-maps-api-key"><?php esc_html_e( 'Google Maps API Key', 'jupiterx-core' ); ?></label>
|
93 |
-
<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">
|
94 |
-
</div>
|
95 |
-
<?php endif; ?>
|
96 |
-
</div>
|
97 |
-
<div class="mt-2">
|
98 |
-
<button type="submit" class="btn btn-primary"><?php esc_html_e( 'Save Settings', 'jupiterx-core' ); ?></button>
|
99 |
-
<span class="jupiterx-cp-settings-save-feedback text-muted ml-2 d-none"><?php esc_html_e( 'Saving...', 'jupiterx-core' ); ?></span>
|
100 |
-
</div>
|
101 |
-
</form>
|
102 |
-
</div>
|
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 if ( ! empty( $post_types ) ) : ?>
|
51 |
+
<?php foreach ( $post_types as $id => $post_type ) : ?>
|
52 |
+
<?php echo '<div class="custom-control custom-checkbox">'; ?>
|
53 |
+
<?php echo '<input type="checkbox" class="custom-control-input" name="jupiterx_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 ) . '">'; ?>
|
54 |
+
<?php echo '<label class="custom-control-label" for="jupiterx_post_type_' . esc_attr( $post_type->name ) . '">' . $post_type->label . '</label>'; ?>
|
55 |
+
<?php echo '</div>'; ?>
|
56 |
+
<?php endforeach; ?>
|
57 |
+
<?php else : ?>
|
58 |
+
<div class="jupiterx-settings-no-post-type">
|
59 |
+
<i class="jupiterx-icon-info-circle"></i><?php esc_html_e( 'No custom post type was found.', 'jupiterx-core' ); ?>
|
60 |
+
</div>
|
61 |
+
<?php endif; ?>
|
62 |
+
</div>
|
63 |
+
<?php do_action( 'jupiterx_control_panel_settings_white_label' ); ?>
|
64 |
+
<?php if ( jupiterx_is_premium() && class_exists( 'Jupiter_Donut' ) ) : ?>
|
65 |
+
<div class="col-md-12"><hr></div>
|
66 |
+
<h5 class="col-md-12 mb-3">Donut Plugin</h5>
|
67 |
+
<div class="form-group col-md-6">
|
68 |
+
<label for="jupiterx-cp-settings-donut-twitter-consumer-key"><?php esc_html_e( 'Twitter Consumer Key', 'jupiterx-core' ); ?></label>
|
69 |
+
<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">
|
70 |
+
</div>
|
71 |
+
<div class="form-group col-md-6">
|
72 |
+
<label for="jupiterx-cp-settings-donut-twitter-consumer-secret"><?php esc_html_e( 'Twitter Consumer Secret', 'jupiterx-core' ); ?></label>
|
73 |
+
<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">
|
74 |
+
</div>
|
75 |
+
<div class="form-group col-md-6">
|
76 |
+
<label for="jupiterx-cp-settings-donut-twitter-access-token"><?php esc_html_e( 'Twitter Access Token', 'jupiterx-core' ); ?></label>
|
77 |
+
<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">
|
78 |
+
</div>
|
79 |
+
<div class="form-group col-md-6">
|
80 |
+
<label for="jupiterx-cp-settings-donut-twitter-access-token-secret"><?php esc_html_e( 'Twitter Access Token Secret', 'jupiterx-core' ); ?></label>
|
81 |
+
<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">
|
82 |
+
</div>
|
83 |
+
<div class="form-group col-md-6">
|
84 |
+
<label for="jupiterx-cp-settings-donut-mailchimp-api-key"><?php esc_html_e( 'MailChimp API Key', 'jupiterx-core' ); ?></label>
|
85 |
+
<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">
|
86 |
+
</div>
|
87 |
+
<div class="form-group col-md-6">
|
88 |
+
<label for="jupiterx-cp-settings-donut-mailchimp-list-id"><?php esc_html_e( 'Mailchimp List ID', 'jupiterx-core' ); ?></label>
|
89 |
+
<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">
|
90 |
+
</div>
|
91 |
+
<div class="form-group col-md-6">
|
92 |
+
<label for="jupiterx-cp-settings-donut-google-maps-api-key"><?php esc_html_e( 'Google Maps API Key', 'jupiterx-core' ); ?></label>
|
93 |
+
<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">
|
94 |
+
</div>
|
95 |
+
<?php endif; ?>
|
96 |
+
</div>
|
97 |
+
<div class="mt-2">
|
98 |
+
<button type="submit" class="btn btn-primary"><?php esc_html_e( 'Save Settings', 'jupiterx-core' ); ?></button>
|
99 |
+
<span class="jupiterx-cp-settings-save-feedback text-muted ml-2 d-none"><?php esc_html_e( 'Saving...', 'jupiterx-core' ); ?></span>
|
100 |
+
</div>
|
101 |
+
</form>
|
102 |
+
</div>
|
103 |
+
</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( 'http://help.artbees.net/getting-started/installing-the-theme/checking-server-requirements', __( '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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|