Skip to content

Add features that allow restriction of the number of wpcom plugins per plan to wpsh #43108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

wpcomsh: add plugin limit features to be used for lower tier plans
15 changes: 15 additions & 0 deletions projects/plugins/wpcomsh/constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,18 @@

// Date for lowering storage from 200 GB to 50 GB for business and higher plans. Ref: D108151-code.
define( 'LEGACY_200GB_CUTOFF_DATE', '2023-07-20' );

define(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the right way, I'll look into it tomorrow and see if I can come up with another way for identifying the default plugins.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find a better way, maybe one will surface during code review. There's a list of woa-specific jetpack plugins that have their activation/deactivation altered but it doesn't include things like the ones here. I'm leaving it as is.

'WOA_SOFTWARE_SET_DEFAULT',
array(
'plugins/akismet',
'plugins/jetpack',
'plugins/classic-editor',
'plugins/gutenberg',
'plugins/layout-grid',
'plugins/page-optimize',
'plugins/crowdsignal-forms',
'plugins/polldaddy',
'themes/pub/twentytwentytwo',
)
);
70 changes: 70 additions & 0 deletions projects/plugins/wpcomsh/feature-plugins/hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,73 @@ function wpcomsh_remove_jetpack_manage_menu_item() {
}

add_action( 'admin_menu', 'wpcomsh_remove_jetpack_manage_menu_item', 1001 ); // Automattic\Jetpack\Admin_UI\Admin_Menu uses 1000.

/**
* Prevent plugin activation if it would exceed the plan's plugin limit.
*
* @param array $new_value The new value of the option.
* @param array $old_value The old value of the option.
* @return array|WP_Error The filtered value.
*/
function wpcomsh_prevent_exceeding_plugin_limit( $new_value, $old_value ) {
// Skip check for network-wide operations
if ( is_multisite() && is_network_admin() ) {
return $new_value;
}

$newly_activated = array_diff( $new_value, $old_value );
if ( empty( $newly_activated ) ) {
return $new_value;
}

// Check if all newly activated plugins are default plugins
$has_non_default = false;
foreach ( $newly_activated as $plugin ) {
if ( ! wpcomsh_is_default_plugin( $plugin ) ) {
$has_non_default = true;
break;
}
}

// If all newly activated plugins are default plugins, allow the activation
if ( ! $has_non_default ) {
return $new_value;
}

// Otherwise check if we would exceed the limit
if ( wpcomsh_would_exceed_plugin_limit( $new_value ) ) {
// Return the old value to prevent the update
return $old_value;
}

return $new_value;
}
add_filter( 'pre_update_option_active_plugins', 'wpcomsh_prevent_exceeding_plugin_limit', 10, 2 );

/**
* Remove activation links for non-default plugins when the plugin limit is reached.
*
* @param array $actions Array of plugin action links.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @return array Modified array of plugin action links.
*/
function wpcomsh_maybe_remove_activation_link( $actions, $plugin_file ) {
// Skip if no activate action or if it's a default plugin
if ( ! isset( $actions['activate'] ) || wpcomsh_is_default_plugin( $plugin_file ) ) {
return $actions;
}

// Get currently active plugins
$active_plugins = get_option( 'active_plugins', array() );

// Add this plugin to the list to simulate its activation
$active_plugins[] = $plugin_file;

// Check if activating this plugin would exceed the limit
if ( wpcomsh_would_exceed_plugin_limit( $active_plugins ) ) {
$actions['activate'] = __( 'Plugin limit reached', 'wpcomsh' );
}

return $actions;
}
add_filter( 'plugin_action_links', 'wpcomsh_maybe_remove_activation_link', 10, 2 );
60 changes: 60 additions & 0 deletions projects/plugins/wpcomsh/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,63 @@ function wpcomsh_newsletter_categories_location() {
* @see https://github.com/Automattic/wp-calypso/issues/100279
*/
add_filter( 'send_email_change_email', '__return_false' );

/**
* Check if a plugin is part of the default WOA software set.
*
* @param string $plugin Plugin path relative to the plugins directory (e.g. 'akismet/akismet.php').
* @return bool True if the plugin is part of the default set, false otherwise.
*/
function wpcomsh_is_default_plugin( $plugin ) {
if ( ! defined( 'WOA_SOFTWARE_SET_DEFAULT' ) ) {
return false;
}

// Extract the plugin folder name from the full plugin path
$plugin_folder = explode( '/', $plugin )[0];

// Check if the plugin folder exists in the default set
foreach ( WOA_SOFTWARE_SET_DEFAULT as $default_item ) {
if ( strpos( $default_item, 'plugins/' ) === 0 && $plugin_folder === substr( $default_item, 8 ) ) {
return true;
}
}

return false;
}

/**
* Check if the given list of plugins would exceed the plan's plugin limit.
*
* @param array $plugins Array of plugin paths to check.
* @return bool True if the plugin count would exceed the limit, false otherwise.
*/
function wpcomsh_would_exceed_plugin_limit( $plugins ) {
if ( ! is_array( $plugins ) ) {
return false;
}

// If site doesn't have either limit feature, no limit applies
if ( ! wpcom_site_has_feature( WPCOM_Features::PLUGINS_ALLOW_ONE ) && ! wpcom_site_has_feature( WPCOM_Features::PLUGINS_ALLOW_THREE ) ) {
return false;
}

// Count non-default active plugins
$active_count = 0;
foreach ( $plugins as $plugin ) {
if ( ! wpcomsh_is_default_plugin( $plugin ) ) {
++$active_count;
}
}

// Check against plan limits
if ( wpcom_site_has_feature( WPCOM_Features::PLUGINS_ALLOW_ONE ) && $active_count > 1 ) {
return true;
}

if ( wpcom_site_has_feature( WPCOM_Features::PLUGINS_ALLOW_THREE ) && $active_count > 3 ) {
return true;
}

return false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ class WPCOM_Features {
public const OPTIONS_PERMALINK = 'options-permalink';
public const PAYMENTS = 'payments';
public const PERFORMANCE_HISTORY = 'performance-history';
public const PLUGINS_ALLOW_ONE = 'plugins-allow-one';
public const PLUGINS_ALLOW_THREE = 'plugins-allow-three';
public const POLLDADDY = 'polldaddy';
public const PREMIUM_CONTENT_CONTAINER = 'premium-content/container';
public const PERSONAL_THEMES = 'personal-themes';
Expand Down Expand Up @@ -884,6 +886,12 @@ class WPCOM_Features {
self::JETPACK_BOOST_PLANS,
self::JETPACK_COMPLETE_PLANS,
),
self::PLUGINS_ALLOW_ONE => array(
self::WPCOM_PERSONAL_PLANS,
),
self::PLUGINS_ALLOW_THREE => array(
self::WPCOM_PREMIUM_PLANS,
),
self::POLLDADDY => array(
self::JETPACK_BUSINESS_PLANS,
),
Expand Down
Loading