skyverge/wc-plugin-framework

View on GitHub
woocommerce/class-sv-wc-plugin-dependencies.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/**
 * WooCommerce Plugin Framework
 *
 * This source file is subject to the GNU General Public License v3.0
 * that is bundled with this package in the file license.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@skyverge.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade the plugin to newer
 * versions in the future. If you wish to customize the plugin for your
 * needs please refer to http://www.skyverge.com
 *
 * @package   SkyVerge/WooCommerce/Plugin/Classes
 * @author    SkyVerge
 * @copyright Copyright (c) 2013-2024, SkyVerge, Inc.
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
 */

namespace SkyVerge\WooCommerce\PluginFramework\v5_12_3;

defined( 'ABSPATH' ) or exit;

if ( ! class_exists( '\\SkyVerge\\WooCommerce\\PluginFramework\\v5_12_3\\SV_WC_Plugin_Dependencies' ) ) :


/**
 * Plugin dependencies handler.
 *
 * @since 5.2.0
 */
#[\AllowDynamicProperties]
class SV_WC_Plugin_Dependencies {


    /** @var array required PHP extensions */
    protected $php_extensions = array();

    /** @var array required PHP functions */
    protected $php_functions = array();

    /** @var array required PHP settings */
    protected $php_settings = array();

    /** @var SV_WC_Plugin plugin instance */
    protected $plugin;


    /**
     * Constructs the class.
     *
     * @since 5.2.0
     *
     * @param SV_WC_Plugin $plugin plugin instance
     * @param array $args {
     *     PHP extension, function, and settings dependencies
     *
     *     @type array $php_extensions PHP extension dependencies
     *     @type array $php_functions  PHP function dependencies
     *     @type array $php_settings   PHP settings dependencies
     * }
     */
    public function __construct( SV_WC_Plugin $plugin, $args = array() ) {

        $this->plugin = $plugin;

        $dependencies = $this->parse_dependencies( $args );

        $this->php_extensions = (array) $dependencies['php_extensions'];
        $this->php_functions  = (array) $dependencies['php_functions'];
        $this->php_settings   = (array) $dependencies['php_settings'];

        // add the action & filter hooks
        $this->add_hooks();
    }


    /**
     * Parses the dependency arguments and sets defaults.
     *
     * @since 5.2.0
     *
     * @param array $args dependency args
     * @return array
     */
    private function parse_dependencies( $args ) {

        $dependencies = wp_parse_args( $args, array(
            'php_extensions' => array(),
            'php_functions'  => array(),
            'php_settings'   => array(),
        ) );

        $default_settings = array(
            'suhosin.post.max_array_index_length'    => 256,
            'suhosin.post.max_totalname_length'      => 65535,
            'suhosin.post.max_vars'                  => 1024,
            'suhosin.request.max_array_index_length' => 256,
            'suhosin.request.max_totalname_length'   => 65535,
            'suhosin.request.max_vars'               => 1024,
        );

        // override any default settings requirements if the plugin specifies them
        if ( ! empty( $dependencies['php_settings'] ) ) {
            $dependencies['php_settings'] = array_merge( $default_settings, $dependencies['php_settings'] );
        }

        return $dependencies;
    }


    /**
     * Adds the action & filter hooks.
     *
     * @since 5.2.0
     */
    protected function add_hooks() {

        // add the admin dependency notices
        add_action( 'admin_init', array( $this, 'add_admin_notices' ) );
    }


    /**
     * Adds the admin dependency notices.
     *
     * @since 5.2.0
     */
    public function add_admin_notices() {

        $this->add_php_extension_notices();
        $this->add_php_function_notices();
        $this->add_php_settings_notices();

        $this->add_deprecated_notices();
    }


    /**
     * Adds notices for any missing PHP extensions.
     *
     * @since 5.2.0
     */
    public function add_php_extension_notices() {

        $missing_extensions = $this->get_missing_php_extensions();

        if ( count( $missing_extensions ) > 0 ) {

            $message = sprintf(
                /* translators: Placeholders: %1$s - plugin name, %2$s - a PHP extension/comma-separated list of PHP extensions */
                _n(
                    '%1$s requires the %2$s PHP extension to function. Contact your host or server administrator to install and configure the missing extension.',
                    '%1$s requires the following PHP extensions to function: %2$s. Contact your host or server administrator to install and configure the missing extensions.',
                    count( $missing_extensions ),
                    'woocommerce-plugin-framework'
                ),
                esc_html( $this->get_plugin()->get_plugin_name() ),
                '<strong>' . implode( ', ', $missing_extensions ) . '</strong>'
            );

            $this->add_admin_notice( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-missing-extensions', $message, 'error' );
        }
    }


    /**
     * Adds notices for any missing PHP functions.
     *
     * @since 5.2.0
     */
    public function add_php_function_notices() {

        $missing_functions = $this->get_missing_php_functions();

        if ( count( $missing_functions ) > 0 ) {

            $message = sprintf(
                /* translators: Placeholders: %1$s - plugin name, %2$s - a PHP function/comma-separated list of PHP functions */
                _n(
                    '%1$s requires the %2$s PHP function to exist.  Contact your host or server administrator to install and configure the missing function.',
                    '%1$s requires the following PHP functions to exist: %2$s.  Contact your host or server administrator to install and configure the missing functions.',
                    count( $missing_functions ),
                    'woocommerce-plugin-framework'
                ),
                esc_html( $this->get_plugin()->get_plugin_name() ),
                '<strong>' . implode( ', ', $missing_functions ) . '</strong>'
            );

            $this->add_admin_notice( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-missing-functions', $message, 'error' );
        }
    }


    /**
     * Adds notices for any incompatible PHP settings.
     *
     * @since 5.2.0
     */
    public function add_php_settings_notices() {

        if ( isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] ) {

            $bad_settings = $this->get_incompatible_php_settings();

            if ( count( $bad_settings ) > 0 ) {

                $message = sprintf(
                    /* translators: Placeholders: %s - plugin name */
                    __( '%s may behave unexpectedly because the following PHP configuration settings are required:' ),
                    '<strong>' . esc_html( $this->get_plugin()->get_plugin_name() ) . '</strong>'
                );

                $message .= '<ul>';

                    foreach ( $bad_settings as $setting => $values ) {

                        $setting_message = '<code>' . $setting . ' = ' . $values['expected'] . '</code>';

                        if ( ! empty( $values['type'] ) && 'min' === $values['type'] ) {

                            $setting_message = sprintf(
                                /* translators: Placeholder: %s - a PHP setting value */
                                __( '%s or higher', 'woocommerce-plugin-framework' ),
                                $setting_message
                            );
                        }

                        $message .= '<li>' . $setting_message . '</li>';
                    }

                $message .= '</ul>';

                $message .= __( 'Please contact your hosting provider or server administrator to configure these settings.', 'woocommerce-plugin-framework' );

                $this->add_admin_notice( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-incompatibile-php-settings', $message, 'warning' );
            }
        }
    }


    /**
     * Gets any deprecated warning notices.
     *
     * @since 5.2.0
     */
    protected function add_deprecated_notices() {

        // add a notice for PHP < 7.4
        if ( version_compare( PHP_VERSION, '7.4.0', '<' ) ) {

            $message = '<p>';

            // for translation purposes, it's easier to keep these strings separate to avoid many tabs and newlines in the compiled pot file
            $lines = [
                /* translators: Placeholders: %1$s - <strong> HTML tag, %2$s - </strong> HTML tag */
                sprintf( __( 'Hey there! We\'ve noticed that your server is running %1$san outdated version of PHP%2$s, which is the programming language that WooCommerce and its extensions are built on.', 'woocommerce-plugin-framework' ), '<strong>', '</strong>' ),
                /* translators: Placeholders: %1$s - <strong> HTML tag, %2$s - </strong> HTML tag */
                sprintf( __( 'The PHP version that is currently used for your site is no longer maintained, nor %1$sreceives security updates%2$s; newer versions are faster and more secure.', 'woocommerce-plugin-framework' ), '<strong>', '</strong>' ),
                /* translators: Context: User is running an outdated PHP Version a plugin is not compatible with. Placeholders: %s - the plugin name */
                sprintf( __( 'As a result, %s no longer supports this version and you should upgrade PHP as soon as possible.', 'woocommerce-plugin-framework' ), esc_html( $this->get_plugin()->get_plugin_name() ) ),
                /* translators: Context: The host can update PHP version for the user. Placeholders: %1$s - <a> HTML tag, %2$s - </a> HTML tag */
                sprintf( __( 'Your hosting provider can do this for you. %1$sHere are some resources to help you upgrade%2$s and to explain PHP versions further.', 'woocommerce-plugin-framework' ), '<a href="https://wordpress.org/support/update-php/">', '</a>' ),
            ];

            $message .= implode( '<br>', $lines);
            $message .= '</p>';

            $this->add_admin_notice( 'sv-wc-deprecated-php-version', $message, 'error' );
        }
    }


    /**
     * Adds an admin notice.
     *
     * @since 5.2.0
     *
     * @param string $id notice ID
     * @param string $message notice message
     * @param string $type notice type
     */
    protected function add_admin_notice( $id, $message, $type = 'info' ) {

        $notice_class = $type;

        // translate the types into WP notice classes
        switch ( $type ) {

            case 'error':
                $notice_class = 'notice-error';
            break;

            case 'warning':
                $notice_class = 'notice-warning';
            break;

            case 'info':
                $notice_class = 'notice-info';
            break;

            case 'success':
                $notice_class = 'notice-success';
            break;
        }

        $this->get_plugin()->get_admin_notice_handler()->add_admin_notice( $message, $id, array(
            'notice_class' => $notice_class,
        ) );
    }


    /**
     * Returns the active scripts optimization plugins.
     *
     * Returns a key-value array where the key contains the plugin file identifier and the value is the name of the plugin.
     *
     * @since 5.7.0
     *
     * @return array
     */
    public function get_active_scripts_optimization_plugins() {

        /**
         * Filters script optimization plugins to look for.
         *
         * @since 5.7.0
         *
         * @param array $plugins an array of file identifiers (keys) and plugin names (values)
         */
        $plugins = (array) apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_scripts_optimization_plugins', [
            'async-javascript.php' => 'Async JavaScript',
            'autoptimize.php'      => 'Autoptimize',
            'wp-hummingbird.php'   => 'Hummingbird',
            'sg-optimizer.php'     => 'SG Optimizer',
            'w3-total-cache.php'   => 'W3 Total Cache',
            'wpFastestCache.php'   => 'WP Fastest Cache',
            'wp-rocket.php'        => 'WP Rocket',
        ] );

        $active_plugins = [];

        foreach ( $plugins as $filename => $plugin_name ) {

            if ( $this->get_plugin()->is_plugin_active( $filename ) ) {

                $active_plugins[ $filename ] = $plugin_name;
            }
        }

        return $active_plugins;
    }


    /**
     * Returns true if any of the known scripts optimization plugins is active.
     *
     * @since 5.7.0
     *
     * @return bool
     */
    public function is_scripts_optimization_plugin_active() {

        return ! empty( $this->get_active_scripts_optimization_plugins() );
    }


    /** Getter methods ********************************************************/


    /**
     * Gets any missing PHP extensions.
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_missing_php_extensions() {

        $missing_extensions = [];

        foreach ( $this->get_php_extensions() as $extension ) {

            if ( ! extension_loaded( $extension ) ) {
                $missing_extensions[] = $extension;
            }
        }

        return $missing_extensions;
    }


    /**
     * Gets the required PHP extensions.
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_php_extensions() {

        return $this->php_extensions;
    }


    /**
     * Gets any missing PHP functions.
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_missing_php_functions() {

        $missing_functions = [];

        foreach ( $this->get_php_functions() as $function ) {

            if ( ! extension_loaded( $function ) ) {
                $missing_functions[] = $function;
            }
        }

        return $missing_functions;
    }


    /**
     * Gets the required PHP functions.
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_php_functions() {

        return $this->php_functions;
    }


    /**
     * Gets any incompatible PHP settings.
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_incompatible_php_settings() {

        $incompatible_settings = [];

        if ( function_exists( 'ini_get' ) ) {

            foreach ( $this->get_php_settings() as $setting => $expected ) {

                $actual = ini_get( $setting );

                if ( ! $actual ) {
                    continue;
                }

                if ( is_int( $expected ) ) {

                    // determine if this is a size string, like "10MB"
                    $is_size = ! is_numeric( substr( $actual, -1 ) );

                    $actual_num = $is_size ? wc_let_to_num( $actual ) : $actual;

                    if ( $actual_num < $expected ) {

                        $incompatible_settings[ $setting ] = [
                            'expected' => $is_size ? size_format( $expected ) : $expected,
                            'actual'   => $is_size ? size_format( $actual_num ) : $actual,
                            'type'     => 'min',
                        ];
                    }

                } elseif ( $actual !== $expected ) {

                    $incompatible_settings[ $setting ] = [
                        'expected' => $expected,
                        'actual'   => $actual,
                    ];
                }
            }
        }

        return $incompatible_settings;
    }


    /**
     * Gets the required PHP settings.
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_php_settings() {

        return $this->php_settings;
    }


    /**
     * Gets the plugin instance.
     *
     * @since 5.2.0
     *
     * @return SV_WC_Plugin
     */
    protected function get_plugin() {

        return $this->plugin;
    }


}


endif;