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

Fix multiple categories and backward compatibility #418

Merged
merged 3 commits into from
Oct 17, 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
39 changes: 18 additions & 21 deletions .github/workflows/test-php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,24 @@ jobs:
phpunit:
name: Phpunit
runs-on: ubuntu-22.04
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Setup PHP version
uses: shivammathur/setup-php@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
php-version: "7.2"
extensions: simplexml, mysql
tools: phpunit-polyfills
- name: Checkout source code
uses: actions/checkout@v2
- name: Install WordPress Test Suite
node-version: "18"
cache: "yarn"
- name: Install NPM deps
run: |
yarn install --frozen-lockfile
- name: Install composer deps
run: composer install
- name: Install environment
run: |
bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:${{ job.services.mysql.ports['3306'] }}
- name: Install composer
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run phpunit
run: phpunit
npm run wp-env start
- name: Prepare Database
run: bash ./bin/e2e-after-setup.sh
- name: Run the tests
run: |
npm run test:unit:php
env:
GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ dist
vendor
languages/woocommerce-product-addon.pot
*.log
artifacts
artifacts
.phpunit.result.cache
28 changes: 20 additions & 8 deletions bin/env/create-products.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
# Create new categories
# NOTE: If the categories with the same slug are already present, it will raise an error.
echo "Created Category 1 with ID: $category1_id"
category1_id=$(wp wc product_cat create --name="Category 1" --slug="test_cat_1" --user=admin --porcelain)

echo "Created Category 2 with ID: $category2_id"
category2_id=$(wp wc product_cat create --name="Category 2" --slug="test_cat_2" --user=admin --porcelain)

echo "Created Category 3 with ID: $category3_id"
category3_id=$(wp wc product_cat create --name="Category 3" --slug="test_cat_3" --user=admin --porcelain)

# Create products and collect their IDs
product1_id=$(wp wc product create --name="Product 1" --type="simple" --regular_price="9.99" --user=admin --porcelain)
echo "Created Product 1 with ID: $product1_id"

product2_id=$(wp wc product create --name="Product 2" --type="simple" --regular_price="19.99" --user=admin --porcelain)
product3_id=$(wp wc product create --name="Product 3" --type="simple" --regular_price="29.99" --user=admin --porcelain)
echo "Created Product 2 with ID: $product2_id"

# Get the first category.
category_id=$(wp wc product_cat list --user=admin --format=ids | awk '{print $1}')
echo "Category ID: $category_id"
product3_id=$(wp wc product create --name="Product 3" --type="simple" --regular_price="29.99" --user=admin --porcelain)
echo "Created Product 3 with ID: $product3_id"

# Add products to the first category
wp wc product update $product1_id --user=admin --categories='[{"id": '$category_id'}]'
wp wc product update $product2_id --user=admin --categories='[{"id": '$category_id'}]'
wp wc product update $product3_id --user=admin --categories='[{"id": '$category_id'}]'
# Add products to the new categories
wp wc product update $product1_id --user=admin --categories='[{"id": '$category1_id'}]'
wp wc product update $product2_id --user=admin --categories='[{"id": '$category2_id'}]'
wp wc product update $product3_id --user=admin --categories='[{"id": '$category3_id'}]'
49 changes: 34 additions & 15 deletions classes/admin.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ public function get_wc_categories( $current_values ) {

$used_categories = array();
if ( ! empty( $current_values['productmeta_categories'] ) ) {
$used_categories = explode( "\n", $current_values['productmeta_categories'] );
$used_categories = preg_split('/\r\n|\n/', $current_values['productmeta_categories'] );
}

foreach ( $product_categories as $category ) {
Expand Down Expand Up @@ -620,21 +620,10 @@ function ppom_attach_ppoms() {
$updated_cat = count( $categories_to_attach );

// +----- Attach Field to Tags -----+
$categories_to_tags = isset( $_POST['ppom-attach-to-tags'] ) && is_array( $_POST['ppom-attach-to-tags'] ) ? array_map( 'sanitize_key', $_POST['ppom-attach-to-tags'] ) : array();
$updated_tags = count( $categories_to_tags );
$tags_to_attach = isset( $_POST['ppom-attach-to-tags'] ) && is_array( $_POST['ppom-attach-to-tags'] ) ? array_map( 'sanitize_key', $_POST['ppom-attach-to-tags'] ) : false;
$updated_tags = is_array( $tags_to_attach) ? count( $tags_to_attach ) : 0;

global $wpdb;
$ppom_table = $wpdb->prefix . PPOM_TABLE_META;
$wpdb->update(
$ppom_table,
array(
'productmeta_categories' => implode( "\n", $categories_to_attach ), // NOTE: Keep the backward compatible format.
'productmeta_tags' => serialize( $categories_to_tags )
), // Data to update
array( 'productmeta_id' => $ppom_id ), // Where clause
array( '%s' ), // Data format
array( '%d' ) // Where format
);
self::save_categories_and_tags( $ppom_id, $categories_to_attach, $tags_to_attach );

$response = array(
'message' => "PPOM updated for {$updated_products} Products, {$updated_cat} Categories and {$updated_tags} Tags.",
Expand All @@ -644,6 +633,36 @@ function ppom_attach_ppoms() {
wp_send_json( $response );
}

/**
* Save the categories and tags to the given PPOM field.
*
* @param int $ppom_id The ID of the PPOM field.
* @param array $categories An array of categories to save.
* @param array|bool $tags An array of tags to save.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
*/
public static function save_categories_and_tags( $ppom_id, $categories, $tags ) {
global $wpdb;
$ppom_table = $wpdb->prefix . PPOM_TABLE_META;

$data_to_update = array(
'productmeta_categories' => implode( "\r\n", $categories ), // NOTE: Keep the backward compatible format.
);

if ( is_array( $tags ) ) {
$data_to_update['productmeta_tags'] = serialize( $tags );
}

$wpdb->update(
$ppom_table,
$data_to_update,
array( 'productmeta_id' => $ppom_id ), // Where clause
array( '%s' ), // Data format
array( '%d' ) // Where format
);
}

/*
* Plugin Validation
Expand Down
3 changes: 2 additions & 1 deletion classes/ppom.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,8 @@ function ppom_has_category_meta($product_id ) {
$meta_found[] = $row->productmeta_id;
} else {
// making array of meta cats
$meta_cat_array = explode( "\r\n", $row->productmeta_categories );

$meta_cat_array = preg_split('/\r\n|\n/', $row->productmeta_categories);
// Now iterating the product_categories to check it's slug in meta cats
foreach ( $product_categories as $cat ) {
if ( in_array( $cat->slug, $meta_cat_array ) ) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@
"test:e2e:debug": "wp-scripts test-playwright --config tests/e2e/playwright.config.js --ui",
"test:unit:php:setup": "wp-env start",
"test:unit:php:setup:debug": "wp-env start --xdebug",
"test:unit:php": "wp-env run --env-cwd='wp-content/plugins/woocommerce-product-addon' tests-wordpress vendor/bin/phpunit -c phpunit.xml.dist --verbose"
"test:unit:php": "wp-env run --env-cwd='wp-content/plugins/woocommerce-product-addon' tests-wordpress vendor/bin/phpunit -c phpunit.xml --verbose"
}
}
3 changes: 3 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
*/
function _register_module() {
require_once dirname( dirname( __FILE__ ) ) . '/woocommerce-product-addon.php';
include_once PPOM_PATH . '/classes/admin.class.php';

$ppom_admin = new NM_PersonalizedProduct_Admin();
}

tests_add_filter( 'muplugins_loaded', '_register_module' );
Expand Down
48 changes: 47 additions & 1 deletion tests/e2e/specs/attach-modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { test, expect } from "@wordpress/e2e-test-utils-playwright";
import { createSimpleGroupField } from "../utils";

test.describe("Attach Modal", () => {
test("attach to products", async ({ page, admin }) => {
/**
* Attach a new group field to the first product in list then check if it is rendered.
*/
test("attach to products and check", async ({ page, admin }) => {
await createSimpleGroupField(admin, page);
await page.waitForTimeout(500);
await admin.visitAdminPage("admin.php?page=ppom");
Expand Down Expand Up @@ -36,4 +39,47 @@ test.describe("Attach Modal", () => {
await expect(elements.nth(i)).toBeVisible();
}
});

/**
* Attach a new group to multiple categories then check.
*/
test("attach to multiple categories", async ({ page, admin }) => {
const categoriesToUse = ["test_cat_1", "test_cat_2"];

await createSimpleGroupField(admin, page);
await page.waitForTimeout(500);
await admin.visitAdminPage("admin.php?page=ppom");

const firstRow = page
.locator("#ppom-groups-export-form tbody tr")
.first();
const ppomId = await firstRow.locator("td").nth(1).innerText();
await firstRow.getByText("Attach to Products").click();
await page.waitForLoadState("networkidle");

await page.evaluate(() => {
document.querySelector('#attach-to-categories > div.postbox').classList.remove('closed');
});

const categoriesSelector = page.locator(
'#ppom-product-modal select[name="ppom-attach-to-categories\\[\\]"]',
);

// NOTE: categories created by `create-prodcuts.sh`
await categoriesSelector.selectOption(
categoriesToUse.map((c) => ({ value: c })),
);
await page.getByRole("button", { name: "Save" }).click();
await page.waitForLoadState("networkidle");
await page.reload();

for (const cat of categoriesToUse) {
await page.goto(`/?product_cat=${cat}`);
await page.locator('a.add_to_cart_button').first().click();

const elements = page.locator(`.ppom-id-${ppomId}`);
const count = await elements.count();
expect(count ).toBeGreaterThan(0);
}
});
});
7 changes: 7 additions & 0 deletions tests/e2e/specs/group-field-edit.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
} from "../utils";

test.describe("Group Fields Edit", () => {

/**
* Create two input fields and change their order then save and check.
*/
test("change fields order on saving", async ({ page, admin }) => {
await createSimpleGroupField(admin, page);
await page.waitForTimeout(500);
Expand Down Expand Up @@ -55,6 +59,9 @@ test.describe("Group Fields Edit", () => {
expect(newOrderFieldIds).not.toEqual(fieldIds);
});

/**
* Create a select input with two option. Save then change their order and check again.
*/
test("change select option order on saving", async ({ page, admin }) => {
await admin.visitAdminPage("admin.php?page=ppom");

Expand Down
49 changes: 49 additions & 0 deletions tests/test-field-saving.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Class Test_Field_Saving
*
* @package ppom-pro
*/

class Test_Field_Saving extends WP_UnitTestCase {

/**
* Test if the saved categories are in a backward compatible format and tags in a serialized format.
*/
public function test_saving_categories_compatibilities() {
global $wpdb;

$table_name = $wpdb->prefix . PPOM_TABLE_META;
$data = array(
'productmeta_name' => 'Test Multiple Categories',
'productmeta_validation' => '',
'dynamic_price_display' => 'no',
'send_file_attachment' => '',
'show_cart_thumb' => '',
'aviary_api_key' => '',
'productmeta_style' => 'selector { }',
'productmeta_js' => '',
'productmeta_categories' => "accessories\r\nclothing",
'the_meta' => '{"1":{"type":"text","title":"Test Cat","data_name":"test_cat","description":"","placeholder":"","error_message":"","maxlength":"","minlength":"","default_value":"","price":"","class":"","input_mask":"","width":"12","visibility":"everyone","visibility_role":"","conditions":{"visibility":"Show","bound":"All","rules":[{"elements":"test_cat","operators":"is","element_values":""}]},"status":"on","ppom_id":"63"}}',
'productmeta_created' => '2024-10-16 11:38:45',
'productmeta_tags' => 'a:1:{i:0;s:8:"test-tag";}'
);

// Insert data into the table
$result = $wpdb->insert($table_name, $data);
$this->assertNotFalse( $result );

$field_id = $wpdb->insert_id;

NM_PersonalizedProduct_Admin::save_categories_and_tags( $field_id, ['accessories', 'clothing', 'test-cat'], false );

$saved_data = $wpdb->get_row( $wpdb->prepare( "SELECT productmeta_categories, productmeta_tags FROM $table_name WHERE productmeta_id = %d", $field_id ), ARRAY_A );

$expected_categories = "accessories\r\nclothing\r\ntest-cat";
$this->assertEquals( $expected_categories, $saved_data['productmeta_categories'] );

// Tags should not be changed.
$expected_tags = 'a:1:{i:0;s:8:"test-tag";}';
$this->assertEquals( $expected_tags, $saved_data['productmeta_tags'] );
}
}
Loading