PluginProbe ʕ •ᴥ•ʔ
WPML Multilingual & Multicurrency for WooCommerce / 5.5.7
WPML Multilingual & Multicurrency for WooCommerce v5.5.7
5.5.7 5.3.8 5.3.9 5.4.3 5.4.4 5.4.5 5.5.1 5.5.1.1 5.5.2.2 5.5.2.3 5.5.3 5.5.3.1 5.5.4 5.5.5 5.5.6 trunk 0.9 1.0 1.1 1.2 1.3 1.4 1.5 2.0 2.2 2.3 2.3.1 2.3.2 3.0 3.0.1 3.1 3.2 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.4 3.4.1 3.4.2 3.4.3 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.6 3.6.1 3.6.10 3.6.11 3.6.2 3.6.3 3.6.4 3.6.5 3.6.5.1 3.6.6 3.6.7 3.6.8 3.6.9 3.7 3.7.1 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.15 3.7.16 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.9.0 3.9.1 3.9.1.1 3.9.2 3.9.3 3.9.4 3.9.5 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 4.11.2 4.11.3.2 4.11.5 4.11.6 4.12.1 4.12.4 4.12.5 4.12.6 4.2.0 4.2.0.1 4.2.1 4.2.1.1 4.2.10 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.7.1 4.2.8 4.2.8.1 4.2.9 4.3.0 4.3.1 4.3.2 4.3.2.1 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0 4.4.1 4.4.2 4.4.2.1 4.5.0 4.6.0 4.6.1 4.6.2 4.6.2.1 4.6.3 4.6.5 4.6.6 4.6.7 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.9.0 4.9.1 5.0.1 5.0.2 5.1.1 5.1.2 5.1.3 5.2.0 5.2.1 5.3.2 5.3.3.1 5.3.4 5.3.5 5.3.6 5.3.7
woocommerce-multilingual / vendor / otgs / installer / includes / class-wp-installer.php
woocommerce-multilingual / vendor / otgs / installer / includes Last commit date
CDTClient 1 month ago admin-notices 1 month ago buy-url 1 month ago debug 1 month ago exceptions 5 years ago instances 1 month ago loader 5 years ago products 1 month ago repository 1 month ago rest 1 month ago site-key 1 month ago support 1 month ago template-service 1 month ago upgrade 1 month ago utilities 1 month ago wpml-content-stats 1 month ago class-installer-dependencies.php 1 month ago class-installer-theme.php 1 month ago class-installer-upgrader-skins.php 1 month ago class-otgs-installer-autoloader.php 5 years ago class-otgs-installer-cloned-sites-handler.php 1 month ago class-otgs-installer-debug-info.php 1 month ago class-otgs-installer-factory.php 1 month ago class-otgs-installer-filename-hooks.php 1 month ago class-otgs-installer-icons.php 1 month ago class-otgs-installer-loader.php 10 months ago class-otgs-installer-package-product-finder.php 1 month ago class-otgs-installer-package-product.php 1 month ago class-otgs-installer-package.php 5 years ago class-otgs-installer-php-functions.php 1 month ago class-otgs-installer-plugin-factory.php 1 month ago class-otgs-installer-plugin-finder.php 1 month ago class-otgs-installer-plugin.php 1 month ago class-otgs-installer-plugins-page-notice.php 1 month ago class-otgs-installer-plugins-update-cache-cleaner.php 5 years ago class-otgs-installer-settings.php 1 month ago class-otgs-installer-source-factory.php 5 years ago class-otgs-installer-source.php 1 month ago class-otgs-installer-subscription-factory.php 5 years ago class-otgs-installer-subscription-warning-message.php 1 month ago class-otgs-installer-subscription.php 1 month ago class-otgs-installer-wp-components-hooks.php 1 month ago class-otgs-installer-wp-components-sender.php 1 month ago class-otgs-installer-wp-components-setting-ajax.php 1 month ago class-otgs-installer-wp-components-setting-resources.php 1 month ago class-otgs-installer-wp-components-storage.php 1 month ago class-otgs-installer-wp-share-local-components-setting-hooks.php 1 month ago class-otgs-installer-wp-share-local-components-setting.php 1 month ago class-translation-service-info.php 1 month ago class-wp-installer-api.php 1 month ago class-wp-installer-channels.php 1 month ago class-wp-installer.php 1 month ago functions-core.php 1 month ago functions-templates.php 1 month ago otgs-installer-autoload-classmap.php 10 months ago
class-wp-installer.php
2729 lines
1 <?php
2
3 use OTGS\Installer\Collection;
4 use OTGS\Installer\Rest\Push;
5 use OTGS\Installer\Recommendations\RecommendationsManager;
6 use OTGS\Installer\CommercialTab\SectionsManager;
7 use OTGS\Installer\Recommendations\Storage;
8 use OTGS\Installer\Settings;
9 use OTGS\Installer\FP\Obj;
10 use OTGS\Installer\Subscription\SubscriptionManagerFactory;
11 use OTGS\Installer\Subscription_Warning_Message;
12 use OTGS\Installer\Upgrade\IncludeAutoUpgrade;
13
14 class WP_Installer {
15
16 const TOOLSET_TYPES = 'Toolset Types';
17 const LEGACY_FREE_TYPES_SUBSCRIPTION_ID = 5495;
18 const GRACE_TIME = MONTH_IN_SECONDS;
19
20 protected static $_instance = null;
21
22 private $settings = array();
23
24 private $repositories = array();
25
26 protected $api_debug = '';
27
28 private $config = array();
29
30 protected $_plugins_renew_warnings = array();
31
32 private $admin_messages = array();
33
34 private $ajax_messages = array();
35
36 private $_using_icl = false;
37 private $_wpml_version = false;
38
39 private $package_source = array();
40
41 private $plugin_finder;
42
43 public $installer_embedded_plugins;
44
45 const SITE_KEY_VALIDATION_SOURCE_OTHER = 0;
46 const SITE_KEY_VALIDATION_SOURCE_DOWNLOAD_SPECIFIC = 1;
47 const SITE_KEY_VALIDATION_SOURCE_DOWNLOAD_REPORT = 2;
48 const SITE_KEY_VALIDATION_SOURCE_REGISTRATION = 3;
49 const SITE_KEY_VALIDATION_SOURCE_REVALIDATION = 4;
50 const SITE_KEY_VALIDATION_SOURCE_UPDATES_CHECK = 5;
51 const SITE_KEY_VALIDATION_SOURCE_REVALIDATION_DAILY = 6;
52
53 public $dependencies;
54
55 private $components_setting;
56
57 private $repositories_already_refreshed = false;
58
59 private $products_config_xml;
60
61 private $products_manager;
62
63 private $recommendations_manager;
64
65 public static function instance() {
66 if ( is_null( self::$_instance ) ) {
67 self::$_instance = new self();
68 }
69
70 return self::$_instance;
71 }
72
73 public function __construct() {
74 add_action( 'admin_notices', array( $this, 'show_admin_messages' ) );
75
76 add_action( 'admin_init', array( $this, 'load_embedded_plugins' ), 0 );
77 add_action( 'admin_init', array( $this, 'load_hardcoded_site_keys' ), 0 );
78
79 add_action( 'admin_menu', array( $this, 'menu_setup' ) );
80 add_action( 'network_admin_menu', array( $this, 'menu_setup' ) );
81 add_filter( 'plugins_api', array( $this, 'custom_plugins_api_call' ), 10, 3 );
82
83 $this->load_repositories_list();
84 $this->products_config_xml = $this->prepare_products_config_xml();
85 $this->products_manager = $this->prepare_products_manager();
86
87 $this->config['plugins_install_tab'] = false;
88
89 add_action( 'init', array( $this, 'init' ) );
90 add_action( 'init', array( $this, 'load_locale' ) );
91 }
92
93 public function __get( $name ) {
94 if ( 'settings' === $name ) {
95 return $this->settings();
96 }
97 }
98
99 private function settings() {
100 if ( empty( $this->settings ) ) {
101 $this->get_settings();
102 }
103
104 return $this->settings;
105 }
106
107 private static function isFreeToolsetTypes( $name, $plugin ) {
108 return 'Toolset Types' === $name && version_compare( $plugin['Version'], '3.0', '<' );
109 }
110
111 public function get_repositories() {
112 return $this->repositories;
113 }
114
115 public function get_products_manager() {
116 return $this->products_manager;
117 }
118
119 public function set_config( $key, $value ) {
120 $this->config[ $key ] = $value;
121 }
122
123 public function init() {
124 global $pagenow;
125
126 $this->dependencies = new Installer_Dependencies;
127 if ( $this->dependencies->php_libraries_missing() ) {
128 return false;
129 }
130
131 if ( ! function_exists( 'get_plugins' ) ) {
132 require_once ABSPATH . 'wp-admin/includes/plugin.php';
133 }
134
135 if (
136 ( isset( $_GET['force-check'] ) && $_GET['force-check'] == 1 )
137 || Settings::requires_update()
138 ) {
139 $this->refresh_repositories_data();
140 $this->refresh_subscriptions_data();
141 }
142
143 $this->_using_icl = function_exists( 'wpml_site_uses_icl' ) && wpml_site_uses_icl();
144 $this->_wpml_version = defined( 'ICL_SITEPRESS_VERSION' ) ? ICL_SITEPRESS_VERSION : '';
145
146 if ( is_multisite() || ! $this->is_installer_running_on_otgs_plugin() || ( $this->is_commercial_page() && $this->is_installer_running_on_otgs_plugin() ) ) {
147 wp_enqueue_script( 'installer-admin', $this->res_url() . '/res/js/admin.js', array( 'jquery' ), $this->version() );
148 wp_enqueue_script( 'otgs-installer-notification', $this->res_url() . '/dist/js/notification/app.js', [], $this->version() );
149 wp_enqueue_style( 'installer-admin', $this->res_url() . '/res/css/admin.css', array(), $this->version() );
150 wp_enqueue_style( 'otgs-icons' );
151 wp_enqueue_style( 'installer-admin-notices', $this->res_url() . '/res/css/admin-notices.css', array(), $this->version() );
152 }
153
154 if ( $this->is_commercial_page() ) {
155 wp_enqueue_script( 'expired-notice', $this->res_url() . '/dist/js/expired-notice/app.js', [], $this->version() );
156 }
157
158 wp_enqueue_script( 'installer-dismiss-nag', $this->res_url() . '/res/js/dismiss-nag.js', array( 'jquery' ), $this->version(), true );
159 wp_enqueue_script( 'install-recommended_plugin', $this->res_url() . '/res/js/install_recommended_plugin.js', array( 'jquery' ), $this->version(), true );
160
161 $translation_array = array(
162 'installing' => __( 'Installing %s', 'installer' ),
163 'updating' => __( 'Updating %s', 'installer' ),
164 'activating' => __( 'Activating %s', 'installer' )
165 );
166
167 wp_localize_script( 'installer-admin', 'installer_strings', $translation_array );
168
169 if ( $pagenow == 'plugins.php' ) {
170 add_action( 'admin_notices', array( $this, 'setup_plugins_page_notices' ) );
171 add_action( 'admin_notices', array( $this, 'setup_plugins_renew_warnings' ), 10 );
172 add_action( 'admin_notices', array( $this, 'queue_plugins_renew_warnings' ), 20 );
173
174 add_action( 'admin_init', array( $this, 'setup_plugins_action_links' ) );
175
176 wp_enqueue_script( 'installer-plugins', $this->res_url() . '/res/js/plugins.js', array( 'jquery' ), $this->version() );
177 wp_enqueue_style( 'installer-admin-notices', $this->res_url() . '/res/css/admin-notices.css', array(), $this->version() );
178 }
179
180 if ( $this->is_repositories_page() ) {
181 add_action( 'admin_init', array( $this, 'validate_repository_subscription' ) );
182 }
183
184 if ( defined( 'DOING_AJAX' ) ) {
185 add_action( 'wp_ajax_installer_download_plugin', array( $this, 'download_plugin_ajax_handler' ) );
186 add_action( 'wp_ajax_installer_activate_plugin', array( $this, 'activate_plugin' ) );
187 }
188
189 if ( $pagenow === 'update.php' ) {
190 if ( isset( $_GET['action'] ) && $_GET['action'] === 'update-selected' ) {
191 add_action( 'admin_head', array( $this, 'plugin_upgrade_custom_errors' ) );
192 } else {
193 add_action( 'all_admin_notices', array( $this, 'plugin_upgrade_custom_errors' ) );
194 }
195 }
196
197 if ( defined( 'DOING_AJAX' ) ) {
198 add_action( 'wp_ajax_update-plugin', array(
199 $this,
200 'plugin_upgrade_custom_errors'
201 ), 0 );
202 }
203
204 $repositories_factory = new \OTGS_Installer_Repositories_Factory();
205 $this->recommendations_manager = new RecommendationsManager(
206 $repositories_factory->create( $this ),
207 new Storage()
208 );
209 $this->recommendations_manager->addHooks();
210
211 include_once $this->plugin_path() . '/includes/class-installer-theme.php';
212
213 $package_source_file = $this->plugin_path() . '/installer-source.json';
214 if ( file_exists( $package_source_file ) ) {
215 WP_Filesystem();
216 global $wp_filesystem;
217 $this->package_source = json_decode( $wp_filesystem->get_contents( $package_source_file ) );
218 }
219
220 add_action( 'rest_api_init', Push::class . '::register_routes' );
221
222 do_action( 'otgs_installer_initialized' );
223 }
224
225 public function get_last_subscriptions_refresh() {
226 if ( isset( $this->settings()['last_subscriptions_update'] ) ) {
227 return $this->settings()['last_subscriptions_update'];
228 }
229
230 return 0;
231 }
232
233 private function prepare_products_manager() {
234 return OTGS_Products_Manager_Factory::create(
235 $this->products_config_xml,
236 otgs_installer_get_logger_storage()
237 );
238 }
239
240 private function prepare_products_config_xml() {
241 return new OTGS_Products_Config_Xml( $this->get_xml_config_file() );
242 }
243
244 private function is_installer_running_on_otgs_plugin() {
245 return ( defined( 'ICL_PLUGIN_PATH' ) && false !== strpos( $this->plugin_path(), (string) realpath( ICL_PLUGIN_PATH ) ) )
246 || ( defined( 'TYPES_ABSPATH' ) && false !== strpos( $this->plugin_path(), (string) realpath( TYPES_ABSPATH ) ) )
247 || ( defined( 'WCML_PLUGIN_PATH' ) && false !== strpos( $this->plugin_path(), (string) realpath( WCML_PLUGIN_PATH ) ) );
248 }
249
250 private function is_commercial_page() {
251 global $pagenow;
252
253 return $pagenow === 'plugin-install.php' && isset( $_GET['tab'] ) && $_GET['tab'] === 'commercial';
254 }
255
256 public function log( $message ) {
257 if ( file_exists( ABSPATH . 'wp-admin/includes/file.php' ) ) {
258 require_once ABSPATH . 'wp-admin/includes/file.php';
259 WP_Filesystem();
260 global $wp_filesystem;
261 if ( defined( 'WPML_INSTALLER_LOGGING' ) && WPML_INSTALLER_LOGGING ) {
262 $wp_filesystem->put_contents( $this->plugin_path() . '/installer.log', current_time( 'mysql' ) . "\t" . $message . "\n" );
263 }
264 }
265 }
266
267 public function register_admin_message( $text, $type = 'updated' ) {
268 $this->admin_messages[] = array( 'text' => $text, 'type' => $type );
269 if ( defined( 'DOING_AJAX' ) ) {
270 $this->ajax_messages[] = '<p>' . $text . '</p>';
271 }
272 }
273
274 public function show_admin_messages() {
275 if ( ! empty( $this->admin_messages ) ) {
276 $types = array( 'error', 'updated', 'notice' );
277 foreach ( $this->admin_messages as $message ) {
278 $class = in_array( $message['type'], $types, true ) ? $message['type'] : 'updated';
279 ?>
280 <div class="<?php
281 echo $class ?>">
282 <p>
283 <?php
284 echo $message['text'] ?>
285 </p>
286 </div>
287 <?php
288 }
289 }
290 }
291
292 public function load_locale() {
293 if ( function_exists( 'get_user_locale' ) ) {
294 $locale = get_user_locale();
295 } else {
296 $locale = get_locale();
297 }
298 $locale = apply_filters( 'plugin_locale', $locale, 'installer' );
299 $mo_file = $this->plugin_path() . '/locale/installer-' . $locale . '.mo';
300 if ( file_exists( $mo_file ) ) {
301 load_textdomain( 'installer', $mo_file );
302 }
303 }
304
305 public function load_embedded_plugins() {
306 if ( file_exists( $this->plugin_path() . '/embedded-plugins' ) ) {
307 include_once $this->plugin_path() . '/embedded-plugins/embedded-plugins.class.php';
308 if ( class_exists( 'Installer_Embedded_Plugins' ) ) {
309 $this->installer_embedded_plugins = new Installer_Embedded_Plugins();
310 }
311 }
312 }
313
314 public function menu_setup() {
315 global $pagenow;
316
317 if ( is_multisite() && ! is_network_admin() ) {
318 $this->menu_multisite_redirect();
319 add_options_page(
320 __( 'Installer', 'installer' ),
321 __( 'Installer', 'installer' ),
322 'install_plugins',
323 'installer',
324 array(
325 $this,
326 'show_products',
327 )
328 );
329 } else {
330 if ( $this->config['plugins_install_tab'] && is_admin() && $pagenow === 'plugin-install.php' ) {
331 add_filter( 'install_plugins_tabs', array( $this, 'add_install_plugins_tab' ) );
332 add_action( 'install_plugins_commercial', array( $this, 'show_products' ) );
333 }
334 }
335 }
336
337 public static function menu_url() {
338 if ( is_multisite() ) {
339 if ( is_network_admin() ) {
340 $url = network_admin_url( 'plugin-install.php?tab=commercial' );
341 } else {
342 $url = admin_url( 'options-general.php?page=installer' );
343 }
344 } else {
345 $url = admin_url( 'plugin-install.php?tab=commercial' );
346 }
347
348 return $url;
349 }
350
351 private function menu_multisite_redirect() {
352 global $pagenow;
353
354 if ( $pagenow === 'plugin-install.php' && isset( $_GET['tab'] ) && $_GET['tab'] === 'commercial' ) {
355 wp_redirect( $this->menu_url() );
356 exit;
357 }
358 }
359
360 public function setup_plugins_action_links() {
361 $plugins = get_plugins();
362
363 $repositories_plugins = array();
364
365 if ( ! empty( $this->settings()['repositories'] ) ) {
366 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
367 foreach ( $repository['data']['packages'] as $package ) {
368 if ( array_key_exists( 'products', $package ) ) {
369 foreach ( $package['products'] as $product ) {
370 if ( array_key_exists( 'plugins', $product ) ) {
371 foreach ( $product['plugins'] as $plugin_slug ) {
372 if ( ! $this->isPluginAvailableInRepositoryDownloads( $repository_id, $plugin_slug ) ) {
373 continue;
374 }
375
376 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
377
378 if ( ! isset( $repositories_plugins[ $repository_id ][ $download['slug'] ] ) ) {
379 $repositories_plugins[ $repository_id ][ $download['slug'] ] = array(
380 'name' => $download['name'],
381 'registered' => $this->plugin_is_registered( $repository_id, $download['slug'] ) ? 1 : 0
382 );
383 }
384 }
385 } else {
386 $this->refresh_repositories_data();
387 }
388 }
389 } else {
390 $this->refresh_repositories_data();
391 }
392 }
393
394 foreach ( $plugins as $plugin_id => $plugin ) {
395 $wp_plugin_slug = dirname( $plugin_id );
396 if ( empty( $wp_plugin_slug ) ) {
397 $wp_plugin_slug = basename( $plugin_id, '.php' );
398 }
399
400 foreach ( $repositories_plugins as $repository_id => $r_plugins ) {
401 foreach ( $r_plugins as $slug => $r_plugin ) {
402 if ( $wp_plugin_slug === $slug || $r_plugin['name'] === $plugin['Name'] || $r_plugin['name'] === $plugin['Title'] ) {
403
404 $plugin_finder = $this->get_plugin_finder();
405 $plugin_obj = $plugin_finder->get_plugin( $slug, (string) $repository_id );
406
407 if ( $plugin_obj && $plugin_obj->get_external_repo() && $plugin_obj->is_lite() ) {
408 continue;
409 }
410
411 if ( $r_plugin['registered'] ) {
412 remove_filter( 'plugin_action_links_' . $plugin_id, array(
413 $this,
414 'plugins_action_links_not_registered'
415 ) );
416
417 add_filter( 'plugin_action_links_' . $plugin_id, array(
418 $this,
419 'plugins_action_links_registered'
420 ) );
421 } else {
422 if ( $this->plugin_is_registered( $plugin_obj->get_external_repo(), $slug ) || $this->plugin_is_registered( 'wpml', $slug ) ) {
423 continue;
424 }
425
426 remove_filter( 'plugin_action_links_' . $plugin_id, array(
427 $this,
428 'plugins_action_links_registered'
429 ) );
430
431 add_filter( 'plugin_action_links_' . $plugin_id, array(
432 $this,
433 'plugins_action_links_not_registered'
434 ) );
435
436 if ( $this->should_display_types_upgrade_link( $r_plugin['name'], $plugin['Version'] ) ) {
437 add_filter( 'plugin_action_links_' . $plugin_id, array( $this, 'types_upgrade_link' ) );
438 }
439 }
440 }
441 }
442 }
443 }
444 }
445 }
446 }
447
448 private function should_display_types_upgrade_link( $name, $version ) {
449 return $name === self::TOOLSET_TYPES && version_compare( $version, '3.0', '<' );
450 }
451
452 public function types_upgrade_link( $links ) {
453 $links[] = '<a style="color: #55AA55" target="_blank" href="' . esc_url( 'https://toolset.com/buy/?utm_source=typesplugin&utm_campaign=moving-types-to-toolset&utm_medium=plugins-page&utm_term=upgrade-link' ) . '">' . __( 'Upgrade', 'installer' ) . '</a>';
454
455 return $links;
456 }
457
458 public function plugins_action_links_registered( $links ) {
459 $links[] = '<a href="' . $this->menu_url() . '">' . __( 'Registered', 'installer' ) . '</a>';
460
461 return $links;
462 }
463
464 public function plugins_action_links_not_registered( $links ) {
465 $links[] = '<a href="' . $this->menu_url() . '">' . __( 'Register', 'installer' ) . '</a>';
466
467 return $links;
468 }
469
470 public function plugin_is_registered( $repository_id, $slug ) {
471 $registered = false;
472
473 if ( $this->repository_has_valid_subscription( $repository_id ) ) {
474 $subscription_type = $this->get_subscription_type_for_repository( $repository_id );
475 $r_plugins = array();
476
477 if ( $subscription_type === self::LEGACY_FREE_TYPES_SUBSCRIPTION_ID && $slug === 'types' ) {
478 return true;
479 }
480
481 foreach ( $this->settings()['repositories'][ $repository_id ]['data']['packages'] as $package ) {
482 foreach ( $package['products'] as $product ) {
483 if ( ! array_key_exists( 'subscription_type_equivalent', $product ) ) {
484 $product['subscription_type_equivalent'] = '';
485 }
486
487 if (
488 $product['subscription_type'] === (int) $subscription_type || (int) $product['subscription_type_equivalent'] === (int) $subscription_type || $this->have_superior_subscription( $subscription_type, $product )
489 ) {
490 foreach ( $product['plugins'] as $plugin_slug ) {
491 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
492 $r_plugins[ $download['slug'] ] = $download['slug'];
493 }
494 }
495 }
496 }
497
498 $registered = isset( $r_plugins[ $slug ] );
499 }
500
501
502 return $registered;
503 }
504
505 public function version() {
506 return WP_INSTALLER_VERSION;
507 }
508
509 public function plugin_path() {
510 return untrailingslashit( plugin_dir_path( dirname( __FILE__ ) ) );
511 }
512
513 public function plugin_url() {
514 if ( isset( $this->config['in_theme_folder'] ) && ! empty( $this->config['in_theme_folder'] ) ) {
515 $url = untrailingslashit( get_template_directory_uri() . '/' . $this->config['in_theme_folder'] );
516 } else {
517 $url = untrailingslashit( plugins_url( '/', dirname( __FILE__ ) ) );
518 }
519
520 return $url;
521 }
522
523 public function vendor_url() {
524 $url = null;
525
526 $site_url = get_site_url();
527 $site_path = ABSPATH;
528 $vendor_path = dirname( dirname( $this->plugin_path() ) );
529
530 return str_replace( '\\', '/', $site_url . '/' . substr( $vendor_path, strlen( $site_path ) ) );
531 }
532
533 public function get_embedded_at() {
534 $embedded_at = str_replace( array( get_template_directory_uri(), plugins_url() ), '', $this->plugin_url() );
535 preg_match( '/\/(.*?)\//', $embedded_at, $matches );
536
537 return isset( $matches[1] ) ? $matches[1] : '';
538 }
539
540 public function is_repositories_page() {
541 global $pagenow;
542
543 return $pagenow == 'plugin-install.php' && isset( $_GET['tab'] ) && $_GET['tab'] == 'commercial';
544 }
545
546 public function res_url() {
547 if ( isset( $this->config['in_theme_folder'] ) && ! empty( $this->config['in_theme_folder'] ) ) {
548 $url = untrailingslashit( get_template_directory_uri() . '/' . $this->config['in_theme_folder'] );
549 } else {
550 $url = $this->plugin_url();
551 }
552
553 return $url;
554 }
555
556 public function save_settings( $settings = null ) {
557 if ( null !== $settings ) {
558 $this->settings = $settings;
559 }
560
561 Settings::save( $this->settings );
562
563 if ( is_multisite() && is_main_site() && isset( $this->settings()['repositories'] ) ) {
564 $network_settings = array();
565
566 foreach ( $this->settings()['repositories'] as $rep_id => $repository ) {
567 if ( isset( $repository['subscription'] ) ) {
568 $network_settings[ $rep_id ] = $repository['subscription'];
569 }
570 }
571
572 update_site_option( 'wp_installer_network', $network_settings );
573 }
574 }
575
576 public function get_settings( $refresh = false ) {
577 if ( $refresh || empty( $this->settings ) ) {
578 $this->settings = Settings::load();
579
580 if ( empty( $this->settings ) ) {
581 $this->settings = array(
582 'repositories' => array()
583 );
584 }
585
586 if ( is_multisite() ) {
587 $network_settings = maybe_unserialize( get_site_option( 'wp_installer_network' ) );
588 if ( $network_settings ) {
589 foreach ( $this->settings()['repositories'] as $rep_id => $repository ) {
590 if ( isset( $network_settings[ $rep_id ] ) ) {
591 $this->settings['repositories'][ $rep_id ]['subscription'] = $network_settings[ $rep_id ];
592 }
593 }
594 }
595 }
596 }
597
598 return $this->settings;
599 }
600
601 public function load_hardcoded_site_keys() {
602 $subscriptions = Settings::load_subscriptions();
603 if ( ! isset( $subscriptions['repositories'] ) || empty( $subscriptions['repositories'] ) ) {
604 return;
605 }
606
607 foreach ( $subscriptions['repositories'] as $repository_id => $repository ) {
608 if ( $site_key = self::get_repository_hardcoded_site_key( $repository_id ) ) {
609 $site_key_missing = empty( $this->settings()['repositories'][ $repository_id ]['subscription']['data'] );
610 $site_key_changed = ! $site_key_missing && $this->settings()['repositories'][ $repository_id ]['subscription']['key'] != $site_key;
611
612 if ( $site_key_missing || $site_key_changed ) {
613 if ( ! function_exists( 'get_plugins' ) ) {
614 require_once ABSPATH . 'wp-admin/includes/plugin.php';
615 }
616 $this->load_repositories_list();
617 $response = $this->save_site_key(
618 array(
619 'repository_id' => $repository_id,
620 'site_key' => $site_key,
621 'return' => true,
622 'nonce' => wp_create_nonce( 'save_site_key_' . $repository_id )
623 )
624 );
625
626 if ( ! empty( $response['error'] ) ) {
627 $this->remove_site_key( $repository_id, false );
628
629 $this->admin_messages[] = array(
630 'type' => 'error',
631 'text' => sprintf( __( 'You are using an invalid site key defined as the constant %s (most likely in wp-config.php).
632 Please remove it or use the correct value in order to be able to register correctly.', 'installer' ), 'OTGS_INSTALLER_SITE_KEY_' . strtoupper( $repository_id ) )
633 );
634 } else {
635 do_action( 'otgs_installer_site_key_update', $repository_id );
636 }
637 }
638 }
639 }
640 }
641
642 public static function get_repository_hardcoded_site_key( $repository_id ) {
643 $site_key = false;
644
645 $site_key_constant = 'OTGS_INSTALLER_SITE_KEY_' . strtoupper( $repository_id );
646 if ( defined( $site_key_constant ) ) {
647 $site_key = constant( $site_key_constant );
648 }
649
650 return $site_key;
651 }
652
653 public function get_installer_site_url( $repository_id = false ) {
654 global $current_site;
655
656 $site_url = defined( 'ATE_CLONED_SITE_URL' ) ? ATE_CLONED_SITE_URL : get_site_url();
657
658 if ( $repository_id && is_multisite() && isset( $subscriptions['repositories'] ) ) {
659 $network_settings = maybe_unserialize( get_site_option( 'wp_installer_network' ) );
660
661 if ( isset( $network_settings[ $repository_id ] ) ) {
662 $site_url = get_site_url( $current_site->blog_id );
663 }
664 }
665
666 $filtered_site_url = filter_var( apply_filters( 'otgs_installer_site_url', $site_url ), FILTER_SANITIZE_URL );
667
668 return $filtered_site_url ? $filtered_site_url : $site_url;
669 }
670
671 public function get_registered_site_url( $repository_id ) {
672 if ( isset( $this->settings()['repositories'][ $repository_id ]['subscription']['site_url'] ) ) {
673 return $this->settings()['repositories'][ $repository_id ]['subscription']['site_url'];
674 }
675
676 return null;
677 }
678
679 public function get_site_key_nags_config() {
680 return isset( $this->config['site_key_nags'] ) ? $this->config['site_key_nags'] : [];
681 }
682
683 public function getRepositories() {
684 $repositories = [];
685 foreach ( $this->repositories as $repositoryId => $repository ) {
686 $repositories[] = [ 'repository_id' => $repositoryId ];
687 }
688
689 return $repositories;
690 }
691
692 public function add_install_plugins_tab( $tabs ) {
693 $tabs['commercial'] = __( 'Commercial', 'installer' );
694
695 return $tabs;
696 }
697
698 public function load_repositories_list() {
699 $config_file = $this->get_xml_config_file();
700
701 if ( $config_file ) {
702 $repos = simplexml_load_file( $config_file );
703
704 if ( $repos ) {
705 foreach ( $repos as $repo ) {
706 $id = strval( $repo->id );
707
708 if ( isset( $this->config['repositories_exclude'] ) && in_array( $id, $this->config['repositories_exclude'] ) ) {
709 continue;
710 }
711
712 $data['api-url'] = strval( $repo->apiurl );
713
714 $this->repositories[ $id ] = $data;
715 $this->set_predefined_config( $id, 'api-url', 'API_URL' );
716 }
717 }
718 }
719 }
720
721 public function get_xml_config_file() {
722 $file_name = 'repositories.xml';
723
724 if ( file_exists( $this->get_config_file_path( $file_name ) ) ) {
725 return $this->get_config_file_path( $file_name );
726 }
727
728 return null;
729 }
730
731 private function get_config_file_path( $file_name ) {
732 return __DIR__ . '/../' . $file_name;
733 }
734
735 private function set_predefined_config( $id, $setting_field, $constant_suffix ) {
736 $repo_upper = strtoupper( $id );
737 if ( defined( "OTGS_INSTALLER_{$repo_upper}_{$constant_suffix}" ) ) {
738 $this->repositories[ $id ][ $setting_field ] = constant( "OTGS_INSTALLER_{$repo_upper}_{$constant_suffix}" );
739 }
740 }
741
742 public function filter_repositories_list() {
743 $this->get_settings();
744 if ( ! empty( $this->settings['repositories'] ) ) {
745 foreach ( $this->settings['repositories'] as $id => $repo_data ) {
746 if ( isset( $this->config['repositories_exclude'] ) && in_array( $id, $this->config['repositories_exclude'] ) ) {
747 unset( $this->settings['repositories'][ $id ] );
748 }
749 }
750 }
751 }
752
753 public function refresh_subscriptions_data() {
754 $this->get_settings();
755 $this->settings['last_subscriptions_update'] = time();
756
757 foreach ( $this->repositories as $repository_id => $data ) {
758 $site_key = $this->get_site_key( $repository_id );
759
760 if ( ! $site_key ) {
761 continue;
762 }
763
764 try {
765 $subscriptionManagerFactory = new SubscriptionManagerFactory();
766 $subscriptionManager = $subscriptionManagerFactory->create( $repository_id, $this->repositories[ $repository_id ]['api-url'] );
767 list ( $subscription_data, $site_key_data ) = $subscriptionManager->fetch( $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION_DAILY );
768
769 if ( ! $subscription_data ) {
770 $message = sprintf(
771 "Installer could not fetch subscription data for %s. Error message: Invalid site key for the current site.",
772 $repository_id
773 );
774
775 $this->log_subscription_update( $message );
776
777 continue;
778 }
779
780 $this->settings['repositories'][ $repository_id ]['subscription']['data'] = $subscription_data;
781 $this->settings['repositories'][ $repository_id ]['subscription']['key_type'] = isset( $site_key_data['type'] )
782 ? (int) $site_key_data['type'] : OTGS_Installer_Subscription::SITE_KEY_TYPE_PRODUCTION;
783
784 $actualSiteUrl = $this->get_installer_site_url( $repository_id );
785 $this->settings['repositories'][ $repository_id ]['site_key_url'] = $actualSiteUrl;
786
787 $this->setLastSuccessSubscriptionFetch( $repository_id );
788 $this->log_subscription_update( "Subscriptions updated successfully." );
789 } catch ( Exception $e ) {
790 $this->log_subscription_update( $repository_id . ': ' . $e->getMessage() );
791 }
792 }
793
794 $this->save_settings();
795 }
796
797 public function shouldDisplayConnectionIssueMessage( $repositoryId ) {
798 return time() - $this->getLastSuccessSubscriptionFetch( $repositoryId ) > WEEK_IN_SECONDS
799 || $this->isUsingProductsFallback( $repositoryId );
800 }
801
802 private function getLastSuccessSubscriptionFetch( $repositoryId ) {
803 if ( defined( 'OTGS_INSTALLER_OVERRIDE_LAST_SUCCESS_SUBSCRIPTION_FETCH' ) ) {
804 return constant( 'OTGS_INSTALLER_OVERRIDE_LAST_SUCCESS_SUBSCRIPTION_FETCH' );
805 }
806
807 $subscriptions = Settings::load_subscriptions();
808 if ( isset( $subscriptions['repositories'][ $repositoryId ]['last_successful_subscription_fetch'] ) ) {
809 return (int) $subscriptions['repositories'][ $repositoryId ]['last_successful_subscription_fetch'];
810 } else {
811 return time();
812 }
813 }
814
815 private function isUsingProductsFallback( $repositoryId ) {
816 return Settings::is_using_products_fallback( $repositoryId );
817 }
818
819 private function setLastSuccessSubscriptionFetch( $repositoryId ) {
820 $this->get_settings();
821 $this->settings['repositories'][ $repositoryId ]['last_successful_subscription_fetch'] = time();
822 }
823
824 private function setUsingProductsFallback( $repositoryId, $value ) {
825 $this->get_settings();
826 $this->settings['repositories'][ $repositoryId ]['using_products_fallback'] = $value;
827 }
828
829 private function log_subscription_update( $message ) {
830 $log = new OTGS_Installer_Log();
831 $log->set_component( OTGS_Installer_Logger_Storage::COMPONENT_SUBSCRIPTION );
832 $log->set_response( $message );
833 otgs_installer_get_logger_storage()->add( $log );
834 }
835
836 public function get_recommendations( $repository_id ) {
837 $subscription = $this->get_subscription( $repository_id );
838 if ( $subscription->is_valid() ) {
839 return $this->recommendations_manager->getRepositoryPluginsRecommendations();
840 }
841
842 return null;
843 }
844
845 public function refresh_repositories_data( $bypass_bucket = false ) {
846 if ( defined( 'OTGS_DISABLE_AUTO_UPDATES' ) && OTGS_DISABLE_AUTO_UPDATES && empty( $_GET['force-check'] ) || $this->repositories_already_refreshed ) {
847 if ( empty( $this->settings()['repositories'] ) && $this->is_repositories_page() ) {
848 foreach ( $this->repositories as $repository_id => $data ) {
849 $repository_names[] = $repository_id;
850 }
851
852 $error = sprintf( __( "Installer cannot display the products information because the automatic updating for %s was explicitly disabled with the configuration below (usually in wp-config.php):", 'installer' ), strtoupper( join( ', ', $repository_names ) ) );
853 $error .= '<br /><br /><code>define("OTGS_DISABLE_AUTO_UPDATES", true);</code><br /><br />';
854 $error .= sprintf( __( "In order to see the products information, please run the %smanual updates check%s to initialize the products list or (temporarily) remove the above code.", 'installer' ), '<a href="' . admin_url( 'update-core.php' ) . '">', '</a>' );
855
856 $this->register_admin_message( $error, 'error' );
857 }
858
859 return;
860 }
861 $this->repositories_already_refreshed = true;
862 $this->get_settings();
863
864 foreach ( $this->repositories as $repository_id => $data ) {
865 $products_url = $this->products_manager->get_products_url(
866 $repository_id,
867 $this->get_repository_site_key( $repository_id ),
868 $this->get_installer_site_url( $repository_id ),
869 $bypass_bucket
870 );
871
872 $response = wp_remote_get( $products_url );
873
874 $products_parser = new OTGS_Installer_Products_Parser(
875 WP_Installer_Channels(),
876 $this->products_config_xml,
877 otgs_installer_get_logger_storage()
878 );
879
880 if ( is_wp_error( $response ) ) {
881 $error
882 = sprintf( __( "Installer cannot contact our updates server to get information about the available products and check for new versions. If you are seeing this message for the first time, you can ignore it, as it may be a temporary communication problem. If the problem persists and your WordPress admin is slowing down, you can disable automated version checks. Add the following line to your wp-config.php file:",
883 'installer' ), strtoupper( $repository_id ) );
884 $error .= '<br /><br /><code>define("OTGS_DISABLE_AUTO_UPDATES", true);</code>';
885 $this->register_admin_message( $error, 'error' );
886 $this->store_log( $products_url, null, OTGS_Installer_Logger_Storage::COMPONENT_REPOSITORIES, $error );
887
888 $this->setUsingProductsFallback( $repository_id, true );
889 $this->settings['repositories'][ $repository_id ]['data'] = $products_parser->get_default_products( $repository_id );
890
891 continue;
892 }
893
894 if ( $response && isset( $response['response']['code'] ) && $response['response']['code'] == 200 ) {
895 try {
896 $products = $products_parser->get_products_from_response( $products_url, $repository_id, $response );
897 $this->handle_product_parsing_notices( $products_parser->get_product_notices() );
898 $this->settings['repositories'][ $repository_id ]['data'] = $products;
899 $this->setUsingProductsFallback( $repository_id, false );
900 } catch ( OTGS_Installer_Products_Parsing_Exception $exception ) {
901 $this->store_log(
902 $products_url,
903 null,
904 OTGS_Installer_Logger_Storage::COMPONENT_REPOSITORIES,
905 $exception->getMessage()
906 );
907 $error = __( "Information about new versions is invalid. It may be a temporary communication problem, please check for updates again.", 'installer' );
908 $this->register_admin_message( $error, 'error' );
909 }
910 } else {
911 $error = __( "Information about new versions is invalid. It may be a temporary communication problem, please check for updates again.", 'installer' );
912 $this->register_admin_message( $error, 'error' );
913 $this->store_log(
914 $products_url,
915 null,
916 OTGS_Installer_Logger_Storage::COMPONENT_REPOSITORIES,
917 $error
918 );
919 }
920 $this->log( sprintf( "Checked for %s updates: %s", $repository_id, $products_url ) );
921 }
922
923 if ( empty( $this->settings['repositories'] ) ) {
924 $this->settings['repositories'] = array();
925 }
926 foreach ( $this->settings['repositories'] as $repository_id => $data ) {
927 if ( ! in_array( $repository_id, array_keys( $this->repositories ) ) ) {
928 unset( $this->settings['repositories'][ $repository_id ] );
929 }
930 }
931
932 delete_site_transient( 'update_plugins' );
933
934 $this->save_settings();
935
936 return $this->ajax_messages;
937 }
938
939 private function handle_product_parsing_notices( $products_notices ) {
940 if ( $products_notices ) {
941 if ( $products_notices ) {
942 $this->register_admin_message( implode( '<br/>', $products_notices ), 'error' );
943 }
944 }
945 }
946
947 public function show_products( $args = array() ) {
948 if ( ! current_user_can( 'install_plugins' ) ) {
949 wp_die( __( 'Sorry, you are not allowed to manage Installer for this site.', 'installer' ) );
950
951 return;
952 }
953
954 $screen = get_current_screen();
955
956 if ( $screen->base === 'settings_page_installer' ) {
957 echo '<div class="wrap">';
958 echo '<h2>' . __( 'Installer', 'installer' ) . '</h2>';
959 }
960
961 if ( ! is_array( $args ) ) {
962 $args = array();
963 }
964 if ( empty( $args['template'] ) ) {
965 $args['template'] = 'default';
966 }
967
968 $this->filter_repositories_list();
969
970 if ( ! empty( $this->settings()['repositories'] ) ) {
971 $this->localize_strings();
972 $this->set_filtered_prices( $args );
973 $this->set_hierarchy_and_order();
974
975 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
976 if ( $args['template'] === 'compact' ) {
977 if ( isset( $args['repository'] ) && $args['repository'] === $repository_id ) {
978 include $this->plugin_path() . '/templates/products-compact.php';
979 }
980 } else {
981 include $this->plugin_path() . '/templates/repository-listing.php';
982 }
983
984 unset( $site_key, $subscription_type, $expired, $upgrade_options, $products_avaliable );
985 }
986 } else {
987 echo '<p>' . __( 'No repositories defined.', 'installer' ) . '</p>';
988 }
989
990 if ( $screen->base === 'settings_page_installer' ) {
991 echo '</div>';
992 }
993 }
994
995 public function get_plugins_sections( $repositoryId, $downloads ) {
996 $sections_manager = new SectionsManager(
997 $this->get_settings()['repositories']
998 );
999
1000 $sections = $sections_manager->getPluginsSections( $repositoryId, $downloads );
1001
1002 if ( count( $sections ) === 1 ) {
1003 reset( $sections );
1004 }
1005
1006 return $sections;
1007 }
1008
1009 public function get_product_price( $repository_id, $package_id, $product_id, $incl_discount = false ) {
1010 $price = false;
1011
1012 foreach ( $this->settings()['repositories'][ $repository_id ]['data']['packages'] as $package ) {
1013 if ( $package['id'] == $package_id ) {
1014 if ( isset( $package['products'][ $product_id ] ) ) {
1015 if ( $incl_discount && isset( $package['products'][ $product_id ]['price_disc'] ) ) {
1016 $price = $package['products'][ $product_id ]['price_disc'];
1017 } elseif ( isset( $package['products'][ $product_id ]['price'] ) ) {
1018 $price = $package['products'][ $product_id ]['price'];
1019 }
1020 }
1021 break;
1022 }
1023 }
1024
1025 return $price;
1026 }
1027
1028 public function get_product_data( $repository_id, $data_type ) {
1029 return isset( $this->settings()['repositories'][ $repository_id ]['data'][ $data_type ] ) ?
1030 $this->settings()['repositories'][ $repository_id ]['data'][ $data_type ]
1031 : null;
1032 }
1033
1034 private function getProductPriceCurrencySymbol( $products ) {
1035 return ( array_key_exists( 'shop_currency_symbol', $products ) ) ? $products['shop_currency_symbol'] : '&#36;';
1036 }
1037
1038 private function getProductPriceCurrency( $products ) {
1039 return ( array_key_exists( 'shop_currency', $products ) ) ? $products['shop_currency'] : 'USD';
1040 }
1041
1042 private function getProductPriceString( $products, $product ) {
1043 $currencySymbol = $this->getProductPriceCurrencySymbol( $products );
1044 $currency = $this->getProductPriceCurrency( $products );
1045
1046 return sprintf( '%s%d (%s)', $currencySymbol, $product['price'], $currency );
1047 }
1048
1049 public function getProductPriceWithDiscountString( $products, $product ) {
1050 $currencySymbol = $this->getProductPriceCurrencySymbol( $products );
1051 $currency = $this->getProductPriceCurrency( $products );
1052
1053 return sprintf( '%s%s %s%s%d%s (%s)', $currencySymbol, $product['price_disc'], '&nbsp;&nbsp;<del>', $currencySymbol, $product['price'], '</del>', $currency );
1054 }
1055
1056 public function getRenderProductPackagesData( $repository, $packages, $subscription_type, $expired, $upgrade_options, $repository_id ) {
1057 return $this->_render_product_packages( $repository, $packages, $subscription_type, $expired, $upgrade_options, $repository_id );
1058 }
1059
1060 private function _render_product_packages( $repository, $packages, $subscription_type, $expired, $upgrade_options, $repository_id ) {
1061 $data = array();
1062 $products = ( array_key_exists( 'data', $repository ) ) ? $repository['data'] : $repository;
1063 $recommended_plugins = $this->get_recommendation_plugins_to_be_installed( $repository_id );
1064
1065 if ( $this->get_subscription( $repository_id )->is_wpml_blog_subscription() ) {
1066 $packages = $this->syncWpmlDescriptionPackageWithBlog( $packages );
1067 }
1068
1069 foreach ( $packages as $package ) {
1070 $row = array( 'products' => array(), 'downloads' => array() );
1071 foreach ( $package['products'] as $product ) {
1072 if ( empty( $product['price'] ) && ( empty( $subscription_type ) || $expired ) ) {
1073 continue;
1074 }
1075
1076 if ( empty( $product['subscription_type_equivalent'] ) ) {
1077 $product['subscription_type_equivalent'] = '';
1078 }
1079
1080 if ( empty( $subscription_type ) || $expired ) {
1081 $p['url'] = $this->append_parameters_to_buy_url( $product['url'], $repository_id );
1082 $p['shouldDisplay'] = ! ( isset( $product['deprecated'] ) ? (bool) $product['deprecated'] : false );
1083
1084 if ( ! empty( $product['price_disc'] ) ) {
1085 $p['label'] = $product['call2action'] . ' - ' . $this->getProductPriceWithDiscountString( $products, $product );
1086 } else {
1087 $p['label'] = $product['call2action'] . ' - ' . $this->getProductPriceString( $products, $product );
1088 }
1089 $row['products'][] = $p;
1090 } elseif ( $product['subscription_type'] == $subscription_type || $product['subscription_type_equivalent'] == $subscription_type ) {
1091 if ( $product['renewals'] ) {
1092 foreach ( $product['renewals'] as $renewal ) {
1093 $p['url'] = $this->append_parameters_to_buy_url( $renewal['url'], $repository_id );
1094 $p['label'] = $renewal['call2action'] . ' - ' . $this->getProductPriceString( $products, $renewal );
1095 }
1096
1097 $row['products'][] = $p;
1098 }
1099 }
1100
1101 if ( ! empty( $upgrade_options[ $product['subscription_type'] ] ) ) {
1102 foreach ( $upgrade_options[ $product['subscription_type'] ] as $stype => $upgrade ) {
1103 if ( $stype != $subscription_type ) {
1104 continue;
1105 }
1106
1107 $p['url'] = $this->append_parameters_to_buy_url( $upgrade['url'], $repository_id );
1108 if ( ! empty( $upgrade['price_disc'] ) ) {
1109 $p['label'] = $upgrade['call2action'] . ' - ' . $this->getProductPriceWithDiscountString( $products, $upgrade );
1110 } else {
1111 $p['label'] = $upgrade['call2action'] . ' - ' . $this->getProductPriceString( $products, $upgrade );
1112 }
1113 $row['products'][] = $p;
1114 }
1115 }
1116
1117 if ( isset( $subscription_type ) && ! $expired && ( $product['subscription_type'] == $subscription_type || $product['subscription_type_equivalent'] == $subscription_type ) ) {
1118 foreach ( $product['plugins'] as $plugin_slug ) {
1119 $plugin_finder = $this->get_plugin_finder();
1120 $plugin = $plugin_finder->get_plugin( $plugin_slug, $repository_id );
1121
1122 if ( ! $plugin ) {
1123 continue;
1124 }
1125
1126 $external_repo = $plugin->get_external_repo();
1127
1128 if ( $external_repo && $this->repository_has_valid_subscription( $external_repo ) ) {
1129 continue;
1130 }
1131
1132 $row['downloads'][ $plugin_slug ] = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
1133 }
1134 }
1135 foreach ( $row['downloads'] as &$download ) {
1136 $download['is_preselected_plugin'] = self::is_plugin_recommended( $download, $recommended_plugins )
1137 && $this->can_plugin_be_installed( $download, $repository_id );
1138 }
1139 unset( $download );
1140
1141 if ( ! empty( $package['sub-packages'] ) ) {
1142 $row['sub-packages'] = $package['sub-packages'];
1143 }
1144 }
1145
1146 $row['id'] = $package['id'];
1147 $row['image_url'] = $package['image_url'];
1148 $row['name'] = $package['name'];
1149 $row['description'] = $package['description'];
1150
1151 $row['notification'] = '';
1152 if ( ! $this->get_subscription( $repository_id )->is_wpml_blog_subscription() && $this->has_any_preselected_plugins( $row['downloads'] ) ) {
1153 $row['notification'] = __( 'We have preselected the plugins your site needs to be fully multilingual.', 'installer' );
1154 }
1155
1156 if ( ! empty( $row['products'] ) || ! empty( $row['downloads'] ) || ! empty( $row['sub-packages'] ) ) {
1157 $data[] = $row;
1158 }
1159 }
1160
1161 return $data;
1162 }
1163
1164 public function can_plugin_be_installed( $plugin, $repository_id ) {
1165 if ( $this->dependencies->cant_download( $repository_id ) ) {
1166 return false;
1167 }
1168
1169 $isPluginIsNotInstalled = $this->plugin_is_not_installed( $plugin['name'], $plugin['slug'], $plugin['version'] );
1170 $isEmbeddedVersion = $this->plugin_is_embedded_version( $plugin['name'], $plugin['slug'] );
1171
1172 return ( $isPluginIsNotInstalled || $isEmbeddedVersion );
1173 }
1174
1175 public function get_recommendation_plugins_to_be_installed( $repository_id ): array {
1176 $recommendations = $this->get_recommendations( $repository_id );
1177 if ( $recommendations === null ) {
1178 return [];
1179 }
1180 $recommended_plugins = isset( $recommendations['plugins'] ) ? $recommendations['plugins'] : [];
1181 if ( empty( $recommended_plugins ) ) {
1182 return [];
1183 }
1184
1185 $slugs = array_map( function ( $plugin ) {
1186 return $plugin['slug'];
1187 }, $recommended_plugins );
1188
1189 return array_values( $slugs );
1190 }
1191
1192 private static function is_plugin_recommended( $plugin, $recommended_plugins ): bool {
1193 return in_array( $plugin['slug'], $recommended_plugins );
1194 }
1195
1196 public function get_end_user_renewal_url( $repository_id ) {
1197 return Collection::of( $this->settings()['repositories'][ $repository_id ]['data']['packages'] )
1198 ->filter( function ( $package ) {
1199 return $package['id'] === 'wpml';
1200 } )
1201 ->head()
1202 ->get( 'products' )
1203 ->get( 'end-user-subscription' )
1204 ->getOrNull( 'url' );
1205 }
1206
1207 public function get_extra_url_parameters() {
1208 $parameters = array();
1209
1210 if ( ! empty( $this->package_source ) ) {
1211 foreach ( $this->package_source as $key => $val ) {
1212 $parameters[ $key ] = $val;
1213 }
1214 }
1215
1216 $parameters['installer_version'] = WP_INSTALLER_VERSION;
1217 $parameters['theme'] = wp_get_theme()->get( 'Name' );
1218 $parameters['site_name'] = get_bloginfo( 'name' );
1219
1220 return $parameters;
1221 }
1222
1223 public function append_parameters_to_buy_url( $url, $repository_id, $args = array() ) {
1224 $url = add_query_arg( array( 'icl_site_url' => $this->get_installer_site_url( $repository_id ) ), $url );
1225
1226 $affiliate_id = false;
1227 $affiliate_key = false;
1228
1229 if ( ! empty( $this->package_source ) ) {
1230 $extra = $this->get_extra_url_parameters();
1231
1232 if ( ! empty( $extra['repository'] ) && $extra['repository'] == $repository_id ) {
1233 if ( ! empty( $extra['affiliate_key'] ) && ! empty( $extra['user_id'] ) ) {
1234 $this->config[ 'affiliate_id:' . $repository_id ] = $extra['user_id'];
1235 $this->config[ 'affiliate_key:' . $repository_id ] = $extra['affiliate_key'];
1236 unset( $extra['affiliate_key'], $extra['user_id'], $extra['repository'] );
1237 }
1238
1239 $url = add_query_arg( $extra, $url );
1240 }
1241 }
1242
1243 if ( isset( $this->config[ 'affiliate_id:' . $repository_id ] ) && isset( $this->config[ 'affiliate_key:' . $repository_id ] ) ) {
1244 $affiliate_id = $this->config[ 'affiliate_id:' . $repository_id ];
1245 $affiliate_key = $this->config[ 'affiliate_key:' . $repository_id ];
1246 } elseif ( isset( $args[ 'affiliate_id:' . $repository_id ] ) && isset( $args[ 'affiliate_key:' . $repository_id ] ) ) {
1247 $affiliate_id = $args[ 'affiliate_id:' . $repository_id ];
1248 $affiliate_key = $args[ 'affiliate_key:' . $repository_id ];
1249 } elseif ( defined( 'ICL_AFFILIATE_ID' ) && defined( 'ICL_AFFILIATE_KEY' ) ) {
1250
1251 $affiliate_id = ICL_AFFILIATE_ID;
1252 $affiliate_key = ICL_AFFILIATE_KEY;
1253 } elseif ( isset( $this->config['affiliate_id'] ) && isset( $this->config['affiliate_key'] ) ) {
1254 $affiliate_id = $this->config['affiliate_id'];
1255 $affiliate_key = $this->config['affiliate_key'];
1256 }
1257
1258 if ( $affiliate_id && $affiliate_key ) {
1259 $url = add_query_arg( array( 'aid' => $affiliate_id, 'affiliate_key' => $affiliate_key ), $url );
1260 }
1261
1262 if ( $repository_id == 'wpml' ) {
1263 $url = add_query_arg( array(
1264 'using_icl' => $this->_using_icl,
1265 'wpml_version' => $this->_wpml_version
1266 ), $url );
1267 }
1268
1269 $url = apply_filters( 'wp_installer_buy_url', $url );
1270
1271 $url = esc_url( $url );
1272
1273 return $url;
1274 }
1275
1276 private function syncWpmlDescriptionPackageWithBlog( array $packages ): array {
1277 $blogPackageIndex = $this->get_blog_package_index( $packages );
1278 $wpmlPackageIndex = $this->get_wpml_package_index( $packages );
1279
1280 if ( $blogPackageIndex === - 1 || $wpmlPackageIndex === - 1 ) {
1281 return $packages;
1282 }
1283
1284 $packages[ $wpmlPackageIndex ]['description'] = $packages[ $blogPackageIndex ]['description'];
1285
1286 return $packages;
1287 }
1288
1289 private function is_wpml_repository( string $repository_id ) {
1290 return $repository_id === 'wpml';
1291 }
1292
1293 private function is_blog_package( string $id ) {
1294 return $id === 'multilingual-blog';
1295 }
1296
1297 private function get_component_setting() {
1298 if ( ! $this->components_setting ) {
1299 $this->components_setting = new OTGS_Installer_WP_Share_Local_Components_Setting();
1300 }
1301
1302 return $this->components_setting;
1303 }
1304
1305 public function save_site_key( $args = array() ) {
1306 $error = '';
1307
1308 if ( isset( $args['repository_id'] ) ) {
1309 $repository_id = $args['repository_id'];
1310 } elseif ( isset( $_POST['repository_id'] ) ) {
1311 $repository_id = sanitize_text_field( $_POST['repository_id'] );
1312 } else {
1313 $repository_id = false;
1314 }
1315
1316 if ( isset( $args['nonce'] ) ) {
1317 $nonce = $args['nonce'];
1318 } elseif ( isset( $_POST['nonce'] ) ) {
1319 $nonce = sanitize_text_field( $_POST['nonce'] );
1320 } else {
1321 $nonce = '';
1322 }
1323
1324 if ( isset( $args['site_key'] ) ) {
1325 $site_key = $args['site_key'];
1326 } else {
1327 $site_key = sanitize_text_field( $_POST[ 'site_key_' . $repository_id ] );
1328 }
1329 $site_key = preg_replace( "/[^A-Za-z0-9]/", '', $site_key );
1330
1331 if ( $repository_id && $nonce && wp_verify_nonce( $nonce, 'save_site_key_' . $repository_id ) ) {
1332 try {
1333 $subscriptionManagerFactory = new SubscriptionManagerFactory();
1334 $subscriptionManager = $subscriptionManagerFactory->create( $repository_id, $this->repositories[ $repository_id ]['api-url'] );
1335 list ( $subscription_data, $site_key_data ) = $subscriptionManager->fetch( $site_key, self::SITE_KEY_VALIDATION_SOURCE_REGISTRATION );
1336
1337 if ( $subscription_data ) {
1338 $this->get_settings();
1339 $this->settings['repositories'][ $repository_id ]['subscription'] = array(
1340 'key' => $site_key,
1341 'key_type' => isset( $site_key_data['type'] )
1342 ? (int) $site_key_data['type'] : OTGS_Installer_Subscription::SITE_KEY_TYPE_PRODUCTION,
1343 'data' => $subscription_data,
1344 'registered_by' => get_current_user_id(),
1345 'site_url' => get_site_url(),
1346 );
1347 $this->save_settings();
1348 $this->clean_plugins_update_cache();
1349
1350 do_action('check_posthog_should_record');
1351 } else {
1352 $error = __( 'Invalid site key for the current site.', 'installer' )
1353 . '<br /> <div class="installer-footnote">' . __( 'Please note that the site key is case sensitive.', 'installer' ) . '</div>';
1354 }
1355 } catch ( Exception $e ) {
1356 $error = $e->getMessage();
1357 if ( preg_match( '#Could not resolve host: (.*)#', $error, $matches ) || preg_match( '#Couldn\'t resolve host \'(.*)\'#', $error, $matches ) ) {
1358 $error = sprintf( __( "%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet.", 'installer' ),
1359 '<strong><i>' . $this->get_generic_product_name( $repository_id ) . '</i></strong>',
1360 '<strong><i>' . $matches[1] . '</i></strong>'
1361 );
1362 }
1363
1364 $this->log_subscription_update( $repository_id . ': ' . $e->getMessage() );
1365 }
1366 }
1367
1368 $return = array( 'error' => $error );
1369
1370 if ( $this->api_debug ) {
1371 $return['debug'] = $this->api_debug;
1372 }
1373
1374 if ( ! empty( $args['return'] ) ) {
1375 return $return;
1376 } else {
1377 echo json_encode( $return );
1378 exit;
1379 }
1380 }
1381
1382 public function get_site_key( $repository_id ) {
1383 return WP_Installer::get_repository_site_key( $repository_id );
1384 }
1385
1386 public function remove_site_key( $repository_id, $refresh_repositories_data = true ) {
1387 $this->get_settings();
1388 if ( isset( $this->settings['repositories'][ $repository_id ] ) ) {
1389 unset( $this->settings['repositories'][ $repository_id ]['subscription'] );
1390 unset( $this->settings['repositories'][ $repository_id ]['last_successful_subscription_fetch'] );
1391
1392 $this->save_settings();
1393 $this->clean_plugins_update_cache();
1394 if ( $refresh_repositories_data ) {
1395 $this->refresh_repositories_data();
1396 }
1397 }
1398 }
1399
1400 public function validate_repository_subscription() {
1401 $repository_id = isset( $_GET['validate_repository'] ) ? sanitize_text_field( $_GET['validate_repository'] ) : false;
1402 if ( $repository_id ) {
1403 $site_key = $this->get_site_key( $repository_id );
1404 if ( $site_key ) {
1405 try {
1406 $subscriptionManagerFactory = new SubscriptionManagerFactory( $this->get_settings() );
1407 $subscriptionManager = $subscriptionManagerFactory->create( $repository_id, $this->repositories[ $repository_id ]['api-url'] );
1408 list ( $subscription_data, $site_key_data ) = $subscriptionManager->fetch( $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION );
1409 } catch ( Exception $e ) {
1410 $subscription_data = false;
1411 }
1412
1413 $this->get_settings();
1414 if ( empty( $subscription_data ) ) {
1415 unset( $this->settings['repositories'][ $repository_id ]['subscription'] );
1416 delete_site_transient( 'update_plugins' );
1417 } else {
1418 $this->settings['repositories'][ $repository_id ]['subscription']['data'] = $subscription_data;
1419 $this->settings['repositories'][ $repository_id ]['subscription']['key_type'] = isset( $site_key_data['type'] )
1420 ? (int) $site_key_data['type'] : OTGS_Installer_Subscription::SITE_KEY_TYPE_PRODUCTION;
1421 }
1422 $this->save_settings();
1423 }
1424
1425 wp_redirect( $this->menu_url() . '#repository-' . $repository_id );
1426 exit;
1427 }
1428 }
1429
1430 public function api_debug_log( $text ) {
1431 if ( defined( 'WPML_DEBUG_INSTALLER' ) && WPML_DEBUG_INSTALLER ) {
1432 if ( ! is_scalar( $text ) ) {
1433 $text = print_r( $text, true );
1434 }
1435
1436 $this->api_debug .= $text . "\n";
1437 }
1438 }
1439
1440 public function get_repository_site_key( $repository_id ) {
1441 $site_key = false;
1442 $subscriptions = Settings::load_subscriptions();
1443
1444 if ( isset( $subscriptions['repositories'][ $repository_id ]['subscription']['key'] ) ) {
1445 $site_key = $subscriptions['repositories'][ $repository_id ]['subscription']['key'];
1446 }
1447
1448 return ! empty( $site_key ) ? $site_key : false;
1449 }
1450
1451 public function get_subscription( $repository_id ) {
1452 $data = null;
1453 $subscriptions = Settings::load_subscriptions();
1454 if ( ! empty( $subscriptions['repositories'][ $repository_id ]['subscription'] ) ) {
1455 $data = $subscriptions['repositories'][ $repository_id ]['subscription'];
1456 }
1457
1458 return new OTGS_Installer_Subscription( $data );
1459 }
1460
1461 public function repository_has_valid_subscription( $repository_id, $expiredForPeriod = 0 ) {
1462 return $this->get_subscription( $repository_id )->is_valid( $expiredForPeriod );
1463 }
1464
1465 public function repository_is_in_grace_period( $repository_id, $expiredForPeriod = 0 ) {
1466 return $this->get_subscription( $repository_id )->is_in_grace( $expiredForPeriod );
1467 }
1468
1469 public function repository_has_refunded_subscription( $repository_id ) {
1470 return $this->get_subscription( $repository_id )->is_refunded();
1471 }
1472
1473 public function should_display_unregister_link_on_refund_notice() {
1474 $hide_till_date = $this->get_hide_unregister_link_on_refund_notice_till_date();
1475
1476 return time() > (int) $hide_till_date;
1477 }
1478
1479 private function get_hide_unregister_link_on_refund_notice_till_date() {
1480 if ( defined( 'OTGS_INSTALLER_OVERRIDE_HIDE_UNREGISTERED_TILL' ) ) {
1481 return constant( 'OTGS_INSTALLER_OVERRIDE_HIDE_UNREGISTERED_TILL' );
1482 }
1483
1484 if ( isset( $this->settings()['hide_unregister_link_on_refund_notice_till'] ) ) {
1485 return $this->settings()['hide_unregister_link_on_refund_notice_till'];
1486 }
1487
1488 $hide_till_date = time() + WEEK_IN_SECONDS;
1489 $this->set_hide_unregister_link_on_refund_notice_date( $hide_till_date );
1490
1491 return $hide_till_date;
1492 }
1493
1494 public function set_hide_unregister_link_on_refund_notice_date( $hide_till_date ) {
1495 $this->get_settings();
1496 $this->settings['hide_unregister_link_on_refund_notice_till'] = $hide_till_date;
1497 $this->save_settings();
1498 }
1499
1500 public function repository_has_subscription( $repository_id ) {
1501 $key = false;
1502 $subscriptions = Settings::load_subscriptions();
1503 if (
1504 isset( $subscriptions['repositories'][ $repository_id ]['subscription']['key'] )
1505 && ! empty( $subscriptions['repositories'][ $repository_id ]['subscription']['key'] )
1506 ) {
1507 $key = $subscriptions['repositories'][ $repository_id ]['subscription']['key'];
1508 }
1509
1510 return $key;
1511 }
1512
1513 public function repository_has_development_site_key( $repository_id ) {
1514 $subscriptions = Settings::load_subscriptions();
1515 return isset( $subscriptions['repositories'][ $repository_id ]['subscription']['key_type'] )
1516 && $subscriptions['repositories'][ $repository_id ]['subscription']['key_type'] === OTGS_Installer_Subscription::SITE_KEY_TYPE_DEVELOPMENT;
1517 }
1518
1519 public function repository_has_legacy_free_subscription( $repository_id ) {
1520 return $this->repository_has_valid_subscription( $repository_id )
1521 && $this->get_subscription_type_for_repository( $repository_id ) === self::LEGACY_FREE_TYPES_SUBSCRIPTION_ID;
1522 }
1523
1524 public function repository_has_expired_subscription( $repository_id, $expiredForPeriod = 0 ) {
1525 return $this->repository_has_subscription( $repository_id )
1526 &&
1527 ! $this->repository_has_valid_subscription( $repository_id, $expiredForPeriod )
1528 &&
1529 ! $this->repository_has_refunded_subscription( $repository_id );
1530 }
1531
1532 public function repository_has_in_grace_subscription( $repository_id, $expiredForPeriod = 0 ) {
1533 return $this->repository_has_expired_subscription( $repository_id ) && $this->repository_is_in_grace_period( $repository_id, $expiredForPeriod );
1534 }
1535
1536 public function get_generic_product_name( $repository_id ) {
1537 return $this->settings()['repositories'][ $repository_id ]['data']['product-name'];
1538 }
1539
1540 public function show_subscription_renew_warning( $repository_id, $subscription_id ) {
1541 $subscriptionWarningMessage = new Subscription_Warning_Message( $this );
1542 $warningMessage = $subscriptionWarningMessage->get( $repository_id, $subscription_id );
1543
1544 if ( ! empty( $warningMessage ) ) {
1545 echo '<div><p class="installer-warn-box notice notice-alt">' . $warningMessage . '</p></div>';
1546 }
1547
1548 return ! empty( $warningMessage );
1549 }
1550
1551 public function setup_plugins_renew_warnings() {
1552 $plugins = get_plugins();
1553 $subscriptions_with_warnings = [];
1554
1555 foreach ( $this->settings()['repositories'] as $repositoryId => $repository ) {
1556 $subscriptionData = Obj::path( [
1557 'repositories',
1558 $repositoryId,
1559 'subscription',
1560 'data'
1561 ], $this->settings );
1562
1563 $subscriptionType = Obj::prop( 'subscription_type', $subscriptionData );
1564
1565 $subscriptionWarningMessage = new Subscription_Warning_Message( $this );
1566 $warningMessage = $subscriptionWarningMessage->get( $repositoryId, $subscriptionType );
1567
1568 if ( ! empty( $warningMessage ) ) {
1569 $subscriptions_with_warnings[ $subscriptionType ] = $warningMessage;
1570 }
1571 }
1572
1573
1574 foreach ( $plugins as $plugin_id => $plugin ) {
1575 $slug = dirname( $plugin_id );
1576 if ( empty( $slug ) ) {
1577 continue;
1578 }
1579
1580 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
1581 if ( $this->repository_has_valid_subscription( $repository_id ) ) {
1582 foreach ( $repository['data']['packages'] as $package ) {
1583 foreach ( $package['products'] as $product ) {
1584 foreach ( $product['plugins'] as $plugin_slug ) {
1585 if ( ! $this->isPluginAvailableInRepositoryDownloads( $repository_id, $plugin_slug ) ) {
1586 continue;
1587 }
1588
1589 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
1590
1591 if ( $download['slug'] == $slug || $download['name'] == $plugin['Name'] || $download['name'] == $plugin['Title'] ) {
1592
1593 if ( isset( $subscriptions_with_warnings[ $product['subscription_type'] ] ) ) {
1594 $this->_plugins_renew_warnings[ $plugin_id ] = $subscriptions_with_warnings[ $product['subscription_type'] ];
1595 }
1596 }
1597 }
1598 }
1599 }
1600 }
1601 }
1602 }
1603 }
1604
1605 public function queue_plugins_renew_warnings() {
1606 if ( ! empty( $this->_plugins_renew_warnings ) ) {
1607 foreach ( $this->_plugins_renew_warnings as $plugin_id => $message ) {
1608 add_action( "after_plugin_row_" . $plugin_id, array( $this, 'plugins_renew_warning' ), 10, 3 );
1609 }
1610 }
1611 }
1612
1613 public function plugins_renew_warning( $plugin_file, $plugin_data, $status ) {
1614 if ( empty( $this->_plugins_renew_warnings[ $plugin_file ] ) ) {
1615 return;
1616 }
1617
1618 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
1619 if ( false === $wp_list_table ) {
1620 return;
1621 }
1622 ?>
1623
1624 <tr id="<?php
1625 echo $plugin_data['slug']; ?>-update" data-slug="<?php
1626 echo $plugin_data['slug']; ?>" data-plugin="<?php
1627 echo $plugin_file ?>">
1628 <td colspan="<?php
1629 echo $wp_list_table->get_column_count(); ?>" class="notice notice-warning notice-otgs">
1630 <p>
1631 <?php
1632 echo $this->_plugins_renew_warnings[ $plugin_file ];
1633 ?>
1634 </p>
1635 </td>
1636 </tr>
1637
1638 <?php
1639 }
1640
1641 public function get_subscription_type_for_repository( $repository_id ) {
1642 $subscription_type = false;
1643
1644 if ( ! empty( $this->settings()['repositories'][ $repository_id ]['subscription'] ) ) {
1645 $subscription_type = $this->settings()['repositories'][ $repository_id ]['subscription']['data']->subscription_type;
1646 }
1647
1648 return $subscription_type;
1649 }
1650
1651 public function have_superior_subscription( $subscription_type, $product ) {
1652 $have = false;
1653
1654 if ( is_array( $product['upgrades'] ) ) {
1655 foreach ( $product['upgrades'] as $u ) {
1656 if ( $u['subscription_type'] == $subscription_type ) {
1657 $have = true;
1658 break;
1659 }
1660 }
1661 }
1662
1663 return $have;
1664 }
1665
1666 public function is_product_available_for_download( $product_name, $repository_id ) {
1667 $available = false;
1668
1669 $subscription_type = $this->get_subscription_type_for_repository( $repository_id );
1670 $expired = $this->repository_has_expired_subscription( $repository_id );
1671
1672 if ( ! $expired && $this->repository_has_subscription( $repository_id ) ) {
1673 $this->set_hierarchy_and_order();
1674
1675 foreach ( $this->settings()['repositories'][ $repository_id ]['data']['packages'] as $package_id => $package ) {
1676 $has_top_package = false;
1677
1678 foreach ( $package['products'] as $product ) {
1679 if ( $subscription_type === (int) $product['subscription_type'] || $subscription_type === (int) $product['subscription_type_equivalent'] ) {
1680 $has_top_package = true;
1681 if ( $product['name'] == $product_name ) {
1682 return $available = true;
1683 }
1684 }
1685 }
1686
1687 if ( ! empty( $package['sub-packages'] ) ) {
1688 foreach ( $package['sub-packages'] as $sub_package ) {
1689 foreach ( $sub_package['products'] as $product ) {
1690 if ( $product['name'] == $product_name && ( $subscription_type === (int) $product['subscription_type'] || $subscription_type === (int) $product['subscription_type_equivalent'] || $has_top_package ) ) {
1691 return $available = true;
1692 }
1693 }
1694 }
1695 }
1696 }
1697 }
1698
1699 return $available;
1700 }
1701
1702 public function get_upgrade_options( $repository_id ) {
1703 $all_upgrades = array();
1704
1705
1706 $all_products = array();
1707 foreach ( $this->settings()['repositories'][ $repository_id ]['data']['packages'] as $package ) {
1708 foreach ( $package['products'] as $product ) {
1709 $all_products[] = $product;
1710 }
1711 if ( ! empty( $package['sub-packages'] ) ) {
1712 foreach ( $package['sub-packages'] as $subpackage ) {
1713 foreach ( $subpackage['products'] as $product ) {
1714 $all_products[] = $product;
1715 }
1716 }
1717 }
1718 }
1719
1720 foreach ( $all_products as $product ) {
1721 if ( $product['upgrades'] ) {
1722 foreach ( $product['upgrades'] as $upgrade ) {
1723 if ( $this->repository_has_valid_subscription( $repository_id ) || ( $this->repository_has_subscription( $repository_id ) && $upgrade['including_expired'] ) ) {
1724 $all_upgrades[ $upgrade['subscription_type'] ][ $product['subscription_type'] ] = $upgrade;
1725 }
1726 }
1727 }
1728 }
1729
1730 return $all_upgrades;
1731 }
1732
1733 public function append_site_key_to_download_url( $url, $key, $repository_id ) {
1734 $url_params['site_key'] = $key;
1735 $url_params['site_url'] = $this->get_installer_site_url( $repository_id );
1736
1737
1738 if ( ! empty( $this->package_source ) ) {
1739 $extra = $this->get_extra_url_parameters();
1740 if ( ! empty( $extra['repository'] ) && $extra['repository'] == $repository_id ) {
1741 unset( $extra['repository'] );
1742 foreach ( $extra as $key => $val ) {
1743 $url_params[ $key ] = $val;
1744 }
1745 }
1746 }
1747
1748 $url = add_query_arg( $url_params, $url );
1749
1750 if ( $repository_id == 'wpml' ) {
1751 $url = add_query_arg( array(
1752 'using_icl' => $this->_using_icl,
1753 'wpml_version' => $this->_wpml_version
1754 ), $url );
1755 }
1756
1757 return $url;
1758 }
1759
1760 public function plugin_is_not_installed( $name, $slug, $version = null ) {
1761 return ! $this->plugin_is_installed( $name, $slug, $version );
1762 }
1763
1764 public function plugin_is_installed( $name, $slug, $version = null ) {
1765 $is = false;
1766
1767 $plugins = get_plugins();
1768
1769 foreach ( $plugins as $plugin_id => $plugin ) {
1770 $wp_plugin_slug = dirname( $plugin_id );
1771
1772 if ( $wp_plugin_slug == $slug || $plugin['Name'] == $name || $plugin['Title'] == $name || ( $wp_plugin_slug == $slug . '-embedded' || $plugin['Name'] == $name . ' Embedded' ) ) {
1773 if ( $version ) {
1774 if ( version_compare( $plugin['Version'], $version, '>=' ) ) {
1775 $is = $plugin['Version'];
1776 }
1777 } else {
1778 $is = $plugin['Version'];
1779 }
1780
1781 break;
1782 }
1783 }
1784
1785 if ( ! $is && $name == 'Types' ) {
1786 return $this->plugin_is_installed( 'Types - Complete Solution for Custom Fields and Types', $slug, $version );
1787 }
1788
1789 return $is;
1790 }
1791
1792 public function plugin_is_embedded_version( $name, $slug ) {
1793 $is = false;
1794
1795 $plugins = get_plugins();
1796
1797 $is_full_installed = false;
1798 foreach ( $plugins as $plugin_id => $plugin ) {
1799 if ( ( $plugin['Name'] == $name && ! preg_match( "#-embedded$#", $slug ) ) ) {
1800 $is_full_installed = true;
1801 break;
1802 }
1803 }
1804
1805 if ( $is_full_installed ) {
1806 return false;
1807 }
1808
1809 foreach ( $plugins as $plugin_id => $plugin ) {
1810 $wp_plugin_slug = dirname( $plugin_id );
1811 if ( $wp_plugin_slug == $slug . '-embedded' && $plugin['Name'] == $name . ' Embedded' ) {
1812 $is = true;
1813 break;
1814 }
1815 }
1816
1817 return $is;
1818 }
1819
1820 public function get_plugin_installed_version( $name, $slug ) {
1821 return $this->plugin_is_installed( $name, $slug );
1822 }
1823
1824 public function get_plugin_repository_version( $repository_id, $slug ) {
1825 $version = false;
1826
1827 if ( ! empty( $this->settings()['repositories'][ $repository_id ]['data']['packages'] ) ) {
1828 foreach ( $this->settings()['repositories'][ $repository_id ]['data']['packages'] as $package ) {
1829 foreach ( $package['products'] as $product ) {
1830 foreach ( $product['plugins'] as $plugin_slug ) {
1831 if ( ! array_key_exists( $plugin_slug, $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'] ) ) {
1832 continue;
1833 }
1834
1835 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
1836
1837 if ( $download['slug'] == $slug ) {
1838 $version = $download['version'];
1839 break ( 3 );
1840 }
1841 }
1842 }
1843 }
1844 }
1845
1846 return $version;
1847 }
1848
1849 public function is_uploading_allowed() {
1850 return $this->dependencies->is_uploading_allowed();
1851 }
1852
1853 public function download_plugin_ajax_handler() {
1854 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1855 require_once $this->plugin_path() . '/includes/class-installer-upgrader-skins.php';
1856
1857 $data = json_decode( base64_decode( sanitize_text_field( $_POST['data'] ) ), true );
1858
1859 $data_url_parsed = wp_parse_url( $data['url'] );
1860 $data_url_args = $data_url_parsed['query'];
1861 unset( $data_url_parsed['query'] );
1862 $data_url = http_build_url( $data_url_parsed );
1863
1864 $ret = false;
1865 $plugin_id = false;
1866 $message = '';
1867 $connection_error = false;
1868
1869 $site_key = $this->get_repository_site_key( $data['repository_id'] );
1870 try {
1871 $subscriptionManagerFactory = new SubscriptionManagerFactory( $this->get_settings() );
1872 $subscriptionManager = $subscriptionManagerFactory->create( $data['repository_id'], $this->repositories[ $data['repository_id'] ]['api-url'] );
1873 list ( $subscription_data, $site_key_data ) = $subscriptionManager->fetch( $site_key, self::SITE_KEY_VALIDATION_SOURCE_DOWNLOAD_REPORT );
1874 } catch ( Exception $e ) {
1875 $connection_error = $e->getMessage();
1876 $subscription_data = false;
1877
1878 $this->store_log( $data_url, $data_url_args, OTGS_Installer_Logger_Storage::COMPONENT_SUBSCRIPTION, $connection_error );
1879 }
1880
1881 if ( $subscription_data && ! is_wp_error( $subscription_data ) && $this->repository_has_valid_subscription( $data['repository_id'] ) ) {
1882 if ( wp_verify_nonce( $data['nonce'], 'install_plugin_' . $data['url'] ) ) {
1883 $upgrader_skins = new Installer_Upgrader_Skins();
1884 $upgrader = new Plugin_Upgrader( $upgrader_skins );
1885
1886 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
1887
1888 $plugins = get_plugins();
1889
1890 $is_embedded = false;
1891 foreach ( $plugins as $id => $plugin ) {
1892 $wp_plugin_slug = dirname( $id );
1893 $is_embedded = $this->plugin_is_embedded_version( preg_replace( '/ Embedded$/', '', $plugin['Name'] ), preg_replace( '/-embedded$/', '', $wp_plugin_slug ) );
1894
1895 if ( $wp_plugin_slug == $data['slug'] || $is_embedded && preg_replace( '/-embedded$/', '', $wp_plugin_slug ) == $data['slug'] ) {
1896 $plugin_id = $id;
1897 break;
1898 }
1899 }
1900
1901 if ( $plugin_id && ! $is_embedded && $this->is_plugin_out_of_date( $plugin_id ) ) {
1902 $response['upgrade'] = 1;
1903
1904 $plugin_is_active = is_plugin_active( $plugin_id );
1905
1906 $ret = $upgrader->upgrade( $plugin_id, [ 'clear_update_cache' => false ] );
1907
1908 if ( ! $ret && ! empty( $upgrader->skin->installer_error ) ) {
1909 if ( is_wp_error( $upgrader->skin->installer_error ) ) {
1910 $message = $upgrader->skin->installer_error->get_error_message() .
1911 ' (' . $upgrader->skin->installer_error->get_error_data() . ')';
1912 }
1913 $plugin_version = 0;
1914 } else {
1915 if ( $plugin_is_active ) {
1916 add_filter( 'wp_redirect', '__return_false' );
1917 activate_plugin( $plugin_id );
1918 }
1919 $plugin_version = $this->get_plugin_repository_version( $data['repository_id'], $data['slug'] );
1920 }
1921 } elseif ( $plugin_id && ! $is_embedded ) {
1922 activate_plugin( $plugin_id );
1923 $ret = true;
1924 } else {
1925
1926 if ( $is_embedded && $plugin_id ) {
1927 delete_plugins( array( $plugin_id ) );
1928 }
1929
1930 $response['install'] = 1;
1931 $ret = $upgrader->install( $data['url'] );
1932 if ( ! $ret && ! empty( $upgrader->skin->installer_error ) ) {
1933 if ( is_wp_error( $upgrader->skin->installer_error ) ) {
1934 $message = $upgrader->skin->installer_error->get_error_message() .
1935 ' (' . $upgrader->skin->installer_error->get_error_data() . ')';
1936 }
1937 }
1938 }
1939
1940 $plugins = get_plugins();
1941
1942 if ( $ret ) {
1943 foreach ( $plugins as $id => $plugin ) {
1944 $wp_plugin_slug = dirname( $id );
1945 if ( $wp_plugin_slug == $data['slug'] ) {
1946 $plugin_version = $plugin['Version'];
1947 $plugin_id = $id;
1948
1949 $include_auto_upgrade = new IncludeAutoUpgrade( $this->settings, $data['repository_id'] );
1950 $include_auto_upgrade->includeDuringInstall( $plugin_id );
1951 break;
1952 }
1953 }
1954 }
1955
1956 if ( WP_Installer_Channels()->get_channel( $data['repository_id'] ) !== WP_Installer_Channels::CHANNEL_PRODUCTION ) {
1957 $download = $this->settings()['repositories'][ $data['repository_id'] ]['data']['downloads']['plugins'][ $data['slug'] ];
1958 $non_stable = WP_Installer_Channels()->get_download_source_channel( $plugin_version, $data['repository_id'], $download['slug'], 'plugins' );
1959 }
1960 }
1961 } elseif ( $connection_error ) {
1962 $ret = false;
1963 $message = sprintf( __( 'Connection failed! Please refresh the page and try again. (%s)', 'installer' ), '<i>' . $connection_error . '</i>' );
1964 } else {
1965 $ret = false;
1966 $message = __( 'Your subscription appears to no longer be valid. Please try to register again using a valid site key.', 'installer' );
1967 }
1968
1969 if ( $message ) {
1970 $this->store_log( $data_url, $data_url_args, OTGS_Installer_Logger_Storage::COMPONENT_DOWNLOAD, $message );
1971 }
1972
1973 $response['version'] = isset( $plugin_version ) ? $plugin_version : 0;
1974 $response['non_stable'] = isset( $non_stable ) ? $non_stable : '';
1975 $response['plugin_id'] = $plugin_id;
1976 $response['nonce'] = wp_create_nonce( 'activate_' . $plugin_id );
1977 $response['success'] = $ret;
1978 $response['message'] = $message;
1979
1980 echo json_encode( $response );
1981 exit;
1982 }
1983
1984 private function is_plugin_out_of_date( $plugin ) {
1985 $current = get_site_transient( 'update_plugins' );
1986
1987 return isset( $current->response[ $plugin ] );
1988 }
1989
1990 public function download_plugin( $slug, $url ) {
1991 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1992 require_once $this->plugin_path() . '/includes/class-installer-upgrader-skins.php';
1993
1994 $upgrader_skins = new Installer_Upgrader_Skins();
1995 $upgrader = new Plugin_Upgrader( $upgrader_skins );
1996
1997 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
1998
1999 $plugins = get_plugins();
2000
2001 $plugin_id = false;
2002
2003 foreach ( $plugins as $id => $plugin ) {
2004 $wp_plugin_slug = dirname( $id );
2005 if ( $wp_plugin_slug == $slug ) {
2006 $plugin_id = $id;
2007 break;
2008 }
2009 }
2010
2011 if ( $plugin_id ) {
2012
2013 $plugin_is_active = is_plugin_active( $plugin_id );
2014
2015 $ret = $upgrader->upgrade( $plugin_id );
2016
2017 if ( $plugin_is_active ) {
2018 activate_plugin( $plugin_id );
2019 }
2020 } else {
2021 $ret = $upgrader->install( $url );
2022 }
2023
2024 return $ret;
2025 }
2026
2027 public function activate_plugin() {
2028 $error = '';
2029
2030 $plugin_id = sanitize_text_field( $_POST['plugin_id'] );
2031
2032 if ( isset( $_POST['nonce'] ) && $plugin_id && wp_verify_nonce( $_POST['nonce'], 'activate_' . $plugin_id ) ) {
2033 $plugin_slug = dirname( $plugin_id );
2034 $active_plugins = get_option( 'active_plugins' );
2035 foreach ( $active_plugins as $plugin ) {
2036 $wp_plugin_slug = dirname( $plugin );
2037 if ( $wp_plugin_slug == $plugin_slug . '-embedded' ) {
2038 deactivate_plugins( array( $plugin ) );
2039 break;
2040 }
2041 }
2042
2043 add_filter( 'wp_redirect', '__return_false', 10000 );
2044
2045 $return = activate_plugin( $plugin_id );
2046
2047 if ( is_wp_error( $return ) ) {
2048 $error = $return->get_error_message();
2049 }
2050 } else {
2051 $error = 'error';
2052 }
2053
2054 $ret = array( 'error' => $error );
2055
2056 echo json_encode( $ret );
2057 exit;
2058 }
2059
2060 public function custom_plugins_api_call( $result, $action, $args ) {
2061 if ( $action == 'plugin_information' ) {
2062 if ( ! function_exists( 'get_plugins' ) ) {
2063 require_once ABSPATH . 'wp-admin/includes/plugin.php';
2064 }
2065
2066 $plugins = get_plugins();
2067 $installed_plugins = array();
2068 foreach ( $plugins as $plugin_id => $plugin ) {
2069 $installed_plugins[ dirname( $plugin_id ) ] = array(
2070 'name' => $plugin['Name'],
2071 'title' => $plugin['Title'],
2072 'is_lite' => false !== stripos( $plugin['Version'], '-lite' ),
2073 );
2074 }
2075
2076 $slug = $args->slug;
2077 $custom_plugin = false;
2078
2079 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
2080 if ( ! $this->repository_has_valid_subscription( $repository_id ) ) {
2081 $site_key = false;
2082 } else {
2083 $site_key = $repository['subscription']['key'];
2084 }
2085
2086 foreach ( $repository['data']['packages'] as $package ) {
2087 foreach ( $package['products'] as $product ) {
2088 foreach ( $product['plugins'] as $plugin_slug ) {
2089 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
2090
2091 if ( $download['slug'] == $slug
2092 || isset( $installed_plugins[ $slug ] )
2093 && (
2094 $installed_plugins[ $slug ]['name'] == $download['name'] || $installed_plugins[ $slug ]['title'] == $download['name']
2095 )
2096 ) {
2097 $this_plugin = new stdClass();
2098 $this_plugin->external = true;
2099
2100 $this_plugin->is_free = $this->should_fallback_under_wp_org_repo( $download,
2101 $site_key );
2102 $this_plugin->is_lite = ! empty( $download['is-lite'] );
2103 $this_plugin->is_download_available = $this->is_product_available_for_download( $product['name'],
2104 $repository_id );
2105
2106 if ( $custom_plugin ) {
2107 if ( ( ! $custom_plugin->is_free && $this_plugin->is_free )
2108 || ( ! $custom_plugin->is_lite && $custom_plugin->is_download_available )
2109 || ( $custom_plugin->is_lite && ! $this_plugin->is_download_available && $installed_plugins[ $slug ]['is_lite'] )
2110 ) {
2111 continue;
2112 }
2113 }
2114 $custom_plugin = $this_plugin;
2115
2116 $custom_plugin->name = $download['name'];
2117 $custom_plugin->slug = $slug;
2118 $custom_plugin->version = $download['version'];
2119 $custom_plugin->author = '';
2120 $custom_plugin->author_profile = '';
2121 $custom_plugin->last_updated = $download['date'];
2122 $custom_plugin->tested = isset( $download['tested'] ) ? $download['tested'] : '';
2123
2124 if ( $site_key ) {
2125 $custom_plugin->download_link = $this->append_site_key_to_download_url( $download['url'],
2126 $site_key, $repository_id );
2127 }
2128
2129 $custom_plugin->homepage = $repository['data']['url'];
2130 $custom_plugin->sections = array(
2131 'Description' => $download['description'],
2132 );
2133
2134 $changelog = Settings::get_changelog_for_plugin( $slug );
2135 if ( $changelog ) {
2136 $custom_plugin->sections['Changelog'] = $changelog;
2137 }
2138 }
2139 }
2140 }
2141 }
2142 }
2143
2144 if ( $custom_plugin ) {
2145 if ( $custom_plugin->is_free ) {
2146 $result = false;
2147 } else {
2148 $result = $custom_plugin;
2149 }
2150 }
2151 }
2152
2153 return $result;
2154 }
2155
2156 private function should_fallback_under_wp_org_repo( $download, $site_key ) {
2157 return ( ! empty( $download['free-on-wporg'] ) || isset( $download['fallback-free-on-wporg'] ) && $download['fallback-free-on-wporg'] && ! $site_key ) && $download['channel'] == WP_Installer_Channels::CHANNEL_PRODUCTION;
2158 }
2159
2160 private function has_non_wporg_upgrade_available( $plugin_id ) {
2161 $plugins_update_data = get_site_transient( 'update_plugins' );
2162
2163 return ! empty( $plugins_update_data->response[ $plugin_id ] )
2164 &&
2165 ! preg_match( '/w\.org/', $plugins_update_data->response[ $plugin_id ]->id );
2166 }
2167
2168 public function setup_plugins_page_notices() {
2169 $plugins = get_plugins();
2170
2171 $template_service = OTGS_Template_Service_Factory::create(
2172 $this->plugin_path() . '/templates/php/components-setting/'
2173 );
2174
2175
2176 $plugin_page_notice = new OTGS_Installer_Plugins_Page_Notice( $template_service, $this->get_plugin_finder() );
2177
2178 foreach ( $plugins as $plugin_id => $plugin ) {
2179 $slug = dirname( $plugin_id );
2180 if ( empty( $slug ) ) {
2181 continue;
2182 }
2183
2184 $name = $plugin['Name'];
2185
2186 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
2187 if ( ! $this->repository_has_valid_subscription( $repository_id ) ) {
2188 $site_key = false;
2189 } else {
2190 $site_key = $repository['subscription']['key'];
2191 }
2192
2193 foreach ( $repository['data']['packages'] as $package ) {
2194 foreach ( $package['products'] as $product ) {
2195 foreach ( $product['plugins'] as $plugin_slug ) {
2196 $plugin_finder = $this->get_plugin_finder();
2197 $plugin_found = $plugin_finder->get_plugin( $plugin_slug, $repository_id );
2198
2199 if ( ! $plugin_found ) {
2200 continue;
2201 }
2202
2203 $external_repo = $plugin_found->get_external_repo();
2204
2205 if ( $external_repo && $this->plugin_is_registered( $external_repo, $plugin_slug ) ) {
2206 continue;
2207 }
2208
2209 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
2210 $display_subscription_notice = false;
2211 $display_setting_notice = false;
2212
2213 if ( $download['slug'] == $slug || $download['name'] == $name ) {
2214 if ( in_array( $name, array( 'Toolset Types', 'WPML Multilingual CMS' ), true ) ) {
2215 $display_setting_notice = true;
2216 }
2217
2218 if ( ! $site_key || ! $this->plugin_is_registered( $repository_id, $download['slug'] ) ) {
2219 $display_setting_notice = false;
2220
2221 if (
2222 self::isFreeToolsetTypes( $name, $plugin ) || $this->isComplementaryWithWPMLSubscription( $name, $slug ) || $download['fallback-free-on-wporg']
2223 ) {
2224 $display_subscription_notice = false;
2225 } else {
2226 if ( $this->repository_has_in_grace_subscription( $repository_id, self::GRACE_TIME ) ) {
2227 $display_subscription_notice = [
2228 'type' => 'in_grace',
2229 'repo' => $repository_id,
2230 'product' => $repository['data']['product-name']
2231 ];
2232 } elseif ( $this->repository_has_expired_subscription( $repository_id ) ) {
2233 $display_subscription_notice = [
2234 'type' => 'expired',
2235 'repo' => $repository_id,
2236 'product' => $repository['data']['product-name']
2237 ];
2238 } elseif ( $this->repository_has_refunded_subscription( $repository_id ) ) {
2239 $display_subscription_notice = [
2240 'type' => 'refunded',
2241 'repo' => $repository_id,
2242 'product' => $repository['data']['product-name']
2243 ];
2244 } elseif ( ! $this->repository_has_subscription( $repository_id ) ) {
2245 $display_subscription_notice = apply_filters(
2246 'otgs_installer_display_subscription_notice',
2247 [
2248 'type' => 'register',
2249 'repo' => $repository_id,
2250 'product' => $repository['data']['product-name']
2251 ]
2252 );
2253 }
2254 }
2255 }
2256 if ( $this->plugin_is_registered( $repository_id, $download['slug'] ) && $this->repository_has_legacy_free_subscription( $repository_id ) ) {
2257 $display_subscription_notice = [
2258 'type' => 'legacy_free',
2259 'repo' => $repository_id,
2260 'product' => $repository['data']['product-name']
2261 ];
2262 }
2263 }
2264
2265 if ( $display_setting_notice || $display_subscription_notice ) {
2266 $plugin_page_notice->add_plugin(
2267 $plugin_id,
2268 array(
2269 OTGS_Installer_Plugins_Page_Notice::DISPLAY_SUBSCRIPTION_NOTICE_KEY => $display_subscription_notice,
2270 OTGS_Installer_Plugins_Page_Notice::DISPLAY_SETTING_NOTICE_KEY => $display_setting_notice,
2271 )
2272 );
2273 }
2274 }
2275 }
2276 }
2277 }
2278 }
2279
2280 $plugin_page_notice->add_hooks();
2281 }
2282
2283 public function localize_strings() {
2284 if ( ! empty( $this->settings()['repositories'] ) ) {
2285 foreach ( $this->settings['repositories'] as $repository_id => $repository ) {
2286 foreach ( $repository['data']['packages'] as $package_id => $package ) {
2287 foreach ( $package['products'] as $product_id => $product ) {
2288 if ( empty( $product['call2action'] ) ) {
2289 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['call2action'] = $product['name'];
2290 }
2291
2292 foreach ( $product['upgrades'] as $idx => $upg ) {
2293 if ( empty( $upg['call2action'] ) ) {
2294 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['upgrades'][ $idx ]['call2action'] = $upg['name'];
2295 }
2296 }
2297
2298 foreach ( $product['renewals'] as $idx => $rnw ) {
2299 if ( empty( $rnw['call2action'] ) ) {
2300 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['renewals'][ $idx ]['call2action'] = $rnw['name'];
2301 }
2302 }
2303 }
2304 }
2305 }
2306 }
2307
2308 global $sitepress;
2309 if ( is_null( $sitepress ) ) {
2310 return;
2311 }
2312
2313 $user_admin_language = $sitepress->get_admin_language();
2314
2315 if ( $user_admin_language != 'en' ) {
2316 foreach ( $this->settings['repositories'] as $repository_id => $repository ) {
2317 $localization = $repository['data']['localization'];
2318
2319 foreach ( $repository['data']['packages'] as $package_id => $package ) {
2320 if ( isset( $localization['packages'][ $package_id ]['name'][ $user_admin_language ] ) ) {
2321 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['name'] = $localization['packages'][ $package_id ]['name'][ $user_admin_language ];
2322 }
2323 if ( isset( $localization['packages'][ $package_id ]['description'][ $user_admin_language ] ) ) {
2324 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['description'] = $localization['packages'][ $package_id ]['description'][ $user_admin_language ];
2325 }
2326 }
2327
2328 foreach ( $repository['data']['packages'] as $package_id => $package ) {
2329 foreach ( $package['products'] as $product_id => $product ) {
2330 if ( isset( $localization['products'][ $product_id ]['name'][ $user_admin_language ] ) ) {
2331 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['name']
2332 = $localization['products'][ $product_id ]['name'][ $user_admin_language ];
2333 }
2334 if ( isset( $localization['products'][ $product_id ]['description'][ $user_admin_language ] ) ) {
2335 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['description']
2336 = $localization['products'][ $product_id ]['description'][ $user_admin_language ];
2337 }
2338 if ( isset( $localization['products'][ $product_id ]['call2action'][ $user_admin_language ] ) ) {
2339 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['name']
2340 = $localization['products'][ $product_id ]['call2action'][ $user_admin_language ];
2341 }
2342 }
2343 }
2344
2345 if ( isset( $repository['data']['subscriptions_meta']['expiration'] ) ) {
2346 foreach ( $repository['data']['subscriptions_meta']['expiration'] as $subscription_id => $note ) {
2347 if ( isset( $localization['subscriptions-notes'][ $subscription_id ]['expiration-warning'][ $user_admin_language ] ) ) {
2348 $this->settings['repositories'][ $repository_id ]['data']['subscriptions_meta']['expiration'][ $subscription_id ]['warning_message']
2349 = $localization['subscriptions-notes'][ $subscription_id ]['expiration-warning'][ $user_admin_language ];
2350 }
2351 }
2352 }
2353 }
2354 }
2355 }
2356
2357 public function get_matching_cp( $repository, $args = array() ) {
2358 $match = false;
2359
2360
2361 $cp_name = $cp_author = false;
2362
2363 if ( isset( $this->config['src_name'] ) && isset( $this->config['src_author'] ) ) {
2364 $cp_name = $this->config['src_name'];
2365 $cp_author = $this->config['src_author'];
2366 } elseif ( isset( $args['src_name'] ) && isset( $args['src_author'] ) ) {
2367 $cp_name = $args['src_name'];
2368 $cp_author = $args['src_author'];
2369 }
2370
2371 if ( isset( $repository['data']['marketing_cp'] ) ) {
2372 foreach ( $repository['data']['marketing_cp'] as $cp ) {
2373 if ( ! empty( $cp['exp'] ) && time() > $cp['exp'] ) {
2374 continue;
2375 }
2376
2377 if ( ! empty( $cp['theme_name'] ) ) {
2378 if ( $cp['author_name'] == $cp_author && $cp['theme_name'] == $cp_name ) {
2379 $match = $cp;
2380 continue;
2381 }
2382 } else {
2383 if ( $cp['author_name'] == $cp_author ) {
2384 $match = $cp;
2385 continue;
2386 }
2387 }
2388 }
2389 }
2390
2391 return $match;
2392 }
2393
2394 public function set_filtered_prices( $args = array() ) {
2395 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
2396 $match = $this->get_matching_cp( $repository, $args );
2397
2398 if ( empty( $match ) ) {
2399 continue;
2400 }
2401
2402 foreach ( $repository['data']['packages'] as $package_id => $package ) {
2403 foreach ( $package['products'] as $product_id => $product ) {
2404 if ( $match['dtp'] == '%' ) {
2405 $fprice = round( $product['price'] * ( 1 - $match['amt'] / 100 ), 2 );
2406 $fprice = $fprice != round( $fprice ) ? sprintf( '%.2f', $fprice ) : round( $fprice, 0 );
2407 } elseif ( $match['dtp'] == '-' ) {
2408 $fprice = $product['price'] - $match['amt'];
2409 } else {
2410 $fprice = $product['price'];
2411 }
2412
2413 if ( $fprice ) {
2414 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['price_disc'] = $fprice;
2415
2416 $url_glue = false !== strpos( $this->settings()['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['url'], '?' ) ? '&' : '?';
2417 $cpndata = base64_encode( (string) json_encode( array(
2418 'theme_author' => $match['author_name'],
2419 'theme_name' => $match['theme_name'],
2420 'vlc' => $match['vlc']
2421 ) ) );
2422 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['url'] .= $url_glue . 'cpn=' . $cpndata;
2423
2424 foreach ( $product['upgrades'] as $upgrade_id => $upgrade ) {
2425 $fprice = false;
2426 if ( $match['dtp'] == '%' ) {
2427 $fprice = round( $upgrade['price'] * ( 1 - $match['amt'] / 100 ), 2 );
2428 $fprice = $fprice != round( $fprice ) ? sprintf( '%.2f', $fprice ) : round( $fprice, 0 );
2429 } elseif ( $match['dtp'] == '-' ) {
2430 $fprice = $upgrade['price'] - $match['amt'];
2431 }
2432 if ( $fprice ) {
2433 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['upgrades'][ $upgrade_id ]['price_disc'] = $fprice;
2434 $this->settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['upgrades'][ $upgrade_id ]['url'] .= $url_glue . 'cpn=' . $cpndata;
2435 }
2436 }
2437 }
2438 }
2439 }
2440 }
2441 }
2442
2443 public function set_hierarchy_and_order() {
2444 if ( ! empty( $this->settings()['repositories'] ) ) {
2445 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
2446 if ( empty( $repository['data']['packages'] ) ) {
2447 continue;
2448 }
2449
2450 $all_packages = $repository['data']['packages'];
2451 $ordered_packages = array();
2452
2453 foreach ( $all_packages as $k => $v ) {
2454 if ( ! isset( $v['order'] ) ) {
2455 $all_packages[ $k ]['order'] = 0;
2456 }
2457 }
2458
2459 foreach ( $all_packages as $package_id => $package ) {
2460 if ( empty( $package['parent'] ) ) {
2461 $ordered_packages[ $package_id ] = $package;
2462 }
2463 }
2464
2465 foreach ( $all_packages as $package_id => $package ) {
2466 if ( ! empty( $package['parent'] ) ) {
2467 if ( isset( $ordered_packages[ $package['parent'] ] ) ) {
2468 $ordered_packages[ $package['parent'] ]['sub-packages'][ $package_id ] = $package;
2469 }
2470 }
2471 }
2472
2473 usort( $ordered_packages, array( $this, 'compare_package_order' ) );
2474 foreach ( $ordered_packages as $package_id => $package ) {
2475 if ( ! empty( $package['sub-packages'] ) ) {
2476 usort( $ordered_packages[ $package_id ]['sub-packages'], array( $this, 'compare_package_order' ) );
2477 }
2478 }
2479
2480 $this->settings['repositories'][ $repository_id ]['data']['packages'] = $ordered_packages;
2481 }
2482 }
2483 }
2484
2485 public function compare_package_order( $a, $b ) {
2486 return $a['order'] - $b['order'];
2487 }
2488
2489 public function get_support_tag_by_name( $name, $repository ) {
2490 if ( is_array( $this->settings()['repositories'][ $repository ]['data']['support_tags'] ) ) {
2491 foreach ( $this->settings()['repositories'][ $repository ]['data']['support_tags'] as $support_tag ) {
2492 if ( $support_tag['name'] == $name ) {
2493 return $support_tag['url'];
2494 }
2495 }
2496 }
2497
2498 return false;
2499 }
2500
2501 private function get_plugin_finder() {
2502 if ( ! $this->plugin_finder ) {
2503 $this->plugin_finder = new OTGS_Installer_Plugin_Finder( new OTGS_Installer_Plugin_Factory(), $this->settings()['repositories'] );
2504 }
2505
2506 return $this->plugin_finder;
2507 }
2508
2509 private function clean_plugins_update_cache() {
2510 do_action( 'otgs_installer_clean_plugins_update_cache' );
2511 }
2512
2513 public function plugin_upgrade_custom_errors() {
2514 if ( isset( $_REQUEST['action'] ) ) {
2515 $action = isset( $_REQUEST['action'] ) ? sanitize_text_field( $_REQUEST['action'] ) : '';
2516
2517 if ( 'update-selected' == $action ) {
2518 global $plugins;
2519
2520 if ( isset( $plugins ) && is_array( $plugins ) ) {
2521 foreach ( $plugins as $k => $plugin ) {
2522 $plugin_repository = false;
2523
2524 $wp_plugin_slug = dirname( $plugin );
2525
2526 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
2527 foreach ( $repository['data']['packages'] as $package ) {
2528 foreach ( $package['products'] as $product ) {
2529 foreach ( $product['plugins'] as $plugin_slug ) {
2530 if ( $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ]['slug'] == $wp_plugin_slug ) {
2531 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
2532 $plugin_repository = $repository_id;
2533 $product_name = $repository['data']['product-name'];
2534 $plugin_name = $download['name'];
2535 $free_on_wporg = ! empty( $download['free-on-wporg'] ) && $download['channel'] == WP_Installer_Channels::CHANNEL_PRODUCTION;
2536 break;
2537 }
2538 }
2539 }
2540 }
2541 }
2542
2543 if ( $plugin_repository ) {
2544 static $sub_cache = array();
2545
2546 if ( empty( $sub_cache[ $plugin_repository ] ) ) {
2547 $subscription_data = false;
2548 $site_key = $this->get_repository_site_key( $plugin_repository );
2549
2550 if ( ! $site_key ) {
2551 list( $plugin_repository, $site_key ) = $this->match_product_in_external_repository( $plugin_repository, $wp_plugin_slug );
2552 }
2553
2554 if ( $site_key ) {
2555 try {
2556 $subscriptionManagerFactory = new SubscriptionManagerFactory( $this->get_settings() );
2557 $subscriptionManager = $subscriptionManagerFactory->create( $plugin_repository, $this->repositories[ $plugin_repository ]['api-url'] );
2558 list ( $subscription_data, $site_key_data ) = $subscriptionManager->fetch( $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION );
2559 } catch ( Exception $e ) {
2560 }
2561 }
2562
2563 $sub_cache[ $plugin_repository ]['site_key'] = $site_key;
2564 $sub_cache[ $plugin_repository ]['subscription_data'] = $subscription_data;
2565 } else {
2566 $site_key = $sub_cache[ $plugin_repository ]['site_key'];
2567 $subscription_data = $sub_cache[ $plugin_repository ]['subscription_data'];
2568 }
2569
2570 if ( ! $site_key && ( ! empty( $free_on_wporg ) || $this->should_fallback_under_wp_org_repo( $download, $site_key ) ) ) {
2571 continue;
2572 }
2573
2574 if ( empty( $site_key ) || empty( $subscription_data ) ) {
2575 $error_message = sprintf( __( "%s cannot update because your site's registration is not valid. Please %sregister %s%s again for this site first.", 'installer' ),
2576 '<strong>' . $plugin_name . '</strong>', '<a target="_top" href="' . $this->menu_url() . '&validate_repository=' . $plugin_repository .
2577 '#repository-' . $plugin_repository . '">', $product_name, '</a>' );
2578
2579 echo '<div class="updated error"><p>' . $error_message . '</p></div>';
2580
2581 unset( $plugins[ $k ] );
2582 }
2583 }
2584 }
2585 }
2586 }
2587
2588
2589 if ( 'upgrade-plugin' == $action || 'update-plugin' == $action ) {
2590 $plugin = isset( $_REQUEST['plugin'] ) ? trim( sanitize_text_field( $_REQUEST['plugin'] ) ) : '';
2591
2592 $wp_plugin_slug = dirname( $plugin );
2593
2594 $plugin_repository = false;
2595
2596 foreach ( $this->settings()['repositories'] as $repository_id => $repository ) {
2597 foreach ( $repository['data']['packages'] as $package ) {
2598 foreach ( $package['products'] as $product ) {
2599 foreach ( $product['plugins'] as $plugin_slug ) {
2600 $download = $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
2601
2602 if ( $download['slug'] == $wp_plugin_slug ) {
2603 $plugin_repository = $repository_id;
2604 $product_name = $repository['data']['product-name'];
2605 $plugin_name = $download['name'];
2606 $free_on_wporg = ! empty( $download['free-on-wporg'] ) && $download['channel'] == WP_Installer_Channels::CHANNEL_PRODUCTION;
2607 break;
2608 }
2609 }
2610 }
2611 }
2612 }
2613
2614 if ( $plugin_repository ) {
2615 $site_key = $this->get_repository_site_key( $plugin_repository );
2616
2617 if ( ! $site_key ) {
2618 list( $plugin_repository, $site_key ) = $this->match_product_in_external_repository( $plugin_repository, $wp_plugin_slug );
2619 }
2620
2621 if ( $site_key ) {
2622 try {
2623 $subscriptionManagerFactory = new SubscriptionManagerFactory( $this->get_settings() );
2624 $subscriptionManager = $subscriptionManagerFactory->create( $plugin_repository, $this->repositories[ $plugin_repository ]['api-url'] );
2625 list ( $subscription_data, $site_key_data ) = $subscriptionManager->fetch( $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION );
2626 } catch ( Exception $e ) {
2627 $subscription_data = false;
2628 }
2629 }
2630
2631 $no_subscription = empty( $site_key ) || empty( $subscription_data );
2632 $not_on_wporg = empty( $free_on_wporg ) && ! $this->should_fallback_under_wp_org_repo( $download, $site_key );
2633
2634 if ( $no_subscription && $not_on_wporg ) {
2635 $error_message = sprintf( __( "%s cannot update because your site's registration is not valid. Please %sregister %s%s again for this site first.", 'installer' ),
2636 '<strong>' . $plugin_name . '</strong>', '<a href="' . $this->menu_url() . '&validate_repository=' . $plugin_repository .
2637 '#repository-' . $plugin_repository . '">', $product_name, '</a>' );
2638
2639 if ( defined( 'DOING_AJAX' ) ) {
2640
2641 $status = array(
2642 'update' => 'plugin',
2643 'plugin' => $plugin,
2644 'slug' => sanitize_key( $_POST['slug'] ),
2645 'oldVersion' => '',
2646 'newVersion' => '',
2647 );
2648
2649 $status['errorCode'] = 'wp_installer_invalid_subscription';
2650 $status['error'] = $error_message;
2651
2652 wp_send_json_error( $status );
2653 } else {
2654 echo '<div class="updated error"><p>' . $error_message . '</p></div>';
2655
2656
2657 echo '<div class="wrap">';
2658 echo '<h2>' . __( 'Update Plugin', 'installer' ) . '</h2>';
2659 echo '<a href="' . admin_url( 'plugins.php' ) . '">' . __( 'Return to the plugins page', 'installer' ) . '</a>';
2660 echo '</div>';
2661 require_once( ABSPATH . 'wp-admin/admin-footer.php' );
2662 exit;
2663 }
2664 }
2665 }
2666 }
2667 }
2668 }
2669
2670 private function store_log( $url, $url_args, $component, $response ) {
2671 $log = new OTGS_Installer_Log();
2672 $log->set_request_url( $url )
2673 ->set_component( $component )
2674 ->set_response( $response )
2675 ->set_request_args( $url_args );
2676
2677 otgs_installer_get_logger_storage()->add( $log );
2678 }
2679
2680 public function get_api_debug() {
2681 return $this->api_debug;
2682 }
2683
2684 private function match_product_in_external_repository( $current_repository, $plugin_slug ) {
2685 foreach ( $this->get_repositories() as $repo => $repo_data ) {
2686 if ( $repo !== $current_repository ) {
2687 $plugin_finder = $this->get_plugin_finder();
2688 $plugin_obj = $plugin_finder->get_plugin( $plugin_slug, $repo );
2689
2690 if ( $plugin_obj ) {
2691 $site_key = $this->get_repository_site_key( $repo );
2692
2693 if ( $site_key ) {
2694 return array( $repo, $site_key );
2695 }
2696 }
2697 }
2698 }
2699
2700 return array( '', '' );
2701 }
2702
2703 private function isComplementaryWithWPMLSubscription( $name, $slug ) {
2704 return Collection::of( [ 'Toolset Types', 'Toolset Module Manager' ] )->contains( $name ) && $this->plugin_is_registered( 'wpml', $slug );
2705 }
2706
2707 private function isPluginAvailableInRepositoryDownloads( $repository_id, $plugin_slug ) {
2708 return $plugin_slug && isset( $this->settings()['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ] );
2709 }
2710
2711 private function has_any_preselected_plugins( array $downloads ) {
2712 return Collection::of( $downloads )->any( function ( $download ) {
2713 return $download['is_preselected_plugin'] === true;
2714 } );
2715 }
2716
2717 private function get_blog_package_index( $packages ) {
2718 return Collection::of( $packages )->firstIndex( function ( $package ) {
2719 return $package['id'] === 'multilingual-blog';
2720 } );
2721 }
2722
2723 private function get_wpml_package_index( $packages ) {
2724 return Collection::of( $packages )->firstIndex( function ( $package ) {
2725 return $package['id'] === 'wpml';
2726 } );
2727 }
2728 }
2729