Version Description
- New: Add filter to change the cache folder for creating & restoring backups #1528
- New: Huge performance improvement for search & replace in cloning / pushing / backup process #1522
- Fix: Call to undefined function human_readable_duration() on backup creation if WP is older than 5.1 #1527 #1525 #1535
- Dev: Add unit tests for Times class that is used in backup listing view
- Dev: Update db_version in SQL dumps to match WordPress 5.9 db version #1539
- Dev: Add command to get db_version from database
Download this release
Release Info
Developer | ReneHermi |
Plugin | WP Staging – DB & File Duplicator & Migration |
Version | 2.9.4 |
Comparing to | |
See all releases |
Code changes from version 2.9.3 to 2.9.4
- Framework/Adapter/Directory.php +6 -2
- Framework/Database/SearchReplace.php +16 -2
- Framework/Filesystem/PathIdentifier.php +10 -0
- Framework/Traits/DbRowsGeneratorTrait.php +94 -22
- Framework/Utils/Times.php +156 -1
- bootstrap.php +25 -1
- constantsFree.php +1 -1
- opcacheBootstrap.php +1 -1
- readme.txt +9 -1
- wp-staging.php +1 -1
Framework/Adapter/Directory.php
CHANGED
@@ -69,7 +69,9 @@ class Directory
|
|
69 |
return $this->cacheDirectory;
|
70 |
}
|
71 |
|
72 |
-
$
|
|
|
|
|
73 |
|
74 |
return $this->cacheDirectory;
|
75 |
}
|
@@ -113,7 +115,9 @@ class Directory
|
|
113 |
return $this->pluginUploadsDirectory;
|
114 |
}
|
115 |
|
116 |
-
$
|
|
|
|
|
117 |
|
118 |
return $this->pluginUploadsDirectory;
|
119 |
}
|
69 |
return $this->cacheDirectory;
|
70 |
}
|
71 |
|
72 |
+
$cachePath = apply_filters('wpstg.directory.cacheDirectory', wp_normalize_path($this->getPluginUploadsDirectory() . 'cache'));
|
73 |
+
|
74 |
+
$this->cacheDirectory = trailingslashit($cachePath);
|
75 |
|
76 |
return $this->cacheDirectory;
|
77 |
}
|
115 |
return $this->pluginUploadsDirectory;
|
116 |
}
|
117 |
|
118 |
+
$pluginUploadsDir = apply_filters('wpstg.directory.pluginUploadsDirectory', wp_normalize_path($this->getUploadsDirectory() . WPSTG_PLUGIN_DOMAIN));
|
119 |
+
|
120 |
+
$this->pluginUploadsDirectory = trailingslashit($pluginUploadsDir);
|
121 |
|
122 |
return $this->pluginUploadsDirectory;
|
123 |
}
|
Framework/Database/SearchReplace.php
CHANGED
@@ -4,6 +4,8 @@ namespace WPStaging\Framework\Database;
|
|
4 |
|
5 |
use RuntimeException;
|
6 |
|
|
|
|
|
7 |
class SearchReplace
|
8 |
{
|
9 |
/** @var array */
|
@@ -38,6 +40,9 @@ class SearchReplace
|
|
38 |
$this->isWpBakeryActive = false;
|
39 |
}
|
40 |
|
|
|
|
|
|
|
41 |
public function getSmallerSearchLength()
|
42 |
{
|
43 |
if ($this->smallerReplacement < PHP_INT_MAX) {
|
@@ -59,6 +64,10 @@ class SearchReplace
|
|
59 |
*/
|
60 |
public function replace($data)
|
61 |
{
|
|
|
|
|
|
|
|
|
62 |
if (!$this->search || !$this->replace) {
|
63 |
return $data;
|
64 |
}
|
@@ -177,7 +186,12 @@ class SearchReplace
|
|
177 |
}
|
178 |
|
179 |
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
180 |
-
|
|
|
|
|
|
|
|
|
|
|
181 |
if ($unserialized !== false) {
|
182 |
return serialize($this->walker($unserialized));
|
183 |
}
|
@@ -213,7 +227,7 @@ class SearchReplace
|
|
213 |
return $data;
|
214 |
}
|
215 |
|
216 |
-
private function strReplace($data)
|
217 |
{
|
218 |
$regexExclude = '';
|
219 |
foreach ($this->exclude as $excludeString) {
|
4 |
|
5 |
use RuntimeException;
|
6 |
|
7 |
+
use function WPStaging\functions\debug_log;
|
8 |
+
|
9 |
class SearchReplace
|
10 |
{
|
11 |
/** @var array */
|
40 |
$this->isWpBakeryActive = false;
|
41 |
}
|
42 |
|
43 |
+
/**
|
44 |
+
* @return int
|
45 |
+
*/
|
46 |
public function getSmallerSearchLength()
|
47 |
{
|
48 |
if ($this->smallerReplacement < PHP_INT_MAX) {
|
64 |
*/
|
65 |
public function replace($data)
|
66 |
{
|
67 |
+
if (defined('DISABLE_WPSTG_SEARCH_REPLACE') && DISABLE_WPSTG_SEARCH_REPLACE) {
|
68 |
+
return $data;
|
69 |
+
}
|
70 |
+
|
71 |
if (!$this->search || !$this->replace) {
|
72 |
return $data;
|
73 |
}
|
186 |
}
|
187 |
|
188 |
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
189 |
+
try {
|
190 |
+
$unserialized = @unserialize($data);
|
191 |
+
} catch (\Exception $e) {
|
192 |
+
debug_log('replaceString. Can not unserialize data. Error: ' . $e->getMessage() . ' Data: ' . $data);
|
193 |
+
}
|
194 |
+
|
195 |
if ($unserialized !== false) {
|
196 |
return serialize($this->walker($unserialized));
|
197 |
}
|
227 |
return $data;
|
228 |
}
|
229 |
|
230 |
+
private function strReplace($data = '')
|
231 |
{
|
232 |
$regexExclude = '';
|
233 |
foreach ($this->exclude as $excludeString) {
|
Framework/Filesystem/PathIdentifier.php
CHANGED
@@ -4,6 +4,16 @@ namespace WPStaging\Framework\Filesystem;
|
|
4 |
|
5 |
use WPStaging\Framework\Adapter\Directory;
|
6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
class PathIdentifier
|
8 |
{
|
9 |
const IDENTIFIER_WP_CONTENT = 'wpstg_c_';
|
4 |
|
5 |
use WPStaging\Framework\Adapter\Directory;
|
6 |
|
7 |
+
/**
|
8 |
+
* This class is used to shorten the full file path
|
9 |
+
* to reduce the overall file size of the backup file.
|
10 |
+
*
|
11 |
+
* A file like wp-content/uploads/wp-staging-pro/wp-staging-pro.zip turn into
|
12 |
+
* wpstg_p_/wp-staging-pro/wp-staging.zip
|
13 |
+
*
|
14 |
+
* @todo rename this class to PathShortener
|
15 |
+
*/
|
16 |
+
|
17 |
class PathIdentifier
|
18 |
{
|
19 |
const IDENTIFIER_WP_CONTENT = 'wpstg_c_';
|
Framework/Traits/DbRowsGeneratorTrait.php
CHANGED
@@ -20,6 +20,58 @@ trait DbRowsGeneratorTrait
|
|
20 |
{
|
21 |
use ResourceTrait;
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
/**
|
24 |
* Returns a generator of rows.
|
25 |
*
|
@@ -28,9 +80,9 @@ trait DbRowsGeneratorTrait
|
|
28 |
* If the current thread is over 80% memory or execution time, then the Generator will yield `null` to stop
|
29 |
* the processing.
|
30 |
*
|
31 |
-
* @param string $table
|
32 |
-
* @param int
|
33 |
-
* @param int
|
34 |
* processed will depend on the server available memory and max request execution time.
|
35 |
* @param \wpdb|null A reference to the database instance to fetch rows from.
|
36 |
*
|
@@ -38,26 +90,31 @@ trait DbRowsGeneratorTrait
|
|
38 |
*/
|
39 |
protected function rowsGenerator($table, $offset, $limit, \wpdb $db = null)
|
40 |
{
|
41 |
-
/* if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
55 |
|
56 |
if (null === $db) {
|
57 |
global $wpdb;
|
58 |
$db = $wpdb;
|
59 |
}
|
60 |
|
|
|
|
|
|
|
|
|
61 |
$suppressErrorsOriginal = $db->suppress_errors;
|
62 |
$db->suppress_errors(false);
|
63 |
|
@@ -69,6 +126,7 @@ trait DbRowsGeneratorTrait
|
|
69 |
// More rows equals more memory; to process more let's reduce the memory footprint by using smaller fetch sizes.
|
70 |
$batchSize = $limit / 5;
|
71 |
$lastFetch = false;
|
|
|
72 |
|
73 |
do {
|
74 |
if (count($rows) === 0) {
|
@@ -76,21 +134,35 @@ trait DbRowsGeneratorTrait
|
|
76 |
break;
|
77 |
}
|
78 |
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
-
|
|
|
82 |
|
83 |
if (!empty($db->last_error)) {
|
84 |
\WPStaging\functions\debug_log($db->last_error);
|
85 |
}
|
86 |
|
|
|
87 |
if (empty($rows)) {
|
88 |
-
// We're done here.
|
89 |
break;
|
90 |
}
|
91 |
|
92 |
if (!is_array($rows)) {
|
93 |
-
\WPStaging\functions\debug_log(sprintf('$rows is not an array. Actual type: %s', gettype($rows)));
|
94 |
}
|
95 |
|
96 |
$offset += $batchSize;
|
@@ -101,8 +173,8 @@ trait DbRowsGeneratorTrait
|
|
101 |
// Take the next row from the ready set.
|
102 |
$row = array_shift($rows);
|
103 |
|
|
|
104 |
if (null === $row) {
|
105 |
-
// We're done, no more rows to process.
|
106 |
break;
|
107 |
}
|
108 |
|
20 |
{
|
21 |
use ResourceTrait;
|
22 |
|
23 |
+
protected $tableName = '';
|
24 |
+
|
25 |
+
/** @var object */
|
26 |
+
private $stagingSiteDb;
|
27 |
+
|
28 |
+
/** @var null */
|
29 |
+
public $hasNumericPrimaryKey = true;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @return string The primary key of the current table, if any.
|
33 |
+
*/
|
34 |
+
protected function getPrimaryKey()
|
35 |
+
{
|
36 |
+
|
37 |
+
if (!$this->hasNumericPrimaryKey) {
|
38 |
+
return false;
|
39 |
+
}
|
40 |
+
|
41 |
+
$dbname = $this->stagingSiteDb->dbname;
|
42 |
+
|
43 |
+
$query = "SELECT COLUMN_NAME
|
44 |
+
FROM INFORMATION_SCHEMA.COLUMNS
|
45 |
+
WHERE TABLE_NAME = '$this->tableName'
|
46 |
+
AND TABLE_SCHEMA = '$dbname'
|
47 |
+
AND IS_NULLABLE = 'NO'
|
48 |
+
AND DATA_TYPE IN ('int', 'bigint', 'smallint', 'mediumint')
|
49 |
+
AND COLUMN_KEY = 'PRI'
|
50 |
+
AND EXTRA like '%auto_increment%';";
|
51 |
+
|
52 |
+
$primaryKey = $this->stagingSiteDb->get_results($query, ARRAY_A);
|
53 |
+
|
54 |
+
$this->stagingSiteDb->flush();
|
55 |
+
|
56 |
+
if (!$primaryKey) {
|
57 |
+
return false;
|
58 |
+
}
|
59 |
+
|
60 |
+
if (!is_array($primaryKey[0])) {
|
61 |
+
return false;
|
62 |
+
}
|
63 |
+
|
64 |
+
if (!array_key_exists('COLUMN_NAME', $primaryKey[0])) {
|
65 |
+
return false;
|
66 |
+
}
|
67 |
+
|
68 |
+
if (empty($primaryKey[0]['COLUMN_NAME'])) {
|
69 |
+
return false;
|
70 |
+
}
|
71 |
+
|
72 |
+
return $primaryKey[0]['COLUMN_NAME'];
|
73 |
+
}
|
74 |
+
|
75 |
/**
|
76 |
* Returns a generator of rows.
|
77 |
*
|
80 |
* If the current thread is over 80% memory or execution time, then the Generator will yield `null` to stop
|
81 |
* the processing.
|
82 |
*
|
83 |
+
* @param string $table The prefixed name of the table to pull rows from.
|
84 |
+
* @param int $offset The number of row to start the work from.
|
85 |
+
* @param int $limit The maximum number of rows to try and process; the actual number of
|
86 |
* processed will depend on the server available memory and max request execution time.
|
87 |
* @param \wpdb|null A reference to the database instance to fetch rows from.
|
88 |
*
|
90 |
*/
|
91 |
protected function rowsGenerator($table, $offset, $limit, \wpdb $db = null)
|
92 |
{
|
93 |
+
/* if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
94 |
+
\WPStaging\functions\debug_log(
|
95 |
+
sprintf(
|
96 |
+
'DbRowsGeneratorTrait: max-memory-limit=%s; script-memory-limit=%s; memory-usage=%s; execution-time-limit=%s; running-time=%s; is-threshold=%s',
|
97 |
+
$this->getMaxMemoryLimit(),
|
98 |
+
$this->getScriptMemoryLimit(),
|
99 |
+
$this->getMemoryUsage(),
|
100 |
+
$this->findExecutionTimeLimit(),
|
101 |
+
$this->getRunningTime(),
|
102 |
+
($this->isThreshold() ? 'yes' : 'no')
|
103 |
+
)
|
104 |
+
);
|
105 |
+
}*/
|
106 |
+
|
107 |
+
$this->tableName = $table;
|
108 |
|
109 |
if (null === $db) {
|
110 |
global $wpdb;
|
111 |
$db = $wpdb;
|
112 |
}
|
113 |
|
114 |
+
$this->stagingSiteDb = $db;
|
115 |
+
|
116 |
+
$numericPrimaryKey = ($key = $this->getPrimaryKey()) ? $key : false;
|
117 |
+
|
118 |
$suppressErrorsOriginal = $db->suppress_errors;
|
119 |
$db->suppress_errors(false);
|
120 |
|
126 |
// More rows equals more memory; to process more let's reduce the memory footprint by using smaller fetch sizes.
|
127 |
$batchSize = $limit / 5;
|
128 |
$lastFetch = false;
|
129 |
+
$batchSize = ceil($batchSize);
|
130 |
|
131 |
do {
|
132 |
if (count($rows) === 0) {
|
134 |
break;
|
135 |
}
|
136 |
|
137 |
+
// Optimal! We have Primary Keys so it doesn't get slower on large offsets.
|
138 |
+
if (!empty($numericPrimaryKey)) {
|
139 |
+
$query = <<<SQL
|
140 |
+
SELECT *
|
141 |
+
FROM `{$table}`
|
142 |
+
WHERE `{$numericPrimaryKey}` > {$offset}
|
143 |
+
ORDER BY `{$numericPrimaryKey}` ASC
|
144 |
+
LIMIT 0, {$batchSize}
|
145 |
+
SQL;
|
146 |
+
} else {
|
147 |
+
$query = "SELECT * FROM `{$table}` LIMIT {$offset}, {$batchSize}";
|
148 |
+
}
|
149 |
+
|
150 |
+
$rows = $db->get_results($query, ARRAY_A);
|
151 |
|
152 |
+
// Call to mysql_free_result
|
153 |
+
$db->flush();
|
154 |
|
155 |
if (!empty($db->last_error)) {
|
156 |
\WPStaging\functions\debug_log($db->last_error);
|
157 |
}
|
158 |
|
159 |
+
// We're done here.
|
160 |
if (empty($rows)) {
|
|
|
161 |
break;
|
162 |
}
|
163 |
|
164 |
if (!is_array($rows)) {
|
165 |
+
\WPStaging\functions\debug_log(sprintf('DbRowsGenerator: $rows is not an array. Actual type: %s', gettype($rows)));
|
166 |
}
|
167 |
|
168 |
$offset += $batchSize;
|
173 |
// Take the next row from the ready set.
|
174 |
$row = array_shift($rows);
|
175 |
|
176 |
+
// We're done, no more rows to process.
|
177 |
if (null === $row) {
|
|
|
178 |
break;
|
179 |
}
|
180 |
|
Framework/Utils/Times.php
CHANGED
@@ -28,9 +28,9 @@ class Times
|
|
28 |
* Uses the `timezone_string` option to get a proper timezone if available,
|
29 |
* otherwise falls back to an offset.
|
30 |
*
|
|
|
31 |
* @see wp_timezone_string()
|
32 |
*
|
33 |
-
* @return mixed|string|void PHP timezone string or a ±HH:MM offset.
|
34 |
*/
|
35 |
public function getSiteTimezoneString()
|
36 |
{
|
@@ -116,4 +116,159 @@ class Times
|
|
116 |
|
117 |
return $values;
|
118 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
}
|
28 |
* Uses the `timezone_string` option to get a proper timezone if available,
|
29 |
* otherwise falls back to an offset.
|
30 |
*
|
31 |
+
* @return mixed|string|void PHP timezone string or a ±HH:MM offset.
|
32 |
* @see wp_timezone_string()
|
33 |
*
|
|
|
34 |
*/
|
35 |
public function getSiteTimezoneString()
|
36 |
{
|
116 |
|
117 |
return $values;
|
118 |
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Alternative to human_readable_duration() as it is not available for WP < 5.1
|
122 |
+
* @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
|
123 |
+
* with a possible prepended negative sign (-).
|
124 |
+
* @return string|false A human readable duration string, false on failure.
|
125 |
+
*/
|
126 |
+
public function getHumanReadableDuration($duration)
|
127 |
+
{
|
128 |
+
if ((empty($duration) || !is_string($duration))) {
|
129 |
+
return false;
|
130 |
+
}
|
131 |
+
|
132 |
+
$duration = trim($duration);
|
133 |
+
|
134 |
+
// Remove prepended negative sign.
|
135 |
+
if ('-' === substr($duration, 0, 1)) {
|
136 |
+
$duration = substr($duration, 1);
|
137 |
+
}
|
138 |
+
|
139 |
+
// Extract duration parts.
|
140 |
+
$duration_parts = array_reverse(explode(':', $duration));
|
141 |
+
$duration_count = count($duration_parts);
|
142 |
+
|
143 |
+
$hour = null;
|
144 |
+
$minute = null;
|
145 |
+
$second = null;
|
146 |
+
|
147 |
+
if (3 === $duration_count) {
|
148 |
+
// Validate HH:ii:ss duration format.
|
149 |
+
if (!((bool)preg_match('/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/', $duration))) {
|
150 |
+
return false;
|
151 |
+
}
|
152 |
+
// Three parts: hours, minutes & seconds.
|
153 |
+
list($second, $minute, $hour) = $duration_parts;
|
154 |
+
} elseif (2 === $duration_count) {
|
155 |
+
// Validate ii:ss duration format.
|
156 |
+
if (!((bool)preg_match('/^([0-5]?[0-9]):([0-5]?[0-9])$/', $duration))) {
|
157 |
+
return false;
|
158 |
+
}
|
159 |
+
// Two parts: minutes & seconds.
|
160 |
+
list($second, $minute) = $duration_parts;
|
161 |
+
} else {
|
162 |
+
return false;
|
163 |
+
}
|
164 |
+
|
165 |
+
$human_readable_duration = [];
|
166 |
+
|
167 |
+
// Add the hour part to the string.
|
168 |
+
if (is_numeric($hour)) {
|
169 |
+
/* translators: %s: Time duration in hour or hours. */
|
170 |
+
$human_readable_duration[] = sprintf(_n('%s hour', '%s hours', $hour), (int)$hour);
|
171 |
+
}
|
172 |
+
|
173 |
+
// Add the minute part to the string.
|
174 |
+
if (is_numeric($minute)) {
|
175 |
+
/* translators: %s: Time duration in minute or minutes. */
|
176 |
+
$human_readable_duration[] = sprintf(_n('%s minute', '%s minutes', $minute), (int)$minute);
|
177 |
+
}
|
178 |
+
|
179 |
+
// Add the second part to the string.
|
180 |
+
if (is_numeric($second)) {
|
181 |
+
/* translators: %s: Time duration in second or seconds. */
|
182 |
+
$human_readable_duration[] = sprintf(_n('%s second', '%s seconds', $second), (int)$second);
|
183 |
+
}
|
184 |
+
|
185 |
+
return implode(', ', $human_readable_duration);
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
*
|
190 |
+
* Alternative to human_time_diff() as it has been changed in WP 5.3
|
191 |
+
* Determines the difference between two timestamps.
|
192 |
+
*
|
193 |
+
* The difference is returned in a human readable format such as "1 hour",
|
194 |
+
* "5 mins", "2 days".
|
195 |
+
*
|
196 |
+
* @param int $from Unix timestamp from which the difference begins.
|
197 |
+
* @param int $to Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
|
198 |
+
* @return string Human readable time difference.
|
199 |
+
* @since 5.3.0 Added support for showing a difference in seconds.
|
200 |
+
*
|
201 |
+
* @since 1.5.0
|
202 |
+
*/
|
203 |
+
public function getHumanTimeDiff($from, $to = 0)
|
204 |
+
{
|
205 |
+
if (empty($to)) {
|
206 |
+
$to = time();
|
207 |
+
}
|
208 |
+
|
209 |
+
$diff = (int)abs($to - $from);
|
210 |
+
|
211 |
+
if ($diff < MINUTE_IN_SECONDS) {
|
212 |
+
$secs = $diff;
|
213 |
+
if ($secs <= 1) {
|
214 |
+
$secs = 1;
|
215 |
+
}
|
216 |
+
/* translators: Time difference between two dates, in seconds. %s: Number of seconds. */
|
217 |
+
$since = sprintf(_n('%s second', '%s seconds', $secs), $secs);
|
218 |
+
} elseif ($diff < HOUR_IN_SECONDS) {
|
219 |
+
$mins = round($diff / MINUTE_IN_SECONDS);
|
220 |
+
if ($mins <= 1) {
|
221 |
+
$mins = 1;
|
222 |
+
}
|
223 |
+
/* translators: Time difference between two dates, in minutes (min=minute). %s: Number of minutes. */
|
224 |
+
$since = sprintf(_n('%s min', '%s mins', $mins), $mins);
|
225 |
+
} elseif ($diff < DAY_IN_SECONDS) {
|
226 |
+
$hours = round($diff / HOUR_IN_SECONDS);
|
227 |
+
if ($hours <= 1) {
|
228 |
+
$hours = 1;
|
229 |
+
}
|
230 |
+
/* translators: Time difference between two dates, in hours. %s: Number of hours. */
|
231 |
+
$since = sprintf(_n('%s hour', '%s hours', $hours), $hours);
|
232 |
+
} elseif ($diff < WEEK_IN_SECONDS) {
|
233 |
+
$days = round($diff / DAY_IN_SECONDS);
|
234 |
+
if ($days <= 1) {
|
235 |
+
$days = 1;
|
236 |
+
}
|
237 |
+
/* translators: Time difference between two dates, in days. %s: Number of days. */
|
238 |
+
$since = sprintf(_n('%s day', '%s days', $days), $days);
|
239 |
+
} elseif ($diff < MONTH_IN_SECONDS) {
|
240 |
+
$weeks = round($diff / WEEK_IN_SECONDS);
|
241 |
+
if ($weeks <= 1) {
|
242 |
+
$weeks = 1;
|
243 |
+
}
|
244 |
+
/* translators: Time difference between two dates, in weeks. %s: Number of weeks. */
|
245 |
+
$since = sprintf(_n('%s week', '%s weeks', $weeks), $weeks);
|
246 |
+
} elseif ($diff < YEAR_IN_SECONDS) {
|
247 |
+
$months = round($diff / MONTH_IN_SECONDS);
|
248 |
+
if ($months <= 1) {
|
249 |
+
$months = 1;
|
250 |
+
}
|
251 |
+
/* translators: Time difference between two dates, in months. %s: Number of months. */
|
252 |
+
$since = sprintf(_n('%s month', '%s months', $months), $months);
|
253 |
+
} elseif ($diff >= YEAR_IN_SECONDS) {
|
254 |
+
$years = round($diff / YEAR_IN_SECONDS);
|
255 |
+
if ($years <= 1) {
|
256 |
+
$years = 1;
|
257 |
+
}
|
258 |
+
/* translators: Time difference between two dates, in years. %s: Number of years. */
|
259 |
+
$since = sprintf(_n('%s year', '%s years', $years), $years);
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Filters the human readable difference between two timestamps.
|
264 |
+
*
|
265 |
+
* @param string $since The difference in human readable text.
|
266 |
+
* @param int $diff The difference in seconds.
|
267 |
+
* @param int $from Unix timestamp from which the difference begins.
|
268 |
+
* @param int $to Unix timestamp to end the time difference.
|
269 |
+
* @since 4.0.0
|
270 |
+
*
|
271 |
+
*/
|
272 |
+
return apply_filters('human_time_diff', $since, $diff, $from, $to);
|
273 |
+
}
|
274 |
}
|
bootstrap.php
CHANGED
@@ -52,7 +52,7 @@ if (!defined('WPSTG_FEATURE_ENABLE_BACKUP')) {
|
|
52 |
define('WPSTG_FEATURE_ENABLE_BACKUP', true);
|
53 |
}
|
54 |
|
55 |
-
// Define
|
56 |
if (!defined('KB_IN_BYTES')) {
|
57 |
define('KB_IN_BYTES', 1024);
|
58 |
}
|
@@ -65,6 +65,30 @@ if (!defined('GB_IN_BYTES')) {
|
|
65 |
define('GB_IN_BYTES', 1024 * MB_IN_BYTES);
|
66 |
}
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
/**
|
69 |
* Register specific Pro and Free constants. We register them here instead of on the
|
70 |
* entrypoint because we want to make sure we are defining constants for the plugins
|
52 |
define('WPSTG_FEATURE_ENABLE_BACKUP', true);
|
53 |
}
|
54 |
|
55 |
+
// Define WordPress default constants if not already defined in outdated WP version for backward compatibility
|
56 |
if (!defined('KB_IN_BYTES')) {
|
57 |
define('KB_IN_BYTES', 1024);
|
58 |
}
|
65 |
define('GB_IN_BYTES', 1024 * MB_IN_BYTES);
|
66 |
}
|
67 |
|
68 |
+
if (!defined('MINUTE_IN_SECONDS')) {
|
69 |
+
define('MINUTE_IN_SECONDS', 60);
|
70 |
+
}
|
71 |
+
|
72 |
+
if (!defined('HOUR_IN_SECONDS')) {
|
73 |
+
define('HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS);
|
74 |
+
}
|
75 |
+
|
76 |
+
if (!defined('DAY_IN_SECONDS')) {
|
77 |
+
define('DAY_IN_SECONDS', 24 * HOUR_IN_SECONDS);
|
78 |
+
}
|
79 |
+
|
80 |
+
if (!defined('WEEK_IN_SECONDS')) {
|
81 |
+
define('WEEK_IN_SECONDS', 7 * DAY_IN_SECONDS);
|
82 |
+
}
|
83 |
+
|
84 |
+
if (!defined('MONTH_IN_SECONDS')) {
|
85 |
+
define('MONTH_IN_SECONDS', 30 * DAY_IN_SECONDS);
|
86 |
+
}
|
87 |
+
|
88 |
+
if (!defined('YEAR_IN_SECONDS')) {
|
89 |
+
define('YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS);
|
90 |
+
}
|
91 |
+
|
92 |
/**
|
93 |
* Register specific Pro and Free constants. We register them here instead of on the
|
94 |
* entrypoint because we want to make sure we are defining constants for the plugins
|
constantsFree.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
// WP STAGING version number
|
4 |
if (!defined('WPSTG_VERSION')) {
|
5 |
-
define('WPSTG_VERSION', '2.9.
|
6 |
}
|
7 |
|
8 |
// Compatible up to WordPress Version
|
2 |
|
3 |
// WP STAGING version number
|
4 |
if (!defined('WPSTG_VERSION')) {
|
5 |
+
define('WPSTG_VERSION', '2.9.4');
|
6 |
}
|
7 |
|
8 |
// Compatible up to WordPress Version
|
opcacheBootstrap.php
CHANGED
@@ -45,7 +45,7 @@ if (!$canInvalidate) {
|
|
45 |
*
|
46 |
* We use the "Version" from the headers of the main file of the plugin to compare.
|
47 |
*/
|
48 |
-
$runtimeVersionDifferentFromBuildVersion = get_file_data($pluginFilePath, ['Version' => 'Version'])['Version'] !== '2.9.
|
49 |
$lastCheckHappenedAfterInterval = current_time('timestamp') > (int)get_site_transient('wpstg.bootstrap.opcache.lastCleared') + 5 * MINUTE_IN_SECONDS;
|
50 |
|
51 |
$shouldClearOpCache = apply_filters('wpstg.bootstrap.opcache.shouldClear', $runtimeVersionDifferentFromBuildVersion && $lastCheckHappenedAfterInterval);
|
45 |
*
|
46 |
* We use the "Version" from the headers of the main file of the plugin to compare.
|
47 |
*/
|
48 |
+
$runtimeVersionDifferentFromBuildVersion = get_file_data($pluginFilePath, ['Version' => 'Version'])['Version'] !== '2.9.4';
|
49 |
$lastCheckHappenedAfterInterval = current_time('timestamp') > (int)get_site_transient('wpstg.bootstrap.opcache.lastCleared') + 5 * MINUTE_IN_SECONDS;
|
50 |
|
51 |
$shouldClearOpCache = apply_filters('wpstg.bootstrap.opcache.shouldClear', $runtimeVersionDifferentFromBuildVersion && $lastCheckHappenedAfterInterval);
|
readme.txt
CHANGED
@@ -9,7 +9,7 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
|
9 |
Tags: backup, database backup, staging, duplication, clone
|
10 |
Requires at least: 3.6+
|
11 |
Tested up to: 5.8
|
12 |
-
Stable tag: 2.9.
|
13 |
Requires PHP: 5.6
|
14 |
|
15 |
Backup & Duplicator Plugin - Clone, move, duplicate & migrate websites to staging, backup, and development sites for authorized users only.
|
@@ -185,6 +185,14 @@ https://wp-staging.com
|
|
185 |
|
186 |
== Changelog ==
|
187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
= 2.9.3 =
|
189 |
* New: Add support for WordPress 5.8.3
|
190 |
* New: Add filter for excluding files during cloning / backup #1494
|
9 |
Tags: backup, database backup, staging, duplication, clone
|
10 |
Requires at least: 3.6+
|
11 |
Tested up to: 5.8
|
12 |
+
Stable tag: 2.9.4
|
13 |
Requires PHP: 5.6
|
14 |
|
15 |
Backup & Duplicator Plugin - Clone, move, duplicate & migrate websites to staging, backup, and development sites for authorized users only.
|
185 |
|
186 |
== Changelog ==
|
187 |
|
188 |
+
= 2.9.4 =
|
189 |
+
* New: Add filter to change the cache folder for creating & restoring backups #1528
|
190 |
+
* New: Huge performance improvement for search & replace in cloning / pushing / backup process #1522
|
191 |
+
* Fix: Call to undefined function human_readable_duration() on backup creation if WP is older than 5.1 #1527 #1525 #1535
|
192 |
+
* Dev: Add unit tests for Times class that is used in backup listing view
|
193 |
+
* Dev: Update db_version in SQL dumps to match WordPress 5.9 db version #1539
|
194 |
+
* Dev: Add command to get db_version from database
|
195 |
+
|
196 |
= 2.9.3 =
|
197 |
* New: Add support for WordPress 5.8.3
|
198 |
* New: Add filter for excluding files during cloning / backup #1494
|
wp-staging.php
CHANGED
@@ -7,7 +7,7 @@
|
|
7 |
* Author: WP-STAGING
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi
|
10 |
-
* Version: 2.9.
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
*
|
7 |
* Author: WP-STAGING
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi
|
10 |
+
* Version: 2.9.4
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
*
|