fix: store cache transient-version markers with an expiration#3266
fix: store cache transient-version markers with an expiration#3266MdAsifHossainNadim wants to merge 5 commits into
Conversation
Cache group version markers were written via set_transient() without an expiration, so WordPress stores them with autoload=yes and never clears them — bloating autoloaded options on sites without a persistent object cache (5,000+ rows reported). Pass a filterable expiration (dokan_cache_transient_version_expiration, default MONTH_IN_SECONDS) so WordPress stores the marker autoload=no with a timeout and garbage-collects it. The default TTL outlives the longest-lived data transient to avoid premature group invalidation. Ref: getdokan/plugin-internal-tasks#1965 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR introduces a configurable expiration for transient cache version markers and adds a new Admin Tools dashboard page with functionality to manage default Dokan pages and clear caches. The Tools page is available in both React (new) and Vue (legacy) with extensible sections for Pro features. Backend logic is centralized in a ChangesTransient cache optimization
Admin Tools feature
Sequence DiagramsequenceDiagram
participant Admin as Admin User
participant UI as React/Vue UI
participant REST as REST/AJAX
participant ToolsActions as ToolsActions Service
participant DB as WordPress DB
participant Cache as WP Object Cache
Admin->>UI: Click "Create Pages" or "Clear Caches"
UI->>REST: POST /dokan/v1/admin/tools/create-pages or clear-caches
REST->>ToolsActions: call create_default_pages() or clear_dokan_caches()
alt Create Default Pages
ToolsActions->>DB: Query wp_posts by page slug
DB-->>ToolsActions: Return existing pages
ToolsActions->>DB: Insert missing pages
ToolsActions->>DB: Update dokan_pages option
ToolsActions->>DB: Flush rewrite rules
DB-->>ToolsActions: Success
else Clear Caches
ToolsActions->>DB: DELETE FROM wp_options WHERE option_name LIKE '_transient_dokan_%'
ToolsActions->>Cache: wp_cache_flush()
Cache-->>ToolsActions: Cache cleared
ToolsActions->>REST: Fire dokan_caches_cleared action
end
ToolsActions-->>REST: Return { success, message }
REST-->>UI: JSON response
UI->>Admin: Show success/error toast, update button state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 4❌ Failed checks (2 warnings, 2 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@includes/Traits/TransientCache.php`:
- Line 51: Replace the placeholder docblock tag "`@since` DOKAN_SINCE" in the
TransientCache trait with the concrete release version string (e.g., "`@since`
3.4.0" or the appropriate current release) so the method/hook documentation is
accurate; locate the docblock inside the includes/Traits/TransientCache.php file
and update the `@since` annotation accordingly for the associated method/hook.
- Around line 56-58: The filtered expiration value from
apply_filters('dokan_cache_transient_version_expiration', MONTH_IN_SECONDS,
$group) must be validated before calling set_transient to avoid non-expiring
markers; update the TransientCache logic to coerce and guard $expiration (ensure
it is a positive integer greater than zero, e.g. (int)$expiration and if <= 0
fallback to MONTH_IN_SECONDS) and then pass the validated value into
set_transient($transient_name, $transient_value, $expiration).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d2a46952-3382-4c10-b5ad-f512f99ed9f4
📒 Files selected for processing (1)
includes/Traits/TransientCache.php
| * core garbage-collect it. The value must outlive the longest-lived data | ||
| * transient in any group, otherwise the group is invalidated prematurely. | ||
| * | ||
| * @since DOKAN_SINCE |
There was a problem hiding this comment.
Replace placeholder @since DOKAN_SINCE with a concrete version
Line 51 still uses a placeholder token in a committed docblock. Please set the actual release version for this hook before merge.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/Traits/TransientCache.php` at line 51, Replace the placeholder
docblock tag "`@since` DOKAN_SINCE" in the TransientCache trait with the concrete
release version string (e.g., "`@since` 3.4.0" or the appropriate current release)
so the method/hook documentation is accurate; locate the docblock inside the
includes/Traits/TransientCache.php file and update the `@since` annotation
accordingly for the associated method/hook.
| $expiration = apply_filters( 'dokan_cache_transient_version_expiration', MONTH_IN_SECONDS, $group ); | ||
|
|
||
| set_transient( $transient_name, $transient_value, $expiration ); |
There was a problem hiding this comment.
Guard filtered expiration to prevent non-expiring markers
Line 56 accepts arbitrary filter output and passes it directly to set_transient(). If a hook returns 0/negative/non-numeric, the marker can become non-expiring again, which defeats this PR’s autoload-bloat fix.
Suggested patch
- $expiration = apply_filters( 'dokan_cache_transient_version_expiration', MONTH_IN_SECONDS, $group );
+ $expiration = (int) apply_filters( 'dokan_cache_transient_version_expiration', MONTH_IN_SECONDS, $group );
+ $expiration = max( 1, $expiration );
set_transient( $transient_name, $transient_value, $expiration );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/Traits/TransientCache.php` around lines 56 - 58, The filtered
expiration value from apply_filters('dokan_cache_transient_version_expiration',
MONTH_IN_SECONDS, $group) must be validated before calling set_transient to
avoid non-expiring markers; update the TransientCache logic to coerce and guard
$expiration (ensure it is a positive integer greater than zero, e.g.
(int)$expiration and if <= 0 fallback to MONTH_IN_SECONDS) and then pass the
validated value into set_transient($transient_name, $transient_value,
$expiration).
…default pages and cache
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@includes/Admin/Tools/ToolsActions.php`:
- Around line 97-99: The `update_option( 'dokan_pages_created', 1 )` call is
executed unconditionally regardless of whether the page creation operations
succeeded or failed. Add conditional logic to only set `dokan_pages_created` to
1 after verifying that all required pages were actually created successfully.
Check the return values or results from the preceding page creation operations
(before the `update_option( 'dokan_pages', $dokan_pages )` call) and only
proceed with marking `dokan_pages_created` as complete if all operations were
successful, otherwise leave the flag unset or set it to 0 to indicate incomplete
setup.
- Around line 142-154: Replace the global wp_cache_flush() call in the
ToolsActions.php file with targeted cache deletion that only removes
Dokan-specific cache keys. Instead of clearing all WordPress caches, use
wp_cache_delete() to selectively clear only the Dokan-related cache entries that
need to be invalidated. This prevents clearing unrelated site caches from other
plugins and services. Identify all critical Dokan cache keys (such as those for
products, settings, vendor data, etc.) and call wp_cache_delete() for each of
them individually.
- Around line 113-116: The method check_all_dokan_pages_exists() is returning
string values '1' and '0' instead of proper booleans, which causes the frontend
contract to break because in JavaScript '0' is truthy. Additionally, the method
only checks a stale dokan_pages_created option rather than verifying actual page
state. Modify the method to return real boolean values (true and false) instead
of strings, and update the logic to verify the actual existence of dokan pages
by querying current page records instead of only relying on the potentially
outdated get_option call.
In `@includes/Ajax.php`:
- Around line 73-80: The create_pages() method is missing nonce verification
which is required to prevent CSRF attacks. Even though the method has a
capability check with current_user_can(), nonce validation is necessary for
state-changing operations. Add nonce verification at the beginning of the
create_pages() method using wp_verify_nonce() to check for a nonce parameter in
the request, and return an error response if verification fails. Follow the
pattern used in the clear_caches() method (referenced at Lines 108-110) which
already implements nonce validation correctly.
In `@src/admin/dashboard/components/Tools/HeaderImage.tsx`:
- Line 1: The HeaderImage function parameter has implicit typing which violates
strict TypeScript mode. Define an explicit props interface or type for the
function parameters. Create a type that specifies the structure of the props
object, explicitly declaring that className is a string type with a default
value of an empty string. Apply this type annotation to the destructured
parameter in the HeaderImage function signature to ensure all component props
are strictly typed.
In `@src/admin/dashboard/components/Tools/sections/InstallationGuide.tsx`:
- Around line 45-54: The useEffect hook that calls apiFetch for the
'/dokan/v1/admin/tools/check-all-dokan-pages-exists' endpoint has a .then
handler but is missing a .catch handler, which can cause unhandled promise
rejections if the request fails. Add a .catch block after the .then to handle
rejection cases appropriately, such as logging any errors that occur during the
API call and optionally setting a fallback state to ensure the component behaves
predictably regardless of whether the request succeeds or fails.
In `@src/admin/pages/Tools.vue`:
- Around line 103-137: The `createPages()` and `checkAllPages()` methods send
AJAX requests without CSRF nonce protection, making them vulnerable to CSRF
attacks. Additionally, `createPages()` only clears the loading flag on success,
which locks the UI if the request fails. Fix this by adding nonce parameters to
both jQuery.post calls (the nonce should be available from the dokan object) and
ensure the loading flag in `createPages()` is cleared in both success and error
scenarios by using error handlers or wrapping the callback logic to guarantee
cleanup on all outcomes.
In `@src/components/ToolsSection.tsx`:
- Line 62: The className string in ToolsSection.tsx contains Tailwind CSS
important modifiers using the legacy prefix syntax (exclamation mark before the
utility class). Update all important modifiers in the className from prefix
placement (like !h-[28px]) to the Tailwind v4 recommended suffix placement
(h-[28px]!) by moving the exclamation mark to the end of each utility class.
This affects all four utility classes in the style definition: h-[28px],
font-[500], text-[12px], and leading-[16px].
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a44b1dea-fc10-4c7d-a3a0-d475e30bafd5
📒 Files selected for processing (18)
includes/Admin/Dashboard/Pages/Tools.phpincludes/Admin/Menu.phpincludes/Admin/Tools/ToolsActions.phpincludes/Ajax.phpincludes/Assets.phpincludes/DependencyManagement/Providers/AdminDashboardServiceProvider.phpincludes/REST/Manager.phpincludes/REST/ToolsController.phpsrc/admin/dashboard/components/Dashboard.tsxsrc/admin/dashboard/components/Tools/HeaderImage.tsxsrc/admin/dashboard/components/Tools/Tools.tsxsrc/admin/dashboard/components/Tools/sections/ClearDokanCaches.tsxsrc/admin/dashboard/components/Tools/sections/InstallationGuide.tsxsrc/admin/dashboard/components/Tools/types.tssrc/admin/pages/Tools.vuesrc/admin/router/index.jssrc/components/ToolsSection.tsxsrc/components/index.tsx
✅ Files skipped from review due to trivial changes (1)
- src/components/index.tsx
| update_option( 'dokan_pages', $dokan_pages ); | ||
| update_option( 'dokan_pages_created', 1 ); | ||
| flush_rewrite_rules(); |
There was a problem hiding this comment.
Do not mark dokan_pages_created as complete unconditionally.
Lines 97–99 set dokan_pages_created = 1 even when one or more inserts fail. That can permanently report a healthy state while required pages are still missing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/Admin/Tools/ToolsActions.php` around lines 97 - 99, The
`update_option( 'dokan_pages_created', 1 )` call is executed unconditionally
regardless of whether the page creation operations succeeded or failed. Add
conditional logic to only set `dokan_pages_created` to 1 after verifying that
all required pages were actually created successfully. Check the return values
or results from the preceding page creation operations (before the
`update_option( 'dokan_pages', $dokan_pages )` call) and only proceed with
marking `dokan_pages_created` as complete if all operations were successful,
otherwise leave the flag unset or set it to 0 to indicate incomplete setup.
| public function check_all_dokan_pages_exists() { | ||
| return [ | ||
| 'all_pages_exists' => get_option( 'dokan_pages_created', false ) ? '1' : '0', | ||
| ]; |
There was a problem hiding this comment.
Return a real boolean and derive page existence from actual page records.
At Line 115, returning '1'/'0' strings breaks the frontend contract: in JS, '0' is truthy, so src/admin/dashboard/components/Tools/sections/InstallationGuide.tsx can disable the button even when pages are missing. Also, this method only mirrors dokan_pages_created, which can be stale and does not verify current page state.
Suggested fix
public function check_all_dokan_pages_exists() {
+ $dokan_pages = get_option( 'dokan_pages', [] );
+ $dokan_pages = is_array( $dokan_pages ) ? $dokan_pages : [];
+ $all_exists = true;
+
+ foreach ( $this->get_default_pages() as $page ) {
+ $id = isset( $dokan_pages[ $page['page_id'] ] ) ? absint( $dokan_pages[ $page['page_id'] ] ) : 0;
+ if ( ! $id || 'page' !== get_post_type( $id ) || 'trash' === get_post_status( $id ) ) {
+ $all_exists = false;
+ break;
+ }
+ }
+
return [
- 'all_pages_exists' => get_option( 'dokan_pages_created', false ) ? '1' : '0',
+ 'all_pages_exists' => $all_exists,
];
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/Admin/Tools/ToolsActions.php` around lines 113 - 116, The method
check_all_dokan_pages_exists() is returning string values '1' and '0' instead of
proper booleans, which causes the frontend contract to break because in
JavaScript '0' is truthy. Additionally, the method only checks a stale
dokan_pages_created option rather than verifying actual page state. Modify the
method to return real boolean values (true and false) instead of strings, and
update the logic to verify the actual existence of dokan pages by querying
current page records instead of only relying on the potentially outdated
get_option call.
| wp_cache_flush(); | ||
|
|
||
| /** | ||
| * Fires after all Dokan caches have been cleared from the admin Tools page. | ||
| * | ||
| * @since DOKAN_SINCE | ||
| */ | ||
| do_action( 'dokan_caches_cleared' ); | ||
|
|
||
| return [ | ||
| 'process' => 'success', | ||
| 'message' => __( 'Dokan caches have been cleared successfully.', 'dokan-lite' ), | ||
| ]; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
Avoid full object-cache flush for a Dokan-scoped action.
At Line 142, wp_cache_flush() clears all groups, not just Dokan keys. This can evict unrelated site caches and cause broad performance degradation after a single Tools click.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/Admin/Tools/ToolsActions.php` around lines 142 - 154, Replace the
global wp_cache_flush() call in the ToolsActions.php file with targeted cache
deletion that only removes Dokan-specific cache keys. Instead of clearing all
WordPress caches, use wp_cache_delete() to selectively clear only the
Dokan-related cache entries that need to be invalidated. This prevents clearing
unrelated site caches from other plugins and services. Identify all critical
Dokan cache keys (such as those for products, settings, vendor data, etc.) and
call wp_cache_delete() for each of them individually.
| public function create_pages() { | ||
| if ( ! current_user_can( 'manage_woocommerce' ) ) { | ||
| wp_send_json_error( __( 'You don\'t have enough permission', 'dokan-lite' ), 403 ); | ||
| } | ||
|
|
||
| $tools = new \WeDevs\Dokan\Admin\Tools\ToolsActions(); | ||
|
|
||
| wp_send_json_success( $tools->create_default_pages() ); |
There was a problem hiding this comment.
Add nonce verification to create_pages() to prevent CSRF.
create_pages() performs a state-changing action but lacks nonce validation (unlike clear_caches() at Lines 108–110). Capability checks alone do not block CSRF.
Suggested fix
public function create_pages() {
+ if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'dokan_admin' ) ) {
+ wp_send_json_error( __( 'Nonce verification failed', 'dokan-lite' ), 403 );
+ }
+
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_send_json_error( __( 'You don\'t have enough permission', 'dokan-lite' ), 403 );
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/Ajax.php` around lines 73 - 80, The create_pages() method is missing
nonce verification which is required to prevent CSRF attacks. Even though the
method has a capability check with current_user_can(), nonce validation is
necessary for state-changing operations. Add nonce verification at the beginning
of the create_pages() method using wp_verify_nonce() to check for a nonce
parameter in the request, and return an error response if verification fails.
Follow the pattern used in the clear_caches() method (referenced at Lines
108-110) which already implements nonce validation correctly.
| @@ -0,0 +1,103 @@ | |||
| function HeaderImage( { className = '' } ) { | |||
There was a problem hiding this comment.
Type the component props explicitly to satisfy strict TypeScript.
className is currently implicit any in the parameter destructuring.
💡 Proposed fix
+type HeaderImageProps = {
+ className?: string;
+};
+
-function HeaderImage( { className = '' } ) {
+function HeaderImage( { className = '' }: HeaderImageProps ) {As per coding guidelines, **/*.{ts,tsx}: TypeScript must be written in strict mode with ESNext target and React-JSX.
📝 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.
| function HeaderImage( { className = '' } ) { | |
| type HeaderImageProps = { | |
| className?: string; | |
| }; | |
| function HeaderImage( { className = '' }: HeaderImageProps ) { |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/admin/dashboard/components/Tools/HeaderImage.tsx` at line 1, The
HeaderImage function parameter has implicit typing which violates strict
TypeScript mode. Define an explicit props interface or type for the function
parameters. Create a type that specifies the structure of the props object,
explicitly declaring that className is a string type with a default value of an
empty string. Apply this type annotation to the destructured parameter in the
HeaderImage function signature to ensure all component props are strictly typed.
Source: Coding guidelines
| useEffect( () => { | ||
| apiFetch( { | ||
| path: '/dokan/v1/admin/tools/check-all-dokan-pages-exists', | ||
| method: 'GET', | ||
| } ).then( ( res ) => { | ||
| if ( res?.all_pages_exists ) { | ||
| setDisabled( true ); | ||
| } | ||
| } ); | ||
| }, [] ); |
There was a problem hiding this comment.
Handle rejection in the initial pages-existence check.
The mount-time apiFetch call has no .catch, so failed requests can surface as unhandled rejections and silently skip state handling.
💡 Proposed fix
useEffect( () => {
apiFetch( {
path: '/dokan/v1/admin/tools/check-all-dokan-pages-exists',
method: 'GET',
} ).then( ( res ) => {
if ( res?.all_pages_exists ) {
setDisabled( true );
}
- } );
+ } ).catch( () => {
+ setDisabled( 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.
| useEffect( () => { | |
| apiFetch( { | |
| path: '/dokan/v1/admin/tools/check-all-dokan-pages-exists', | |
| method: 'GET', | |
| } ).then( ( res ) => { | |
| if ( res?.all_pages_exists ) { | |
| setDisabled( true ); | |
| } | |
| } ); | |
| }, [] ); | |
| useEffect( () => { | |
| apiFetch( { | |
| path: '/dokan/v1/admin/tools/check-all-dokan-pages-exists', | |
| method: 'GET', | |
| } ).then( ( res ) => { | |
| if ( res?.all_pages_exists ) { | |
| setDisabled( true ); | |
| } | |
| } ).catch( () => { | |
| setDisabled( false ); | |
| } ); | |
| }, [] ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/admin/dashboard/components/Tools/sections/InstallationGuide.tsx` around
lines 45 - 54, The useEffect hook that calls apiFetch for the
'/dokan/v1/admin/tools/check-all-dokan-pages-exists' endpoint has a .then
handler but is missing a .catch handler, which can cause unhandled promise
rejections if the request fails. Add a .catch block after the .then to handle
rejection cases appropriately, such as logging any errors that occur during the
API call and optionally setting a fallback state to ensure the component behaves
predictably regardless of whether the request succeeds or fails.
| createPages() { | ||
| let self = this; | ||
|
|
||
| if ( self.allPageStatus.loading ) { | ||
| return; | ||
| } | ||
|
|
||
| self.allPageStatus.loading = true; | ||
|
|
||
| jQuery.post( dokan.ajaxurl, { action: 'create_pages' }, function ( res ) { | ||
| if ( res.success ) { | ||
| self.$notify( { | ||
| title: self.__( 'Success!', 'dokan-lite' ), | ||
| text: res.data.message, | ||
| type: 'success', | ||
| } ); | ||
| self.allPageStatus.exists = true; | ||
| } else { | ||
| self.$notify( { | ||
| title: self.__( 'Failure!', 'dokan-lite' ), | ||
| text: self.__( 'Something went wrong.', 'dokan-lite' ), | ||
| type: 'warn', | ||
| } ); | ||
| } | ||
|
|
||
| self.allPageStatus.loading = false; | ||
| } ); | ||
| }, | ||
|
|
||
| checkAllPages() { | ||
| let self = this; | ||
|
|
||
| jQuery.post( dokan.ajaxurl, this.allPageStatus.data, function ( res ) { | ||
| self.allPageStatus.exists = res.data.all_pages_exists === '1'; | ||
| } ); |
There was a problem hiding this comment.
Add nonce protection for page-install actions and handle AJAX failures consistently.
createPages()/checkAllPages() call privileged AJAX actions without a nonce, and the corresponding backend handlers shown in includes/Ajax.php also skip nonce verification. That leaves create_pages CSRF-prone. Also, createPages() only clears allPageStatus.loading on success, so network/HTTP failures can lock the button until refresh.
Suggested patch (client-side)
createPages() {
let self = this;
if ( self.allPageStatus.loading ) {
return;
}
self.allPageStatus.loading = true;
- jQuery.post( dokan.ajaxurl, { action: 'create_pages' }, function ( res ) {
+ jQuery.post( dokan.ajaxurl, { action: 'create_pages', nonce: dokan.nonce } )
+ .done( function ( res ) {
if ( res.success ) {
self.$notify( {
title: self.__( 'Success!', 'dokan-lite' ),
text: res.data.message,
type: 'success',
} );
self.allPageStatus.exists = true;
} else {
self.$notify( {
title: self.__( 'Failure!', 'dokan-lite' ),
text: self.__( 'Something went wrong.', 'dokan-lite' ),
type: 'warn',
} );
}
-
- self.allPageStatus.loading = false;
- } );
+ } )
+ .fail( function ( jqXHR ) {
+ self.$notify( {
+ title: self.__( 'Failure!', 'dokan-lite' ),
+ text: jqXHR?.responseJSON?.data || self.__( 'Something went wrong.', 'dokan-lite' ),
+ type: 'warn',
+ } );
+ } )
+ .always( function () {
+ self.allPageStatus.loading = false;
+ } );
},
checkAllPages() {
let self = this;
- jQuery.post( dokan.ajaxurl, this.allPageStatus.data, function ( res ) {
- self.allPageStatus.exists = res.data.all_pages_exists === '1';
- } );
+ jQuery.post( dokan.ajaxurl, { ...this.allPageStatus.data, nonce: dokan.nonce } )
+ .done( function ( res ) {
+ self.allPageStatus.exists = res?.data?.all_pages_exists === '1';
+ } )
+ .fail( function () {
+ self.allPageStatus.exists = false;
+ } );
},Also add wp_verify_nonce(..., 'dokan_admin') in create_pages and check_all_dokan_pages_exists handlers in includes/Ajax.php to close the server-side gap.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/admin/pages/Tools.vue` around lines 103 - 137, The `createPages()` and
`checkAllPages()` methods send AJAX requests without CSRF nonce protection,
making them vulnerable to CSRF attacks. Additionally, `createPages()` only
clears the loading flag on success, which locks the UI if the request fails. Fix
this by adding nonce parameters to both jQuery.post calls (the nonce should be
available from the dokan object) and ensure the loading flag in `createPages()`
is cleared in both success and error scenarios by using error handlers or
wrapping the callback logic to guarantee cleanup on all outcomes.
| loading={ loading } | ||
| onClick={ () => onClick( type ) } | ||
| label={ type?.button } | ||
| className="!h-[28px] !font-[500] !text-[12px] !leading-[16px]" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find v3-style Tailwind important prefix usage in TS/TSX/JS/JSX files
rg -nP --glob '**/*.{ts,tsx,js,jsx}' '(?<![A-Za-z0-9_-])![A-Za-z0-9_-]+\['Repository: getdokan/dokan
Length of output: 50371
🏁 Script executed:
# Check Tailwind version and config
find . -maxdepth 3 -name "package.json" -o -name "tailwind.config.*" | head -5Repository: getdokan/dokan
Length of output: 97
🏁 Script executed:
# Look at package.json to find Tailwind version
rg -A 2 -B 2 "tailwindcss" package.jsonRepository: getdokan/dokan
Length of output: 497
🌐 Web query:
Tailwind CSS v4 important modifier syntax ! prefix vs suffix
💡 Result:
In Tailwind CSS v4, the recommended syntax for the important modifier is to use a trailing exclamation mark (!) suffix [1][2]. While Tailwind CSS v4 maintains backwards compatibility for the legacy prefix syntax (e.g., !text-blue-500) [3][4][5], the move to a suffix-based syntax (e.g., text-blue-500!) is the established convention [1][2]. This change aligns the modifier's position with native CSS, where !important is placed after the declaration, and improves clarity when combining the modifier with various variants [1][2]. Key details regarding this syntax include: - Usage: Append the ! character directly to the end of the utility class, such as flex-col! or items-start! [1]. - Backwards Compatibility: The legacy prefix syntax (placing ! before the utility) remains supported in v4 [3][4][5]. - CSS @apply: Within CSS @apply directives, the !important flag syntax used in v3 is no longer supported [1][5]. Instead, you must append the ! suffix to each individual utility class to mark it as important [1][5]. This shift to the suffix convention helps resolve ambiguity and simplifies parsing, particularly when complex variant stacks are involved [1].
Citations:
- 1: Add initial codemod tooling tailwindlabs/tailwindcss#14434
- 2: https://stackoverflow.com/questions/75664539/tailwind-css-class-precedence-is-not-respected
- 3: https://tailwindlabs-tailwindcss.mintlify.app/advanced/important-modifier
- 4: [v4] Support old important modifier position tailwindlabs/tailwindcss#13103
- 5: PostCSS + TailwindCSS 4 throws error on important! and ! modifiers tailwindlabs/tailwindcss#18570
Update to Tailwind v4 important modifier suffix syntax.
In Tailwind v4, the important modifier should use suffix placement (h-[28px]!) instead of the legacy prefix (!h-[28px]). While both syntaxes remain backwards compatible, the suffix syntax is now the recommended convention.
Proposed fix
- className="!h-[28px] !font-[500] !text-[12px] !leading-[16px]"
+ className="h-[28px]! font-[500]! text-[12px]! leading-[16px]!"📝 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.
| className="!h-[28px] !font-[500] !text-[12px] !leading-[16px]" | |
| className="h-[28px]! font-[500]! text-[12px]! leading-[16px]!" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/ToolsSection.tsx` at line 62, The className string in
ToolsSection.tsx contains Tailwind CSS important modifiers using the legacy
prefix syntax (exclamation mark before the utility class). Update all important
modifiers in the className from prefix placement (like !h-[28px]) to the
Tailwind v4 recommended suffix placement (h-[28px]!) by moving the exclamation
mark to the end of each utility class. This affects all four utility classes in
the style definition: h-[28px], font-[500], text-[12px], and leading-[16px].
Summary
Cache group transient-version markers are written via
set_transient()with no expiration, so WordPress stores them withautoload = yesand never clears them. On sites without a persistent object cache this bloats the autoloaded options (a client reported 5,000+ autoloaded rows, mostly_transient_dokan_cache_*-transient-version).This adds a filterable expiration to the marker so WordPress stores it
autoload = no(with a_transient_timeout_companion) and garbage-collects it like any transient.Related PR: https://github.com/getdokan/dokan-pro/pull/5765
Closes: https://github.com/getdokan/plugin-internal-tasks/issues/1965
Change
includes/Traits/TransientCache.php—get_transient_version()now sets the marker with:The default TTL (1 month) comfortably outlives the longest-lived data transient (≤ 1 week), so cache groups are not invalidated prematurely.
How to test
autoload = yes, no_transient_timeout_companion.autoload = no(oroff) with a matching_transient_timeout_…row ~30 days out.Verified
Local site, forcing the DB transient path: marker stored
autoload = offwith a~2592000s(30-day) timeout; cache read-back unaffected.Ref: getdokan/plugin-internal-tasks#1965 · Companion Pro PR adds a Clear Dokan Caches admin tool.
🤖 Generated with Claude Code
Summary by CodeRabbit
Summary