| 1 |
<?php |
| 2 |
|
| 3 |
namespace Microthemer; |
| 4 |
|
| 5 |
use Microthemer\Dependencies\Minify; |
| 6 |
|
| 7 |
/* |
| 8 |
* Direct PHP filesystem APIs are used for micro-themes under wp-content (typically directly writable). |
| 9 |
* WP_Filesystem can prompt for FTP credentials and break the AJAX editor; unzip still uses WP_Filesystem. |
| 10 |
* |
| 11 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fopen |
| 12 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fwrite |
| 13 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fclose |
| 14 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fread |
| 15 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_mkdir |
| 16 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_rmdir |
| 17 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_chmod |
| 18 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_touch |
| 19 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_is_writable |
| 20 |
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_is_writeable |
| 21 |
* phpcs:disable WordPress.WP.AlternativeFunctions.unlink_unlink |
| 22 |
* phpcs:disable WordPress.WP.AlternativeFunctions.rename_rename |
| 23 |
*/ |
| 24 |
trait FileTrait { |
| 25 |
|
| 26 |
function setup_micro_themes_dir($activated = false){ |
| 27 |
|
| 28 |
// create micro-themes directory and some subdirectories |
| 29 |
// the parent directory is created so just need define subdirectories |
| 30 |
$directories = array( |
| 31 |
$this->micro_root_dir . 'mt/conditional/draft/', |
| 32 |
$this->micro_root_dir . 'mt/conditional/active/', |
| 33 |
$this->micro_root_dir . 'mt/js/draft/npm/', |
| 34 |
$this->micro_root_dir . 'mt/js/active/npm/', |
| 35 |
$this->micro_root_dir . 'mt/cache/themes/' . get_stylesheet() . '/', |
| 36 |
$this->micro_root_dir . 'mt/cache/tailwind/classes/', |
| 37 |
$this->micro_root_dir . 'mt/cache/tailwind/styles/', |
| 38 |
$this->micro_root_dir . 'mt/cache/content/', |
| 39 |
$this->micro_root_dir . 'Content/', |
| 40 |
); |
| 41 |
|
| 42 |
foreach ($directories as $path){ |
| 43 |
|
| 44 |
if ( !is_dir($path) ) { |
| 45 |
|
| 46 |
// create micro-themes dirs or log an error |
| 47 |
if ( !wp_mkdir_p($path) ) { |
| 48 |
|
| 49 |
$this->log( |
| 50 |
esc_html__('/micro-themes create directory error', 'microthemer'), |
| 51 |
'<p>' . sprintf( |
| 52 |
/* translators: %s: directory path */ |
| 53 |
esc_html__('WordPress was not able to create the directory: %s', 'microthemer'), |
| 54 |
$this->root_rel($path) |
| 55 |
) . $this->permissionshelp . '</p>' |
| 56 |
); |
| 57 |
|
| 58 |
return false; |
| 59 |
} |
| 60 |
} |
| 61 |
} |
| 62 |
|
| 63 |
/*else { |
| 64 |
//micro-themes dir does exist, clean lose pack files that may exist due to past bug |
| 65 |
$this->maybe_clean_micro_root(); // 7.7.2016 - we can remove after a few months. |
| 66 |
}*/ |
| 67 |
|
| 68 |
// create _scss dir if it doesn't exist (at some point) |
| 69 |
|
| 70 |
// copy animation-events over if needed |
| 71 |
if (!$this->maybe_copy_to_micro_root($activated)) { |
| 72 |
return false; |
| 73 |
}; |
| 74 |
|
| 75 |
// update the template cache for the current theme if not created yet |
| 76 |
Common::maybeUpdateTemplateCache($this->micro_root_dir); |
| 77 |
|
| 78 |
// also create blank active-styles else 404 before user adds styles |
| 79 |
/*$prime_files = array( |
| 80 |
$this->micro_root_dir.'active-styles.css', |
| 81 |
$this->micro_root_dir.'min.active-styles.css', |
| 82 |
$this->micro_root_dir.'draft-styles.css', |
| 83 |
$this->micro_root_dir.'min.draft-styles.css', |
| 84 |
$this->micro_root_dir.'active-styles.scss', |
| 85 |
); |
| 86 |
|
| 87 |
if (!$this->maybe_create_stylesheet($prime_files)) { |
| 88 |
return false; |
| 89 |
}*/ |
| 90 |
|
| 91 |
// all good |
| 92 |
return true; |
| 93 |
} |
| 94 |
|
| 95 |
function dir_loop($dir, $result = array()) { |
| 96 |
|
| 97 |
foreach(scandir($dir) as $filename) { |
| 98 |
|
| 99 |
if ($filename[0] === '.' || $filename[0] === '..' || $filename === 'stock' || $filename === 'mt' || $filename === 'Content') { |
| 100 |
continue; |
| 101 |
} |
| 102 |
|
| 103 |
//wp_die('$filename: <pre>'.print_r($filename, 1).'</pre>' ); |
| 104 |
|
| 105 |
$filePath = $dir . DIRECTORY_SEPARATOR . $filename; |
| 106 |
|
| 107 |
if (is_dir($filePath)) { |
| 108 |
$result[$filename] = $this->dir_loop($filePath); |
| 109 |
} |
| 110 |
|
| 111 |
else { |
| 112 |
if ($this->is_screenshot($filename)){ |
| 113 |
$result['screenshot'] = $filename; |
| 114 |
} else { |
| 115 |
$result[$filename] = 1; |
| 116 |
} |
| 117 |
} |
| 118 |
} |
| 119 |
|
| 120 |
// sort alphabetically |
| 121 |
if (is_array($result)) { |
| 122 |
ksort($result); |
| 123 |
} |
| 124 |
|
| 125 |
return $result; |
| 126 |
} |
| 127 |
|
| 128 |
// get extension |
| 129 |
function has_extension($file) { |
| 130 |
return count(explode('.', $file)) > 1; |
| 131 |
//return preg_match('/\..+$/', explode('?', $file)[0]); |
| 132 |
} |
| 133 |
|
| 134 |
// create active-styles if it doesn't already exist |
| 135 |
function maybe_create_stylesheet($prime_files){ |
| 136 |
if (is_array($prime_files)){ |
| 137 |
foreach($prime_files as $key => $file){ |
| 138 |
if (!file_exists($file)) { |
| 139 |
if (!$write_file = @fopen($file, 'w')) { |
| 140 |
$this->log( |
| 141 |
esc_html__('Create stylesheet error', 'microthemer'), |
| 142 |
'<p>' . esc_html__('WordPress does not have permission to create: ', 'microthemer') . |
| 143 |
$this->root_rel($file) . '. '.$this->permissionshelp.'</p>' |
| 144 |
); |
| 145 |
return false; |
| 146 |
} |
| 147 |
fclose($write_file); |
| 148 |
} |
| 149 |
} |
| 150 |
} |
| 151 |
return true; |
| 152 |
} |
| 153 |
|
| 154 |
// copy files from Microthemer plugin dir to micro-themes for use when MT is inactive |
| 155 |
function maybe_copy_to_micro_root($activated){ |
| 156 |
|
| 157 |
$orig_files = array( |
| 158 |
'/js-min/animation-events.js', |
| 159 |
'/stock/stock.zip', |
| 160 |
'/src/autoload.php', |
| 161 |
'/src/AssetLoad.php', |
| 162 |
'/src/Logic.php', |
| 163 |
'/src/Helper.php', |
| 164 |
|
| 165 |
'/src/FrontAndBackTrait.php', |
| 166 |
'/src/TimerTrait.php', |
| 167 |
'/src/Content/AssetLoadContent.php', |
| 168 |
'/src/Content/HTML.php', |
| 169 |
'/src/Content/ContentHelper.php', |
| 170 |
|
| 171 |
'/includes/animation/animation-code.inc.php', |
| 172 |
'/js-min/amender.zip', |
| 173 |
'/js-min/npm.zip', |
| 174 |
); |
| 175 |
|
| 176 |
$new_files = array( |
| 177 |
'animation-events.js', |
| 178 |
'stock.zip', |
| 179 |
'autoload.php', |
| 180 |
'AssetLoad.php', |
| 181 |
'Logic.php', |
| 182 |
'Helper.php', |
| 183 |
'FrontAndBackTrait.php', |
| 184 |
'TimerTrait.php', |
| 185 |
'Content/AssetLoadContent.php', |
| 186 |
'Content/HTML.php', |
| 187 |
'Content/ContentHelper.php', |
| 188 |
'animation-code.inc.php', |
| 189 |
'mt/js/amender.zip', |
| 190 |
'mt/js/draft/npm.zip', |
| 191 |
); |
| 192 |
|
| 193 |
// unzipped equivalents of the zip archives - preferred when present |
| 194 |
// (zip files are not permitted in the wp.org build, which ships these assets loose) |
| 195 |
$loose_dirs = array( |
| 196 |
'stock.zip' => 'images/stock-min/', |
| 197 |
'mt/js/amender.zip' => 'js-min/front-deps/amender/', |
| 198 |
'mt/js/draft/npm.zip' => 'js-min/front-deps/draft/npm/', |
| 199 |
); |
| 200 |
$i = 0; |
| 201 |
|
| 202 |
foreach($orig_files as $file){ |
| 203 |
|
| 204 |
$orig = $this->thisplugindir . $file; |
| 205 |
$newFileName = $new_files[$i]; |
| 206 |
$dirName = trailingslashit(explode('.', $newFileName)[0]); |
| 207 |
$new = $this->micro_root_dir . $newFileName; |
| 208 |
$i++; |
| 209 |
$isZipFile = strpos($newFileName, '.zip'); |
| 210 |
|
| 211 |
// copy the unzipped directory if the build ships one instead of a zip |
| 212 |
if ($isZipFile !== false && isset($loose_dirs[$newFileName])){ |
| 213 |
|
| 214 |
$looseSource = $this->thisplugindir . $loose_dirs[$newFileName]; |
| 215 |
|
| 216 |
if (is_dir($looseSource)){ |
| 217 |
|
| 218 |
if ($activated || !is_dir($this->micro_root_dir . $dirName)){ |
| 219 |
|
| 220 |
$subdir = $newFileName === 'stock.zip' ? '' : $dirName; |
| 221 |
$allowOverwrite = $newFileName !== 'mt/js/draft/npm.zip'; |
| 222 |
|
| 223 |
if ($this->copyFolder( |
| 224 |
trailingslashit($looseSource), |
| 225 |
trailingslashit($this->micro_root_dir . $subdir), |
| 226 |
false, false, $allowOverwrite |
| 227 |
) === false){ |
| 228 |
$this->log( |
| 229 |
esc_html__('Folder not copied', 'microthemer'), |
| 230 |
'<p>' . sprintf( |
| 231 |
/* translators: %s: plugin subdirectory name */ |
| 232 |
esc_html__('Plugin folder (%s) could not be copied to the /micro-themes directory.', 'microthemer'), |
| 233 |
$loose_dirs[$newFileName] |
| 234 |
) . '</p>', |
| 235 |
'error' |
| 236 |
); |
| 237 |
} |
| 238 |
} |
| 239 |
|
| 240 |
continue; |
| 241 |
} |
| 242 |
} |
| 243 |
|
| 244 |
// amender.zip will not be available if content is not included |
| 245 |
if (!file_exists($orig)){ |
| 246 |
continue; |
| 247 |
} |
| 248 |
|
| 249 |
// if we are updating / activating |
| 250 |
if ($activated |
| 251 |
|
| 252 |
// or it's a zip file and the folder hasn't already been extracted |
| 253 |
|| ($isZipFile&& !is_dir($this->micro_root_dir. $dirName)) |
| 254 |
|
| 255 |
// or it's any other file, which doesn't exist |
| 256 |
|| (!$isZipFile && !file_exists($new)) |
| 257 |
){ |
| 258 |
|
| 259 |
//wp_die('We need to copy file: '. $this->micro_root_dir.'stock'); |
| 260 |
|
| 261 |
// attempt copy, and notify if it fails |
| 262 |
if (!copy($orig, $new)){ |
| 263 |
$this->log( |
| 264 |
esc_html__('File not copied', 'microthemer'), |
| 265 |
'<p>' . sprintf( |
| 266 |
/* translators: %s: plugin file name */ |
| 267 |
esc_html__('Plugin file (%s) could not be copied to the |
| 268 |
/micro-themes directory.', 'microthemer'), |
| 269 |
$file |
| 270 |
) . '</p>', |
| 271 |
'error' |
| 272 |
); |
| 273 |
return false; |
| 274 |
} |
| 275 |
|
| 276 |
// copy was successful |
| 277 |
else { |
| 278 |
|
| 279 |
if ($isZipFile){ |
| 280 |
|
| 281 |
$error_logged = false; |
| 282 |
$success = false; |
| 283 |
|
| 284 |
//wp_die('Copy successful, try extracting '. $newFileName); |
| 285 |
|
| 286 |
// try WordPress function fallback |
| 287 |
if (!$success){ |
| 288 |
|
| 289 |
$subdir = $newFileName === 'stock.zip' ? '' : $dirName; |
| 290 |
|
| 291 |
$allowOverwrite = $newFileName !== 'mt/js/draft/npm.zip'; |
| 292 |
$result = $this->wp_extract_files($this->micro_root_dir . $subdir, $new, $allowOverwrite); |
| 293 |
$success = $result['success']; |
| 294 |
|
| 295 |
if (!$success){ |
| 296 |
|
| 297 |
//wp_die('Extract WP attempt'. print_r($result, true)); |
| 298 |
|
| 299 |
$this->log( |
| 300 |
esc_html__('Extract zip error', 'microthemer'), |
| 301 |
'<p>' . $newFileName . ' could not be extracted to ' . $this->root_rel($this->micro_root_dir.$dirName) .'</p>' . '<p><pre>'. print_r($result['data']->errors, true).'</pre></p>' |
| 302 |
); |
| 303 |
|
| 304 |
$error_logged = true; |
| 305 |
} |
| 306 |
|
| 307 |
} |
| 308 |
|
| 309 |
// try PCLZip library fallback - no this returns true even though nothing happens |
| 310 |
// maye need to update the condition, but WP does this anyway. |
| 311 |
/*if (!$success){ |
| 312 |
$success = $this->extract_files($this->micro_root_dir, $new); |
| 313 |
$error_logged = true; |
| 314 |
}*/ |
| 315 |
|
| 316 |
if ($success){ |
| 317 |
//wp_die('Extract successful: '. $this->micro_root_dir.'stock'); |
| 318 |
@unlink($new); |
| 319 |
} |
| 320 |
|
| 321 |
else { |
| 322 |
if (!$error_logged){ |
| 323 |
$this->log( |
| 324 |
esc_html__('Extract zip error', 'microthemer'), |
| 325 |
'<p>' . $newFileName . ' could not be extracted to ' . $this->root_rel($this->micro_root_dir.$dirName.'/') .'</p>' |
| 326 |
); |
| 327 |
} |
| 328 |
|
| 329 |
} |
| 330 |
|
| 331 |
|
| 332 |
} |
| 333 |
} |
| 334 |
} |
| 335 |
} |
| 336 |
|
| 337 |
return true; |
| 338 |
} |
| 339 |
|
| 340 |
// Copy an entire folder |
| 341 |
function copyFolder($from, $to, $minifyCSS = false, $minifyJS = false, $overwrite = true, $recursive = true) { |
| 342 |
|
| 343 |
if (!is_dir($from)) { |
| 344 |
return false; // bail if no directory to copy |
| 345 |
} if (!is_dir($to)) { |
| 346 |
if (!wp_mkdir_p($to)) { |
| 347 |
return false; // bail if we can't create destination folder |
| 348 |
}; |
| 349 |
} |
| 350 |
|
| 351 |
// Copy folder files recursively |
| 352 |
$dir = opendir($from); |
| 353 |
while (($ff = readdir($dir)) !== false) { |
| 354 |
if ($ff != "." && $ff != "..") { |
| 355 |
if (is_dir("$from$ff")) { |
| 356 |
if ($recursive){ |
| 357 |
$this->copyFolder("$from$ff/", "$to$ff/", $minifyCSS, $minifyJS, $overwrite, $recursive); |
| 358 |
} |
| 359 |
} else { |
| 360 |
if ($overwrite || !file_exists("$to$ff")){ |
| 361 |
|
| 362 |
// copy or copy and minify the file |
| 363 |
$ext = $this->get_extension($ff); |
| 364 |
$doMinify = $ext === 'css' && $minifyCSS || $ext === 'js' && $minifyJS; |
| 365 |
if ($doMinify){ |
| 366 |
$this->minify("$from$ff", $ext, "$to$ff"); |
| 367 |
} else { |
| 368 |
copy("$from$ff", "$to$ff"); |
| 369 |
} |
| 370 |
} |
| 371 |
|
| 372 |
} |
| 373 |
} |
| 374 |
} |
| 375 |
|
| 376 |
closedir($dir); |
| 377 |
} |
| 378 |
|
| 379 |
// clean lose pack files that may exist due to past bug |
| 380 |
function maybe_clean_micro_root(){ |
| 381 |
$files = array( |
| 382 |
'meta.txt', |
| 383 |
'debug-save.txt', |
| 384 |
'debug-current.txt', |
| 385 |
'debug-pulled-data.txt', |
| 386 |
'debug-selective-export.txt', |
| 387 |
'debug-merge.txt', |
| 388 |
'debug-overwrite.txt' |
| 389 |
); |
| 390 |
foreach ($files as $key => $file){ |
| 391 |
$file = $this->micro_root_dir . $file; |
| 392 |
if (file_exists($file)){ |
| 393 |
unlink($file); |
| 394 |
} |
| 395 |
} |
| 396 |
} |
| 397 |
|
| 398 |
|
| 399 |
function wp_extract_files($dest, $zip_file, $allowOverwrite = true){ |
| 400 |
|
| 401 |
global $wp_filesystem; |
| 402 |
|
| 403 |
// ensure file_system object is initiated |
| 404 |
if (!$wp_filesystem){ |
| 405 |
|
| 406 |
// call file system manually if function not loaded yet |
| 407 |
if (!function_exists('WP_Filesystem')){ |
| 408 |
|
| 409 |
$fileSystemClass = ABSPATH . 'wp-admin/includes/file.php'; |
| 410 |
|
| 411 |
if (!file_exists($fileSystemClass)){ |
| 412 |
return false; |
| 413 |
} |
| 414 |
|
| 415 |
// include class manually |
| 416 |
require_once($fileSystemClass); |
| 417 |
} |
| 418 |
|
| 419 |
// initiate file_system, which unzip_file assumes is set up |
| 420 |
\WP_Filesystem(); |
| 421 |
|
| 422 |
} |
| 423 |
|
| 424 |
// Support unzip without overwriting existing - needed for vendor JS scripts which should not auto-update |
| 425 |
$unzipDir = $dest; |
| 426 |
if (!$allowOverwrite){ |
| 427 |
$unzipDir = untrailingslashit($dest) . '/tmp/'; |
| 428 |
} |
| 429 |
|
| 430 |
// Unzip |
| 431 |
$result = unzip_file($zip_file, $unzipDir); |
| 432 |
|
| 433 |
// Copy unzipped from tmp dir if being careful not to overwrite |
| 434 |
if ($result === TRUE){ |
| 435 |
if (!$allowOverwrite){ |
| 436 |
|
| 437 |
// copy files without overwriting |
| 438 |
$this->copyFolder($unzipDir, $dest, false, false, false); |
| 439 |
|
| 440 |
// Delete tmp directory |
| 441 |
$this->destroyDirectoryAndContents($unzipDir); |
| 442 |
} |
| 443 |
} |
| 444 |
|
| 445 |
/*if (str_contains($zip_file, 'amender.zip')){ |
| 446 |
wp_die('Result: '. print_r([$allowOverwrite, $zip_file, $unzipDir, $result], true)); |
| 447 |
}*/ |
| 448 |
|
| 449 |
return array( |
| 450 |
'success' => ($result === TRUE), |
| 451 |
'data' => $result |
| 452 |
); |
| 453 |
} |
| 454 |
|
| 455 |
function destroyDirectoryAndContents($dir, $baseDir = null) { |
| 456 |
|
| 457 |
if (!is_dir($dir)) { |
| 458 |
return false; |
| 459 |
} |
| 460 |
|
| 461 |
// If this is the initial call, set the trusted base directory. |
| 462 |
if ($baseDir === null) { |
| 463 |
$baseDir = realpath($dir); |
| 464 |
if ($baseDir === false) { |
| 465 |
$this->log('Directory Deletion Error', '<p>Could not resolve the base path for deletion.</p>'); |
| 466 |
return false; |
| 467 |
} |
| 468 |
} |
| 469 |
|
| 470 |
$items = scandir($dir); |
| 471 |
foreach ($items as $item) { |
| 472 |
|
| 473 |
if ($item == '.' || $item == '..') { |
| 474 |
continue; |
| 475 |
} |
| 476 |
|
| 477 |
$path = $dir . DIRECTORY_SEPARATOR . $item; |
| 478 |
|
| 479 |
if (!$this->checkExpectedPath($path, $baseDir)) { |
| 480 |
$this->log('Directory Deletion Error', '<p>Wrong directory</p>'); |
| 481 |
return false; |
| 482 |
} |
| 483 |
|
| 484 |
if (is_dir($path)) { |
| 485 |
if (!$this->destroyDirectoryAndContents($path, $baseDir)) { |
| 486 |
return false; |
| 487 |
} |
| 488 |
} else { |
| 489 |
if (!unlink($path)) { |
| 490 |
return false; |
| 491 |
} |
| 492 |
} |
| 493 |
} |
| 494 |
|
| 495 |
return rmdir($dir); |
| 496 |
} |
| 497 |
|
| 498 |
function extract_files_native($dest, $zip_file){ |
| 499 |
|
| 500 |
$res = false; |
| 501 |
|
| 502 |
if (class_exists( 'ZipArchive')){ |
| 503 |
$zip = new \ZipArchive; |
| 504 |
$res = $zip->open($zip_file); |
| 505 |
} |
| 506 |
|
| 507 |
if ($res === TRUE) { |
| 508 |
$zip->extractTo($dest); |
| 509 |
$zip->close(); |
| 510 |
return true; |
| 511 |
} else { |
| 512 |
return false; |
| 513 |
} |
| 514 |
} |
| 515 |
|
| 516 |
// handle zip extraction |
| 517 |
function extract_files($dir, $file) { |
| 518 |
|
| 519 |
// tap into native WP zip handling |
| 520 |
if( !class_exists('PclZip')) { |
| 521 |
require_once(ABSPATH . 'wp-admin/includes/class-pclzip.php'); |
| 522 |
} |
| 523 |
|
| 524 |
|
| 525 |
$archive = new \PclZip($file); |
| 526 |
// extract all files in one folder - the callback functions |
| 527 |
// (tvr_microthemer_getOnlyValid) |
| 528 |
// have to be external to this class |
| 529 |
if ($archive->extract(PCLZIP_OPT_PATH, $dir, PCLZIP_OPT_REMOVE_ALL_PATH, |
| 530 |
PCLZIP_CB_PRE_EXTRACT, '\Microthemer\tvr_microthemer_getOnlyValid') == 0) { |
| 531 |
|
| 532 |
|
| 533 |
$this->log( |
| 534 |
esc_html__('Extract zip error', 'microthemer'), |
| 535 |
'<p>' . esc_html__('Error : ', 'microthemer') . $archive->errorInfo(true).'</p>' |
| 536 |
); |
| 537 |
|
| 538 |
return false; |
| 539 |
} |
| 540 |
|
| 541 |
return true; |
| 542 |
} |
| 543 |
|
| 544 |
// handle zip archiving |
| 545 |
function create_zip($path_to_dir, $dir_name, $zip_store) { |
| 546 |
$error = false; |
| 547 |
if( !class_exists('PclZip')) { |
| 548 |
require_once(ABSPATH . 'wp-admin/includes/class-pclzip.php'); |
| 549 |
} |
| 550 |
// check if the /zip-exports dir is writable first |
| 551 |
if (is_writable($zip_store)) { |
| 552 |
$archive = new \PclZip($zip_store.$dir_name.'.zip'); |
| 553 |
// create zip |
| 554 |
$v_list = $archive->create($path_to_dir.$dir_name, |
| 555 |
PCLZIP_OPT_REMOVE_PATH, $path_to_dir); |
| 556 |
|
| 557 |
if ($v_list == 0) { |
| 558 |
$error = true; |
| 559 |
$this->log( |
| 560 |
esc_html__('Create zip error', 'microthemer'), |
| 561 |
'<p>' . esc_html__('Error : ', 'microthemer') . $archive->errorInfo(true).'</p>' |
| 562 |
); |
| 563 |
} |
| 564 |
else { |
| 565 |
$this->log( |
| 566 |
esc_html__('Zip package created', 'microthemer'), |
| 567 |
'<p>' . esc_html__('Zip package successfully created.', 'microthemer') . |
| 568 |
'<a href="'.$this->thispluginurl.'zip-exports/'.$dir_name.'.zip">' . |
| 569 |
esc_html__('Download zip file', 'microthemer') . '</a> |
| 570 |
</p>', |
| 571 |
'notice' |
| 572 |
); |
| 573 |
} |
| 574 |
} |
| 575 |
else { |
| 576 |
$error = true; |
| 577 |
$this->log( |
| 578 |
esc_html__('Zip store error', 'microthemer'), |
| 579 |
'<p>' . sprintf( |
| 580 |
/* translators: %s: directory path */ |
| 581 |
esc_html__('The directory %s is not writable.', 'microthemer'), |
| 582 |
$this->root_rel($zip_store) |
| 583 |
) . $this->permissionshelp . '</p>' |
| 584 |
); |
| 585 |
} |
| 586 |
// verdict |
| 587 |
if ($error){ |
| 588 |
return false; |
| 589 |
} else { |
| 590 |
return true; |
| 591 |
} |
| 592 |
} |
| 593 |
|
| 594 |
// Get the URL for the downloadable microloader plugin zip. |
| 595 |
// Premium builds bundle includes/inactive-loading/microloader.zip, but the wp.org |
| 596 |
// build ships the microloader as a loose directory (zip files are not permitted |
| 597 |
// in the hosted plugin), so we generate the zip on demand in /micro-themes. |
| 598 |
function microloader_zip_url(){ |
| 599 |
|
| 600 |
$bundledZip = $this->thisplugindir . 'includes/inactive-loading/microloader.zip'; |
| 601 |
|
| 602 |
if (file_exists($bundledZip)){ |
| 603 |
return $this->thispluginurl . 'includes/inactive-loading/microloader.zip'; |
| 604 |
} |
| 605 |
|
| 606 |
$sourceDir = $this->thisplugindir . 'includes/inactive-loading/microloader'; |
| 607 |
$zipFile = $this->micro_root_dir . 'microloader.zip'; |
| 608 |
|
| 609 |
if (!file_exists($zipFile)){ |
| 610 |
|
| 611 |
if (!is_dir($sourceDir) || !wp_mkdir_p($this->micro_root_dir)){ |
| 612 |
return false; |
| 613 |
} |
| 614 |
|
| 615 |
if (!class_exists('PclZip')) { |
| 616 |
require_once(ABSPATH . 'wp-admin/includes/class-pclzip.php'); |
| 617 |
} |
| 618 |
|
| 619 |
$archive = new \PclZip($zipFile); |
| 620 |
$v_list = $archive->create($sourceDir, |
| 621 |
PCLZIP_OPT_REMOVE_PATH, dirname($sourceDir)); |
| 622 |
|
| 623 |
if ($v_list == 0){ |
| 624 |
return false; |
| 625 |
} |
| 626 |
} |
| 627 |
|
| 628 |
return $this->micro_root_url . 'microloader.zip'; |
| 629 |
} |
| 630 |
|
| 631 |
/*function getDirectoryFileList($directory){ |
| 632 |
return array_diff(scandir($directory), array('..', '.')); |
| 633 |
}*/ |
| 634 |
|
| 635 |
// Get a flat list of relative paths of files in directory and sub-directory |
| 636 |
function getDirectoryFileList($directory, $relativePath = '') { |
| 637 |
$fileList = array(); |
| 638 |
$items = scandir($directory); |
| 639 |
|
| 640 |
foreach ($items as $item) { |
| 641 |
if ($item === '.' || $item === '..') { |
| 642 |
continue; |
| 643 |
} |
| 644 |
|
| 645 |
$dir_sep = '/'; // DIRECTORY_SEPARATOR |
| 646 |
$fullPath = $directory . $dir_sep . $item; |
| 647 |
$currentPath = ltrim($relativePath . $dir_sep . $item, $dir_sep); |
| 648 |
|
| 649 |
if (is_dir($fullPath)) { |
| 650 |
$fileList = array_merge($fileList, $this->getDirectoryFileList($fullPath, $currentPath)); |
| 651 |
} else { |
| 652 |
$fileList[] = $currentPath; |
| 653 |
} |
| 654 |
} |
| 655 |
|
| 656 |
return $fileList; |
| 657 |
} |
| 658 |
|
| 659 |
function maybeLoadMinify(){ |
| 660 |
|
| 661 |
if (!class_exists('Microthemer\Dependencies\Minify')){ |
| 662 |
|
| 663 |
$path = dirname(__FILE__) . '/Dependencies/Minify'; |
| 664 |
require_once $path . '/minify/src/Minify.php'; |
| 665 |
require_once $path . '/minify/src/CSS.php'; |
| 666 |
require_once $path . '/minify/src/JS.php'; |
| 667 |
require_once $path . '/minify/src/Exception.php'; |
| 668 |
require_once $path . '/minify/src/Exceptions/BasicException.php'; |
| 669 |
require_once $path . '/minify/src/Exceptions/FileImportException.php'; |
| 670 |
require_once $path . '/minify/src/Exceptions/IOException.php'; |
| 671 |
require_once $path . '/path-converter/src/ConverterInterface.php'; |
| 672 |
require_once $path . '/path-converter/src/Converter.php'; |
| 673 |
} |
| 674 |
|
| 675 |
} |
| 676 |
|
| 677 |
function minify($data = null, $type = 'css', $file = false){ |
| 678 |
|
| 679 |
$this->maybeLoadMinify(); |
| 680 |
|
| 681 |
// setup minifier for CSS or JavaScript |
| 682 |
if ($type === 'css'){ |
| 683 |
$minifier = new Minify\CSS($data); |
| 684 |
} else { |
| 685 |
$minifier = new Minify\JS($data); |
| 686 |
} |
| 687 |
|
| 688 |
// return minified data or write directly to a file |
| 689 |
if ($file){ |
| 690 |
$minifier->minify($file); |
| 691 |
return true; |
| 692 |
} else { |
| 693 |
return $minifier->minify(); |
| 694 |
} |
| 695 |
|
| 696 |
} |
| 697 |
|
| 698 |
// write to a file |
| 699 |
// the file will be created if it doesn't exist. Otherwise, it is overwritten. |
| 700 |
function write_file($file, $data, $minify = false, $dataType = false, $deleteFirst = false){ |
| 701 |
|
| 702 |
// Ensure the directory exists |
| 703 |
$dir = dirname($file); |
| 704 |
if (!is_dir($dir) && !mkdir($dir, 0775, true)) { |
| 705 |
$this->log( |
| 706 |
esc_html__('Directory creation error', 'microthemer'), |
| 707 |
'<p>' . sprintf( |
| 708 |
/* translators: %s: directory path */ |
| 709 |
esc_html__('Failed to create directory: %s', 'microthemer'), |
| 710 |
$this->root_rel($dir)) . '</p>' |
| 711 |
); |
| 712 |
return false; |
| 713 |
} |
| 714 |
|
| 715 |
if ($deleteFirst && file_exists($file)){ |
| 716 |
unlink($file); |
| 717 |
} |
| 718 |
|
| 719 |
$write_file = fopen($file, 'w'); |
| 720 |
$write_data = &$data; |
| 721 |
|
| 722 |
// perhaps we minify |
| 723 |
if ($minify){ |
| 724 |
$write_data = $this->minify($data, $dataType); |
| 725 |
} |
| 726 |
|
| 727 |
// if write is unsuccessful for some reason |
| 728 |
if (false === fwrite($write_file, $write_data)) { |
| 729 |
|
| 730 |
fclose($write_file); |
| 731 |
|
| 732 |
$this->log( |
| 733 |
esc_html__('File write error', 'microthemer'), |
| 734 |
'<p>' . sprintf( |
| 735 |
/* translators: %s: file path */ |
| 736 |
esc_html__('Writing to %s failed.', 'microthemer'), |
| 737 |
$this->root_rel($file)) . $this->permissionshelp.'</p>' |
| 738 |
); |
| 739 |
|
| 740 |
return false; |
| 741 |
} |
| 742 |
|
| 743 |
fclose($write_file); |
| 744 |
|
| 745 |
return true; |
| 746 |
} |
| 747 |
|
| 748 |
|
| 749 |
|
| 750 |
|
| 751 |
} |
| 752 |
// phpcs:enable |
| 753 |
|