| Server IP : 146.59.209.152 / Your IP : 216.73.216.152 Web Server : Apache System : Linux webm009.cluster131.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64 User : monpetu ( 144298) PHP Version : 7.4.33 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/monpetu/www/ipprint/wp-content/plugins/modern-cart/ |
Upload File : |
<?php
/**
* Plugin Loader.
*
* @package modern-cart
* @since 0.0.1
*/
namespace ModernCart;
use ModernCart\Admin_Core\Admin_Menu;
use ModernCart\Inc\Abilities\Register_Abilities;
use ModernCart\Inc\Admin_Notices;
use ModernCart\Inc\Floating;
use ModernCart\Inc\Floating_Ajax;
use ModernCart\Inc\Helper;
use ModernCart\Inc\Scripts;
use ModernCart\Inc\Order_Tracking;
use ModernCart\Inc\Slide_Out;
use ModernCart\Inc\Slide_Out_Ajax;
/**
* Plugin_Loader
*
* @since 0.0.1
*/
class Plugin_Loader {
/**
* Instance
*
* @access private
* @var object Class Instance.
* @since 0.0.1
*/
private static $instance;
/**
* Constructor
*
* @since 0.0.1
*/
public function __construct() {
spl_autoload_register( [ $this, 'autoload' ] );
register_activation_hook( __DIR__ . '/modern-cart.php', [ $this, 'activate' ] );
add_action( 'plugins_loaded', [ $this, 'load_classes' ] );
add_action( 'init', [ $this, 'save_version_info' ] );
add_action( 'init', [ $this, 'register_bsf_analytics_entity' ], 20 );
add_action( 'admin_init', [ $this, 'redirect_to_onboarding' ] );
if ( defined( 'MODERNCART_BASE' ) ) {
add_filter( 'plugin_action_links_' . MODERNCART_BASE, [ $this, 'action_links' ] );
}
do_action( 'moderncart_loaded' );
}
/**
* Load plugin text domain.
*
* @since 1.0.9
* @return void
*/
public function load_textdomain(): void {
$site_locale = apply_filters( 'plugin_locale', get_locale(), 'modern-cart' );
// Global translations directory takes priority (Loco Translate / manual uploads).
$mofile = WP_LANG_DIR . '/plugins/modern-cart-' . $site_locale . '.mo';
if ( ! file_exists( $mofile ) ) {
// Fall back to bundled translations shipped with the plugin.
$mofile = MODERNCART_DIR . 'languages/modern-cart-' . $site_locale . '.mo';
}
if ( ! file_exists( $mofile ) ) {
return;
}
// Load translations for the site locale.
load_textdomain( 'modern-cart', $mofile, $site_locale );
// In AJAX context (admin-ajax.php), WP_Translation_Controller calls
// determine_locale() at translate-time, which returns the logged-in user's
// profile language rather than the site language. Loading the site translations
// under the request locale too ensures the controller finds them regardless
// of which locale it looks up — without modifying any global WordPress filters.
$request_locale = determine_locale();
if ( $request_locale !== $site_locale ) {
load_textdomain( 'modern-cart', $mofile, $request_locale );
}
}
/**
* Activate plugin and set onboarding redirect.
*/
public function activate(): void {
// Record install timestamp for days_since_install analytics metric.
if ( ! get_option( 'mcw_usage_installed_time', false ) ) {
update_option( 'mcw_usage_installed_time', time(), false );
}
$is_onboarding_complete = get_option( 'moderncart_is_onboarding_complete', 'no' );
if ( 'yes' === $is_onboarding_complete ) {
return;
}
// Short-lived flag: the onboarding redirect is only relevant on the page
// load immediately following activation. Expiring it after 30 seconds
// prevents a stale flag from hijacking an unrelated admin navigation later
// (e.g. when Modern Cart is activated alongside another plugin).
set_transient( 'moderncart_redirect_to_onboarding', 'yes', 30 );
}
/**
* Redirect to onboarding page.
*/
public function redirect_to_onboarding(): void {
if ( ! get_transient( 'moderncart_redirect_to_onboarding' ) ) {
return;
}
// Never redirect during AJAX, cron, or network-admin requests.
if ( wp_doing_ajax() || wp_doing_cron() || is_network_admin() ) {
return;
}
global $pagenow;
// Only auto-open onboarding from the Plugins screen — the page WordPress
// lands on right after a single activation. This stops the flag from
// hijacking an unrelated navigation (e.g. Power Coupons "Add coupon",
// which loads post-new.php) when the redirect did not fire on activation,
// such as when Modern Cart is activated alongside another plugin. Also skip
// bulk activation, where the user expects to stay on the plugins list.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( 'plugins.php' !== $pagenow || isset( $_GET['activate-multi'] ) ) {
return;
}
$url = add_query_arg(
[
'page' => 'moderncart_settings',
'nonce' => wp_create_nonce( 'moderncart_onboarding_nonce' ),
'onboarding' => 1,
],
admin_url( 'admin.php' )
);
delete_transient( 'moderncart_redirect_to_onboarding' );
wp_safe_redirect( $url );
exit;
}
/**
* Save version information.
*/
public function save_version_info(): void {
$version = get_option( 'moderncart_version' );
if ( is_array( $version ) && isset( $version['current'] ) && MODERNCART_VER === $version['current'] ) {
// Already updated.
return;
}
// Backfill install time for sites that activated before this tracking was added.
if ( ! get_option( 'mcw_usage_installed_time', false ) ) {
update_option( 'mcw_usage_installed_time', time(), false );
}
$version = [
'current' => MODERNCART_VER,
'previous' => ( is_array( $version ) && isset( $version['current'] ) ) ? $version['current'] : '',
];
update_option( 'moderncart_version', $version );
}
/**
* Initiator
*
* @since 0.0.1
* @return object initialized object of class.
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Autoload classes.
*
* @param string $class class name.
*/
public function autoload( $class ): void {
if ( 0 !== strpos( $class, __NAMESPACE__ ) ) {
return;
}
$class_to_load = $class;
$filename = preg_replace(
[ '/^' . __NAMESPACE__ . '\\\/', '/([a-z])([A-Z])/', '/_/', '/\\\/' ],
[ '', '$1-$2', '-', DIRECTORY_SEPARATOR ],
$class_to_load
);
if ( is_string( $filename ) ) {
$filename = strtolower( $filename );
$file = MODERNCART_DIR . $filename . '.php';
// if the file redable, include it.
if ( is_readable( $file ) ) {
require_once $file;
}
}
}
/**
* Declare the woo HPOS compatibility.
*
* @since 1.0.1
* @return void
*/
public function declare_woo_hpos_compatibility() {
if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', MODERNCART_FILE, true );
}
}
/**
* Loads plugin classes as per requirement.
*
* @return void
* @since 0.0.1
*/
public function load_classes(): void {
$this->load_textdomain();
$this->load_bsf_analytics_loader();
if ( ! class_exists( 'woocommerce' ) ) {
return;
}
// Let WooCommerce know, CartFlows is compatible with HPOS.
add_action( 'before_woocommerce_init', array( $this, 'declare_woo_hpos_compatibility' ) );
if ( is_admin() ) {
Admin_Menu::get_instance();
$this->load_astra_notices();
Admin_Notices::get_instance();
}
$this->load_integration_classes();
Scripts::get_instance();
Floating::get_instance();
Slide_Out::get_instance();
Slide_Out_Ajax::get_instance();
Floating_Ajax::get_instance();
Register_Abilities::get_instance();
Order_Tracking::get_instance();
}
/**
* Adds links in Plugins page.
*
* @param array<string> $links Existing links.
* @return array<string> Filtered links with settings added.
* @since 0.0.1
*/
public function action_links( $links ) {
$plugin_links = apply_filters(
'moderncart_cpsw_plugin_action_links',
[
'moderncart_settings' => '<a href="' . admin_url( 'admin.php?page=moderncart_settings' ) . '">' . __( 'Settings', 'modern-cart' ) . '</a>',
]
);
return array_merge( $plugin_links, $links );
}
/**
* Load the Astra Notices library.
*
* @since 1.0.9
* @return void
*/
public function load_astra_notices() {
if ( ! class_exists( 'Astra_Notices' ) ) {
require_once MODERNCART_DIR . 'inc/libraries/astra-notices/class-astra-notices.php';
}
}
/**
* Require the BSF Analytics Loader and trigger its constructor.
*
* Runs on plugins_loaded so the BSF_Analytics_Loader class is available
* for all plugins before init fires. Entity registration with translatable
* strings is intentionally deferred to register_bsf_analytics_entity()
* which runs on init after the textdomain has been loaded.
*
* @since 1.0.8
* @return void
*/
public function load_bsf_analytics_loader() {
if ( ! class_exists( 'BSF_Analytics_Loader' ) ) {
require_once MODERNCART_DIR . 'inc/libraries/bsf-analytics/class-bsf-analytics-loader.php';
}
}
/**
* Register the Modern Cart entity with BSF Analytics.
*
* Runs on init:10, registered in the constructor so it queues before
* BSF_Analytics_Loader::load_analytics (registered during plugins_loaded).
* Translatable strings are safe here because the textdomain is loaded by init.
*
* Also performs a one-time migration of the legacy cf_analytics_optin option
* to mcw_usage_optin before the analytics class reads it.
*
* Backward compatibility matrix (keyed on MODERNCART_VER / MODERNCART_PRO_VER):
* - Latest Free + Latest Pro (Free ≥ 1.0.8, Pro ≥ 1.2.4): Free registers entity;
* Pro defers and sends data via filter. ← this method runs fully.
* - Latest Free + Older Pro (Free ≥ 1.0.8, Pro < 1.2.4): Old Pro registers its
* own entity and does not defer. Free must not register a duplicate. ← early return.
* - Older Free + Latest Pro (Free < 1.0.8, Pro ≥ 1.2.4): Free does not have this
* method; Pro handles analytics via its own fallback. No conflict.
* - Older Free + Older Pro (Free < 1.0.8, Pro < 1.2.4): Neither plugin runs this
* code; no change in behaviour.
*
* @since 1.0.8
* @return void
*/
public function register_bsf_analytics_entity() {
if ( ! class_exists( 'BSF_Analytics_Loader' ) ) {
return;
}
$this->maybe_migrate_analytics_optin();
$plugin_slug = 'modern-cart';
$bsf_analytics = \BSF_Analytics_Loader::get_instance();
$bsf_analytics->set_entity(
array(
'mcw' => array(
'hide_optin_checkbox' => true,
'product_name' => 'Modern Cart',
'usage_doc_link' => 'https://my.cartflows.com/usage-tracking/',
'path' => MODERNCART_DIR . 'inc/libraries/bsf-analytics',
'author' => 'CartFlows',
'deactivation_survey' => apply_filters(
'moderncart_bsf_analytics_deactivation_survey_data',
array(
array(
'id' => 'deactivation-survey-' . $plugin_slug,
'popup_logo' => MODERNCART_URL . 'admin-core/assets/images/logo.svg',
'plugin_slug' => $plugin_slug,
'plugin_version' => MODERNCART_VER,
'popup_title' => __( 'Quick Feedback', 'modern-cart' ),
'support_url' => 'https://cartflows.com/contact/',
'popup_description' => __( 'If you have a moment, please share why you are deactivating Modern Cart Starter:', 'modern-cart' ),
'show_on_screens' => array( 'plugins' ),
),
)
),
),
)
);
// Ensure BSF_Analytics_Events is loaded before instantiating Modern_Cart_Analytics.
// class-bsf-analytics-events.php is normally loaded inside BSF_Analytics::includes(),
// which runs on init at priority 10 via BSF_Analytics_Loader::load_analytics(). Since
// register_bsf_analytics_entity() also runs on init (priority 20), BSF_Analytics_Loader
// should have already run — but we require it explicitly here as a safety guarantee so
// detect_state_events() always finds BSF_Analytics_Events available.
if ( ! class_exists( 'BSF_Analytics_Events' ) ) {
require_once MODERNCART_DIR . 'inc/libraries/bsf-analytics/class-bsf-analytics-events.php';
}
require_once MODERNCART_DIR . 'inc/libraries/class-modern-cart-analytics.php';
}
/**
* Migrate legacy cf_analytics_optin to mcw_usage_optin.
*
* Sites that previously ran a CartFlows-era version of this plugin may
* have the analytics opt-in stored under cf_analytics_optin. This copies
* the value to the current key and removes the legacy option.
*
* Skips silently if cf_analytics_optin does not exist, or if
* mcw_usage_optin already has a value.
*
* @since 1.0.8
* @return void
*/
private function maybe_migrate_analytics_optin() {
$legacy_value = get_option( 'cf_analytics_optin' );
if ( false === $legacy_value ) {
// Legacy option absent — nothing to migrate.
return;
}
if ( false !== get_option( 'mcw_usage_optin' ) ) {
// New option already set — just clean up the legacy key.
return;
}
update_option( 'mcw_usage_optin', $legacy_value );
}
/**
* Loads integration classes like mcw-zipwp-helper.
*
* @since x.x.x
* @return void
*/
public function load_integration_classes() {
require_once MODERNCART_DIR . 'inc/integrations/mcw-zipwp-helper.php';
}
}
/**
* Kicking this off by calling 'get_instance()' method
*/
Plugin_Loader::get_instance();