Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/ocean-extra/includes/client-migration/edd.php
+++ b/ocean-extra/includes/client-migration/edd.php
@@ -6,112 +6,117 @@
* @since 1.0.3
*/
- if ( ! defined( 'ABSPATH' ) ) {
- exit;
- }
-
- if ( ! class_exists( 'FS_Client_License_Abstract_v2' ) ) {
- require_once dirname( __FILE__ ) . '/class-fs-client-license-abstract.php';
- }
-
- if ( ! class_exists( 'FS_EDD_Client_Migration_v2' ) ) {
- require_once dirname( __FILE__ ) . '/class-fs-edd-client-migration.php';
- }
-
- /**
- * You should use your own unique CLASS name, and be sure to replace it
- * throughout this file. For example, if your product's name is "Awesome Product"
- * then you can rename it to "Awesome_Product_EDD_License_Key".
- */
- class OceanWP_EDD_License_Key extends FS_Client_License_Abstract_v2 {
- /**
- * @var array<string,string>
- */
- public static $paid_addons = array(
- 'Ocean_Cookie_Notice' => array(
- 'name' => 'Cookie Notice',
- 'fs_id' => '3765',
- 'fs_shortcode' => 'ocean_cookie_notice_fs',
- ),
- 'Ocean_Elementor_Widgets' => array(
- 'name' => 'Elementor Widgets',
- 'fs_id' => '3757',
- 'fs_shortcode' => 'ocean_elementor_widgets_fs',
- ),
- 'Ocean_Footer_Callout' => array(
- 'name' => 'Footer Callout',
- 'fs_id' => '3754',
- 'fs_shortcode' => 'ocean_footer_callout_fs',
- ),
- 'Ocean_Full_Screen' => array(
- 'name' => 'Full Screen',
- 'fs_id' => '3766',
- 'fs_shortcode' => 'ocean_full_screen_fs',
- ),
- 'Ocean_Hooks' => array(
- 'name' => 'Ocean Hooks',
- 'fs_id' => '3758',
- 'fs_shortcode' => 'oh_fs',
- ),
- /*'Ocean_Instagram' => array(
- 'name' => 'Instagram',
- 'fs_id' => '3763',
- 'fs_shortcode' => 'ocean_instagram_fs',
- ),*/
- 'Ocean_Popup_Login' => array(
- 'name' => 'Popup Login',
- 'fs_id' => '3764',
- 'fs_shortcode' => 'ocean_popup_login_fs',
- ),
- 'Ocean_Portfolio' => array(
- 'name' => 'Portfolio',
- 'fs_id' => '3761',
- 'fs_shortcode' => 'ocean_portfolio_fs',
- ),
- 'Ocean_Pro_Demos' => array(
- 'name' => 'Pro Demos',
- 'fs_id' => '3797',
- 'fs_shortcode' => 'ocean_pro_demos_fs',
- ),
- 'Ocean_Side_Panel' => array(
- 'name' => 'Side Panel',
- 'fs_id' => '3756',
- 'fs_shortcode' => 'ocean_side_panel_fs',
- ),
- 'Ocean_Sticky_Footer' => array(
- 'name' => 'Sticky Footer',
- 'fs_id' => '3759',
- 'fs_shortcode' => 'ocean_sticky_footer_fs',
- ),
- 'Ocean_Sticky_Header' => array(
- 'name' => 'Sticky Header',
- 'fs_id' => '3755',
- 'fs_shortcode' => 'ocean_sticky_header_fs',
- ),
- 'Ocean_White_Label' => array(
- 'name' => 'White Label',
- 'fs_id' => '3762',
- 'fs_shortcode' => 'ocean_white_label_fs',
- ),
- 'Ocean_Woo_Popup' => array(
- 'name' => 'Woo Popup',
- 'fs_id' => '3760',
- 'fs_shortcode' => 'ocean_woo_popup_fs',
- ),
- );
-
- public static $separate_addons = array(
- 'Ocean_eCommerce' => array(
- 'name' => 'Ocean Treasure Box',
- 'fs_id' => '11449',
- 'fs_shortcode' => 'oet_fs',
- ),
- 'Ocean_Gutenberg_Blocks' => array(
- 'name' => 'Ocean Gutenberg Blocks',
- 'fs_id' => '9081',
- 'fs_shortcode' => 'ocean_gutenberg_blocks_fs',
- ),
- );
+ if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+ }
+
+ if ( ! class_exists( 'FS_Client_License_Abstract_v2' ) ) {
+ require_once dirname( __FILE__ ) . '/class-fs-client-license-abstract.php';
+ }
+
+ if ( ! class_exists( 'FS_EDD_Client_Migration_v2' ) ) {
+ require_once dirname( __FILE__ ) . '/class-fs-edd-client-migration.php';
+ }
+
+ /**
+ * You should use your own unique CLASS name, and be sure to replace it
+ * throughout this file. For example, if your product's name is "Awesome Product"
+ * then you can rename it to "Awesome_Product_EDD_License_Key".
+ */
+ class OceanWP_EDD_License_Key extends FS_Client_License_Abstract_v2 {
+ /**
+ * @var array<string,string>
+ */
+ public static $paid_addons = array(
+ 'Ocean_Cookie_Notice' => array(
+ 'name' => 'Cookie Notice',
+ 'fs_id' => '3765',
+ 'fs_shortcode' => 'ocean_cookie_notice_fs',
+ ),
+ 'Ocean_Elementor_Widgets' => array(
+ 'name' => 'Elementor Widgets',
+ 'fs_id' => '3757',
+ 'fs_shortcode' => 'ocean_elementor_widgets_fs',
+ ),
+ 'Ocean_Footer_Callout' => array(
+ 'name' => 'Footer Callout',
+ 'fs_id' => '3754',
+ 'fs_shortcode' => 'ocean_footer_callout_fs',
+ ),
+ 'Ocean_Full_Screen' => array(
+ 'name' => 'Full Screen',
+ 'fs_id' => '3766',
+ 'fs_shortcode' => 'ocean_full_screen_fs',
+ ),
+ 'Ocean_Hooks' => array(
+ 'name' => 'Ocean Hooks',
+ 'fs_id' => '3758',
+ 'fs_shortcode' => 'oh_fs',
+ ),
+ /*'Ocean_Instagram' => array(
+ 'name' => 'Instagram',
+ 'fs_id' => '3763',
+ 'fs_shortcode' => 'ocean_instagram_fs',
+ ),*/
+ 'Ocean_Popup_Login' => array(
+ 'name' => 'Popup Login',
+ 'fs_id' => '3764',
+ 'fs_shortcode' => 'ocean_popup_login_fs',
+ ),
+ 'Ocean_Portfolio' => array(
+ 'name' => 'Portfolio',
+ 'fs_id' => '3761',
+ 'fs_shortcode' => 'ocean_portfolio_fs',
+ ),
+ 'Ocean_Pro_Demos' => array(
+ 'name' => 'Pro Demos',
+ 'fs_id' => '3797',
+ 'fs_shortcode' => 'ocean_pro_demos_fs',
+ ),
+ 'Ocean_Side_Panel' => array(
+ 'name' => 'Side Panel',
+ 'fs_id' => '3756',
+ 'fs_shortcode' => 'ocean_side_panel_fs',
+ ),
+ 'Ocean_Sticky_Footer' => array(
+ 'name' => 'Sticky Footer',
+ 'fs_id' => '3759',
+ 'fs_shortcode' => 'ocean_sticky_footer_fs',
+ ),
+ 'Ocean_Sticky_Header' => array(
+ 'name' => 'Sticky Header',
+ 'fs_id' => '3755',
+ 'fs_shortcode' => 'ocean_sticky_header_fs',
+ ),
+ 'Ocean_White_Label' => array(
+ 'name' => 'White Label',
+ 'fs_id' => '3762',
+ 'fs_shortcode' => 'ocean_white_label_fs',
+ ),
+ 'Ocean_Woo_Popup' => array(
+ 'name' => 'Woo Popup',
+ 'fs_id' => '3760',
+ 'fs_shortcode' => 'ocean_woo_popup_fs',
+ ),
+ );
+
+ public static $separate_addons = array(
+ 'Ocean_eCommerce' => array(
+ 'name' => 'Ocean Treasure Box',
+ 'fs_id' => '11449',
+ 'fs_shortcode' => 'oet_fs',
+ ),
+ 'Ocean_Gutenberg_Blocks' => array(
+ 'name' => 'Ocean Gutenberg Blocks',
+ 'fs_id' => '9081',
+ 'fs_shortcode' => 'ocean_gutenberg_blocks_fs',
+ ),
+ 'Ocean_Site_Booster' => array(
+ 'name' => 'Ocean Site Booster',
+ 'fs_id' => '17389',
+ 'fs_shortcode' => 'osb_fs',
+ ),
+ );
private $_is_valid;
private $_is_bundle;
--- a/ocean-extra/includes/freemius/includes/class-freemius.php
+++ b/ocean-extra/includes/freemius/includes/class-freemius.php
@@ -110,6 +110,12 @@
private $_enable_anonymous = true;
/**
+ * @since 2.9.1
+ * @var string|null Hints the SDK whether the plugin supports parallel activation mode, preventing the auto-deactivation of the free version when the premium version is activated, and vice versa.
+ */
+ private $_premium_plugin_basename_from_parallel_activation;
+
+ /**
* @since 1.1.7.5
* @var bool Hints the SDK if plugin should run in anonymous mode (only adds feedback form).
*/
@@ -1651,6 +1657,31 @@
);
}
}
+
+ if (
+ $this->is_user_in_admin() &&
+ $this->is_parallel_activation() &&
+ $this->_premium_plugin_basename !== $this->_premium_plugin_basename_from_parallel_activation
+ ) {
+ $this->_premium_plugin_basename = $this->_premium_plugin_basename_from_parallel_activation;
+
+ register_activation_hook(
+ dirname( $this->_plugin_dir_path ) . '/' . $this->_premium_plugin_basename,
+ array( &$this, '_activate_plugin_event_hook' )
+ );
+ }
+ }
+
+ /**
+ * Determines if a plugin is running in parallel activation mode.
+ *
+ * @author Leo Fajardo (@leorw)
+ * @since 2.9.1
+ *
+ * @return bool
+ */
+ private function is_parallel_activation() {
+ return ! empty( $this->_premium_plugin_basename_from_parallel_activation );
}
/**
@@ -5155,11 +5186,35 @@
$this->_plugin :
new FS_Plugin();
+ $is_premium = $this->get_bool_option( $plugin_info, 'is_premium', true );
$premium_suffix = $this->get_option( $plugin_info, 'premium_suffix', '(Premium)' );
+ $module_type = $this->get_option( $plugin_info, 'type', $this->_module_type );
+
+ $parallel_activation = $this->get_option( $plugin_info, 'parallel_activation' );
+
+ if (
+ ! $is_premium &&
+ is_array( $parallel_activation ) &&
+ ( WP_FS__MODULE_TYPE_PLUGIN === $module_type ) &&
+ $this->get_bool_option( $parallel_activation, 'enabled' )
+ ) {
+ $premium_basename = $this->get_option( $parallel_activation, 'premium_version_basename' );
+
+ if ( empty( $premium_basename ) ) {
+ throw new Exception('You need to specify the premium version basename to enable parallel version activation.');
+ }
+
+ $this->_premium_plugin_basename_from_parallel_activation = $premium_basename;
+
+ if ( is_plugin_active( $premium_basename ) ) {
+ $is_premium = true;
+ }
+ }
+
$plugin->update( array(
'id' => $id,
- 'type' => $this->get_option( $plugin_info, 'type', $this->_module_type ),
+ 'type' => $module_type,
'public_key' => $public_key,
'slug' => $this->_slug,
'premium_slug' => $this->get_option( $plugin_info, 'premium_slug', "{$this->_slug}-premium" ),
@@ -5167,7 +5222,7 @@
'version' => $this->get_plugin_version(),
'title' => $this->get_plugin_name( $premium_suffix ),
'file' => $this->_plugin_basename,
- 'is_premium' => $this->get_bool_option( $plugin_info, 'is_premium', true ),
+ 'is_premium' => $is_premium,
'premium_suffix' => $premium_suffix,
'is_live' => $this->get_bool_option( $plugin_info, 'is_live', true ),
'affiliate_moderation' => $this->get_option( $plugin_info, 'has_affiliation' ),
@@ -5236,7 +5291,14 @@
$this->_anonymous_mode = false;
} else {
$this->_enable_anonymous = $this->get_bool_option( $plugin_info, 'enable_anonymous', true );
- $this->_anonymous_mode = $this->get_bool_option( $plugin_info, 'anonymous_mode', false );
+ $this->_anonymous_mode = (
+ $this->get_bool_option( $plugin_info, 'anonymous_mode', false ) ||
+ (
+ $this->apply_filters( 'playground_anonymous_mode', true ) &&
+ ! empty( $_SERVER['HTTP_HOST'] ) &&
+ FS_Site::is_playground_wp_environment_by_host( $_SERVER['HTTP_HOST'] )
+ )
+ );
}
$this->_permissions = $this->get_option( $plugin_info, 'permissions', array() );
$this->_is_bundle_license_auto_activation_enabled = $this->get_option( $plugin_info, 'bundle_license_auto_activation', false );
@@ -5444,7 +5506,7 @@
if ( $this->is_registered() ) {
// Schedule code type changes event.
- $this->schedule_install_sync();
+ $this->maybe_schedule_install_sync_cron();
}
/**
@@ -6508,6 +6570,33 @@
}
/**
+ * Instead of running blocking install sync event, execute non blocking scheduled cron job.
+ *
+ * @param int $except_blog_id Since 2.0.0 when running in a multisite network environment, the cron execution is consolidated. This param allows excluding specified blog ID from being the cron job executor.
+ *
+ * @author Leo Fajardo (@leorw)
+ * @since 2.9.1
+ */
+ private function maybe_schedule_install_sync_cron( $except_blog_id = 0 ) {
+ if ( ! $this->is_user_in_admin() ) {
+ return;
+ }
+
+ if ( $this->is_clone() ) {
+ return;
+ }
+
+ if (
+ // The event has been properly scheduled, so no need to reschedule it.
+ is_numeric( $this->next_install_sync() )
+ ) {
+ return;
+ }
+
+ $this->schedule_cron( 'install_sync', 'install_sync', 'single', WP_FS__SCRIPT_START_TIME, false, $except_blog_id );
+ }
+
+ /**
* @author Vova Feldman (@svovaf)
* @since 1.1.7.3
*
@@ -6605,22 +6694,6 @@
}
/**
- * Instead of running blocking install sync event, execute non blocking scheduled wp-cron.
- *
- * @author Vova Feldman (@svovaf)
- * @since 1.1.7.3
- *
- * @param int $except_blog_id Since 2.0.0 when running in a multisite network environment, the cron execution is consolidated. This param allows excluding excluded specified blog ID from being the cron executor.
- */
- private function schedule_install_sync( $except_blog_id = 0 ) {
- if ( $this->is_clone() ) {
- return;
- }
-
- $this->schedule_cron( 'install_sync', 'install_sync', 'single', WP_FS__SCRIPT_START_TIME, false, $except_blog_id );
- }
-
- /**
* Unix timestamp for previous install sync cron execution or false if never executed.
*
* @todo There's some very strange bug that $this->_storage->install_sync_timestamp value is not being updated. But for sure the sync event is working.
@@ -7411,7 +7484,7 @@
*/
if (
is_plugin_active( $other_version_basename ) &&
- $this->apply_filters( 'deactivate_on_activation', true )
+ $this->apply_filters( 'deactivate_on_activation', ! $this->is_parallel_activation() )
) {
deactivate_plugins( $other_version_basename );
}
@@ -7425,7 +7498,7 @@
// Schedule re-activation event and sync.
// $this->sync_install( array(), true );
- $this->schedule_install_sync();
+ $this->maybe_schedule_install_sync_cron();
// If activating the premium module version, add an admin notice to congratulate for an upgrade completion.
if ( $is_premium_version_activation ) {
@@ -8616,7 +8689,7 @@
return;
}
- $this->schedule_install_sync();
+ $this->maybe_schedule_install_sync_cron();
// $this->sync_install( array(), true );
}
@@ -15974,7 +16047,7 @@
if ( $this->is_install_sync_scheduled() &&
$context_blog_id == $this->get_install_sync_cron_blog_id()
) {
- $this->schedule_install_sync( $context_blog_id );
+ $this->maybe_schedule_install_sync_cron( $context_blog_id );
}
}
@@ -23927,13 +24000,15 @@
// Start trial button.
$button = ' ' . sprintf(
- '<a style="margin-left: 10px; vertical-align: super;" href="%s"><button class="button button-primary">%s ➜</button></a>',
+ '<div><a class="button button-primary" href="%s">%s ➜</a></div>',
$trial_url,
$this->get_text_x_inline( 'Start free trial', 'call to action', 'start-free-trial' )
);
+ $message_text = $this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string}" );
+
$this->_admin_notices->add_sticky(
- $this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string} {$button}" ),
+ "<div class="fs-trial-message-container"><div>{$message_text}</div> {$button}</div>",
'trial_promotion',
'',
'promotion'
@@ -25403,7 +25478,7 @@
$img_dir = WP_FS__DIR_IMG;
// Locate the main assets folder.
- if ( 1 < count( $fs_active_plugins->plugins ) ) {
+ if ( ! empty( $fs_active_plugins->plugins ) ) {
$plugin_or_theme_img_dir = ( $this->is_plugin() ? WP_PLUGIN_DIR : get_theme_root( get_stylesheet() ) );
foreach ( $fs_active_plugins->plugins as $sdk_path => &$data ) {
--- a/ocean-extra/includes/freemius/includes/class-fs-plugin-updater.php
+++ b/ocean-extra/includes/freemius/includes/class-fs-plugin-updater.php
@@ -542,24 +542,8 @@
global $wp_current_filter;
- $current_plugin_version = $this->_fs->get_plugin_version();
-
- if ( ! empty( $wp_current_filter ) && 'upgrader_process_complete' === $wp_current_filter[0] ) {
- if (
- is_null( $this->_update_details ) ||
- ( is_object( $this->_update_details ) && $this->_update_details->new_version !== $current_plugin_version )
- ) {
- /**
- * After an update, clear the stored update details and reparse the plugin's main file in order to get
- * the updated version's information and prevent the previous update information from showing up on the
- * updates page.
- *
- * @author Leo Fajardo (@leorw)
- * @since 2.3.1
- */
- $this->_update_details = null;
- $current_plugin_version = $this->_fs->get_plugin_version( true );
- }
+ if ( ! empty( $wp_current_filter ) && in_array( 'upgrader_process_complete', $wp_current_filter ) ) {
+ return $transient_data;
}
if ( ! isset( $this->_update_details ) ) {
@@ -568,7 +552,7 @@
false,
fs_request_get_bool( 'force-check' ),
FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
- $current_plugin_version
+ $this->_fs->get_plugin_version()
);
$this->_update_details = false;
--- a/ocean-extra/includes/freemius/includes/entities/class-fs-plugin-plan.php
+++ b/ocean-extra/includes/freemius/includes/entities/class-fs-plugin-plan.php
@@ -13,7 +13,6 @@
/**
* Class FS_Plugin_Plan
*
- * @property FS_Pricing[] $pricing
*/
class FS_Plugin_Plan extends FS_Entity {
--- a/ocean-extra/includes/freemius/includes/entities/class-fs-site.php
+++ b/ocean-extra/includes/freemius/includes/entities/class-fs-site.php
@@ -10,16 +10,16 @@
exit;
}
- /**
- * @property int $blog_id
- */
- #[AllowDynamicProperties]
class FS_Site extends FS_Scope_Entity {
/**
* @var number
*/
public $site_id;
/**
+ * @var int
+ */
+ public $blog_id;
+ /**
* @var number
*/
public $plugin_id;
@@ -190,7 +190,7 @@
fs_ends_with( $subdomain, '.cloudwaysapps.com' ) ||
// Kinsta
(
- ( fs_starts_with( $subdomain, 'staging-' ) || fs_starts_with( $subdomain, 'env-' ) ) &&
+ ( fs_starts_with( $subdomain, 'stg-' ) || fs_starts_with( $subdomain, 'staging-' ) || fs_starts_with( $subdomain, 'env-' ) ) &&
( fs_ends_with( $subdomain, '.kinsta.com' ) || fs_ends_with( $subdomain, '.kinsta.cloud' ) )
) ||
// DesktopServer
@@ -208,6 +208,40 @@
);
}
+ /**
+ * @author Leo Fajardo (@leorw)
+ * @since 2.9.1
+ *
+ * @param string $host
+ *
+ * @return bool
+ */
+ static function is_playground_wp_environment_by_host( $host ) {
+ // Services aimed at providing a WordPress sandbox environment.
+ $sandbox_wp_environment_domains = array(
+ // InstaWP
+ 'instawp.xyz',
+
+ // TasteWP
+ 'tastewp.com',
+
+ // WordPress Playground
+ 'playground.wordpress.net',
+ );
+
+ foreach ( $sandbox_wp_environment_domains as $domain) {
+ if (
+ ( $host === $domain ) ||
+ fs_ends_with( $host, '.' . $domain ) ||
+ fs_ends_with( $host, '-' . $domain )
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
function is_localhost() {
return ( WP_FS__IS_LOCALHOST_FOR_SERVER || self::is_localhost_by_address( $this->url ) );
}
--- a/ocean-extra/includes/freemius/includes/entities/class-fs-user.php
+++ b/ocean-extra/includes/freemius/includes/entities/class-fs-user.php
@@ -48,6 +48,19 @@
parent::__construct( $user );
}
+ /**
+ * This method removes the deprecated 'is_beta' property from the serialized data.
+ * Should clean up the serialized data to avoid PHP 8.2 warning on next execution.
+ *
+ * @return void
+ */
+ function __wakeup() {
+ if ( property_exists( $this, 'is_beta' ) ) {
+ // If we enter here, and we are running PHP 8.2, we already had the warning. But we sanitize data for next execution.
+ unset( $this->is_beta );
+ }
+ }
+
function get_name() {
return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) );
}
--- a/ocean-extra/includes/freemius/includes/managers/class-fs-admin-menu-manager.php
+++ b/ocean-extra/includes/freemius/includes/managers/class-fs-admin-menu-manager.php
@@ -699,16 +699,36 @@
$menu = $this->find_main_submenu();
}
+ $menu_slug = $menu['menu'][2];
$parent_slug = isset( $menu['parent_slug'] ) ?
- $menu['parent_slug'] :
- 'admin.php';
+ $menu['parent_slug'] :
+ 'admin.php';
- return admin_url(
- $parent_slug .
- ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
- 'page=' .
- $menu['menu'][2]
- );
+ if ( fs_apply_filter( $this->_module_unique_affix, 'enable_cpt_advanced_menu_logic', false ) ) {
+ $parent_slug = 'admin.php';
+
+ /**
+ * This line and the `if` block below it are based on the `menu_page_url()` function of WordPress.
+ *
+ * @author Leo Fajardo (@leorw)
+ * @since 2.10.2
+ */
+ global $_parent_pages;
+
+ if ( ! empty( $_parent_pages[ $menu_slug ] ) ) {
+ $_parent_slug = $_parent_pages[ $menu_slug ];
+ $parent_slug = isset( $_parent_pages[ $_parent_slug ] ) ?
+ $parent_slug :
+ $menu['parent_slug'];
+ }
+ }
+
+ return admin_url(
+ $parent_slug .
+ ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
+ 'page=' .
+ $menu_slug
+ );
}
/**
--- a/ocean-extra/includes/freemius/includes/managers/class-fs-admin-notice-manager.php
+++ b/ocean-extra/includes/freemius/includes/managers/class-fs-admin-notice-manager.php
@@ -194,8 +194,14 @@
* @since 1.0.7
*/
static function _add_sticky_dismiss_javascript() {
+ $sticky_admin_notice_js_template_name = 'sticky-admin-notice-js.php';
+
+ if ( ! file_exists( fs_get_template_path( $sticky_admin_notice_js_template_name ) ) ) {
+ return;
+ }
+
$params = array();
- fs_require_once_template( 'sticky-admin-notice-js.php', $params );
+ fs_require_once_template( $sticky_admin_notice_js_template_name, $params );
}
private static $_added_sticky_javascript = false;
--- a/ocean-extra/includes/freemius/start.php
+++ b/ocean-extra/includes/freemius/start.php
@@ -15,7 +15,7 @@
*
* @var string
*/
- $this_sdk_version = '2.9.0';
+ $this_sdk_version = '2.11.0';
#region SDK Selection Logic --------------------------------------------------------------------
@@ -36,7 +36,16 @@
require_once dirname( __FILE__ ) . '/includes/fs-essential-functions.php';
}
- /**
+ /**
+ * We updated the logic to support SDK loading from a subfolder of a theme as well as from a parent theme
+ * If the SDK is found in the active theme, it sets the relative path accordingly.
+ * If not, it checks the parent theme and sets the relative path if found there.
+ * This allows the SDK to be loaded from composer dependencies or from a custom `vendor/freemius` folder.
+ *
+ * @author Daniele Alessandra (@DanieleAlessandra)
+ * @since 2.9.0.5
+ *
+ *
* This complex logic fixes symlink issues (e.g. with Vargant). The logic assumes
* that if it's a file from an SDK running in a theme, the location of the SDK
* is in the main theme's folder.
@@ -83,16 +92,50 @@
*/
$themes_directory = get_theme_root( get_stylesheet() );
$themes_directory_name = basename( $themes_directory );
- $theme_candidate_basename = basename( dirname( $fs_root_path ) ) . '/' . basename( $fs_root_path );
- if ( $file_path == fs_normalize_path( realpath( trailingslashit( $themes_directory ) . $theme_candidate_basename . '/' . basename( $file_path ) ) )
- ) {
- $this_sdk_relative_path = '../' . $themes_directory_name . '/' . $theme_candidate_basename;
- $is_theme = true;
- } else {
- $this_sdk_relative_path = plugin_basename( $fs_root_path );
- $is_theme = false;
- }
+ // This change ensures that the condition works even if the SDK is located in a subdirectory (e.g., vendor)
+ $theme_candidate_sdk_basename = str_replace( $themes_directory . '/' . get_stylesheet() . '/', '', $fs_root_path );
+
+ // Check if the current file is part of the active theme.
+ $is_current_sdk_from_active_theme = $file_path == $themes_directory . '/' . get_stylesheet() . '/' . $theme_candidate_sdk_basename . '/' . basename( $file_path );
+ $is_current_sdk_from_parent_theme = false;
+
+ // Check if the current file is part of the parent theme.
+ if ( ! $is_current_sdk_from_active_theme ) {
+ $theme_candidate_sdk_basename = str_replace( $themes_directory . '/' . get_template() . '/',
+ '',
+ $fs_root_path );
+ $is_current_sdk_from_parent_theme = $file_path == $themes_directory . '/' . get_template() . '/' . $theme_candidate_sdk_basename . '/' . basename( $file_path );
+ }
+
+ $theme_name = null;
+ if ( $is_current_sdk_from_active_theme ) {
+ $theme_name = get_stylesheet();
+ $this_sdk_relative_path = '../' . $themes_directory_name . '/' . $theme_name . '/' . $theme_candidate_sdk_basename;
+ $is_theme = true;
+ } else if ( $is_current_sdk_from_parent_theme ) {
+ $theme_name = get_template();
+ $this_sdk_relative_path = '../' . $themes_directory_name . '/' . $theme_name . '/' . $theme_candidate_sdk_basename;
+ $is_theme = true;
+ } else {
+ $this_sdk_relative_path = plugin_basename( $fs_root_path );
+ $is_theme = false;
+
+ /**
+ * If this file was included from another plugin with lower SDK version, and if this plugin is symlinked, then we need to get the actual plugin path,
+ * as the value right now will be wrong, it will only remove the directory separator from the file_path.
+ *
+ * The check of `fs_find_direct_caller_plugin_file` determines that this file was indeed included by a different plugin than the main plugin.
+ */
+ if ( DIRECTORY_SEPARATOR . $this_sdk_relative_path === $fs_root_path && function_exists( 'fs_find_direct_caller_plugin_file' ) ) {
+ $original_plugin_dir_name = dirname( fs_find_direct_caller_plugin_file( $file_path ) );
+
+ // Remove everything before the original plugin directory name.
+ $this_sdk_relative_path = substr( $this_sdk_relative_path, strpos( $this_sdk_relative_path, $original_plugin_dir_name ) );
+
+ unset( $original_plugin_dir_name );
+ }
+ }
if ( ! isset( $fs_active_plugins ) ) {
// Load all Freemius powered active plugins.
@@ -176,7 +219,8 @@
$this_sdk_version != $fs_active_plugins->plugins[ $this_sdk_relative_path ]->version
) {
if ( $is_theme ) {
- $plugin_path = basename( dirname( $this_sdk_relative_path ) );
+ // Saving relative path and not only directory name as it could be a subfolder
+ $plugin_path = $theme_name;
} else {
$plugin_path = plugin_basename( fs_find_direct_caller_plugin_file( $file_path ) );
}
@@ -225,11 +269,23 @@
$is_newest_sdk_type_theme = ( isset( $fs_newest_sdk->type ) && 'theme' === $fs_newest_sdk->type );
- if ( ! $is_newest_sdk_type_theme ) {
- $is_newest_sdk_plugin_active = is_plugin_active( $fs_newest_sdk->plugin_path );
- } else {
- $current_theme = wp_get_theme();
- $is_newest_sdk_plugin_active = ( $current_theme->stylesheet === $fs_newest_sdk->plugin_path );
+ /**
+ * @var bool $is_newest_sdk_module_active
+ * True if the plugin with the newest SDK is active.
+ * True if the newest SDK is part of the current theme or current theme's parent.
+ * False otherwise.
+ */
+ if ( ! $is_newest_sdk_type_theme ) {
+ $is_newest_sdk_module_active = is_plugin_active( $fs_newest_sdk->plugin_path );
+ } else {
+ $current_theme = wp_get_theme();
+ // Detect if current theme is the one registered as newer SDK
+ $is_newest_sdk_module_active = (
+ strpos(
+ $fs_newest_sdk->plugin_path,
+ '../' . $themes_directory_name . '/' . $current_theme->get_stylesheet() . '/'
+ ) === 0
+ );
$current_theme_parent = $current_theme->parent();
@@ -237,13 +293,19 @@
* If the current theme is a child of the theme that has the newest SDK, this prevents a redirects loop
* from happening by keeping the SDK info stored in the `fs_active_plugins` option.
*/
- if ( ! $is_newest_sdk_plugin_active && $current_theme_parent instanceof WP_Theme ) {
- $is_newest_sdk_plugin_active = ( $fs_newest_sdk->plugin_path === $current_theme_parent->stylesheet );
+ if ( ! $is_newest_sdk_module_active && $current_theme_parent instanceof WP_Theme ) {
+ // Detect if current theme parent is the one registered as newer SDK
+ $is_newest_sdk_module_active = (
+ strpos(
+ $fs_newest_sdk->plugin_path,
+ '../' . $themes_directory_name . '/' . $current_theme_parent->get_stylesheet() . '/'
+ ) === 0
+ );
}
}
if ( $is_current_sdk_newest &&
- ! $is_newest_sdk_plugin_active &&
+ ! $is_newest_sdk_module_active &&
! $fs_active_plugins->newest->in_activation
) {
// If current SDK is the newest and the plugin is NOT active, it means
@@ -262,14 +324,14 @@
. '/start.php' );
}
- $is_newest_sdk_path_valid = ( $is_newest_sdk_plugin_active || $fs_active_plugins->newest->in_activation ) && file_exists( $sdk_starter_path );
+ $is_newest_sdk_path_valid = ( $is_newest_sdk_module_active || $fs_active_plugins->newest->in_activation ) && file_exists( $sdk_starter_path );
if ( ! $is_newest_sdk_path_valid && ! $is_current_sdk_newest ) {
// Plugin with newest SDK is no longer active, or SDK was moved to a different location.
unset( $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ] );
}
- if ( ! ( $is_newest_sdk_plugin_active || $fs_active_plugins->newest->in_activation ) ||
+ if ( ! ( $is_newest_sdk_module_active || $fs_active_plugins->newest->in_activation ) ||
! $is_newest_sdk_path_valid ||
// Is newest SDK downgraded.
( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&
@@ -284,7 +346,7 @@
// Find the active plugin with the newest SDK version and update the newest reference.
fs_fallback_to_newest_active_sdk();
} else {
- if ( $is_newest_sdk_plugin_active &&
+ if ( $is_newest_sdk_module_active &&
$this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&
( $fs_active_plugins->newest->in_activation ||
( class_exists( 'Freemius' ) && ( ! defined( 'WP_FS__SDK_VERSION' ) || version_compare( WP_FS__SDK_VERSION, $this_sdk_version, '<' ) ) )
@@ -313,7 +375,7 @@
return;
}
- if ( version_compare( $this_sdk_version, $fs_active_plugins->newest->version, '<' ) ) {
+ if ( isset( $fs_active_plugins->newest ) && version_compare( $this_sdk_version, $fs_active_plugins->newest->version, '<' ) ) {
$newest_sdk = $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ];
$plugins_or_theme_dir_path = ( ! isset( $newest_sdk->type ) || 'theme' !== $newest_sdk->type ) ?
--- a/ocean-extra/includes/freemius/templates/forms/license-activation.php
+++ b/ocean-extra/includes/freemius/templates/forms/license-activation.php
@@ -569,7 +569,7 @@
licenseKey = $otherLicenseKey.val();
} else {
if ( ! hasLicensesDropdown ) {
- licenseID = $availableLicenseKey.data( 'id' );
+ licenseID = $availableLicenseKey.data( 'id' ).toString();
} else {
licenseID = $licensesDropdown.val();
}
--- a/ocean-extra/includes/freemius/templates/pricing.php
+++ b/ocean-extra/includes/freemius/templates/pricing.php
@@ -69,6 +69,11 @@
wp_enqueue_script( 'freemius-pricing', $pricing_js_url );
+ $pricing_css_path = $fs->apply_filters( 'pricing/css_path', null );
+ if ( is_string( $pricing_css_path ) ) {
+ wp_enqueue_style( 'freemius-pricing', fs_asset_url( $pricing_css_path ) );
+ }
+
$has_tabs = $fs->_add_tabs_before_content();
if ( $has_tabs ) {
@@ -95,6 +100,8 @@
'unique_affix' => $fs->get_unique_affix(),
'show_annual_in_monthly' => $fs->apply_filters( 'pricing/show_annual_in_monthly', true ),
'license' => $fs->has_active_valid_license() ? $fs->_get_license() : null,
+ 'plugin_icon' => $fs->get_local_icon_url(),
+ 'disable_single_package' => $fs->apply_filters( 'pricing/disable_single_package', false ),
), $query_params );
wp_add_inline_script( 'freemius-pricing', 'Freemius.pricing.new( ' . json_encode( $pricing_config ) . ' )' );
--- a/ocean-extra/includes/plugins-tab.php
+++ b/ocean-extra/includes/plugins-tab.php
@@ -34,8 +34,8 @@
* Enqueues the necessary scripts for handling AJAX plugin installation.
*/
public function enqueue_scripts( $hook_suffix ) {
- // Only enqueue the scripts on the plugin installation page.
- if ( $hook_suffix === 'plugin-install.php' || $hook_suffix === 'plugin-information' ) {
+ // Only enqueue the scripts on the plugin installation page and our custom tab.
+ if ( 'plugin-install.php' === $hook_suffix && isset( $_GET['tab'] ) && 'oceanwp_plugins_tab' === $_GET['tab'] ) {
wp_enqueue_script( 'plugin-install' );
wp_enqueue_script( 'updates' );
wp_enqueue_script( 'oceanwp-plugin-install', plugin_dir_url( __FILE__ ) . '../assets/js/oceanwp-plugin-install.js', array( 'jquery' ), OE_VERSION, true );
@@ -72,29 +72,32 @@
if ( ! current_user_can( 'install_plugins' ) ) {
wp_die( __( 'You do not have sufficient permissions to access this page.', 'ocean-extra' ) );
}
-
+
?>
<div class="wrap">
<h2><?php _e( 'For OceanWP', 'ocean-extra' ); ?></h2>
- <?php
- // Query Plugins by Author.
- $api = plugins_api(
- 'query_plugins',
- array(
- 'author' => 'oceanwp',
- 'per_page' => 20,
- )
- );
-
- if ( is_wp_error( $api ) ) {
- echo '<div class="error"><p>' . $api->get_error_message() . '</p></div>';
- } else {
- $this->ocean_display_plugins_table( $api->plugins );
- }
- ?>
+ <div id="oceanwp-plugin-list">
+ <?php
+ // Query Plugins by Author.
+ $api = plugins_api(
+ 'query_plugins',
+ array(
+ 'author' => 'oceanwp',
+ 'per_page' => 20,
+ )
+ );
+
+ if ( is_wp_error( $api ) ) {
+ echo '<div class="error"><p>' . $api->get_error_message() . '</p></div>';
+ } else {
+ $this->ocean_display_plugins_table( $api->plugins );
+ }
+ ?>
+ </div>
</div>
<?php
}
+
/**
* Displays the plugins using the default WordPress layout.
--- a/ocean-extra/includes/post-settings/assets/index.asset.php
+++ b/ocean-extra/includes/post-settings/assets/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-primitives'), 'version' => '1bc0ef77bcda560111fc');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-primitives'), 'version' => '73df94afd5b3eb33ddab');
--- a/ocean-extra/includes/preloader/customizer.php
+++ b/ocean-extra/includes/preloader/customizer.php
@@ -205,7 +205,7 @@
'oe_title_for_preloader_default_settings' => [
'type' => 'ocean-title',
- 'label' => esc_html__( 'Defualt Preloader Settings', 'ocean-extra' ),
+ 'label' => esc_html__( 'Default Preloader Settings', 'ocean-extra' ),
'section' => 'ocean_preloader',
'transport' => 'postMessage',
'priority' => 10,
--- a/ocean-extra/includes/update-message.php
+++ b/ocean-extra/includes/update-message.php
@@ -92,18 +92,54 @@
}
/**
- * Enqueue scripts
- *
- * @since 2.2.9
+ * Tested up to.
*/
- public function plugin_update_message( $plugin_data, $new_data ) {
+ public function plugin_tested_up_to_content() {
- if ( isset( $plugin_data['update'] ) && $plugin_data['update'] ) {
+ $current_theme_version = oe_get_theme_version();
+ $requires_at_least = $this->oe_get_plugin_header_data( 'ocean-extra/ocean-extra.php', 'RequiresOWP' );
- $this->plugin_update_content();
+ ?>
- }
+ <hr class="owp-update-warning__separator">
+ <div class="owp-update-warning">
+ <div class="warning-info-icon">
+ <span class="dashicons dashicons-info"></span>
+ </div>
+ <div>
+ <div class="warning__title">
+ <?php echo esc_html__( 'Compatibility Alert.', 'ocean-extra' ); ?>
+ </div>
+ <div class="warning__message">
+ <?php
+ printf(
+ esc_html__(
+ 'This plugin update requires compatibility with specific OceanWP theme versions. Please ensure your theme meets the following requirements before proceeding:',
+ 'ocean-extra'
+ ),
+
+ );
+ ?>
+ </div>
+ <div class="owp-required-products">
+ <table class="owp-required-version-table">
+ <tbody>
+ <tr>
+ <th><?php echo esc_html__( 'Items', 'ocean-extra' ); ?></th>
+ <th><?php echo esc_html__( 'Requires at Least', 'ocean-extra' ); ?></th>
+ </tr>
+ <tr>
+ <td><?php echo esc_html__( 'OceanWP', 'ocean-extra' ); ?></td>
+ <td><?php echo esc_attr( $requires_at_least ); ?></td>
+ </tr>
+
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <?php
}
/**
@@ -111,23 +147,40 @@
*
* @since 2.2.9
*/
- public function ms_plugin_update_message( $file, $plugin ) {
+ public function plugin_update_message( $plugin_data, $new_data ) {
- if ( is_multisite() && version_compare( $plugin['Version'], $plugin['new_version'], '<') ) {
+ $current_theme_version = oe_get_theme_version();
- $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
+ if ( ! empty( $current_theme_version ) && version_compare( $current_theme_version, '3.6.1', '<=' ) ) {
+ if ( isset( $plugin_data['update'] ) && $plugin_data['update'] ) {
+ $this->plugin_update_content();
+ }
+ }
- printf(
- '<tr class="plugin-update-tr">
- <td colspan="%s" class="plugin-update update-message notice inline notice-warning notice-alt">%s</td>
- </tr>',
- $wp_list_table->get_column_count(),
- $this->plugin_update_content()
- );
+ $requires_at_least = $this->oe_get_plugin_header_data( 'ocean-extra/ocean-extra.php', 'RequiresOWP' );
+ if ( ! empty( $current_theme_version ) && version_compare( $current_theme_version, $requires_at_least, '<=' ) ) {
+ if ( isset( $plugin_data['update'] ) && $plugin_data['update'] ) {
+ $this->plugin_tested_up_to_content();
+ }
}
}
+ public function oe_get_plugin_header_data( $plugin_slug, $key_name ) {
+
+ $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_slug;
+
+ $headers = array(
+ 'RequiresOWP' => 'OceanWP requires at least',
+ );
+
+ $plugin_data = get_file_data( $plugin_file, $headers );
+
+ $get_data = isset( $plugin_data[$key_name] ) ? $plugin_data[$key_name] : false;
+
+ return $get_data;
+ }
+
/**
* Script
*/
--- a/ocean-extra/ocean-extra.php
+++ b/ocean-extra/ocean-extra.php
@@ -3,11 +3,12 @@
* Plugin Name: Ocean Extra
* Plugin URI: https://oceanwp.org/extension/ocean-extra/
* Description: Add extra features and flexibility to your OceanWP theme for a turbocharged premium experience and full control over every aspect of your website.
- * Version: 2.4.2
+ * Version: 2.4.4
* Author: OceanWP
* Author URI: https://oceanwp.org/
* Requires at least: 5.6
* Tested up to: 6.7
+ * OceanWP requires at least: 4.0.0
* Text Domain: ocean-extra
* Domain Path: /languages
*
@@ -155,9 +156,7 @@
}
$required_theme_version = '3.3.3';
- if ( ! empty( $current_theme_version ) && version_compare( $current_theme_version, '3.6.1', '<=' ) ) {
- include_once $this->plugin_path . '/includes/update-message.php';
- }
+ include_once $this->plugin_path . '/includes/update-message.php';
if ( file_exists( OE_PATH . '/includes/panel/theme-panel.php' ) ) {
require_once OE_PATH . '/includes/panel/theme-panel.php';
@@ -822,6 +821,27 @@
}
+function oe_get_theme_version() {
+
+ $theme = wp_get_theme();
+
+ $current_theme_version = '';
+
+ if ( 'OceanWP' == $theme->name || 'oceanwp' == $theme->template ) {
+
+ if ( get_template_directory() == get_stylesheet_directory() ) {
+ $current_theme_version = $theme->get( 'Version' );
+ } else {
+ $parent = $theme->parent();
+ if ( ! empty( $parent) ) {
+ $current_theme_version = $parent->Version;
+ }
+ }
+ }
+
+ return $current_theme_version;
+}
+
/**
* Display Notice when Ocean Extra is outdated.
*