536 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			536 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Plugin Name: Easy Digital Downloads
 | |
|  * Plugin URI: https://easydigitaldownloads.com
 | |
|  * Description: The easiest way to sell digital products with WordPress.
 | |
|  * Author: Easy Digital Downloads
 | |
|  * Author URI: https://easydigitaldownloads.com
 | |
|  * Version: 3.1.0.3
 | |
|  * Text Domain: easy-digital-downloads
 | |
|  * Domain Path: languages
 | |
|  * Requires PHP: 5.6
 | |
|  *
 | |
|  * Easy Digital Downloads is free software: you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation, either version 2 of the License, or
 | |
|  * any later version.
 | |
|  *
 | |
|  * Easy Digital Downloads is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with Easy Digital Downloads. If not, see <http://www.gnu.org/licenses/>.
 | |
|  *
 | |
|  * @package EDD
 | |
|  * @category Core
 | |
|  * @author Easy Digital Downloads
 | |
|  * @version 3.1.0.3
 | |
|  */
 | |
| 
 | |
| // Exit if accessed directly.
 | |
| defined( 'ABSPATH' ) || exit;
 | |
| 
 | |
| /**
 | |
|  * The main plugin requirements checker
 | |
|  *
 | |
|  * @since 3.0
 | |
|  */
 | |
| final class EDD_Requirements_Check {
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin file
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @var string
 | |
| 	 */
 | |
| 	private $file = '';
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin basename
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @var string
 | |
| 	 */
 | |
| 	private $base = '';
 | |
| 
 | |
| 	/**
 | |
| 	 * Requirements array
 | |
| 	 *
 | |
| 	 * @todo Extend WP_Dependencies
 | |
| 	 * @var array
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	private $requirements = array(
 | |
| 
 | |
| 		// PHP
 | |
| 		'php' => array(
 | |
| 			'minimum' => '5.6',
 | |
| 			'name'    => 'PHP',
 | |
| 			'exists'  => true,
 | |
| 			'current' => false,
 | |
| 			'checked' => false,
 | |
| 			'met'     => false
 | |
| 		),
 | |
| 
 | |
| 		// WordPress
 | |
| 		'wp' => array(
 | |
| 			'minimum' => '4.9.0',
 | |
| 			'name'    => 'WordPress',
 | |
| 			'exists'  => true,
 | |
| 			'current' => false,
 | |
| 			'checked' => false,
 | |
| 			'met'     => false
 | |
| 		)
 | |
| 	);
 | |
| 
 | |
| 	/**
 | |
| 	 * Setup plugin requirements
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	public function __construct() {
 | |
| 
 | |
| 		// Setup file & base
 | |
| 		$this->file = __FILE__;
 | |
| 		$this->base = plugin_basename( $this->file );
 | |
| 
 | |
| 		// Always load translations
 | |
| 		add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
 | |
| 
 | |
| 		// Load or quit
 | |
| 		$this->met()
 | |
| 			? $this->load()
 | |
| 			: $this->quit();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Quit without loading
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	private function quit() {
 | |
| 		add_action( 'admin_head',                        array( $this, 'admin_head'        ) );
 | |
| 		add_filter( "plugin_action_links_{$this->base}", array( $this, 'plugin_row_links'  ) );
 | |
| 		add_action( "after_plugin_row_{$this->base}",    array( $this, 'plugin_row_notice' ) );
 | |
| 	}
 | |
| 
 | |
| 	/** Specific Methods ******************************************************/
 | |
| 
 | |
| 	/**
 | |
| 	 * Load normally
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	private function load() {
 | |
| 
 | |
| 		// Maybe include the bundled bootstrapper
 | |
| 		if ( ! class_exists( 'Easy_Digital_Downloads' ) ) {
 | |
| 			require_once dirname( $this->file ) . '/includes/class-easy-digital-downloads.php';
 | |
| 		}
 | |
| 
 | |
| 		// Maybe hook-in the bootstrapper
 | |
| 		if ( class_exists( 'Easy_Digital_Downloads' ) ) {
 | |
| 
 | |
| 			// Bootstrap to plugins_loaded before priority 10 to make sure
 | |
| 			// add-ons are loaded after us.
 | |
| 			add_action( 'plugins_loaded', array( $this, 'bootstrap' ), 4 );
 | |
| 
 | |
| 			// Register the activation hook
 | |
| 			register_activation_hook( $this->file, array( $this, 'install' ) );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Install, usually on an activation hook.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	public function install() {
 | |
| 
 | |
| 		// Bootstrap to include all of the necessary files
 | |
| 		$this->bootstrap();
 | |
| 
 | |
| 		// Network wide?
 | |
| 		$network_wide = ! empty( $_GET['networkwide'] )
 | |
| 			? (bool) $_GET['networkwide']
 | |
| 			: false;
 | |
| 
 | |
| 		// Call the installer directly during the activation hook
 | |
| 		edd_install( $network_wide );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Bootstrap everything.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	public function bootstrap() {
 | |
| 		Easy_Digital_Downloads::instance( $this->file );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific URL for an external requirements page.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_url() {
 | |
| 		return 'https://easydigitaldownloads.com/recommended-wordpress-hosting/';
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific text to quickly explain what's wrong.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_text() {
 | |
| 		esc_html_e( 'This plugin is not fully active.', 'easy-digital-downloads' );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific text to describe a single unmet requirement.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_description_text() {
 | |
| 		return esc_html__( 'Requires %s (%s), but (%s) is installed.', 'easy-digital-downloads' );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific text to describe a single missing requirement.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_missing_text() {
 | |
| 		return esc_html__( 'Requires %s (%s), but it appears to be missing.', 'easy-digital-downloads' );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific text used to link to an external requirements page.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_link() {
 | |
| 		return esc_html__( 'Requirements', 'easy-digital-downloads' );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific aria label text to describe the requirements link.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_label() {
 | |
| 		return esc_html__( 'Easy Digital Download Requirements', 'easy-digital-downloads' );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific text used in CSS to identify attribute IDs and classes.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function unmet_requirements_name() {
 | |
| 		return 'edd-requirements';
 | |
| 	}
 | |
| 
 | |
| 	/** Agnostic Methods ******************************************************/
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin agnostic method to output the additional plugin row
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	public function plugin_row_notice() {
 | |
| 		// wp_is_auto_update_enabled_for_type was introduced in WordPress 5.5.
 | |
| 		$colspan = function_exists( 'wp_is_auto_update_enabled_for_type' ) && wp_is_auto_update_enabled_for_type( 'plugin' ) ? 2 : 1;
 | |
| 		?>
 | |
| 		<tr class="active <?php echo esc_attr( $this->unmet_requirements_name() ); ?>-row">
 | |
| 			<th class="check-column">
 | |
| 				<span class="dashicons dashicons-warning"></span>
 | |
| 			</th>
 | |
| 			<td class="column-primary">
 | |
| 				<?php $this->unmet_requirements_text(); ?>
 | |
| 			</td>
 | |
| 			<td class="column-description" colspan="<?php echo esc_attr( $colspan ); ?>">
 | |
| 				<?php $this->unmet_requirements_description(); ?>
 | |
| 			</td>
 | |
| 		</tr>
 | |
| 		<?php
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin agnostic method used to output all unmet requirement information
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	private function unmet_requirements_description() {
 | |
| 		foreach ( $this->requirements as $properties ) {
 | |
| 			if ( empty( $properties['met'] ) ) {
 | |
| 				$this->unmet_requirement_description( $properties );
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin agnostic method to output specific unmet requirement information
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @param array $requirement
 | |
| 	 */
 | |
| 	private function unmet_requirement_description( $requirement = array() ) {
 | |
| 
 | |
| 		// Requirement exists, but is out of date
 | |
| 		if ( ! empty( $requirement['exists'] ) ) {
 | |
| 			$text = sprintf(
 | |
| 				$this->unmet_requirements_description_text(),
 | |
| 				'<strong>' . esc_html( $requirement['name']    ) . '</strong>',
 | |
| 				'<strong>' . esc_html( $requirement['minimum'] ) . '</strong>',
 | |
| 				'<strong>' . esc_html( $requirement['current'] ) . '</strong>'
 | |
| 			);
 | |
| 
 | |
| 			// Requirement could not be found
 | |
| 		} else {
 | |
| 			$text = sprintf(
 | |
| 				$this->unmet_requirements_missing_text(),
 | |
| 				'<strong>' . esc_html( $requirement['name']    ) . '</strong>',
 | |
| 				'<strong>' . esc_html( $requirement['minimum'] ) . '</strong>'
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		// Output the description
 | |
| 		echo '<p>' . $text . '</p>';
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin agnostic method to output unmet requirements styling
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	public function admin_head() {
 | |
| 
 | |
| 		// Get the requirements row name
 | |
| 		$name = $this->unmet_requirements_name(); ?>
 | |
| 
 | |
| 		<style id="<?php echo esc_attr( $name ); ?>">
 | |
| 			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] th,
 | |
| 			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] td,
 | |
| 			.plugins .<?php echo esc_html( $name ); ?>-row th,
 | |
| 			.plugins .<?php echo esc_html( $name ); ?>-row td {
 | |
| 				background: #fff5f5;
 | |
| 			}
 | |
| 			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] th {
 | |
| 				box-shadow: none;
 | |
| 			}
 | |
| 			.plugins .<?php echo esc_html( $name ); ?>-row th span {
 | |
| 				margin-left: 6px;
 | |
| 				color: #dc3232;
 | |
| 			}
 | |
| 			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] th,
 | |
| 			.plugins .<?php echo esc_html( $name ); ?>-row th.check-column {
 | |
| 				border-left: 4px solid #dc3232 !important;
 | |
| 			}
 | |
| 			.plugins .<?php echo esc_html( $name ); ?>-row .column-description p {
 | |
| 				margin: 0;
 | |
| 				padding: 0;
 | |
| 			}
 | |
| 			.plugins .<?php echo esc_html( $name ); ?>-row .column-description p:not(:last-of-type) {
 | |
| 				margin-bottom: 8px;
 | |
| 			}
 | |
| 		</style>
 | |
| 		<?php
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin agnostic method to add the "Requirements" link to row actions
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 * @param array $links
 | |
| 	 * @return array
 | |
| 	 */
 | |
| 	public function plugin_row_links( $links = array() ) {
 | |
| 
 | |
| 		// Add the Requirements link
 | |
| 		$links['requirements'] =
 | |
| 			'<a href="' . esc_url( $this->unmet_requirements_url() ) . '" aria-label="' . esc_attr( $this->unmet_requirements_label() ) . '">'
 | |
| 			. esc_html( $this->unmet_requirements_link() )
 | |
| 			. '</a>';
 | |
| 
 | |
| 		// Return links with Requirements link
 | |
| 		return $links;
 | |
| 	}
 | |
| 
 | |
| 	/** Checkers **************************************************************/
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific requirements checker
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 */
 | |
| 	private function check() {
 | |
| 
 | |
| 		// Loop through requirements
 | |
| 		foreach ( $this->requirements as $dependency => $properties ) {
 | |
| 
 | |
| 			// Which dependency are we checking?
 | |
| 			switch ( $dependency ) {
 | |
| 
 | |
| 				// PHP
 | |
| 				case 'php' :
 | |
| 					$version = phpversion();
 | |
| 					break;
 | |
| 
 | |
| 				// WP
 | |
| 				case 'wp' :
 | |
| 					$version = get_bloginfo( 'version' );
 | |
| 					break;
 | |
| 
 | |
| 				// Unknown
 | |
| 				default :
 | |
| 					$version = false;
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			// Merge to original array
 | |
| 			if ( ! empty( $version ) ) {
 | |
| 				$this->requirements[ $dependency ] = array_merge( $this->requirements[ $dependency ], array(
 | |
| 					'current' => $version,
 | |
| 					'checked' => true,
 | |
| 					'met'     => version_compare( $version, $properties['minimum'], '>=' )
 | |
| 				) );
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Have all requirements been met?
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 *
 | |
| 	 * @return boolean
 | |
| 	 */
 | |
| 	public function met() {
 | |
| 
 | |
| 		// Run the check
 | |
| 		$this->check();
 | |
| 
 | |
| 		// Default to true (any false below wins)
 | |
| 		$retval  = true;
 | |
| 		$to_meet = wp_list_pluck( $this->requirements, 'met' );
 | |
| 
 | |
| 		// Look for unmet dependencies, and exit if so
 | |
| 		foreach ( $to_meet as $met ) {
 | |
| 			if ( empty( $met ) ) {
 | |
| 				$retval = false;
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Return
 | |
| 		return $retval;
 | |
| 	}
 | |
| 
 | |
| 	/** Translations **********************************************************/
 | |
| 
 | |
| 	/**
 | |
| 	 * Plugin specific text-domain loader.
 | |
| 	 *
 | |
| 	 * @since 1.4
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	public function load_textdomain() {
 | |
| 
 | |
| 		/*
 | |
| 		 * Due to the introduction of language packs through translate.wordpress.org,
 | |
| 		 * loading our textdomain is complex.
 | |
| 		 *
 | |
| 		 * In v2.4.6, our textdomain changed from "edd" to "easy-digital-downloads".
 | |
| 		 *
 | |
| 		 * To support existing translation files from before the change, we must
 | |
| 		 * look for translation files in several places and under several names.
 | |
| 		 *
 | |
| 		 * - wp-content/languages/plugins/easy-digital-downloads (introduced with language packs)
 | |
| 		 * - wp-content/languages/edd/ (custom folder we have supported since 1.4)
 | |
| 		 * - wp-content/plugins/easy-digital-downloads/languages/
 | |
| 		 *
 | |
| 		 * In wp-content/languages/edd/ we must look for:
 | |
| 		 * - "easy-digital-downloads-{lang}_{country}.mo"
 | |
| 		 *
 | |
| 		 * In wp-content/languages/edd/ we must look for:
 | |
| 		 * - "edd-{lang}_{country}.mo" as that was the old file naming convention
 | |
| 		 *
 | |
| 		 * In wp-content/languages/plugins/easy-digital-downloads/ we only need to look for:
 | |
| 		 * - "easy-digital-downloads-{lang}_{country}.mo" as that is the new structure
 | |
| 		 *
 | |
| 		 * In wp-content/plugins/easy-digital-downloads/languages/, we must look for:
 | |
| 		 * - both naming conventions. This is done by filtering "load_textdomain_mofile"
 | |
| 		 */
 | |
| 		add_filter( 'load_textdomain_mofile', array( $this, 'load_old_textdomain' ), 10, 2 );
 | |
| 
 | |
| 		// Set filter for plugin's languages directory.
 | |
| 		$edd_lang_dir = dirname( $this->base ) . '/languages/';
 | |
| 		$edd_lang_dir = apply_filters( 'edd_languages_directory', $edd_lang_dir );
 | |
| 
 | |
| 		unload_textdomain( 'easy-digital-downloads' );
 | |
| 
 | |
| 		/**
 | |
| 		 * Defines the plugin language locale used in Easy Digital Downloads.
 | |
| 		 *
 | |
| 		 * @var $get_locale The locale to use.
 | |
| 		 */
 | |
| 		$locale = apply_filters( 'plugin_locale', get_user_locale(), 'easy-digital-downloads' );
 | |
| 		$mofile = sprintf( '%1$s-%2$s.mo', 'easy-digital-downloads', $locale );
 | |
| 
 | |
| 		// Look for wp-content/languages/edd/easy-digital-downloads-{lang}_{country}.mo
 | |
| 		$mofile_global1 = WP_LANG_DIR . "/edd/easy-digital-downloads-{$locale}.mo";
 | |
| 
 | |
| 		// Look for wp-content/languages/edd/edd-{lang}_{country}.mo
 | |
| 		$mofile_global2 = WP_LANG_DIR . "/edd/edd-{$locale}.mo";
 | |
| 
 | |
| 		// Look in wp-content/languages/plugins/easy-digital-downloads
 | |
| 		$mofile_global3 = WP_LANG_DIR . "/plugins/easy-digital-downloads/{$mofile}";
 | |
| 
 | |
| 		// Try to load from first global location
 | |
| 		if ( file_exists( $mofile_global1 ) ) {
 | |
| 			load_textdomain( 'easy-digital-downloads', $mofile_global1 );
 | |
| 
 | |
| 			// Try to load from next global location
 | |
| 		} elseif ( file_exists( $mofile_global2 ) ) {
 | |
| 			load_textdomain( 'easy-digital-downloads', $mofile_global2 );
 | |
| 
 | |
| 			// Try to load from next global location
 | |
| 		} elseif ( file_exists( $mofile_global3 ) ) {
 | |
| 			load_textdomain( 'easy-digital-downloads', $mofile_global3 );
 | |
| 
 | |
| 			// Load the default language files
 | |
| 		} else {
 | |
| 			load_plugin_textdomain( 'easy-digital-downloads', false, $edd_lang_dir );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Load a .mo file for the old textdomain if one exists.
 | |
| 	 *
 | |
| 	 * @see https://github.com/10up/grunt-wp-plugin/issues/21#issuecomment-62003284
 | |
| 	 */
 | |
| 	public function load_old_textdomain( $mofile, $textdomain ) {
 | |
| 
 | |
| 		// Fallback for old text domain
 | |
| 		if ( ( 'easy-digital-downloads' === $textdomain ) && ! file_exists( $mofile ) ) {
 | |
| 			$mofile = dirname( $mofile ) . DIRECTORY_SEPARATOR . str_replace( $textdomain, 'edd', basename( $mofile ) );
 | |
| 		}
 | |
| 
 | |
| 		// Return (possibly overridden) mofile
 | |
| 		return $mofile;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Invoke the checker
 | |
| new EDD_Requirements_Check();
 |