PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.8
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / vendor / codeinwp / themeisle-sdk / src / Modules / Rollback.php

Rollback.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.10.8, at vendor/codeinwp/themeisle-sdk/src/Modules/Rollback.php

401 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The rollback class for ThemeIsle SDK.
4 *
5 * @package ThemeIsleSDK
6 * @subpackage Rollback
7 * @copyright Copyright (c) 2017, Marius Cristea
8 * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9 * @since 1.0.0
10 */
11
12 namespace ThemeisleSDK\Modules;
13
14 // Exit if accessed directly.
15 use ThemeisleSDK\Common\Abstract_Module;
16 use ThemeisleSDK\Product;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Rollback for ThemeIsle SDK.
24 */
25 class Rollback extends Abstract_Module {
26
27 /**
28 * Add js scripts for themes rollback.
29 */
30 public function add_footer() {
31 $screen = get_current_screen();
32 if ( ! isset( $screen->parent_file ) ) {
33 return;
34 }
35 if ( 'themes.php' !== $screen->parent_file ) {
36 return;
37 }
38 if ( ! $this->product->is_theme() ) {
39 return;
40 }
41 $version = $this->get_rollback();
42 if ( empty( $version ) ) {
43 return;
44 }
45 ?>
46 <script type="text/javascript">
47 jQuery(document).ready(function ($) {
48 setInterval(checkTheme, 500);
49
50 function checkTheme() {
51 var theme = '<?php echo esc_attr( $this->product->get_slug() ); ?>-action';
52
53 if (jQuery('#' + theme).length > 0) {
54 if (jQuery('.theme-overlay.active').is(':visible')) {
55 if (jQuery('#' + theme + '-rollback').length === 0) {
56 jQuery('.theme-actions .active-theme').prepend('<a class="button" style="float:left" id="' + theme + '-rollback" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=' . $this->product->get_key() . '_rollback' ), $this->product->get_key() . '_rollback' ) ); ?>">Rollback to v<?php echo esc_attr( $version['version'] ); ?></a>')
57 }
58 }
59
60 }
61 }
62 })
63
64 </script>
65 <?php
66
67 }
68
69 /**
70 * Get the last rollback for this product.
71 *
72 * @return array The rollback version.
73 */
74 public function get_rollback() {
75 $rollback = array();
76 $versions = $this->get_api_versions();
77 $versions = apply_filters( $this->product->get_key() . '_rollbacks', $versions );
78 if ( empty( $versions ) ) {
79 return $rollback;
80 }
81 if ( $versions ) {
82 usort( $versions, array( $this, 'sort_rollback_array' ) );
83 foreach ( $versions as $version ) {
84 if ( isset( $version['version'] ) && isset( $version['url'] ) && version_compare( $this->product->get_version(), $version['version'], '>' ) ) {
85 $rollback = $version;
86 break;
87 }
88 }
89 }
90
91 return $rollback;
92 }
93
94 /**
95 * Get versions array from wp.org
96 *
97 * @return array Array of versions.
98 */
99 private function get_api_versions() {
100
101 $cache_key = $this->product->get_cache_key();
102 $cache_versions = get_transient( $cache_key );
103 if ( false === $cache_versions ) {
104 $versions = $this->get_remote_versions();
105 set_transient( $cache_key, $versions, 5 * DAY_IN_SECONDS );
106 } else {
107 $versions = is_array( $cache_versions ) ? $cache_versions : array();
108 }
109
110 return $versions;
111 }
112
113 /**
114 * Get remote versions zips.
115 *
116 * @return array Array of available versions.
117 */
118 private function get_remote_versions() {
119 $url = $this->get_versions_api_url();
120 if ( empty( $url ) ) {
121 return [];
122 }
123 $response = function_exists( 'wp_remote_get_wp_remote_get' )
124 ? wp_remote_get_wp_remote_get( $url )
125 : wp_remote_get( $url ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.wp_remote_get_wp_remote_get
126 if ( is_wp_error( $response ) ) {
127 return array();
128 }
129 $response = wp_remote_retrieve_body( $response );
130
131 if ( is_serialized( $response ) ) {
132 $response = maybe_unserialize( $response );
133 } else {
134 $response = json_decode( $response );
135 }
136
137 if ( ! is_object( $response ) ) {
138 return array();
139 }
140 if ( ! isset( $response->versions ) ) {
141 return array();
142 }
143
144 $versions = array();
145 foreach ( $response->versions as $key => $value ) {
146 $versions[] = array(
147 'version' => is_object( $value ) ? $value->version : $key,
148 'url' => is_object( $value ) ? $value->file : $value,
149 );
150 }
151
152 return $versions;
153 }
154
155 /**
156 * Return url where to check for versions.
157 *
158 * @return string Url where to check for versions.
159 */
160 private function get_versions_api_url() {
161 if ( $this->product->is_wordpress_available() && $this->product->is_plugin() ) {
162 return sprintf( 'https://api.wordpress.org/plugins/info/1.0/%s', $this->product->get_slug() );
163 }
164 if ( $this->product->is_wordpress_available() && $this->product->is_theme() ) {
165 return sprintf( 'https://api.wordpress.org/themes/info/1.1/?action=theme_information&request[slug]=%s&request[fields][versions]=true', $this->product->get_slug() );
166 }
167 $license = $this->product->get_license();
168 if ( $this->product->requires_license() && strlen( $license ) < 10 ) {
169 return '';
170 }
171
172 return sprintf( '%slicense/versions/%s/%s/%s/%s', Product::API_URL, rawurlencode( $this->product->get_name() ), $license, urlencode( get_site_url() ), $this->product->get_version() );
173 }
174
175 /**
176 * Show the rollback links in the plugin page.
177 *
178 * @param array $links Plugin links.
179 *
180 * @return array $links Altered links.
181 */
182 public function add_rollback_link( $links ) {
183 $version = $this->get_rollback();
184 if ( empty( $version ) ) {
185 return $links;
186 }
187 $links[] = '<a href="' . wp_nonce_url( admin_url( 'admin-post.php?action=' . $this->product->get_key() . '_rollback' ), $this->product->get_key() . '_rollback' ) . '">' . sprintf( apply_filters( $this->product->get_key() . '_rollback_label', 'Rollback to v%s' ), $version['version'] ) . '</a>';
188
189 return $links;
190 }
191
192 /**
193 * Start the rollback operation.
194 */
195 public function start_rollback() {
196 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], $this->product->get_key() . '_rollback' ) ) { //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
197 wp_nonce_ays( '' );
198 }
199
200 if ( $this->product->is_plugin() ) {
201 $this->start_rollback_plugin();
202
203 return;
204 }
205 if ( $this->product->is_theme() ) {
206 $this->start_rollback_theme();
207
208 return;
209 }
210 }
211
212 /**
213 * Start the rollback operation for the plugin.
214 */
215 private function start_rollback_plugin() {
216 $rollback = $this->get_rollback();
217 $plugin_transient = get_site_transient( 'update_plugins' );
218 $plugin_folder = $this->product->get_slug();
219 $plugin_file = $this->product->get_file();
220 $version = $rollback['version'];
221 $temp_array = array(
222 'slug' => $plugin_folder,
223 'new_version' => $version,
224 'package' => $rollback['url'],
225 );
226
227 $temp_object = (object) $temp_array;
228 $plugin_transient->response[ $plugin_folder . '/' . $plugin_file ] = $temp_object;
229 set_site_transient( 'update_plugins', $plugin_transient );
230
231 $transient = get_transient( $this->product->get_key() . '_warning_rollback' );
232
233 // Style fix for the api link that gets outside the content.
234 echo '<style>body#error-page{word-break:break-word;}</style>';
235
236 if ( false === $transient ) {
237 set_transient( $this->product->get_key() . '_warning_rollback', 'in progress', 30 );
238 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
239 $title = sprintf( apply_filters( $this->product->get_key() . '_rollback_message', 'Rolling back %s to v%s' ), $this->product->get_name(), $version );
240 $plugin = $plugin_folder . '/' . $plugin_file;
241 $nonce = 'upgrade-plugin_' . $plugin;
242 $url = 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin );
243 $upgrader_skin = new \Plugin_Upgrader_Skin( compact( 'title', 'nonce', 'url', 'plugin' ) );
244 $upgrader = new \Plugin_Upgrader( $upgrader_skin );
245 $upgrader->upgrade( $plugin );
246 delete_transient( $this->product->get_key() . '_warning_rollback' );
247 wp_die(
248 '',
249 esc_attr( $title ),
250 array(
251 'response' => 200,
252 )
253 );
254 }
255 }
256
257 /**
258 * Start the rollback operation for the theme.
259 */
260 private function start_rollback_theme() {
261 add_filter( 'update_theme_complete_actions', array( $this, 'alter_links_theme_upgrade' ) );
262 $rollback = $this->get_rollback();
263 $transient = get_site_transient( 'update_themes' );
264 $folder = $this->product->get_slug();
265 $version = $rollback['version'];
266 $temp_array = array(
267 'new_version' => $version,
268 'package' => $rollback['url'],
269 );
270
271 $transient->response[ $folder . '/style.css' ] = $temp_array;
272 set_site_transient( 'update_themes', $transient );
273
274 $transient = get_transient( $this->product->get_key() . '_warning_rollback' );
275
276 // Style fix for the api link that gets outside the content.
277 echo '<style>body#error-page{word-break:break-word;}</style>';
278
279 if ( false === $transient ) {
280 set_transient( $this->product->get_key() . '_warning_rollback', 'in progress', 30 );
281 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
282 $title = sprintf( apply_filters( $this->product->get_key() . '_rollback_message', 'Rolling back %s to v%s' ), $this->product->get_name(), $version );
283 $theme = $folder . '/style.css';
284 $nonce = 'upgrade-theme_' . $theme;
285 $url = 'update.php?action=upgrade-theme&theme=' . urlencode( $theme );
286
287 $upgrader = new \Theme_Upgrader( new \Theme_Upgrader_Skin( compact( 'title', 'nonce', 'url', 'theme' ) ) );
288 $upgrader->upgrade( $theme );
289 delete_transient( $this->product->get_key() . '_warning_rollback' );
290 wp_die(
291 '',
292 esc_attr( $title ),
293 array(
294 'response' => 200,
295 )
296 );
297 }
298 }
299
300 /**
301 * Alter links and remove duplicate customize message.
302 *
303 * @param array $links Array of old links.
304 *
305 * @return mixed Array of links.
306 */
307 public function alter_links_theme_upgrade( $links ) {
308 if ( isset( $links['preview'] ) ) {
309 $links['preview'] = str_replace( '<span aria-hidden="true">Customize</span>', '', $links['preview'] );
310 }
311
312 return $links;
313 }
314
315 /**
316 * Loads product object.
317 *
318 * @param Product $product Product object.
319 *
320 * @return bool Should we load the module?
321 */
322 public function can_load( $product ) {
323 if ( $this->is_from_partner( $product ) ) {
324 return false;
325 }
326 if ( $product->is_theme() && ! current_user_can( 'switch_themes' ) ) {
327 return false;
328 }
329
330 if ( $product->is_plugin() && ! current_user_can( 'install_plugins' ) ) {
331 return false;
332 }
333
334 return true;
335 }
336
337 /**
338 * Sort the rollbacks array in descending order.
339 *
340 * @param mixed $a First version to compare.
341 * @param mixed $b Second version to compare.
342 *
343 * @return bool Which version is greater?
344 */
345 public function sort_rollback_array( $a, $b ) {
346 return version_compare( $b['version'], $a['version'] );
347 }
348
349 /**
350 * Load module logic.
351 *
352 * @param Product $product Product object.
353 *
354 * @return $this Module object.
355 */
356 public function load( $product ) {
357 $this->product = $product;
358 $this->show_link();
359 $this->add_hooks();
360
361 return $this;
362 }
363
364 /**
365 * If product can be rolled back, show the link to rollback.
366 */
367 private function show_link() {
368 add_filter(
369 'plugin_action_links_' . plugin_basename( $this->product->get_basefile() ),
370 array(
371 $this,
372 'add_rollback_link',
373 )
374 );
375 }
376
377 /**
378 * Fires after the option has been updated.
379 *
380 * @param mixed $old_value The old option value.
381 * @param mixed $value The new option value.
382 * @param string $option Option name.
383 */
384 public function update_active_plugins_action( $old_value, $value, $option ) {
385 delete_site_transient( 'update_plugins' );
386 wp_cache_delete( 'plugins', 'plugins' );
387 }
388
389 /**
390 * Set the rollback hook. Strangely, this does not work if placed in the ThemeIsle_SDK_Rollback class, so it is being called from there instead.
391 */
392 public function add_hooks() {
393 add_action( 'admin_post_' . $this->product->get_key() . '_rollback', array( $this, 'start_rollback' ) );
394 add_action( 'admin_footer', array( $this, 'add_footer' ) );
395
396 // This hook will be invoked after the plugin activation.
397 // We use this to force an update of the cache so that Update is present immediate after a rollback.
398 add_action( 'update_option_active_plugins', array( $this, 'update_active_plugins_action' ), 10, 3 );
399 }
400 }
401