canary-deployment.php (5037B)
1 <?php 2 namespace Elementor\Core\Admin; 3 4 use Elementor\Api; 5 use Elementor\Core\Base\Module; 6 7 if ( ! defined( 'ABSPATH' ) ) { 8 exit; // Exit if accessed directly. 9 } 10 11 class Canary_Deployment extends Module { 12 13 const CURRENT_VERSION = ELEMENTOR_VERSION; 14 const PLUGIN_BASE = ELEMENTOR_PLUGIN_BASE; 15 16 private $canary_deployment_info = null; 17 18 /** 19 * Get module name. 20 * 21 * Retrieve the module name. 22 * 23 * @since 2.6.0 24 * @access public 25 * 26 * @return string Module name. 27 */ 28 public function get_name() { 29 return 'canary-deployment'; 30 } 31 32 /** 33 * Check version. 34 * 35 * @since 2.6.0 36 * @access public 37 * 38 * @param object $transient Plugin updates data. 39 * 40 * @return object Plugin updates data. 41 */ 42 public function check_version( $transient ) { 43 // First transient before the real check. 44 if ( ! isset( $transient->response ) ) { 45 return $transient; 46 } 47 48 // Placeholder 49 $stable_version = '0.0.0'; 50 51 if ( ! empty( $transient->response[ static::PLUGIN_BASE ]->new_version ) ) { 52 $stable_version = $transient->response[ static::PLUGIN_BASE ]->new_version; 53 } 54 55 if ( null === $this->canary_deployment_info ) { 56 $this->canary_deployment_info = $this->get_canary_deployment_info(); 57 } 58 59 // Can be false - if canary version is not available. 60 if ( empty( $this->canary_deployment_info ) ) { 61 return $transient; 62 } 63 64 if ( ! version_compare( $this->canary_deployment_info['new_version'], $stable_version, '>' ) ) { 65 return $transient; 66 } 67 68 $canary_deployment_info = $this->canary_deployment_info; 69 70 // Most of plugin info comes from the $transient but on first check - the response is empty. 71 if ( ! empty( $transient->response[ static::PLUGIN_BASE ] ) ) { 72 $canary_deployment_info = array_merge( (array) $transient->response[ static::PLUGIN_BASE ], $canary_deployment_info ); 73 } 74 75 $transient->response[ static::PLUGIN_BASE ] = (object) $canary_deployment_info; 76 77 return $transient; 78 } 79 80 protected function get_canary_deployment_remote_info( $force ) { 81 return Api::get_canary_deployment_info( $force ); 82 } 83 84 private function get_canary_deployment_info() { 85 global $pagenow; 86 87 $force = 'update-core.php' === $pagenow && isset( $_GET['force-check'] ); 88 89 $canary_deployment = $this->get_canary_deployment_remote_info( $force ); 90 91 if ( empty( $canary_deployment['plugin_info']['new_version'] ) ) { 92 return false; 93 } 94 95 $canary_version = $canary_deployment['plugin_info']['new_version']; 96 97 if ( version_compare( $canary_version, static::CURRENT_VERSION, '<=' ) ) { 98 return false; 99 } 100 101 if ( ! empty( $canary_deployment['conditions'] ) && ! $this->check_conditions( $canary_deployment['conditions'] ) ) { 102 return false; 103 } 104 105 return $canary_deployment['plugin_info']; 106 } 107 108 private function check_conditions( $groups ) { 109 foreach ( $groups as $group ) { 110 if ( $this->check_group( $group ) ) { 111 return true; 112 } 113 } 114 115 return false; 116 } 117 118 private function check_group( $group ) { 119 $is_or_relation = ! empty( $group['relation'] ) && 'OR' === $group['relation']; 120 unset( $group['relation'] ); 121 $result = false; 122 123 foreach ( $group as $condition ) { 124 // Reset results for each condition. 125 $result = false; 126 switch ( $condition['type'] ) { 127 case 'wordpress': // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled 128 // include an unmodified $wp_version 129 include ABSPATH . WPINC . '/version.php'; 130 $result = version_compare( $wp_version, $condition['version'], $condition['operator'] ); 131 break; 132 case 'multisite': 133 $result = is_multisite() === $condition['multisite']; 134 break; 135 case 'language': 136 $in_array = in_array( get_locale(), $condition['languages'], true ); 137 $result = 'in' === $condition['operator'] ? $in_array : ! $in_array; 138 break; 139 case 'plugin': 140 if ( ! empty( $condition['plugin_file'] ) ) { 141 $plugin_file = $condition['plugin_file']; // For PHP Unit tests. 142 } else { 143 $plugin_file = WP_PLUGIN_DIR . '/' . $condition['plugin']; // Default. 144 } 145 146 $version = ''; 147 148 if ( is_plugin_active( $condition['plugin'] ) && file_exists( $plugin_file ) ) { 149 $plugin_data = get_plugin_data( $plugin_file ); 150 if ( isset( $plugin_data['Version'] ) ) { 151 $version = $plugin_data['Version']; 152 } 153 } 154 155 $result = version_compare( $version, $condition['version'], $condition['operator'] ); 156 break; 157 case 'theme': 158 $theme = wp_get_theme(); 159 if ( wp_get_theme()->parent() ) { 160 $theme = wp_get_theme()->parent(); 161 } 162 163 if ( $theme->get_template() === $condition['theme'] ) { 164 $version = $theme->version; 165 } else { 166 $version = ''; 167 } 168 169 $result = version_compare( $version, $condition['version'], $condition['operator'] ); 170 break; 171 172 } 173 174 if ( ( $is_or_relation && $result ) || ( ! $is_or_relation && ! $result ) ) { 175 return $result; 176 } 177 } 178 179 return $result; 180 } 181 182 /** 183 * @since 2.6.0 184 * @access public 185 */ 186 public function __construct() { 187 add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'check_version' ] ); 188 } 189 }