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

Enahance/product category rest api #2508

Closed
wants to merge 2 commits into from

Conversation

osmansufy
Copy link
Contributor

@osmansufy osmansufy commented Jan 9, 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

  • 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 managing product categories for vendors
    • Supports advanced filtering, pagination, and field selection for product categories
  • Tests

    • Added comprehensive test suite for the new product categories API endpoint
    • Verified permissions, pagination, search, and filtering capabilities

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

coderabbitai bot commented Jan 9, 2025

Walkthrough

This pull request introduces a new REST API endpoint for managing product categories specifically for vendors in the Dokan plugin. The implementation includes a new ProductCategoriesVendorController that extends the existing DokanRESTVendorController, providing comprehensive functionality for retrieving product categories with advanced filtering, pagination, and field selection capabilities. The changes also update the REST API manager to map the new controller and include a corresponding test suite to validate the endpoint's behavior.

Changes

File Change Summary
includes/REST/Manager.php Added mapping for ProductCategoriesVendorController in get_rest_api_class_map method
includes/REST/ProductCategoriesVendorController.php New REST API controller for vendor product categories with methods for route registration, category retrieval, and response formatting
tests/php/src/ProductCategory/ProductCategoryApiTest.php New test class to validate product category API endpoint functionality, including permission checks, pagination, search, and field selection

Sequence Diagram

sequenceDiagram
    participant Client
    participant REST API
    participant ProductCategoriesVendorController
    participant WordPress

    Client->>REST API: GET Product Categories Request
    REST API->>ProductCategoriesVendorController: Validate Request
    ProductCategoriesVendorController->>WordPress: Query Product Categories
    WordPress-->>ProductCategoriesVendorController: Return Categories
    ProductCategoriesVendorController->>ProductCategoriesVendorController: Format Response
    ProductCategoriesVendorController-->>REST API: Return Filtered Categories
    REST API-->>Client: Send Response
Loading

Possibly related PRs

Suggested labels

QA approved, Dev Review Done, Needs: Testing

Suggested reviewers

  • mrabbani

Poem

🐰 Hop, hop, through categories we go!
A vendor's view, now in REST's glow
Filtering, searching with rabbit-like grace
Our product categories find their place
Code hops, endpoints dance with glee! 🌟

Finishing Touches

  • 📝 Generate Docstrings

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.

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 (3)
includes/REST/ProductCategoriesVendorController.php (1)

34-43: Simplify parameter retrieval by using sanitized and defaulted values

The parameters retrieved from the request can be accessed directly using $request['param_name']. Since you've defined defaults and sanitization callbacks in get_collection_params(), these parameters are already sanitized and have default values applied. This simplifies the code and ensures consistency.

Apply this diff to streamline parameter retrieval:

-        $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' );
+        $per_page   = $request['per_page'];
+        $page       = $request['page'];
+        $search     = $request['search'];
+        $exclude    = $request['exclude'];
+        $include    = $request['include'];
+        $order      = $request['order'];
+        $orderby    = $request['orderby'];
+        $hide_empty = $request['hide_empty'];
+        $parent     = $request['parent'];
+        $fields     = $request['_fields'];
tests/php/src/ProductCategory/ProductCategoryApiTest.php (2)

69-69: Remove debug statements from test methods

There are print_r statements in your test methods, likely leftover from debugging. These should be removed to keep the test output clean.

Apply this diff to remove the debug statements:

         // Check if the response is an array and has 5 items
-        print_r( $data );
         $this->assertIsArray( $data );
-        print_r( $data[0]['name'] );

Also applies to: 97-97


80-99: Make the search test more reliable

The test_get_categories_with_search method may not reliably find categories matching the search term 'term' since the generated category names are random. To ensure the test is robust, create a category with a specific name that includes the search term.

Consider adjusting the test as follows:

             // Create a category with a known name
-            $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
+            $search_term = 'TestTerm';
+            $this->factory()->term->create( [
+                'taxonomy' => 'product_cat',
+                'name'     => $search_term,
+            ] );

             $route     = $this->get_route( $this->rest_base . '/' );
             $request   = new \WP_REST_Request( 'GET', $route );
             $seller_id = $this->seller_id1;
             wp_set_current_user( $seller_id );
-            $request->set_param( 'search', 'term' );
+            $request->set_param( 'search', $search_term );

             $response = $this->server->dispatch( $request );

             $this->assertEquals( 200, $response->get_status() );
             $data = $response->get_data();

             // Check if the response includes the category with the search term
             $this->assertIsArray( $data );
             $this->assertCount( 1, $data );
-            $this->assertStringContainsStringIgnoringCase( 'term', $data[0]['name'] );
+            $this->assertEquals( $search_term, $data[0]['name'] );
📜 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: api tests (1, 1)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (2)
tests/php/src/ProductCategory/ProductCategoryApiTest.php (1)

21-25: Endpoint registration test is correctly implemented

The test test_endpoint_exists effectively verifies that the REST API route for product categories is registered as expected.

includes/REST/Manager.php (1)

204-204: Controller registration added to REST API manager

The ProductCategoriesVendorController has been correctly added to the REST API class map in the get_rest_api_class_map method, ensuring that the new endpoint is registered and accessible.

$include = $request->get_param( 'include' );
$order = $request->get_param( 'order' );
$orderby = $request->get_param( 'orderby' );
$hide_empty = $request->get_param( 'hide_empty' );
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

Use boolean values directly for the 'hide_empty' parameter

The parameter hide_empty is defined as a boolean in get_collection_params(). Comparing it to the string 'true' may not yield the expected results. You can use the boolean value directly in your arguments.

Apply this diff to correct the handling of the hide_empty parameter:

-        $hide_empty = $request->get_param( 'hide_empty' );
...
-        'hide_empty' => $hide_empty === 'true',
+        $hide_empty = $request['hide_empty'];
...
+        'hide_empty' => $hide_empty,

Also applies to: 49-49

Comment on lines +80 to +83
$total_args = $args;
unset( $total_args['number'] );
unset( $total_args['offset'] );
$total_categories = wp_count_terms( $args );
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

Ensure correct total category count for pagination

After unsetting 'number' and 'offset' from $total_args, you should use $total_args when calling wp_count_terms() to get an accurate total count for pagination. Currently, $args is used, which still contains 'number' and 'offset', potentially leading to incorrect counts.

Apply this diff to fix the total count calculation:

         unset( $total_args['number'] );
         unset( $total_args['offset'] );
-        $total_categories = wp_count_terms( $args );
+        $total_categories = wp_count_terms( $total_args );
📝 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
$total_args = $args;
unset( $total_args['number'] );
unset( $total_args['offset'] );
$total_categories = wp_count_terms( $args );
$total_args = $args;
unset( $total_args['number'] );
unset( $total_args['offset'] );
$total_categories = wp_count_terms( $total_args );

'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.

⚠️ Potential issue

Handle potential WP_Error from get_term_link

The get_term_link function can return a WP_Error object if there is an error generating the term link. To prevent potential issues, you should check for WP_Error before using the link.

Apply this diff to handle possible errors:

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

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

Comment on lines +106 to +129
public function test_get_categories_with_exclude() {

// create 10 categories for testing with factory
$categories = $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
$exclude = $categories[0];
// convert the exclude integer to string
$exclude = strval( $exclude );
$route = $this->get_route( $this->rest_base . '/' );
$request = new \WP_REST_Request( 'GET', $route );
$seller_id = $this->seller_id1;
wp_set_current_user( $seller_id );
$request->set_param( 'search', 'term' );

$response = $this->server->dispatch( $request );
$request->set_param( 'exclude', $exclude );

$response = $this->server->dispatch( $request );

$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
// Check if the response is an array and does not include the excluded category
$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 test logic for excluding categories

In the test_get_categories_with_exclude method:

  • The initial dispatch before setting the 'exclude' parameter is unnecessary.
  • The assertion assertNotContains( $exclude, $data ); may not work as intended because $data is an array of category arrays, not IDs.

Apply this diff to correct the test logic:

             // Remove the unnecessary initial request
-            $response = $this->server->dispatch( $request );
             $request->set_param( 'exclude', $exclude );

             $response = $this->server->dispatch( $request );

             $this->assertEquals( 200, $response->get_status() );
             $data = $response->get_data();
             // Check if the response is an array and does not include the excluded category
             $this->assertIsArray( $data );
-            $this->assertNotContains( $exclude, $data );
+            foreach ( $data as $category ) {
+                $this->assertNotEquals( $exclude, $category['id'] );
+            }
📝 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 test_get_categories_with_exclude() {
// create 10 categories for testing with factory
$categories = $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
$exclude = $categories[0];
// convert the exclude integer to string
$exclude = strval( $exclude );
$route = $this->get_route( $this->rest_base . '/' );
$request = new \WP_REST_Request( 'GET', $route );
$seller_id = $this->seller_id1;
wp_set_current_user( $seller_id );
$request->set_param( 'search', 'term' );
$response = $this->server->dispatch( $request );
$request->set_param( 'exclude', $exclude );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
// Check if the response is an array and does not include the excluded category
$this->assertIsArray( $data );
$this->assertNotContains( $exclude, $data );
}
public function test_get_categories_with_exclude() {
// create 10 categories for testing with factory
$categories = $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
$exclude = $categories[0];
// convert the exclude integer to string
$exclude = strval( $exclude );
$route = $this->get_route( $this->rest_base . '/' );
$request = new \WP_REST_Request( 'GET', $route );
$seller_id = $this->seller_id1;
wp_set_current_user( $seller_id );
$request->set_param( 'search', 'term' );
$request->set_param( 'exclude', $exclude );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
// Check if the response is an array and does not include the excluded category
$this->assertIsArray( $data );
foreach ( $data as $category ) {
$this->assertNotEquals( $exclude, $category['id'] );
}
}

Comment on lines +135 to +160
public function test_get_categories_with_include() {

// create 10 categories for testing with factory
$categories = $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
$include = $categories[0];
// convert the include integer to string
$include = strval( $include );
$route = $this->get_route( $this->rest_base . '/' );
$request = new \WP_REST_Request( 'GET', $route );
$seller_id = $this->seller_id1;
wp_set_current_user( $seller_id );
$request->set_param( 'search', 'term' );

$response = $this->server->dispatch( $request );
$request->set_param( 'include', $include );

$response = $this->server->dispatch( $request );

$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();

// Check if the response is an array and includes the included category
$this->assertIsArray( $data );
$this->assertCount( 1, $data );
$this->assertEquals( $include, $data[0]['id'] );
}
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 test logic for including categories

In the test_get_categories_with_include method:

  • The initial dispatch before setting the 'include' parameter is unnecessary.
  • Ensure that the response data is correctly validated to contain only the included category.

Apply this diff to correct the test logic:

             // Remove the unnecessary initial request
-            $response = $this->server->dispatch( $request );
             $request->set_param( 'include', $include );

             $response = $this->server->dispatch( $request );

             $this->assertEquals( 200, $response->get_status() );
             $data = $response->get_data();

             // Check if the response includes only the included category
             $this->assertIsArray( $data );
             $this->assertCount( 1, $data );
             $this->assertEquals( $include, $data[0]['id'] );
📝 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 test_get_categories_with_include() {
// create 10 categories for testing with factory
$categories = $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
$include = $categories[0];
// convert the include integer to string
$include = strval( $include );
$route = $this->get_route( $this->rest_base . '/' );
$request = new \WP_REST_Request( 'GET', $route );
$seller_id = $this->seller_id1;
wp_set_current_user( $seller_id );
$request->set_param( 'search', 'term' );
$response = $this->server->dispatch( $request );
$request->set_param( 'include', $include );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
// Check if the response is an array and includes the included category
$this->assertIsArray( $data );
$this->assertCount( 1, $data );
$this->assertEquals( $include, $data[0]['id'] );
}
public function test_get_categories_with_include() {
// create 10 categories for testing with factory
$categories = $this->factory()->term->create_many( 10, [ 'taxonomy' => 'product_cat' ] );
$include = $categories[0];
// convert the include integer to string
$include = strval( $include );
$route = $this->get_route( $this->rest_base . '/' );
$request = new \WP_REST_Request( 'GET', $route );
$seller_id = $this->seller_id1;
wp_set_current_user( $seller_id );
$request->set_param( 'search', 'term' );
$request->set_param( 'include', $include );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
// Check if the response is an array and includes the included category
$this->assertIsArray( $data );
$this->assertCount( 1, $data );
$this->assertEquals( $include, $data[0]['id'] );
}

@osmansufy osmansufy closed this Jan 13, 2025
@osmansufy osmansufy deleted the enahance/product-category-rest-api branch January 13, 2025 02:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant