mirror of https://github.com/vtrois/kratos
				
				
				
			
		
			
				
	
	
		
			295 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			295 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
<?php
 | 
						|
namespace YahnisElsts\PluginUpdateChecker\v5p2\Plugin;
 | 
						|
 | 
						|
if ( !class_exists('Ui', false) ):
 | 
						|
	/**
 | 
						|
	 * Additional UI elements for plugins.
 | 
						|
	 */
 | 
						|
	class Ui {
 | 
						|
		private $updateChecker;
 | 
						|
		private $manualCheckErrorTransient = '';
 | 
						|
 | 
						|
		/**
 | 
						|
		 * @param UpdateChecker $updateChecker
 | 
						|
		 */
 | 
						|
		public function __construct($updateChecker) {
 | 
						|
			$this->updateChecker = $updateChecker;
 | 
						|
			$this->manualCheckErrorTransient = $this->updateChecker->getUniqueName('manual_check_errors');
 | 
						|
 | 
						|
			add_action('admin_init', array($this, 'onAdminInit'));
 | 
						|
		}
 | 
						|
 | 
						|
		public function onAdminInit() {
 | 
						|
			if ( $this->updateChecker->userCanInstallUpdates() ) {
 | 
						|
				$this->handleManualCheck();
 | 
						|
 | 
						|
				add_filter('plugin_row_meta', array($this, 'addViewDetailsLink'), 10, 3);
 | 
						|
				add_filter('plugin_row_meta', array($this, 'addCheckForUpdatesLink'), 10, 2);
 | 
						|
				add_action('all_admin_notices', array($this, 'displayManualCheckResult'));
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/**
 | 
						|
		 * Add a "View Details" link to the plugin row in the "Plugins" page. By default,
 | 
						|
		 * the new link will appear before the "Visit plugin site" link (if present).
 | 
						|
		 *
 | 
						|
		 * You can change the link text by using the "puc_view_details_link-$slug" filter.
 | 
						|
		 * Returning an empty string from the filter will disable the link.
 | 
						|
		 *
 | 
						|
		 * You can change the position of the link using the
 | 
						|
		 * "puc_view_details_link_position-$slug" filter.
 | 
						|
		 * Returning 'before' or 'after' will place the link immediately before/after
 | 
						|
		 * the "Visit plugin site" link.
 | 
						|
		 * Returning 'append' places the link after any existing links at the time of the hook.
 | 
						|
		 * Returning 'replace' replaces the "Visit plugin site" link.
 | 
						|
		 * Returning anything else disables the link when there is a "Visit plugin site" link.
 | 
						|
		 *
 | 
						|
		 * If there is no "Visit plugin site" link 'append' is always used!
 | 
						|
		 *
 | 
						|
		 * @param array $pluginMeta Array of meta links.
 | 
						|
		 * @param string $pluginFile
 | 
						|
		 * @param array $pluginData Array of plugin header data.
 | 
						|
		 * @return array
 | 
						|
		 */
 | 
						|
		public function addViewDetailsLink($pluginMeta, $pluginFile, $pluginData = array()) {
 | 
						|
			if ( $this->isMyPluginFile($pluginFile) && !isset($pluginData['slug']) ) {
 | 
						|
				$linkText = apply_filters($this->updateChecker->getUniqueName('view_details_link'), __('View details'));
 | 
						|
				if ( !empty($linkText) ) {
 | 
						|
					$viewDetailsLinkPosition = 'append';
 | 
						|
 | 
						|
					//Find the "Visit plugin site" link (if present).
 | 
						|
					$visitPluginSiteLinkIndex = count($pluginMeta) - 1;
 | 
						|
					if ( $pluginData['PluginURI'] ) {
 | 
						|
						$escapedPluginUri = esc_url($pluginData['PluginURI']);
 | 
						|
						foreach ($pluginMeta as $linkIndex => $existingLink) {
 | 
						|
							if ( strpos($existingLink, $escapedPluginUri) !== false ) {
 | 
						|
								$visitPluginSiteLinkIndex = $linkIndex;
 | 
						|
								$viewDetailsLinkPosition = apply_filters(
 | 
						|
									$this->updateChecker->getUniqueName('view_details_link_position'),
 | 
						|
									'before'
 | 
						|
								);
 | 
						|
								break;
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					$viewDetailsLink = sprintf('<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
 | 
						|
						esc_url(network_admin_url('plugin-install.php?tab=plugin-information&plugin=' . urlencode($this->updateChecker->slug) .
 | 
						|
							'&TB_iframe=true&width=600&height=550')),
 | 
						|
						esc_attr(sprintf(__('More information about %s'), $pluginData['Name'])),
 | 
						|
						esc_attr($pluginData['Name']),
 | 
						|
						$linkText
 | 
						|
					);
 | 
						|
					switch ($viewDetailsLinkPosition) {
 | 
						|
						case 'before':
 | 
						|
							array_splice($pluginMeta, $visitPluginSiteLinkIndex, 0, $viewDetailsLink);
 | 
						|
							break;
 | 
						|
						case 'after':
 | 
						|
							array_splice($pluginMeta, $visitPluginSiteLinkIndex + 1, 0, $viewDetailsLink);
 | 
						|
							break;
 | 
						|
						case 'replace':
 | 
						|
							$pluginMeta[$visitPluginSiteLinkIndex] = $viewDetailsLink;
 | 
						|
							break;
 | 
						|
						case 'append':
 | 
						|
						default:
 | 
						|
							$pluginMeta[] = $viewDetailsLink;
 | 
						|
							break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return $pluginMeta;
 | 
						|
		}
 | 
						|
 | 
						|
		/**
 | 
						|
		 * Add a "Check for updates" link to the plugin row in the "Plugins" page. By default,
 | 
						|
		 * the new link will appear after the "Visit plugin site" link if present, otherwise
 | 
						|
		 * after the "View plugin details" link.
 | 
						|
		 *
 | 
						|
		 * You can change the link text by using the "puc_manual_check_link-$slug" filter.
 | 
						|
		 * Returning an empty string from the filter will disable the link.
 | 
						|
		 *
 | 
						|
		 * @param array $pluginMeta Array of meta links.
 | 
						|
		 * @param string $pluginFile
 | 
						|
		 * @return array
 | 
						|
		 */
 | 
						|
		public function addCheckForUpdatesLink($pluginMeta, $pluginFile) {
 | 
						|
			if ( $this->isMyPluginFile($pluginFile) ) {
 | 
						|
				$linkUrl = wp_nonce_url(
 | 
						|
					add_query_arg(
 | 
						|
						array(
 | 
						|
							'puc_check_for_updates' => 1,
 | 
						|
							'puc_slug'              => $this->updateChecker->slug,
 | 
						|
						),
 | 
						|
						self_admin_url('plugins.php')
 | 
						|
					),
 | 
						|
					'puc_check_for_updates'
 | 
						|
				);
 | 
						|
 | 
						|
				$linkText = apply_filters(
 | 
						|
					$this->updateChecker->getUniqueName('manual_check_link'),
 | 
						|
					__('Check for updates', 'plugin-update-checker')
 | 
						|
				);
 | 
						|
				if ( !empty($linkText) ) {
 | 
						|
					/** @noinspection HtmlUnknownTarget */
 | 
						|
					$pluginMeta[] = sprintf('<a href="%s">%s</a>', esc_attr($linkUrl), $linkText);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return $pluginMeta;
 | 
						|
		}
 | 
						|
 | 
						|
		protected function isMyPluginFile($pluginFile) {
 | 
						|
			return ($pluginFile == $this->updateChecker->pluginFile)
 | 
						|
				|| (!empty($this->updateChecker->muPluginFile) && ($pluginFile == $this->updateChecker->muPluginFile));
 | 
						|
		}
 | 
						|
 | 
						|
		/**
 | 
						|
		 * Check for updates when the user clicks the "Check for updates" link.
 | 
						|
		 *
 | 
						|
		 * @see self::addCheckForUpdatesLink()
 | 
						|
		 *
 | 
						|
		 * @return void
 | 
						|
		 */
 | 
						|
		public function handleManualCheck() {
 | 
						|
			$shouldCheck =
 | 
						|
				isset($_GET['puc_check_for_updates'], $_GET['puc_slug'])
 | 
						|
				&& $_GET['puc_slug'] == $this->updateChecker->slug
 | 
						|
				&& check_admin_referer('puc_check_for_updates');
 | 
						|
 | 
						|
			if ( $shouldCheck ) {
 | 
						|
				$update = $this->updateChecker->checkForUpdates();
 | 
						|
				$status = ($update === null) ? 'no_update' : 'update_available';
 | 
						|
				$lastRequestApiErrors = $this->updateChecker->getLastRequestApiErrors();
 | 
						|
 | 
						|
				if ( ($update === null) && !empty($lastRequestApiErrors) ) {
 | 
						|
					//Some errors are not critical. For example, if PUC tries to retrieve the readme.txt
 | 
						|
					//file from GitHub and gets a 404, that's an API error, but it doesn't prevent updates
 | 
						|
					//from working. Maybe the plugin simply doesn't have a readme.
 | 
						|
					//Let's only show important errors.
 | 
						|
					$foundCriticalErrors = false;
 | 
						|
					$questionableErrorCodes = array(
 | 
						|
						'puc-github-http-error',
 | 
						|
						'puc-gitlab-http-error',
 | 
						|
						'puc-bitbucket-http-error',
 | 
						|
					);
 | 
						|
 | 
						|
					foreach ($lastRequestApiErrors as $item) {
 | 
						|
						$wpError = $item['error'];
 | 
						|
						/** @var \WP_Error $wpError */
 | 
						|
						if ( !in_array($wpError->get_error_code(), $questionableErrorCodes) ) {
 | 
						|
							$foundCriticalErrors = true;
 | 
						|
							break;
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					if ( $foundCriticalErrors ) {
 | 
						|
						$status = 'error';
 | 
						|
						set_site_transient($this->manualCheckErrorTransient, $lastRequestApiErrors, 60);
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				wp_redirect(add_query_arg(
 | 
						|
					array(
 | 
						|
						'puc_update_check_result' => $status,
 | 
						|
						'puc_slug'                => $this->updateChecker->slug,
 | 
						|
					),
 | 
						|
					self_admin_url('plugins.php')
 | 
						|
				));
 | 
						|
				exit;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/**
 | 
						|
		 * Display the results of a manual update check.
 | 
						|
		 *
 | 
						|
		 * @see self::handleManualCheck()
 | 
						|
		 *
 | 
						|
		 * You can change the result message by using the "puc_manual_check_message-$slug" filter.
 | 
						|
		 */
 | 
						|
		public function displayManualCheckResult() {
 | 
						|
			//phpcs:disable WordPress.Security.NonceVerification.Recommended -- Just displaying a message.
 | 
						|
			if ( isset($_GET['puc_update_check_result'], $_GET['puc_slug']) && ($_GET['puc_slug'] == $this->updateChecker->slug) ) {
 | 
						|
				$status = sanitize_key($_GET['puc_update_check_result']);
 | 
						|
				$title = $this->updateChecker->getInstalledPackage()->getPluginTitle();
 | 
						|
				$noticeClass = 'updated notice-success';
 | 
						|
				$details = '';
 | 
						|
 | 
						|
				if ( $status == 'no_update' ) {
 | 
						|
					$message = sprintf(_x('The %s plugin is up to date.', 'the plugin title', 'plugin-update-checker'), $title);
 | 
						|
				} else if ( $status == 'update_available' ) {
 | 
						|
					$message = sprintf(_x('A new version of the %s plugin is available.', 'the plugin title', 'plugin-update-checker'), $title);
 | 
						|
				} else if ( $status === 'error' ) {
 | 
						|
					$message = sprintf(_x('Could not determine if updates are available for %s.', 'the plugin title', 'plugin-update-checker'), $title);
 | 
						|
					$noticeClass = 'error notice-error';
 | 
						|
 | 
						|
					$details = $this->formatManualCheckErrors(get_site_transient($this->manualCheckErrorTransient));
 | 
						|
					delete_site_transient($this->manualCheckErrorTransient);
 | 
						|
				} else {
 | 
						|
					$message = sprintf(__('Unknown update checker status "%s"', 'plugin-update-checker'), $status);
 | 
						|
					$noticeClass = 'error notice-error';
 | 
						|
				}
 | 
						|
 | 
						|
				$message = esc_html($message);
 | 
						|
 | 
						|
				//Plugins can replace the message with their own, including adding HTML.
 | 
						|
				$message = apply_filters(
 | 
						|
					$this->updateChecker->getUniqueName('manual_check_message'),
 | 
						|
					$message,
 | 
						|
					$status
 | 
						|
				);
 | 
						|
 | 
						|
				printf(
 | 
						|
					'<div class="notice %s is-dismissible"><p>%s</p>%s</div>',
 | 
						|
					esc_attr($noticeClass),
 | 
						|
					//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Was escaped above, and plugins can add HTML.
 | 
						|
					$message,
 | 
						|
					//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Contains HTML. Content should already be escaped.
 | 
						|
					$details
 | 
						|
				);
 | 
						|
			}
 | 
						|
			//phpcs:enable
 | 
						|
		}
 | 
						|
 | 
						|
		/**
 | 
						|
		 * Format the list of errors that were thrown during an update check.
 | 
						|
		 *
 | 
						|
		 * @param array $errors
 | 
						|
		 * @return string
 | 
						|
		 */
 | 
						|
		protected function formatManualCheckErrors($errors) {
 | 
						|
			if ( empty($errors) ) {
 | 
						|
				return '';
 | 
						|
			}
 | 
						|
			$output = '';
 | 
						|
 | 
						|
			$showAsList = count($errors) > 1;
 | 
						|
			if ( $showAsList ) {
 | 
						|
				$output .= '<ol>';
 | 
						|
				$formatString = '<li>%1$s <code>%2$s</code></li>';
 | 
						|
			} else {
 | 
						|
				$formatString = '<p>%1$s <code>%2$s</code></p>';
 | 
						|
			}
 | 
						|
			foreach ($errors as $item) {
 | 
						|
				$wpError = $item['error'];
 | 
						|
				/** @var \WP_Error $wpError */
 | 
						|
				$output .= sprintf(
 | 
						|
					$formatString,
 | 
						|
					esc_html($wpError->get_error_message()),
 | 
						|
					esc_html($wpError->get_error_code())
 | 
						|
				);
 | 
						|
			}
 | 
						|
			if ( $showAsList ) {
 | 
						|
				$output .= '</ol>';
 | 
						|
			}
 | 
						|
 | 
						|
			return $output;
 | 
						|
		}
 | 
						|
 | 
						|
		public function removeHooks() {
 | 
						|
			remove_action('admin_init', array($this, 'onAdminInit'));
 | 
						|
			remove_filter('plugin_row_meta', array($this, 'addViewDetailsLink'), 10);
 | 
						|
			remove_filter('plugin_row_meta', array($this, 'addCheckForUpdatesLink'), 10);
 | 
						|
			remove_action('all_admin_notices', array($this, 'displayManualCheckResult'));
 | 
						|
		}
 | 
						|
	}
 | 
						|
endif;
 |