PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.2.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.2.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / includes / backup / cli.php

cli.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.2.0, at includes/backup/cli.php

159 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * StoreEngine full backup — WP-CLI commands.
4 *
5 * @version 1.0.0
6 */
7
8 namespace StoreEngine\Backup;
9
10 use WP_CLI;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Export / import a complete StoreEngine backup.
18 */
19 class Cli {
20
21 /**
22 * Export all StoreEngine data into a single .zip archive.
23 *
24 * ## OPTIONS
25 *
26 * [--file=<path>]
27 * : Destination .zip path. Defaults to the private backups dir (path printed).
28 *
29 * [--groups=<list>]
30 * : Comma list of optional groups to include: licensing,logs,users,files.
31 * (Core store data + settings + catalog are always included.)
32 * Default: licensing.
33 *
34 * ## EXAMPLES
35 *
36 * wp storeengine backup export --file=/tmp/se.zip --groups=licensing,users
37 *
38 * @when after_wp_load
39 */
40 public function export( $args, $assoc_args ) {
41 $groups = array_filter( array_map( 'trim', explode( ',', (string) ( $assoc_args['groups'] ?? 'licensing' ) ) ) );
42 $opts = [
43 'licensing' => in_array( 'licensing', $groups, true ),
44 'deployments' => in_array( 'deployments', $groups, true ),
45 'logs' => in_array( 'logs', $groups, true ),
46 'users' => in_array( 'users', $groups, true ),
47 'files' => in_array( 'files', $groups, true ),
48 ];
49
50 $progress = WP_CLI\Utils\make_progress_bar( 'Exporting', 100 );
51 $last = 0;
52 $exporter = new Exporter( $opts, function ( $percent ) use ( $progress, &$last ) {
53 $tick = (int) $percent - $last;
54 if ( $tick > 0 ) {
55 $progress->tick( $tick );
56 $last = (int) $percent;
57 }
58 } );
59
60 $path = $exporter->run();
61 $progress->finish();
62
63 if ( ! empty( $assoc_args['file'] ) ) {
64 // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename
65 rename( $path, $assoc_args['file'] );
66 $path = $assoc_args['file'];
67 }
68
69 WP_CLI::success( sprintf( 'Backup written to %s (%s)', $path, size_format( (int) filesize( $path ) ) ) );
70 }
71
72 /**
73 * Restore a StoreEngine backup (REPLACES existing StoreEngine data).
74 *
75 * ## OPTIONS
76 *
77 * --file=<path>
78 * : Path to the backup .zip.
79 *
80 * [--yes]
81 * : Skip the confirmation prompt.
82 *
83 * [--no-safety]
84 * : Skip the automatic pre-restore safety backup (not recommended).
85 *
86 * ## EXAMPLES
87 *
88 * wp storeengine backup import --file=/tmp/se.zip --yes
89 *
90 * @when after_wp_load
91 */
92 public function import( $args, $assoc_args ) {
93 $file = (string) ( $assoc_args['file'] ?? '' );
94 if ( ! is_file( $file ) ) {
95 WP_CLI::error( 'File not found: ' . $file );
96 }
97
98 $preview = ( new Importer() )->inspect( $file );
99 $manifest = $preview['manifest'];
100 WP_CLI::log( sprintf( 'Backup from %s (%s), generated %s.', $manifest['site_url'] ?? '?', $manifest['plugin_version'] ?? '?', $manifest['generated_at'] ?? '?' ) );
101 WP_CLI::log( sprintf( '%d tables; %d will be skipped (addon not installed).', count( (array) ( $manifest['tables'] ?? [] ) ), count( $preview['missing_tables'] ) ) );
102
103 WP_CLI::confirm( 'This will REPLACE all StoreEngine data on this site. Continue?', $assoc_args );
104
105 $progress = WP_CLI\Utils\make_progress_bar( 'Restoring', 100 );
106 $last = 0;
107 $importer = new Importer( function ( $percent ) use ( $progress, &$last ) {
108 $tick = (int) $percent - $last;
109 if ( $tick > 0 ) {
110 $progress->tick( $tick );
111 $last = (int) $percent;
112 }
113 } );
114
115 $result = $importer->run( $file, [ 'safety' => ! isset( $assoc_args['no-safety'] ) ] );
116 $progress->finish();
117
118 WP_CLI::log( sprintf( 'Restored %d tables, skipped %d.', count( $result['restored'] ), count( $result['skipped'] ) ) );
119 if ( ! empty( $result['safety_backup'] ) ) {
120 WP_CLI::log( 'Pre-restore safety backup: ' . $result['safety_backup'] );
121 }
122 WP_CLI::success( 'Restore complete.' );
123 }
124
125 /**
126 * Compare a backup's manifest row counts against the current database.
127 *
128 * ## OPTIONS
129 *
130 * --file=<path>
131 * : Path to the backup .zip.
132 *
133 * @when after_wp_load
134 */
135 public function verify( $args, $assoc_args ) {
136 global $wpdb;
137 $file = (string) ( $assoc_args['file'] ?? '' );
138 if ( ! is_file( $file ) ) {
139 WP_CLI::error( 'File not found: ' . $file );
140 }
141 $manifest = ( new Importer() )->inspect( $file )['manifest'];
142 $rows = [];
143 foreach ( (array) ( $manifest['tables'] ?? [] ) as $t ) {
144 $local = $wpdb->prefix . 'storeengine_' . $t['name'];
145 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Prepared (%i) row count on a custom StoreEngine table for CLI backup verification; no cache layer applies.
146 $live = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM %i", $local ) );
147 $rows[] = [
148 'table' => $t['name'],
149 'in_backup' => (int) $t['row_count'],
150 'in_db' => $live,
151 'match' => ( (int) $t['row_count'] === $live ) ? 'yes' : 'NO',
152 ];
153 }
154 WP_CLI\Utils\format_items( 'table', $rows, [ 'table', 'in_backup', 'in_db', 'match' ] );
155 }
156 }
157
158 // End of file cli.php.
159