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

Enhancement: product commission bulk edit #2464

Merged
merged 6 commits into from
Dec 6, 2024
Merged
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
46 changes: 46 additions & 0 deletions includes/Admin/Hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace WeDevs\Dokan\Admin;

use WeDevs\Dokan\Product\Hooks as ProductHooks;
use WP_Post;

// don't call the file directly
Expand Down Expand Up @@ -35,6 +36,9 @@ public function __construct() {

// Ajax hooks
add_action( 'wp_ajax_dokan_product_search_author', [ $this, 'search_vendors' ] );

add_action( 'woocommerce_product_bulk_edit_end', [ $this, 'add_product_commission_bulk_edit_field' ] );
add_action( 'woocommerce_product_bulk_edit_save', [ $this, 'save_custom_bulk_edit_field' ], 10, 1 );
}

/**
Expand Down Expand Up @@ -223,4 +227,46 @@ public function update_pages( $value, $name ) {

return array_replace_recursive( $current_settings, $value );
}

/**
* Add commission settings in bulk product edit.
*
* @since DOKAN_SINCE
*
* @return void
*/
public function add_product_commission_bulk_edit_field() {
dokan_get_template_part( 'products/dokan-products-edit-bulk-commission', '', [] );
}

/**
* Save commission settings from bulk product edit
*
* @since DOKAN_SINCE
*
* @param \WC_Product $product
*
* @return void
*/
public function save_custom_bulk_edit_field( $product ) {
$excluded_product_types = apply_filters( 'dokan_excluded_product_types_for_bulk_edit', [ 'product_pack', 'external', 'grouped' ] );
$dokan_advertisement_product_id = intval( get_option( 'dokan_advertisement_product_id', '' ) );
$dokan_reverse_withdrawal_product_id = intval( get_option( 'dokan_reverse_withdrawal_product_id', '' ) );
$product_id = $product->get_id();

if (
! current_user_can( 'manage_woocommerce' ) ||
in_array( $product->get_type(), $excluded_product_types, true ) ||
$product_id === $dokan_advertisement_product_id ||
$product_id === $dokan_reverse_withdrawal_product_id
) {
return;
}

if ( ! isset( $_REQUEST['dokan_override_bulk_product_commission'] ) || intval( sanitize_text_field( $_REQUEST['dokan_override_bulk_product_commission'] ) ) !== 1 ) { // phpcs:ignore
return;
}

ProductHooks::save_per_product_commission_options( $product->get_id(), $_REQUEST ); // phpcs:ignore
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

Avoid Direct Use of $_REQUEST and Suppressing PHPCS Warnings

Directly accessing $_REQUEST and ignoring PHPCS warnings is discouraged. Instead, sanitize and validate the input properly without suppressing coding standards.

Refactor to sanitize inputs and adhere to coding standards:

-    ProductHooks::save_per_product_commission_options( $product->get_id(), $_REQUEST ); // phpcs:ignore
+    $sanitized_data = filter_input_array( INPUT_POST, [
+        '_per_product_admin_commission_type'   => FILTER_SANITIZE_STRING,
+        '_per_product_admin_commission'        => FILTER_SANITIZE_STRING,
+        '_per_product_admin_additional_fee'    => FILTER_SANITIZE_STRING,
+    ] );
+    ProductHooks::save_per_product_commission_options( $product->get_id(), $sanitized_data );

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

}
}
35 changes: 22 additions & 13 deletions includes/Product/Hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace WeDevs\Dokan\Product;

use WeDevs\Dokan\Commission\Formula\Fixed;
use WeDevs\Dokan\ProductCategory\Helper;
use WC_Product;

Expand Down Expand Up @@ -188,11 +189,11 @@
<div class="dokan-store-products-filter-area dokan-clearfix">
<form class="dokan-store-products-ordeby" method="get">
<input type="text" name="product_name" class="product-name-search dokan-store-products-filter-search"
placeholder="<?php esc_attr_e( 'Enter product name', 'dokan-lite' ); ?>" autocomplete="off"

Check warning on line 192 in includes/Product/Hooks.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 3 spaces.
data-store_id="<?php echo esc_attr( $store_id ); ?>">

Check warning on line 193 in includes/Product/Hooks.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 3 spaces.
<div id="dokan-store-products-search-result" class="dokan-ajax-store-products-search-result"></div>
<input type="submit" name="search_store_products" class="search-store-products dokan-btn-theme"
value="<?php esc_attr_e( 'Search', 'dokan-lite' ); ?>">

Check warning on line 196 in includes/Product/Hooks.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 3 spaces.

<?php if ( is_array( $orderby_options['catalogs'] ) && isset( $orderby_options['orderby'] ) ) : ?>
<select name="product_orderby" class="orderby orderby-search"
Expand Down Expand Up @@ -521,37 +522,45 @@
*
* @since 2.4.12
*
* @param integer $post_id
* @param integer $post_id
* @param array $data
*
* @return void
*/
public static function save_per_product_commission_options( $post_id ) {
public static function save_per_product_commission_options( $post_id, $data = [] ) {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return;
}

$commission_type = '';
$commission_type = Fixed::SOURCE;
Comment on lines +530 to +535
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

Refactor to Avoid Direct Access to $_POST and PHPCS Ignore

Accessing $_POST directly is discouraged due to security and code quality concerns. The use of // phpcs:ignore suppresses potential warnings, but it's better to adhere to coding standards.

Consider refactoring to use filter_input_array for better input handling and compliance:

 public static function save_per_product_commission_options( $post_id, $data = [] ) {
     if ( ! current_user_can( 'manage_woocommerce' ) ) {
         return;
     }

-    $data = empty( $data ) ? $_POST : $data; // phpcs:ignore
+    if ( empty( $data ) ) {
+        $data = filter_input_array( INPUT_POST, [
+            '_per_product_admin_commission_type' => FILTER_SANITIZE_STRING,
+            '_per_product_admin_commission'      => FILTER_SANITIZE_STRING,
+            '_per_product_admin_additional_fee'  => FILTER_SANITIZE_STRING,
+        ] );
+    }

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

$admin_commission = '';
$additional_fee = '';
$data = empty( $data ) ? $_POST : $data; // phpcs:ignore

if ( isset( $_POST['_per_product_admin_commission_type'] ) ) { // phpcs:ignore
$commission_type = ! empty( $_POST['_per_product_admin_commission_type'] ) ? sanitize_text_field( $_POST['_per_product_admin_commission_type'] ) : 'percentage'; // phpcs:ignore
update_post_meta( $post_id, '_per_product_admin_commission_type', $commission_type );
if ( isset( $data['_per_product_admin_commission_type'] ) ) {
$commission_type = ! empty( $data['_per_product_admin_commission_type'] ) ? sanitize_text_field( $data['_per_product_admin_commission_type'] ) : Fixed::SOURCE;
}

if ( isset( $_POST['_per_product_admin_commission'] ) ) { // phpcs:ignore
$_per_product_admin_commission = wc_format_decimal( sanitize_text_field( $_POST['_per_product_admin_commission'] ) ); // phpcs:ignore
if ( isset( $data['_per_product_admin_commission'] ) ) {
$_per_product_admin_commission = wc_format_decimal( sanitize_text_field( $data['_per_product_admin_commission'] ) );

if ( 0 <= $_per_product_admin_commission && 100 >= $_per_product_admin_commission ) {
$admin_commission = ( '' === $_POST['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission; // phpcs:ignore
$admin_commission = ( '' === $data['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission;
Comment on lines +545 to +548
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Validate Commission Percentage Input

When processing the commission percentage, consider adding validation to ensure the input is numeric and within the expected range (0 to 100). Currently, non-numeric input could cause unintended behavior.

Add a check to validate the input:

     $_per_product_admin_commission = wc_format_decimal( sanitize_text_field( $data['_per_product_admin_commission'] ) );

+    if ( ! is_numeric( $_per_product_admin_commission ) ) {
+        $_per_product_admin_commission = 0;
+    }

     if ( 0 <= $_per_product_admin_commission && 100 >= $_per_product_admin_commission ) {
         $admin_commission = ( '' === $data['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission;
     }
📝 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
$_per_product_admin_commission = wc_format_decimal( sanitize_text_field( $data['_per_product_admin_commission'] ) );
if ( 0 <= $_per_product_admin_commission && 100 >= $_per_product_admin_commission ) {
$admin_commission = ( '' === $_POST['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission; // phpcs:ignore
$admin_commission = ( '' === $data['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission;
$_per_product_admin_commission = wc_format_decimal( sanitize_text_field( $data['_per_product_admin_commission'] ) );
if ( ! is_numeric( $_per_product_admin_commission ) ) {
$_per_product_admin_commission = 0;
}
if ( 0 <= $_per_product_admin_commission && 100 >= $_per_product_admin_commission ) {
$admin_commission = ( '' === $data['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission;

}
}

if ( isset( $_POST['_per_product_admin_additional_fee'] ) ) { // phpcs:ignore
$additional_fee = ( '' === $_POST['_per_product_admin_additional_fee'] ) ? '' : sanitize_text_field( $_POST['_per_product_admin_additional_fee'] ); // phpcs:ignore
if ( isset( $data['_per_product_admin_additional_fee'] ) ) {
$additional_fee = ( '' === $data['_per_product_admin_additional_fee'] ) ? '' : sanitize_text_field( $data['_per_product_admin_additional_fee'] );
$additional_fee = wc_format_decimal( $additional_fee );
Comment on lines +552 to +554
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add validation for additional fee

The additional fee should be validated to prevent negative values.

     if ( isset( $data['_per_product_admin_additional_fee'] ) ) {
         $additional_fee = ( '' === $data['_per_product_admin_additional_fee'] ) ? '' : sanitize_text_field( $data['_per_product_admin_additional_fee'] );
         $additional_fee = wc_format_decimal( $additional_fee );
+        if ( $additional_fee < 0 ) {
+            $additional_fee = 0;
+        }
     }
📝 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
if ( isset( $data['_per_product_admin_additional_fee'] ) ) {
$additional_fee = ( '' === $data['_per_product_admin_additional_fee'] ) ? '' : sanitize_text_field( $data['_per_product_admin_additional_fee'] );
$additional_fee = wc_format_decimal( $additional_fee );
if ( isset( $data['_per_product_admin_additional_fee'] ) ) {
$additional_fee = ( '' === $data['_per_product_admin_additional_fee'] ) ? '' : sanitize_text_field( $data['_per_product_admin_additional_fee'] );
$additional_fee = wc_format_decimal( $additional_fee );
if ( $additional_fee < 0 ) {
$additional_fee = 0;
}

}

update_post_meta( $post_id, '_per_product_admin_commission', $admin_commission );
update_post_meta( $post_id, '_per_product_admin_additional_fee', wc_format_decimal( $additional_fee ) );
dokan()->product->save_commission_settings(
$post_id,
[
'type' => $commission_type,
'percentage' => $admin_commission,
'flat' => $additional_fee,
]
);
}
}
42 changes: 42 additions & 0 deletions templates/products/dokan-products-edit-bulk-commission.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/**
* Template Name: Dokan commission setting bulk product edit
*
* @since DOKAN_SINCE
*
* @package Dokan
*/

use WeDevs\Dokan\Commission\Formula\Fixed;
?>

<div class="inline-edit-col" style="float: left">
<h4><?php esc_html_e( 'Commission settings', 'dokan-lite' ); ?></h4>
<div class="inline-edit-group">
<label class="alignleft">
<span class="title"><?php esc_html_e( 'Commission', 'dokan-lite' ); ?></span>
<span class="input-text-wrap">
<select class="dokan_override_bulk_product_commission change_to" name="dokan_override_bulk_product_commission">
<option value=""><?php esc_html_e( '— No change —', 'dokan-lite' ); ?></option>
<option value="1"><?php esc_html_e( 'Change to:', 'dokan-lite' ); ?></option>
</select>
</span>
</label>
<div class="change-input inline-edit-group dokan-admin-bulk-product-commission-data-box" style="">
<div>
<label for="admin_commission">
<?php esc_html_e( 'Fixed', 'dokan-lite' ); ?>
</label>

<span class="input-text-wrap" style="display: flex">
<input type="hidden" name="_per_product_admin_commission_type" value="<?php echo esc_attr( Fixed::SOURCE ); ?>">
<input class="input-text wc_input_price" min="0" max="100" type="text" name="_per_product_admin_commission" value=""/>
<span style="display: flex; align-items: center">%&nbsp;&nbsp;+</span>
<input type="text" name="_per_product_admin_additional_fee" class="input-text wc_input_price" value="">
</span>
</span>
</div>
</div>
</div>
</div>
Loading