Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public function __construct(
) {
$this->new_repo = $new_repo ?? new SettingsRepository();
$this->bridge = $bridge ?? new LegacySettingsBridge();
add_action( 'init', [ $this, 'init' ] );
}
public function init(): void {

foreach ( $this->known_sections() as $section ) {
add_action( "update_option_{$section}", [ $this, 'on_section_changed' ] );
Expand Down
42 changes: 35 additions & 7 deletions includes/Shortcodes/FullWidthVendorLayout.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,29 @@ class FullWidthVendorLayout implements Hookable {
*/
public function register_hooks(): void {
add_action( 'dokan_setup_wizard_styles', [ $this, 'update_layout_style' ] );
// Register vendor dashboard assets if the vendor layout is not legacy.
$vendor_layout = dokan_get_option( 'vendor_layout_style', 'dokan_appearance', 'legacy' );
if ( 'latest' === $vendor_layout ) {
add_action( 'init', [ $this, 'register_vendor_dashboard_assets' ], 99 );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_vendor_dashboard_assets' ] );
add_filter( 'template_include', [ $this, 'rewrite_vendor_dashboard_template' ] );
}
add_action( 'init', [ $this, 'register_vendor_dashboard_assets' ], 99 );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_vendor_dashboard_assets' ] );
add_filter( 'template_include', [ $this, 'rewrite_vendor_dashboard_template' ] );
}

/**
* Whether the marketplace runs the React (latest) vendor dashboard layout.
*
* Deliberately resolved per callback instead of once in `register_hooks()`:
* hooks are registered on `plugins_loaded`, and reading a Dokan setting
* walks the legacy settings bridge, which builds the translated admin
* settings schema. Doing that before `init` — where
* `load_plugin_textdomain()` runs — trips WordPress 6.7+'s
* `_load_textdomain_just_in_time` notice on every request. Every callback
* below fires on `init` or later, and the repository memoizes the section
* snapshot, so the deferred read costs nothing.
*
* @since DOKAN_SINCE
*
* @return bool
*/
protected function is_latest_layout(): bool {
return 'latest' === dokan_get_option( 'vendor_layout_style', 'dokan_appearance', 'legacy' );
}

/**
Expand Down Expand Up @@ -70,6 +86,10 @@ public function update_layout_style(): void {
* @return string Modified template path
*/
public function rewrite_vendor_dashboard_template( $template ) {
if ( ! $this->is_latest_layout() ) {
return $template;
}

// Check if we should load the fullwidth template.
if ( ! dokan_is_seller_dashboard() ) {
return $template;
Expand All @@ -94,6 +114,10 @@ public function rewrite_vendor_dashboard_template( $template ) {
* @return void
*/
public function register_vendor_dashboard_assets() {
if ( ! $this->is_latest_layout() ) {
return;
}

$admin_dashboard_file = DOKAN_DIR . '/assets/js/vendor-dashboard/layout/index.asset.php';
if ( file_exists( $admin_dashboard_file ) ) {
$dashboard_script = require $admin_dashboard_file;
Expand Down Expand Up @@ -213,6 +237,10 @@ public function register_vendor_dashboard_assets() {
* @return void
*/
public function enqueue_vendor_dashboard_assets() {
if ( ! $this->is_latest_layout() ) {
return;
}

if ( ! is_user_logged_in() || ! dokan_is_seller_dashboard() ) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,47 @@ public function test_class_implements_interface(): void {
$this->assertInstanceOf( LegacySettingsRepositoryInterface::class, $repo );
}

/**
* The repository is resolved from the container by `dokan_get_option()`,
* which callers reach as early as `plugins_loaded` (hook registration).
* Building the settings schema there runs hundreds of `esc_html__()`
* calls before `init` — WordPress 6.7+ answers that with a
* `_load_textdomain_just_in_time` doing-it-wrong notice, and every
* front-end request pays to assemble an admin-only schema.
*/
public function test_constructor_does_not_build_the_settings_schema(): void {
$calls = 0;
$counter = function ( $elements ) use ( &$calls ) {
++$calls;
return $elements;
};

add_filter( 'dokan_get_admin_settings_schema', $counter );

try {
new LegacySettingsRepository();
} finally {
remove_filter( 'dokan_get_admin_settings_schema', $counter );
}

$this->assertSame( 0, $calls );
}

/**
* Cache invalidation must not depend on the section being present in the
* bridge mapping — any warmed snapshot is stale once its option changes.
*/
public function test_write_to_unmapped_section_flushes_its_snapshot(): void {
update_option( 'dokan_unmapped_section', [ 'foo' => 'before' ] );

$repo = new LegacySettingsRepository();
$repo->all( 'dokan_unmapped_section' );

update_option( 'dokan_unmapped_section', [ 'foo' => 'after' ] );

$this->assertSame( 'after', $repo->get( 'dokan_unmapped_section', 'foo' ) );
}

public function test_all_returns_empty_array_when_option_missing(): void {
delete_option( 'dokan_general' );

Expand Down
96 changes: 96 additions & 0 deletions tests/php/src/Shortcodes/FullWidthVendorLayoutTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace WeDevs\Dokan\Test\Shortcodes;

use WeDevs\Dokan\Admin\Settings\Repository\LegacySettingsRepository;
use WeDevs\Dokan\Shortcodes\FullWidthVendorLayout;
use WeDevs\Dokan\Test\DokanTestCase;

/**
* @group admin-settings
*/
class FullWidthVendorLayoutTest extends DokanTestCase {

public function set_up() {
parent::set_up();

// The shared repository memoizes per-section snapshots, which would let a
// settings read at registration time slip past the assertions below.
if ( function_exists( 'dokan_get_container' ) ) {
try {
dokan_get_container()->get( LegacySettingsRepository::class )->flush_cache( null );
} catch ( \Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
unset( $e );
}
}
}

/**
* Count `dokan_appearance` reads while running `$callback`.
*
* @param callable $callback Code under test.
*
* @return int
*/
private function count_appearance_reads( callable $callback ): int {
$reads = 0;
$counter = function ( $pre ) use ( &$reads ) {
++$reads;
return $pre;
};

add_filter( 'pre_option_dokan_appearance', $counter );

try {
$callback();
} finally {
remove_filter( 'pre_option_dokan_appearance', $counter );
}

return $reads;
}

/**
* `register_hooks()` runs on `plugins_loaded` (see `WeDevs_Dokan::init_hooks()`).
* Reading a Dokan setting there resolves the legacy settings bridge, which
* builds the translated admin settings schema — before `init`, where
* `load_plugin_textdomain()` runs. WordPress 6.7+ answers that with a
* `_load_textdomain_just_in_time` doing-it-wrong notice on every request.
*/
public function test_register_hooks_does_not_read_settings(): void {
$layout = new FullWidthVendorLayout();

$this->assertSame( 0, $this->count_appearance_reads( [ $layout, 'register_hooks' ] ) );
}

/**
* Gating moved from hook registration into the callbacks, so the template
* override must still be inert while the marketplace runs the legacy layout.
*/
public function test_template_is_untouched_for_legacy_layout(): void {
update_option( 'dokan_appearance', [ 'vendor_layout_style' => 'legacy' ] );

$layout = new FullWidthVendorLayout();
$layout->register_hooks();

$this->assertSame( 'theme-template.php', $layout->rewrite_vendor_dashboard_template( 'theme-template.php' ) );
}

/**
* The deferred gate must still consult the setting when a callback runs.
*/
public function test_layout_setting_is_read_when_a_callback_runs(): void {
update_option( 'dokan_appearance', [ 'vendor_layout_style' => 'legacy' ] );

$layout = new FullWidthVendorLayout();
$layout->register_hooks();

$reads = $this->count_appearance_reads(
function () use ( $layout ) {
$layout->rewrite_vendor_dashboard_template( 'theme-template.php' );
}
);

$this->assertGreaterThan( 0, $reads );
}
}
Loading