Skip to content
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

🚀 enhance: StoreGrowth listed to the admin setup wizard recommendation plugins #2512

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Binary file added assets/images/store-growth-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions includes/Admin/RecommendedPlugins.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

namespace WeDevs\Dokan\Admin;

/**
* Recommended Plugins Class.
*
* @since DOKAN_SINCE
*/
class RecommendedPlugins {

/**
* Array of Recommended Plugins.
*
* @var array
*/
protected array $plugins;

/**
* Class Constructor.
*
* @since DOKAN_SINCE
*/
public function __construct() {
$this->plugins = [
[
'type' => 'store_growth',
'title' => __( 'StoreGrowth', 'dokan-lite' ),
'description' => __( 'Best WooCommerce Marketing Solution!', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/store-growth-logo.png',
'img_alt' => __( 'StoreGrowth logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'StoreGrowth', 'dokan-lite' ),
'slug' => 'storegrowth-sales-booster',
'basename' => 'storegrowth-sales-booster/storegrowth-sales-booster.php',
],
],
],
[
'type' => 'wemail',
'title' => __( 'weMail', 'dokan-lite' ),
'description' => __( 'Simplified Email Marketing Solution for WordPress!', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/wemail-logo.png',
'img_alt' => __( 'weMail logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'weMail', 'dokan-lite' ),
'slug' => 'wemail',
'basename' => 'wemail/wemail.php',
],
],
],
[
'type' => 'wc_conversion_tracking',
'title' => __( 'WooCommerce Conversion Tracking', 'dokan-lite' ),
'description' => __( 'Track conversions on your WooCommerce store like a pro!', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/wc-conversion-tracking-logo.png',
'img_alt' => __( 'WooCommerce Conversion Tracking logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'WooCommerce Conversion Tracking', 'dokan-lite' ),
'slug' => 'woocommerce-conversion-tracking',
'basename' => 'woocommerce-conversion-tracking/conversion-tracking.php',
],
],
],
[
'type' => 'texty',
'title' => __( 'Texty', 'dokan-lite' ),
'description' => __( 'SMS Notification for WordPress, WooCommerce, Dokan and more!', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/texty-logo.png',
'img_alt' => __( 'Texty logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'Texty', 'dokan-lite' ),
'slug' => 'texty',
'basename' => 'texty/texty.php',
],
],
],
];
}

/**
* Get All Enlisted Plugins.
*
* @since DOKAN_SINCE
*
* @return array
*/
protected function get_enlisted_plugins(): array {
return apply_filters( 'dokan_recommended_plugins_list', $this->plugins );
}

/**
* Is Plugin Active.
*
* @since DOKAN_SINCE
*
* @param string $basename
*
* @return bool
*/
protected function is_active( string $basename ): bool {
return apply_filters( 'dokan_recommended_plugin_is_active', is_plugin_active( $basename ), $basename );
}

/**
* Get List of Recommended Inactive Plugins.
*
* @since DOKAN_SINCE
*
* @return array
*/
public function get(): array {
$enlisted_plugins = $this->get_enlisted_plugins();

$recommended_plugins = array_filter(
$enlisted_plugins,
function ( $plugin ) {
return isset( $plugin['plugins'][0]['basename'] ) && ! $this->is_active( $plugin['plugins'][0]['basename'] );
}
);

return apply_filters( 'dokan_recommended_inactive_plugins', $recommended_plugins );
}
}
175 changes: 52 additions & 123 deletions includes/Admin/SetupWizard.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ class SetupWizard {
*/
private $deferred_actions = [];

/**
* Instance of RecommendedPlugins class for managing plugin recommendations.
*
* @since DOKAN_SINCE
*
* @var RecommendedPlugins Handles the retrieval and management of recommended plugins
*/
private RecommendedPlugins $recommended_plugins;

/**
* Hook in tabs.
*/
Expand All @@ -35,6 +44,8 @@ public function __construct() {
}

if ( current_user_can( 'manage_woocommerce' ) ) {
$this->recommended_plugins = new RecommendedPlugins();

add_action( 'admin_menu', [ $this, 'admin_menus' ] );
add_action( 'admin_init', [ $this, 'setup_wizard' ], 99 );

Expand Down Expand Up @@ -699,58 +710,8 @@ public function dokan_setup_recommended() {
<ul class="recommended-step">
<?php
if ( $this->user_can_install_plugin() ) {
if ( ! $this->is_wc_conversion_tracking_active() ) {
$this->display_recommended_item(
[
'type' => 'wc_conversion_tracking',
'title' => __( 'WooCommerce Conversion Tracking', 'dokan-lite' ),
'description' => __( 'Track conversions on your WooCommerce store like a pro!', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/wc-conversion-tracking-logo.png',
'img_alt' => __( 'WooCommerce Conversion Tracking logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'WooCommerce Conversion Tracking', 'dokan-lite' ),
'slug' => 'woocommerce-conversion-tracking',
],
],
]
);
}

if ( ! $this->is_wemail_active() ) {
$this->display_recommended_item(
[
'type' => 'wemail',
'title' => __( 'weMail', 'dokan-lite' ),
'description' => __( 'Simplified Email Marketing Solution for WordPress!', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/wemail-logo.png',
'img_alt' => __( 'weMail logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'weMail', 'dokan-lite' ),
'slug' => 'wemail',
],
],
]
);
}

if ( ! $this->is_texty_active() ) {
$this->display_recommended_item(
[
'type' => 'texty',
'title' => __( 'Texty', 'dokan-lite' ),
'description' => __( 'SMS Notification for WordPress, WooCommerce, Dokan and more', 'dokan-lite' ),
'img_url' => DOKAN_PLUGIN_ASSEST . '/images/texty-logo.png',
'img_alt' => __( 'Texty logo', 'dokan-lite' ),
'plugins' => [
[
'name' => __( 'Texty', 'dokan-lite' ),
'slug' => 'texty',
],
],
]
);
foreach ( $this->recommended_plugins->get() as $plugin ) {
$this->display_recommended_item( $plugin );
}
}
?>
Expand All @@ -772,41 +733,25 @@ public function dokan_setup_recommended() {
* @return void
*/
public function dokan_setup_recommended_save() {
check_admin_referer( 'dokan-setup' );
foreach ( $this->recommended_plugins->get() as $plugin ) {
if ( ! $this->should_install_plugin( $plugin ) ) {
continue;
}

$setup_wc_conversion_tracking = isset( $_POST['setup_wc_conversion_tracking'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['setup_wc_conversion_tracking'] ) );
$setup_wemail = isset( $_POST['setup_wemail'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['setup_wemail'] ) );
$setup_texty = isset( $_POST['setup_texty'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['setup_texty'] ) );
$plugin_details = $plugin['plugins'][0] ?? null;

if ( $setup_wc_conversion_tracking && ! $this->is_wc_conversion_tracking_active() ) {
$this->install_plugin(
'woocommerce-conversion-tracking',
[
'name' => __( 'WooCommerce Conversion Tracking', 'dokan-lite' ),
'repo-slug' => 'woocommerce-conversion-tracking',
'file' => 'conversion-tracking.php',
]
);
}
if ( ! $plugin_details ) {
continue;
}

if ( $setup_wemail && ! $this->is_wemail_active() ) {
$this->install_plugin(
'wemail',
[
'name' => __( 'weMail', 'dokan-lite' ),
'repo-slug' => 'wemail',
'file' => 'wemail.php',
]
);
}
$plugin_details_arr = explode( '/', $plugin_details['basename'] ?? '' );

if ( $setup_texty && ! $this->is_texty_active() ) {
$this->install_plugin(
'texty',
$plugin_details['slug'],
[
'name' => __( 'Texty', 'dokan-lite' ),
'repo-slug' => 'texty',
'file' => 'texty.php',
'name' => $plugin_details['name'] ?? '',
'repo-slug' => $plugin_details_arr[0] ?? '',
'file' => $plugin_details_arr[1] ?? '',
Comment on lines +736 to +754
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance array access safety and consistency.

Consider these improvements for safer array handling:

  1. Use null coalescing operator consistently
  2. Add validation for plugin details array structure
  3. Use array_key_exists for safer checks

Apply this diff to improve the code:

 foreach ( $this->recommended_plugins->get() as $plugin ) {
     if ( ! $this->should_install_plugin( $plugin ) ) {
         continue;
     }

-    $plugin_details = $plugin['plugins'][0] ?? null;
+    if ( ! isset( $plugin['plugins'] ) || ! is_array( $plugin['plugins'] ) || empty( $plugin['plugins'] ) ) {
+        continue;
+    }
+
+    $plugin_details = $plugin['plugins'][0];

     if ( ! $plugin_details ) {
         continue;
     }

-    $plugin_details_arr = explode( '/', $plugin_details['basename'] ?? '' );
+    $basename = $plugin_details['basename'] ?? '';
+    if ( empty( $basename ) ) {
+        continue;
+    }
+
+    $plugin_details_arr = explode( '/', $basename );

     $this->install_plugin(
         $plugin_details['slug'],
         [
-            'name'      => $plugin_details['name'] ?? '',
-            'repo-slug' => $plugin_details_arr[0] ?? '',
-            'file'      => $plugin_details_arr[1] ?? '',
+            'name'      => $plugin_details['name'] ?? 'Unknown Plugin',
+            'repo-slug' => $plugin_details_arr[0] ?? $plugin_details['slug'],
+            'file'      => $plugin_details_arr[1] ?? $plugin_details['slug'] . '.php',
         ]
     );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
foreach ( $this->recommended_plugins->get() as $plugin ) {
if ( ! $this->should_install_plugin( $plugin ) ) {
continue;
}
$setup_wc_conversion_tracking = isset( $_POST['setup_wc_conversion_tracking'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['setup_wc_conversion_tracking'] ) );
$setup_wemail = isset( $_POST['setup_wemail'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['setup_wemail'] ) );
$setup_texty = isset( $_POST['setup_texty'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['setup_texty'] ) );
$plugin_details = $plugin['plugins'][0] ?? null;
if ( $setup_wc_conversion_tracking && ! $this->is_wc_conversion_tracking_active() ) {
$this->install_plugin(
'woocommerce-conversion-tracking',
[
'name' => __( 'WooCommerce Conversion Tracking', 'dokan-lite' ),
'repo-slug' => 'woocommerce-conversion-tracking',
'file' => 'conversion-tracking.php',
]
);
}
if ( ! $plugin_details ) {
continue;
}
if ( $setup_wemail && ! $this->is_wemail_active() ) {
$this->install_plugin(
'wemail',
[
'name' => __( 'weMail', 'dokan-lite' ),
'repo-slug' => 'wemail',
'file' => 'wemail.php',
]
);
}
$plugin_details_arr = explode( '/', $plugin_details['basename'] ?? '' );
if ( $setup_texty && ! $this->is_texty_active() ) {
$this->install_plugin(
'texty',
$plugin_details['slug'],
[
'name' => __( 'Texty', 'dokan-lite' ),
'repo-slug' => 'texty',
'file' => 'texty.php',
'name' => $plugin_details['name'] ?? '',
'repo-slug' => $plugin_details_arr[0] ?? '',
'file' => $plugin_details_arr[1] ?? '',
foreach ( $this->recommended_plugins->get() as $plugin ) {
if ( ! $this->should_install_plugin( $plugin ) ) {
continue;
}
if ( ! isset( $plugin['plugins'] ) || ! is_array( $plugin['plugins'] ) || empty( $plugin['plugins'] ) ) {
continue;
}
$plugin_details = $plugin['plugins'][0];
if ( ! $plugin_details ) {
continue;
}
$basename = $plugin_details['basename'] ?? '';
if ( empty( $basename ) ) {
continue;
}
$plugin_details_arr = explode( '/', $basename );
$this->install_plugin(
$plugin_details['slug'],
[
'name' => $plugin_details['name'] ?? 'Unknown Plugin',
'repo-slug' => $plugin_details_arr[0] ?? $plugin_details['slug'],
'file' => $plugin_details_arr[1] ?? $plugin_details['slug'] . '.php',
]
);

]
);
}
Expand All @@ -827,6 +772,27 @@ public function dokan_setup_recommended_save() {
exit;
}

/**
* Determines if a plugin should be installed based on POST data.
*
* @since DOKAN_SINCE
*
* @param array $plugin Plugin configuration array
*
* @return bool
*/
private function should_install_plugin( array $plugin ): bool {
check_admin_referer( 'dokan-setup' );

$setup_key = 'setup_' . $plugin['type'];

if ( ! isset( $_POST[ $setup_key ] ) ) {
return false;
}

return 'yes' === sanitize_text_field( wp_unslash( $_POST[ $setup_key ] ) );
}
Comment on lines +775 to +794
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve security and validation in should_install_plugin method.

Consider these improvements:

  1. Move nonce verification to the caller (dokan_setup_recommended_save)
  2. Add validation for the plugin array structure

Apply this diff to improve the code:

 private function should_install_plugin( array $plugin ): bool {
-    check_admin_referer( 'dokan-setup' );
+    if ( ! isset( $plugin['type'] ) || empty( $plugin['type'] ) ) {
+        return false;
+    }

     $setup_key = 'setup_' . $plugin['type'];

     if ( ! isset( $_POST[ $setup_key ] ) ) {
         return false;
     }

     return 'yes' === sanitize_text_field( wp_unslash( $_POST[ $setup_key ] ) );
 }

And in dokan_setup_recommended_save method:

 public function dokan_setup_recommended_save() {
+    check_admin_referer( 'dokan-setup' );
+
     foreach ( $this->recommended_plugins->get() as $plugin ) {

Committable suggestion skipped: line range outside the PR's diff.


/**
* Save withdraw options.
*/
Expand Down Expand Up @@ -891,54 +857,13 @@ protected function should_show_recommended_step() {
return false;
}

if ( $this->is_wc_conversion_tracking_active() ) {
return false;
}

if ( $this->is_wemail_active() ) {
return false;
}

if ( $this->is_texty_active() ) {
if ( ! count( $this->recommended_plugins->get() ) ) {
return false;
}

return true;
}

/**
* Check if WC Conversion Tracking is active or not
*
* @since 2.8.7
*
* @return bool
*/
protected function is_wc_conversion_tracking_active() {
return is_plugin_active( 'woocommerce-conversion-tracking/conversion-tracking.php' );
}

/**
* Check if weMail is active or not
*
* @since 3.0.0
*
* @return bool
*/
protected function is_wemail_active() {
return is_plugin_active( 'wemail/wemail.php' );
}

/**
* Check if texty is active or not
*
* @since 3.2.11
*
* @return bool
*/
protected function is_texty_active() {
return is_plugin_active( 'texty/texty.php' );
}

/**
* Should we show the WooCommerce Conversion Tracking install option?
*
Expand Down Expand Up @@ -1012,6 +937,10 @@ public function plugin_install_info() {
* @param array $plugin_info Plugin info array containing name and repo-slug, and optionally file if different from [repo-slug].php.
*/
protected function install_plugin( $plugin_id, $plugin_info ) {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return;
}

// Make sure we don't trigger multiple simultaneous installs.
if ( get_option( 'woocommerce_setup_background_installing_' . $plugin_id ) ) {
return;
Expand Down
3 changes: 2 additions & 1 deletion tests/pw/pages/adminPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ export class AdminPage extends BasePage {
await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.backend.dokan.setupWizardWithdraw, setupWizardAdmin.continue, 302);

// Recommended
await this.disableSwitcherSetupWizard(setupWizardAdmin.wooCommerceConversionTracking);
await this.disableSwitcherSetupWizard(setupWizardAdmin.storeGrowth);
await this.disableSwitcherSetupWizard(setupWizardAdmin.weMail);
await this.disableSwitcherSetupWizard(setupWizardAdmin.wooCommerceConversionTracking);
await this.disableSwitcherSetupWizard(setupWizardAdmin.texty);
await this.click(setupWizardAdmin.continueRecommended);

Expand Down
3 changes: 2 additions & 1 deletion tests/pw/pages/commissionPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ export class CommissionPage extends AdminPage {
await this.click(setupWizardAdmin.skipThisStep);

// recommended
await this.disableSwitcherSetupWizard(setupWizardAdmin.wooCommerceConversionTracking);
await this.disableSwitcherSetupWizard(setupWizardAdmin.storeGrowth);
await this.disableSwitcherSetupWizard(setupWizardAdmin.weMail);
await this.disableSwitcherSetupWizard(setupWizardAdmin.wooCommerceConversionTracking);
await this.disableSwitcherSetupWizard(setupWizardAdmin.texty);
await this.click(setupWizardAdmin.continueRecommended);

Expand Down
3 changes: 2 additions & 1 deletion tests/pw/pages/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2664,8 +2664,9 @@ export const selector = {

// Recommended
recommendedHeading: '//h1[normalize-space()="Recommended for All Dokan Marketplaces"]',
wooCommerceConversionTracking: '//label[@for="dokan_recommended_wc_conversion_tracking"]',
storeGrowth: '//label[@for="dokan_recommended_store_growth"]',
weMail: '//label[@for="dokan_recommended_wemail"]',
wooCommerceConversionTracking: '//label[@for="dokan_recommended_wc_conversion_tracking"]',
texty: '//label[@for="dokan_recommended_texty"]',
continueRecommended: '.button-primary',

Expand Down
Loading