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/product category rest api #2510

Conversation

osmansufy
Copy link
Contributor

@osmansufy osmansufy commented Jan 13, 2025

All Submissions:

  • My code follow the WordPress' coding standards
  • My code satisfies feature requirements
  • My code is tested
  • My code passes the PHPCS tests
  • My code has proper inline documentation
  • I've included related pull request(s) (optional)
  • I've included developer documentation (optional)
  • I've added proper labels to this pull request

Changes proposed in this Pull Request:

Related Pull Request(s)

  • Full PR Link

Closes

How to test the changes in this Pull Request:

  • Steps or issue link

Changelog entry

Title

Detailed Description of the pull request. What was previous behaviour
and what will be changed in this PR.

Before Changes

Describe the issue before changes with screenshots(s).

After Changes

Describe the issue after changes with screenshot(s).

Feature Video (optional)

Link of detailed video if this PR is for a feature.

PR Self Review Checklist:

  • Code is not following code style guidelines
  • Bad naming: make sure you would understand your code if you read it a few months from now.
  • KISS: Keep it simple, Sweetie (not stupid!).
  • DRY: Don't Repeat Yourself.
  • Code that is not readable: too many nested 'if's are a bad sign.
  • Performance issues
  • Complicated constructions that need refactoring or comments: code should almost always be self-explanatory.
  • Grammar errors.

FOR PR REVIEWER ONLY:

As a reviewer, your feedback should be focused on the idea, not the person. Seek to understand, be respectful, and focus on constructive dialog.

As a contributor, your responsibility is to learn from suggestions and iterate your pull request should it be needed based on feedback. Seek to collaborate and produce the best possible contribution to the greater whole.

  • Correct — Does the change do what it’s supposed to? ie: code 100% fulfilling the requirements?
  • Secure — Would a nefarious party find some way to exploit this change? ie: everything is sanitized/escaped appropriately for any SQL or XSS injection possibilities?
  • Readable — Will your future self be able to understand this change months down the road?
  • Elegant — Does the change fit aesthetically within the overall style and architecture?

Summary by CodeRabbit

  • New Features

    • Added a new REST API endpoint for vendor product categories.
    • Implemented vendor-specific product category retrieval and filtering.
    • Enhanced product category management for vendors.
  • Tests

    • Added comprehensive test suite for product category API endpoint.
    • Included tests for authentication, pagination, search, and filtering.
  • Improvements

    • Refined access controls for product category operations.

@osmansufy osmansufy self-assigned this Jan 13, 2025
Copy link
Contributor

coderabbitai bot commented Jan 13, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This pull request introduces a new REST API endpoint for vendor product categories in the Dokan plugin. It includes a new VendorProductCategoriesController that extends the WooCommerce product categories controller, implementing vendor-specific permissions and filtering. A corresponding test suite, ProductCategoryApiTest, is created to validate the functionality of this new endpoint, ensuring proper access control, filtering, and API behavior for vendor product categories.

Changes

File Change Summary
includes/REST/Manager.php Added mapping for VendorProductCategoriesController in $class_map
includes/REST/VendorProductCategoriesController.php New REST API controller for vendor product categories with custom permissions and filtering
tests/php/src/ProductCategory/ProductCategoryApiTest.php New test class to validate vendor product categories API endpoint

Possibly related PRs

Suggested labels

Needs: Testing

Suggested reviewers

  • mrabbani

Poem

🐰 Hop, hop, a new API takes flight,
Vendor categories, shining bright!
Permissions checked with rabbit's care,
REST endpoints dancing everywhere,
A furry friend of code delight! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@osmansufy osmansufy requested a review from mrabbani January 13, 2025 02:20
@osmansufy osmansufy added the Needs: Dev Review It requires a developer review and approval label Jan 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
includes/REST/ProductCategoriesVendorController.php (1)

41-49: Properly handle boolean 'hide_empty' parameter

The 'hide_empty' parameter is compared to the string 'true' in line 49, which may not handle other truthy values correctly. It's better to explicitly cast the parameter to a boolean or use WordPress's built-in functions to handle this.

Update the 'hide_empty' parameter in get_collection_params():

'hide_empty' => array(
    'description'       => 'Whether to hide terms not assigned to any posts.',
    'type'              => 'boolean',
    'default'           => false,
+   'sanitize_callback' => 'rest_sanitize_boolean',
),

Then, adjust the assignment in your code:

-            'hide_empty' => $hide_empty === 'true',
+            'hide_empty' => (bool) $hide_empty,
tests/php/src/ProductCategory/ProductCategoryApiTest.php (2)

117-118: Remove unnecessary 'search' parameter in exclude test

Including the 'search' parameter may filter out categories and interfere with testing the 'exclude' parameter. Since you're testing exclusion, it's best to omit 'search' to ensure accurate results.

Apply this diff to remove the 'search' parameter:

-            $request->set_param( 'search', 'term' );

146-146: Remove unnecessary 'search' parameter in include test

In the test_get_categories_with_include method, setting the 'search' parameter could prevent the included category from appearing if it doesn't match the search term. Remove the 'search' parameter to focus solely on testing the 'include' functionality.

Apply this diff to remove the 'search' parameter:

-            $request->set_param( 'search', 'term' );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00d3c5d and bd6867f.

📒 Files selected for processing (3)
  • includes/REST/Manager.php (1 hunks)
  • includes/REST/ProductCategoriesVendorController.php (1 hunks)
  • tests/php/src/ProductCategory/ProductCategoryApiTest.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (1)
includes/REST/Manager.php (1)

204-204: New REST controller registered successfully

The ProductCategoriesVendorController is properly added to the REST API class map, ensuring that the new endpoint is registered and functional.

includes/REST/ProductCategoriesVendorController.php Outdated Show resolved Hide resolved
Comment on lines 34 to 43
$per_page = $request->get_param( 'per_page' ) ? $request->get_param( 'per_page' ) : 10;
$page = $request->get_param( 'page' ) ? $request->get_param( 'page' ) : 1;
$search = $request->get_param( 'search' );
$exclude = $request->get_param( 'exclude' );
$include = $request->get_param( 'include' );
$order = $request->get_param( 'order' );
$orderby = $request->get_param( 'orderby' );
$hide_empty = $request->get_param( 'hide_empty' );
$parent = $request->get_param( 'parent' );
$fields = $request->get_param( '_fields' );
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

Sanitize and validate request parameters

The request parameters such as 'order', 'orderby', 'parent', and others are not sanitized or validated. This could lead to unexpected behavior or security issues if invalid data is passed. It's important to add 'sanitize_callback' and 'validate_callback' functions to these parameters in your get_collection_params() method.

For example, update the 'order' parameter:

'order' => array(
    'description'       => 'Order sort attribute ascending or descending.',
    'type'              => 'string',
    'default'           => 'ASC',
    'enum'              => array( 'ASC', 'DESC' ),
+   'sanitize_callback' => 'sanitize_text_field',
+   'validate_callback' => 'rest_validate_request_arg',
),

Similarly, add appropriate callbacks for 'orderby', 'parent', and other parameters to ensure they're properly sanitized and validated.

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

tests/php/src/ProductCategory/ProductCategoryApiTest.php Outdated Show resolved Hide resolved
Comment on lines 127 to 191
$this->assertIsArray( $data );
$this->assertNotContains( $exclude, $data );
}
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

Correct the assertion in exclude categories test

In the test_get_categories_with_exclude method, the assertion on line 128 is incorrect because $data is an array of category arrays, not category IDs. You need to extract the IDs before performing the assertion.

Apply this diff to fix the assertion:

-            $this->assertNotContains( $exclude, $data );
+            $category_ids = wp_list_pluck( $data, 'id' );
+            $this->assertNotContains( (int) $exclude, $category_ids );
📝 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
$this->assertIsArray( $data );
$this->assertNotContains( $exclude, $data );
}
$this->assertIsArray( $data );
$category_ids = wp_list_pluck( $data, 'id' );
$this->assertNotContains( (int) $exclude, $category_ids );
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
tests/php/src/ProductCategory/ProductCategoryApiTest.php (4)

37-39: Fix indentation: Use spaces instead of tabs

The indentation in the test data creation uses tabs instead of spaces, which is inconsistent with the rest of the codebase.

Apply this diff to fix the indentation:

-				'taxonomy' => 'product_cat',
-				'name'    => 'Parent Category 1',
+                'taxonomy' => 'product_cat',
+                'name'    => 'Parent Category 1',

Also applies to: 44-46, 52-55, 60-63, 69-70


126-153: Enhance pagination test with total count assertion

While the pagination test covers basic scenarios, it would be more robust to verify the exact total count matches the expected number of categories (10 in this case: 2 parents + 2 children + 6 additional).

Add this assertion after line 151:

         $this->assertArrayHasKey( 'X-WP-Total', $headers );
+        $this->assertEquals( 10, $headers['X-WP-Total'] );
         $this->assertArrayHasKey( 'X-WP-TotalPages', $headers );
+        $this->assertEquals( 2, $headers['X-WP-TotalPages'] );

201-214: Add edge cases to fields parameter test

Consider adding tests for invalid field names to ensure the API handles them gracefully.

Add this test case:

         $this->assertArrayNotHasKey( 'description', $category );
         $this->assertArrayNotHasKey( 'parent', $category );
     }
+
+    // Test invalid field
+    $response = $this->make_request( [ '_fields' => 'id,invalid_field' ] );
+    $data = $response->get_data();
+    foreach ( $data as $category ) {
+        $this->assertArrayHasKey( 'id', $category );
+        $this->assertArrayNotHasKey( 'invalid_field', $category );
+    }
 }

235-248: Optimize category cleanup in tearDown

The current implementation uses nested loops. Consider using array_merge to flatten the category IDs and delete them in a single loop.

Apply this optimization:

     public function tearDown(): void {
-        // Delete test categories
-        foreach ( $this->categories as $category_id ) {
-            if ( is_array( $category_id ) ) {
-                foreach ( $category_id as $id ) {
-                    wp_delete_term( $id, 'product_cat' );
-                }
-            } else {
-                wp_delete_term( $category_id, 'product_cat' );
-            }
-        }
+        // Flatten and delete all category IDs
+        $category_ids = array_reduce(
+            $this->categories,
+            function ( $ids, $category_id ) {
+                return array_merge(
+                    $ids,
+                    is_array( $category_id ) ? $category_id : [ $category_id ]
+                );
+            },
+            []
+        );
+        foreach ( $category_ids as $id ) {
+            wp_delete_term( $id, 'product_cat' );
+        }
 
         parent::tearDown();
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6001c6 and 068ac08.

📒 Files selected for processing (1)
  • tests/php/src/ProductCategory/ProductCategoryApiTest.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: api tests (1, 1)
🔇 Additional comments (2)
tests/php/src/ProductCategory/ProductCategoryApiTest.php (2)

79-88: LGTM! Well-structured helper method for API requests

The make_request helper method is well-designed, making it easy to test different API scenarios with various parameters.


100-121: LGTM! Comprehensive authentication test coverage

The authentication test cases effectively verify:

  • Endpoint registration
  • Unauthorized access handling
  • Vendor authorization

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
includes/REST/ProductCategoriesVendorController.php (1)

85-85: ⚠️ Potential issue

Fix incorrect total categories count for pagination

The total count calculation is using the wrong arguments array, which includes pagination parameters. This will result in incorrect pagination headers.

-        $total_categories = wp_count_terms( $args );
+        $total_categories = wp_count_terms( $total_args );
🧹 Nitpick comments (3)
includes/REST/ProductCategoriesVendorController.php (3)

14-26: Consider using WP_REST_Server constants for HTTP methods

Replace the hardcoded 'GET' string with WP_REST_Server::READABLE constant for better maintainability and consistency with WordPress coding standards.

-                    'methods'             => 'GET',
+                    'methods'             => WP_REST_Server::READABLE,

51-51: Improve boolean conversion for hide_empty parameter

The current string comparison could be made more robust using WordPress's built-in function.

-            'hide_empty' => $hide_empty === 'true',
+            'hide_empty' => rest_sanitize_boolean( $hide_empty ),

73-79: Enhance error handling with specific error codes

The error handling could be more specific to help clients better understand and handle different types of failures.

         if ( is_wp_error( $categories ) ) {
+            $error_code = $categories->get_error_code();
+            $error_message = $categories->get_error_message();
             return new WP_Error(
-                'rest_category_error',
-                __( 'Error retrieving product categories.', 'dokan-lite' ),
+                'dokan_rest_' . $error_code,
+                $error_message ?: __( 'Error retrieving product categories.', 'dokan-lite' ),
                 array( 'status' => 400 )
             );
         }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 068ac08 and 20b746a.

📒 Files selected for processing (1)
  • includes/REST/ProductCategoriesVendorController.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)

Comment on lines 162 to 165
'search' => array(
'description' => 'Limit results to those matching a string.',
'type' => 'string',
),
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

Add sanitization callbacks for string parameters

The search, exclude, and include parameters should have sanitization callbacks to prevent potential security issues.

             'search' => array(
                 'description' => 'Limit results to those matching a string.',
                 'type' => 'string',
+                'sanitize_callback' => 'sanitize_text_field',
             ),
             'exclude' => array(
                 'description' => 'Ensure result set excludes specific IDs.',
                 'type' => 'string',
+                'sanitize_callback' => 'sanitize_text_field',
+                'validate_callback' => array( $this, 'validate_id_string' ),
             ),
             'include' => array(
                 'description' => 'Limit result set to specific IDs.',
                 'type' => 'string',
+                'sanitize_callback' => 'sanitize_text_field',
+                'validate_callback' => array( $this, 'validate_id_string' ),
             ),

Add this validation method to your class:

/**
 * Validate a comma-separated string of IDs
 *
 * @param string $value The value to validate
 * @return bool|WP_Error
 */
public function validate_id_string( $value ) {
    if ( ! preg_match( '/^[\d,]+$/', $value ) ) {
        return new WP_Error(
            'rest_invalid_param',
            __( 'String of IDs must contain only numbers and commas.', 'dokan-lite' )
        );
    }
    return true;
}

Also applies to: 166-169, 170-173

Comment on lines 195 to 198
'_fields' => array(
'description' => 'Limit response to specific fields.',
'type' => 'string',
),
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

Add validation for _fields parameter

The _fields parameter should validate that only existing fields are requested.

             '_fields' => array(
                 'description' => 'Limit response to specific fields.',
                 'type' => 'string',
+                'validate_callback' => array( $this, 'validate_fields' ),
             ),

Add this validation method to your class:

/**
 * Validate requested fields
 *
 * @param string $value Comma-separated list of fields
 * @return bool|WP_Error
 */
protected function validate_fields( $value ) {
    $valid_fields = array( 'id', 'name', 'slug', 'parent', 'description', 'count', 'thumbnail', 'link' );
    $requested_fields = explode( ',', $value );
    $invalid_fields = array_diff( $requested_fields, $valid_fields );
    
    if ( ! empty( $invalid_fields ) ) {
        return new WP_Error(
            'rest_invalid_fields',
            sprintf(
                __( 'Invalid field(s): %s. Valid fields are: %s', 'dokan-lite' ),
                implode( ', ', $invalid_fields ),
                implode( ', ', $valid_fields )
            )
        );
    }
    return true;
}

'description' => $category->description,
'count' => (int) $category->count,
'thumbnail' => $thumbnail_url,
'link' => get_term_link( $category ),
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

Add error handling for term link generation

The get_term_link() function can return WP_Error, which should be handled.

-            'link' => get_term_link( $category ),
+            'link' => is_wp_error( $term_link = get_term_link( $category ) ) ? '' : $term_link,
📝 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
'link' => get_term_link( $category ),
'link' => is_wp_error( $term_link = get_term_link( $category ) ) ? '' : $term_link,

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
includes/REST/ProductCategoriesVendorController.php (3)

84-84: ⚠️ Potential issue

Fix incorrect total categories count for pagination

The total count calculation is using the wrong arguments, which could lead to incorrect pagination.

-$total_categories = wp_count_terms( $args );
+$total_args = $args;
+unset( $total_args['number'], $total_args['offset'] );
+$total_categories = wp_count_terms( $total_args );

123-123: ⚠️ Potential issue

Add error handling for term link generation

The get_term_link function can return WP_Error, which should be handled.

-            'link' => get_term_link( $category ),
+            'link' => is_wp_error( $term_link = get_term_link( $category ) ) ? '' : $term_link,

167-171: 🛠️ Refactor suggestion

Add validation for exclude and include parameters

The exclude and include parameters should validate that they contain only comma-separated integers.

             'exclude' => array(
                 'description' => 'Ensure result set excludes specific IDs.',
                 'type' => 'string',
                 'sanitize_callback' => 'sanitize_text_field',
+                'validate_callback' => array( $this, 'validate_id_string' ),
             ),
             'include' => array(
                 'description' => 'Limit result set to specific IDs.',
                 'type' => 'string',
                 'sanitize_callback' => 'sanitize_text_field',
+                'validate_callback' => array( $this, 'validate_id_string' ),
             ),

Also applies to: 173-176

🧹 Nitpick comments (3)
includes/REST/ProductCategoriesVendorController.php (3)

10-10: Add class-level PHPDoc

Add a descriptive PHPDoc block for the class to document its purpose and responsibilities.

+/**
+ * REST controller for managing product categories in Dokan.
+ *
+ * @since x.x.x
+ *
+ * @package WeDevs\Dokan\REST
+ */
 class ProductCategoriesVendorController extends DokanRESTVendorController {

51-51: Improve boolean conversion for hide_empty parameter

The current boolean conversion is not robust enough and could lead to unexpected behavior.

-            'hide_empty' => $hide_empty === 'true',
+            'hide_empty' => in_array( $hide_empty, [ 'true', '1', true, 1 ], true ),

113-113: Add error handling for thumbnail URL generation

The wp_get_attachment_url function can return false, which should be handled explicitly.

-        $thumbnail_url = $thumbnail_id ? wp_get_attachment_url( $thumbnail_id ) : '';
+        $thumbnail_url = $thumbnail_id ? (wp_get_attachment_url( $thumbnail_id ) ?: '') : '';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a797ee3 and 60b9be2.

📒 Files selected for processing (1)
  • includes/REST/ProductCategoriesVendorController.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (1)
includes/REST/ProductCategoriesVendorController.php (1)

134-137: 🛠️ Refactor suggestion

Add validation for requested fields

The method should validate that only existing fields are requested to prevent unexpected behavior.

     protected function filter_response_by_fields( $response, $fields ) {
+        $valid_fields = array_keys( $response );
         $fields = explode( ',', $fields );
+        $invalid_fields = array_diff( $fields, $valid_fields );
+        if ( ! empty( $invalid_fields ) ) {
+            return $response;
+        }
         return array_intersect_key( $response, array_flip( $fields ) );
     }

Likely invalid or redundant comment.

Comment on lines 198 to 201
'parent' => array(
'description' => 'Limit result set to terms assigned to a specific parent.',
'type' => 'integer',
),
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

Add validation for parent parameter

The parent parameter should be validated to ensure it's a positive integer.

             'parent' => array(
                 'description' => 'Limit result set to terms assigned to a specific parent.',
                 'type' => 'integer',
+                'minimum' => 0,
+                'sanitize_callback' => 'absint',
+                'validate_callback' => 'rest_validate_request_arg',
             ),
📝 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
'parent' => array(
'description' => 'Limit result set to terms assigned to a specific parent.',
'type' => 'integer',
),
'parent' => array(
'description' => 'Limit result set to terms assigned to a specific parent.',
'type' => 'integer',
'minimum' => 0,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
),

Comment on lines 36 to 37
$per_page = $request->get_param( 'per_page' ) ? $request->get_param( 'per_page' ) : 10;
$page = $request->get_param( 'page' ) ? $request->get_param( 'page' ) : 1;
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

Validate maximum value for per_page parameter

The per_page parameter should be capped at 100 as defined in get_collection_params().

-        $per_page = $request->get_param( 'per_page' ) ? $request->get_param( 'per_page' ) : 10;
+        $per_page = min( $request->get_param( 'per_page' ) ? (int) $request->get_param( 'per_page' ) : 10, 100 );
📝 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_page = $request->get_param( 'per_page' ) ? $request->get_param( 'per_page' ) : 10;
$page = $request->get_param( 'page' ) ? $request->get_param( 'page' ) : 1;
$per_page = min( $request->get_param( 'per_page' ) ? (int) $request->get_param( 'per_page' ) : 10, 100 );
$page = $request->get_param( 'page' ) ? $request->get_param( 'page' ) : 1;

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
tests/php/src/ProductCategory/ProductCategoryApiTest.php (3)

97-97: Fix extra blank line before function closing brace
A blank line precedes the closing brace at line 97, which violates WordPress coding standards.

Apply this diff to remove the extra blank line:

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 97-97:
Function closing brace must go on the next line following the body; found 1 blank lines before brace


109-113: Extend endpoint existence test to include single-category route
While test_endpoint_exists currently checks for the base route, you may also confirm that the single category route is registered and accessible. This ensures both endpoints are covered.


241-251: Add negative test scenario for invalid category ID
test_single_category_response only verifies a valid category. Consider adding a test for invalid or non-existent IDs to confirm that a 404 error is returned, mirroring real-world scenarios.

includes/REST/ProductCategoriesVendorController.php (3)

14-37: Consider registering additional HTTP methods or documentation for future expansion
Currently, only GET routes are registered. If future requirements demand category creation, updates, or deletions, you might add other REST methods (POST, PUT, PATCH, DELETE) or provide documentation clarifying these endpoints’ statuses.

🧰 Tools
🪛 GitHub Actions: Inspections

[warning] It is recommended not to use reserved keyword "object" as function parameter name. Found: $object


69-74: Avoid broad catching of generic Exceptions
Catching the base Exception may inadvertently mask unexpected errors. Consider narrowing the catch scope if feasible or adding logging to help diagnose unexpected failures.

🧰 Tools
🪛 GitHub Actions: Inspections

[warning] It is recommended not to use reserved keyword "object" as function parameter name. Found: $object


130-131: Use a separate array for pagination count arguments
Directly mutating $args by unsetting 'number' and 'offset' is functionally correct, but creating a dedicated $total_args to hold unpaginated parameters can improve readability and reduce confusion.

Example refactor:

🧰 Tools
🪛 GitHub Actions: Inspections

[warning] It is recommended not to use reserved keyword "object" as function parameter name. Found: $object

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60b9be2 and c2853a1.

📒 Files selected for processing (2)
  • includes/REST/ProductCategoriesVendorController.php (1 hunks)
  • tests/php/src/ProductCategory/ProductCategoryApiTest.php (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Inspections
includes/REST/ProductCategoriesVendorController.php

[warning] It is recommended not to use reserved keyword "object" as function parameter name. Found: $object

🪛 GitHub Check: Run PHPCS inspection
tests/php/src/ProductCategory/ProductCategoryApiTest.php

[failure] 97-97:
Function closing brace must go on the next line following the body; found 1 blank lines before brace

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: api tests (1, 1)
🔇 Additional comments (2)
includes/REST/ProductCategoriesVendorController.php (2)

90-116: Sanitize and validate request parameters ()
This was previously suggested. The parameters (order, orderby, search, exclude, include, etc.) lack explicit sanitization or validation callbacks. While WordPress core sanitizes some fields, adding callbacks in get_collection_params() offers better safety and consistency, preventing potential user input issues or query errors.

🧰 Tools
🪛 GitHub Actions: Inspections

[warning] It is recommended not to use reserved keyword "object" as function parameter name. Found: $object


89-91: Verify handling of 'orderby' and 'order' parameters
Ensure 'orderby' values like 'rand' or invalid fields don’t cause unexpected behavior or potential injection. Validate these fields with a strict set of allowable values.

✅ Verification successful

Parameter handling is properly implemented and secure

The orderby parameter is safely handled through:

  1. WordPress REST API parameter validation
  2. WordPress core get_terms() function's built-in sanitization
  3. Default value of 'name' when parameter is not provided
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for possible "orderby" usage or sanitization across the codebase
rg -A 3 $'orderby'

Length of output: 104975


Script:

#!/bin/bash
# Get the complete implementation of ProductCategoriesVendorController
ast-grep --pattern 'class ProductCategoriesVendorController {
  $$$
}'

# Get any parent class or interface implementations
rg -A 5 "class ProductCategoriesVendorController extends|implements" 

# Look for parameter validation/sanitization
rg -B 2 -A 5 "get_param.*orderby|sanitize.*orderby" includes/REST/ProductCategoriesVendorController.php

Length of output: 15852


Script:

#!/bin/bash
# Get parent class implementation
rg -A 10 "class DokanRESTVendorController"

# Find REST API parameter registration for orderby
rg -B 2 -A 10 "register_rest_route.*product-categories" includes/REST/ProductCategoriesVendorController.php

# Find where $args array is used in query construction
ast-grep --pattern 'get_terms($$$args$$$)' includes/REST/ProductCategoriesVendorController.php

Length of output: 1463


Script:

#!/bin/bash
# Get the complete file content
cat includes/REST/ProductCategoriesVendorController.php

# Look for REST API schema validation
rg -B 2 -A 10 "get_collection_params|get_item_schema" includes/REST/ProductCategoriesVendorController.php

Length of output: 8682


Script:

#!/bin/bash
# Find get_collection_params implementation
rg -B 2 -A 10 "function get_collection_params" includes/

# Look for DokanRESTBaseController implementation
rg -B 2 -A 10 "class DokanRESTBaseController" includes/

Length of output: 2938

🧰 Tools
🪛 GitHub Actions: Inspections

[warning] It is recommended not to use reserved keyword "object" as function parameter name. Found: $object

…pi' into enhance/product-category-rest-api

# Conflicts:
#	includes/REST/ProductCategoriesVendorController.php
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
includes/REST/VendorProductCategoriesController.php (1)

11-166: Add docblocks for $request parameters.
Several methods lack a param doc comment for $request (e.g., update_item_permissions_check, delete_item_permissions_check). Adding these would improve readability and maintain compliance with WordPress docs standards.

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 31-31:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 31-31:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 38-38:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 38-38:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 46-46:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 46-46:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 47-47:
Opening brace should be on the same line as the declaration


[failure] 56-56:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 56-56:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 66-66:
Expected 1 spaces after opening parenthesis; 0 found

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2853a1 and abb0efe.

📒 Files selected for processing (2)
  • includes/REST/Manager.php (1 hunks)
  • includes/REST/VendorProductCategoriesController.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/REST/Manager.php
🧰 Additional context used
🪛 GitHub Check: Run PHPCS inspection
includes/REST/VendorProductCategoriesController.php

[failure] 31-31:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 31-31:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 38-38:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 38-38:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 46-46:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 46-46:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 47-47:
Opening brace should be on the same line as the declaration


[failure] 56-56:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 56-56:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 66-66:
Expected 1 spaces after opening parenthesis; 0 found

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: api tests (1, 1)
🔇 Additional comments (7)
includes/REST/VendorProductCategoriesController.php (7)

11-11: Good extension approach.
Extending WC_REST_Product_Categories_Controller is a clean solution for customizing WordPress/WooCommerce REST endpoints. This ensures consistent behavior with WooCommerce’s standards.


66-98: Overall logic looks good.
This method properly uses the parent’s implementation, filters the categories, and handles vendor subscription limits. Good usage of is_wp_error checks, as well as apply_filters.

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 66-66:
Expected 1 spaces after opening parenthesis; 0 found


118-147: Proper vendor restrictions check.
Returning a WP_Error with 403 is correct for disallowed categories. Overall, good approach to ensure category usage stays within subscription limits.


154-165: Extend get_collection_params effectively.
Allowing a vendor_allowed filter param for additional control is a neat extension. Ensure it’s well documented so integrators can leverage it.


66-98: Validate dokan_pro() usage.
You are calling dokan_pro() directly. Ensure it is always defined and safely handles the case when Dokan Pro isn’t installed or active, to avoid potential fatal errors.

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 66-66:
Expected 1 spaces after opening parenthesis; 0 found


56-58: Verify that the 'dokandar' capability is defined.
If this capability is entirely custom, ensure it is added to user roles or else calls to current_user_can( 'dokandar' ) may fail.

✅ Verification successful

The 'dokandar' capability is properly defined and assigned
The capability is correctly added to both 'administrator' and 'shop_manager' roles during plugin installation, making the permission check in VendorProductCategoriesController valid and secure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Confirm 'dokandar' capability is defined and assigned in the codebase.
rg "add_cap\(.*dokandar"

Length of output: 205


Script:

#!/bin/bash
# Check for plugin activation and installer usage
rg -A 2 "register_activation_hook|dokan_install" 

# Check for any capability removal
rg "remove_cap\(.*dokandar"

Length of output: 2960


Script:

#!/bin/bash
# Check the activate method implementation
ast-grep --pattern 'function activate() {
  $$$
}'

# Also check for any direct class instantiation
rg -B 2 "new .*Installer"

Length of output: 774

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 56-56:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 56-56:
Expected 1 spaces before closing parenthesis; 0 found


24-24: Confirm route conflict avoidance.
Using the same /products/categories base as WooCommerce can cause accidental conflicts if WooCommerce natively registers an overlapping route. Ensure there are no collisions by verifying that only Dokan’s version handles vendor-specific logic.

✅ Verification successful

No route conflicts detected - implementation is properly namespaced
The controller uses the 'dokan/v1' namespace which prevents any conflicts with WooCommerce's '/wc/v3/products/categories' routes. The implementation safely extends WooCommerce's controller while adding vendor-specific logic and proper permission checks.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify no route conflict with WooCommerce or other plugins
rg "register_rest_route\(\s*['\"]\w+['\"],\s*['\"]products/categories"

Length of output: 78


Script:

#!/bin/bash
# Search for products/categories string and REST controllers
echo "=== Searching for products/categories strings ==="
rg "products/categories"

echo -e "\n=== Looking for REST controller class definitions ==="
ast-grep --pattern 'class $_ extends \$_Controller'

echo -e "\n=== Checking WooCommerce product category endpoints ==="
rg -B2 -A2 "products/categories" --type php

Length of output: 2538


Script:

#!/bin/bash
# Check the namespace and route registration in VendorProductCategoriesController
echo "=== Checking Dokan's controller namespace ==="
rg -B5 "rest_base = 'products/categories'" includes/REST/VendorProductCategoriesController.php

echo -e "\n=== Looking for namespace definition ==="
ast-grep --pattern 'namespace $_' includes/REST/VendorProductCategoriesController.php

Length of output: 502


Script:

#!/bin/bash
# Get the complete controller file content
echo "=== Checking complete controller file ==="
cat includes/REST/VendorProductCategoriesController.php

echo -e "\n=== Looking for parent controller class ==="
rg -l "class \w+Controller" includes/REST/

Length of output: 5838

* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function get_item($request) {
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

Add spacing around $request.
Align function signatures with the rest of the file for consistency.

-    public function get_item($request) {
+    public function get_item( $request ) {
📝 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
public function get_item($request) {
public function get_item( $request ) {

Comment on lines 56 to 58
public function get_items_permissions_check($request) {
return current_user_can( 'dokandar' );
}
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

Enforce spacing around $request.

-    public function get_items_permissions_check($request) {
+    public function get_items_permissions_check( $request ) {
     return current_user_can( 'dokandar' );
 }
📝 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
public function get_items_permissions_check($request) {
return current_user_can( 'dokandar' );
}
public function get_items_permissions_check( $request ) {
return current_user_can( 'dokandar' );
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 56-56:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 56-56:
Expected 1 spaces before closing parenthesis; 0 found

Comment on lines 38 to 40
public function delete_item_permissions_check($request) {
return false;
}
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

Apply the same coding standards fix.

-    public function delete_item_permissions_check($request) {
+    public function delete_item_permissions_check( $request ) {
     return false;
 }
📝 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
public function delete_item_permissions_check($request) {
return false;
}
public function delete_item_permissions_check( $request ) {
return false;
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 38-38:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 38-38:
Expected 1 spaces before closing parenthesis; 0 found

Comment on lines 31 to 33
public function create_item_permissions_check($request) {
return false;
}
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

Adhere to WordPress coding standards for function definitions.
WordPress standards require spaces around $request and the brace on the same line.

-    public function create_item_permissions_check($request) {
+    public function create_item_permissions_check( $request ) {
     return false;
 }
📝 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
public function create_item_permissions_check($request) {
return false;
}
public function create_item_permissions_check( $request ) {
return false;
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 31-31:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 31-31:
Expected 1 spaces before closing parenthesis; 0 found

Comment on lines 46 to 49
public function update_item_permissions_check($request)
{
return false;
}
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

Correct brace placement and spacing.
The opening brace should be on the same line as the declaration, plus spaces around $request.

-    public function update_item_permissions_check($request)
-    {
+    public function update_item_permissions_check( $request ) {
     return false;
 }
📝 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
public function update_item_permissions_check($request)
{
return false;
}
public function update_item_permissions_check( $request ) {
return false;
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 46-46:
Expected 1 spaces after opening parenthesis; 0 found


[failure] 46-46:
Expected 1 spaces before closing parenthesis; 0 found


[failure] 47-47:
Opening brace should be on the same line as the declaration

@osmansufy osmansufy changed the base branch from develop to update/product-data-store-with-product-and-categories-api-extend January 31, 2025 06:29
@osmansufy osmansufy merged commit 35268fb into update/product-data-store-with-product-and-categories-api-extend Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Dev Review It requires a developer review and approval
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant