Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .wp-env.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"testsEnvironment": false,
"plugins": [
".",
"./vendor/wp-content/plugins/woocommerce",
"https://downloads.wordpress.org/plugin/ai-provider-for-openai.zip"
],
"themes": [ "./test/emptytheme" ],
Expand Down
37 changes: 37 additions & 0 deletions plugins/otter-pro/inc/plugins/class-woocommerce-builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class WooCommerce_Builder {
*/
public function init() {
add_action( 'add_meta_boxes', array( $this, 'register_metabox' ) );
add_action( 'enqueue_block_editor_assets', array( $this, 'ensure_metabox_panel_visible' ) );
add_filter( 'use_block_editor_for_post_type', array( $this, 'enable_block_editor' ), 11, 2 );
add_filter( 'wc_get_template_part', array( $this, 'wc_get_template_part' ), 1000, 3 );
add_action( 'otter_blocks_woocommerce_content', 'the_content' );
Expand Down Expand Up @@ -92,6 +93,42 @@ public function render_metabox( $post_type ) {
}
}

/**
* Keep the WooCommerce Product data metabox visible in the block editor.
*
* Products using the WooCommerce Builder are edited in the block editor,
* where WordPress 6.7+ collapses the meta boxes panel by default — hiding
* the Product data options (price, inventory, etc.). Open the panel by
* default; an explicit user preference still wins over the default.
*
* @access public
* @return void
*/
public function ensure_metabox_panel_visible() {
$post = get_post();

if ( ! $post || 'product' !== $post->post_type ) {
return;
}

if ( ! boolval( get_post_meta( $post->ID, '_themeisle_gutenberg_woo_builder', true ) ) ) {
return;
}

wp_add_inline_script(
'wp-edit-post',
"( function() {
if ( ! window.wp || ! wp.data || ! wp.domReady ) {
return;
}

wp.domReady( function() {
wp.data.dispatch( 'core/preferences' ).setDefaults( 'core/edit-post', { metaBoxesMainIsOpen: true } );
} );
} )();"
);
}

Comment thread
Soare-Robert-Daniel marked this conversation as resolved.
Outdated
/**
* Enable the Block Editfor
*
Expand Down
109 changes: 109 additions & 0 deletions src/blocks/test/e2e/blocks/woocommerce-builder.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* WordPress dependencies
*/
import { test, expect } from '@wordpress/e2e-test-utils-playwright';

/**
* External dependencies
*/
import { execSync } from 'child_process';

/**
* Regression tests for https://github.com/Codeinwp/otter-blocks/issues/2822
*
* Enabling `WooCommerce Builder by Otter` on a product stores the
* `_themeisle_gutenberg_woo_builder` meta, and `WooCommerce_Builder::enable_block_editor()`
* then forces the block editor for that product. WooCommerce's `Product data`
* metabox (price fields included) must stay reachable on the product edit
* screen either way — merchants otherwise lose access to pricing options.
*/

const runWpCli = ( command ) => execSync( `npx wp-env run cli -- ${ command }`, { encoding: 'utf8' });

const tryRunWpCli = ( command ) => {
try {
return runWpCli( command );
} catch ( error ) {
return '';
}
};

const createProduct = ( title ) => {
const output = runWpCli( `wp post create --post_type=product --post_status=publish --post_title="${ title }" --porcelain` );
const match = output.match( /^\s*(\d+)\s*$/m );
return Number( match[ 1 ]);
};

const attachScreenshot = async( testInfo, page, name ) => {
await testInfo.attach( name, {
body: await page.screenshot({ fullPage: true }),
contentType: 'image/png'
});
};

test.describe( 'WooCommerce Builder product editing (issue #2822)', () => {
let productId;

test.beforeAll( () => {

// Prevent the WooCommerce activation redirect from hijacking admin page loads.
tryRunWpCli( 'wp transient delete _wc_activation_redirect' );

// Drop persisted editor preferences so the assertions exercise the
// plugin-provided "Meta Boxes" panel default rather than a leftover choice.
tryRunWpCli( 'wp user meta delete 1 wp_persisted_preferences' );
Comment thread
Soare-Robert-Daniel marked this conversation as resolved.
Outdated
});

test.beforeEach( async({}, testInfo ) => {
productId = createProduct( `Woo Builder ${ testInfo.workerIndex }-${ testInfo.retry }-${ Date.now() }` );
});

test.afterEach( () => {
tryRunWpCli( `wp post delete ${ productId } --force` );
});

test( 'product edit screen shows the Product data panel and the builder toggle', async({ admin, page }) => {
await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` );

await expect( page.locator( '#woocommerce-product-data' ) ).toBeVisible();
await expect( page.locator( '#_regular_price' ) ).toBeVisible();

// The license is stubbed as active in e2e, so the Otter metabox must offer the toggle.
await expect( page.locator( '#otter_woo_builder' ) ).toBeVisible();
await expect( page.locator( 'a#otter-woo-builder' ) ).toHaveText( /Enable WooCommerce Builder/ );
});

test( 'Product data panel stays reachable after enabling the builder', async({ admin, page }, testInfo ) => {
await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` );
await page.locator( 'a#otter-woo-builder' ).click({ timeout: 120000 });
await page.waitForLoadState( 'domcontentloaded', { timeout: 120000 });

// The toggle must persist the builder flag server-side.
expect( runWpCli( `wp post meta get ${ productId } _themeisle_gutenberg_woo_builder` ) ).toContain( '1' );

// Re-open the edit screen the way a merchant would after the toggle.
await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` );

const isBlockEditor = ( await page.locator( 'body.block-editor-page' ).count() ) > 0;
testInfo.annotations.push({ type: 'editor-loaded', description: isBlockEditor ? 'block editor' : 'classic editor' });
await attachScreenshot( testInfo, page, 'product-edit-screen-with-builder-enabled' );
Comment thread
Soare-Robert-Daniel marked this conversation as resolved.
Outdated

// Whichever editor loads, the WooCommerce product options must stay editable.
await expect( page.locator( '#woocommerce-product-data' ) ).toBeVisible();
await expect( page.locator( '#_regular_price' ) ).toBeVisible();
});

test( 'disabling the builder restores the Product data panel', async({ admin, page }) => {

// Enable, then disable through the same query-arg toggle the metabox buttons use.
await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit&otter-woo-builder=1` );
await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit&otter-woo-builder=0` );

expect( tryRunWpCli( `wp post meta get ${ productId } _themeisle_gutenberg_woo_builder` ) ).not.toContain( '1' );
Comment thread
Soare-Robert-Daniel marked this conversation as resolved.
Outdated

await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` );

await expect( page.locator( '#woocommerce-product-data' ) ).toBeVisible();
await expect( page.locator( '#_regular_price' ) ).toBeVisible();
});
});
12 changes: 11 additions & 1 deletion tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@

function _manually_load_plugin() {
require dirname( dirname( __FILE__ ) ) . '/otter-blocks.php';
require dirname( dirname( __FILE__ ) ) . '/vendor/wp-content/plugins/woocommerce/woocommerce.php';

// Prefer the copy in the plugins directory (mounted there by wp-env) so the
// activate_plugin() call below resolves to the already-loaded file instead
// of redeclaring WooCommerce from the composer-vendored copy.
$woocommerce = WP_PLUGIN_DIR . '/woocommerce/woocommerce.php';

if ( ! file_exists( $woocommerce ) ) {
$woocommerce = dirname( dirname( __FILE__ ) ) . '/vendor/wp-content/plugins/woocommerce/woocommerce.php';
}

require $woocommerce;
}

tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
Expand Down
Loading