feat(admin): Settings 分區即時儲存(backport A v3.0.2)
7 個設定分區各自加「儲存此區塊」按鈕,經 wp_ajax_wpdo_save_settings_section 以 AJAX 存檔,不再需要整頁 reload。 - 新增 ajax_save_settings_section() + 7 個 private save_section_*() - 新增 admin/assets/wpdo-settings.js(106 行)與 4 條 CSS 規則 - render_settings() 的 7 個 h3 各包上 .wpdo-settings-section[data-section] - 全頁送出按鈕改標「儲存全部設定」,原本的 POST handler 保持不變(漸進增強) hp-transient / wc-term-count 兩個分區的 toggle 仍由核心 admin 呈現(實作在 AddOn),只寫 wp_options,故不需 class_exists 守衛。
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* WP Data Optimizer — Settings per-section instant save.
|
||||
*
|
||||
* Each .wpdo-settings-section card has a "儲存此區塊" button that posts only
|
||||
* that section's fields via AJAX, updating options without a full page reload.
|
||||
*
|
||||
* @since 3.0.2
|
||||
*/
|
||||
/* global wpdoSettings */
|
||||
( function () {
|
||||
'use strict';
|
||||
|
||||
if ( typeof wpdoSettings === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { ajaxUrl, nonce, i18n } = wpdoSettings;
|
||||
|
||||
/**
|
||||
* Collect form fields within a section into a FormData object.
|
||||
* Unchecked checkboxes are intentionally omitted (server does isset() ? '1' : '0').
|
||||
*
|
||||
* @param {HTMLElement} section
|
||||
* @returns {FormData}
|
||||
*/
|
||||
function collectFields( section ) {
|
||||
const fd = new FormData();
|
||||
section.querySelectorAll( 'input, select, textarea' ).forEach( ( el ) => {
|
||||
if ( ! el.name ) {
|
||||
return;
|
||||
}
|
||||
if ( el.type === 'checkbox' ) {
|
||||
if ( el.checked ) {
|
||||
fd.append( el.name, el.value );
|
||||
}
|
||||
} else if ( el.type === 'radio' ) {
|
||||
if ( el.checked ) {
|
||||
fd.append( el.name, el.value );
|
||||
}
|
||||
} else {
|
||||
fd.append( el.name, el.value );
|
||||
}
|
||||
} );
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a transient status message, then fade it out after 2.5s.
|
||||
*
|
||||
* @param {HTMLElement} statusEl
|
||||
* @param {string} message
|
||||
* @param {boolean} isError
|
||||
*/
|
||||
function showStatus( statusEl, message, isError ) {
|
||||
statusEl.textContent = message;
|
||||
statusEl.style.color = isError ? 'var(--color-error, #b03d3d)' : 'var(--color-success, #5a8c5a)';
|
||||
statusEl.classList.add( 'visible' );
|
||||
clearTimeout( statusEl._wpdo_timer );
|
||||
statusEl._wpdo_timer = setTimeout( () => {
|
||||
statusEl.classList.remove( 'visible' );
|
||||
}, 2500 );
|
||||
}
|
||||
|
||||
document.addEventListener( 'click', function ( e ) {
|
||||
const btn = e.target.closest( '.wpdo-section-save' );
|
||||
if ( ! btn ) {
|
||||
return;
|
||||
}
|
||||
const section = btn.closest( '.wpdo-settings-section' );
|
||||
const statusEl = btn.nextElementSibling;
|
||||
const sectionKey = section ? section.dataset.section : '';
|
||||
if ( ! sectionKey ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalLabel = btn.textContent;
|
||||
btn.disabled = true;
|
||||
btn.textContent = i18n.saving;
|
||||
|
||||
const fd = collectFields( section );
|
||||
fd.append( 'action', 'wpdo_save_settings_section' );
|
||||
fd.append( '_ajax_nonce', nonce );
|
||||
fd.append( 'section', sectionKey );
|
||||
|
||||
fetch( ajaxUrl, {
|
||||
method : 'POST',
|
||||
credentials : 'same-origin',
|
||||
body : fd,
|
||||
} )
|
||||
.then( ( r ) => r.json() )
|
||||
.then( ( data ) => {
|
||||
if ( data.success ) {
|
||||
showStatus( statusEl, i18n.saved, false );
|
||||
} else {
|
||||
showStatus( statusEl, i18n.error, true );
|
||||
}
|
||||
} )
|
||||
.catch( () => {
|
||||
showStatus( statusEl, i18n.error, true );
|
||||
} )
|
||||
.finally( () => {
|
||||
btn.disabled = false;
|
||||
btn.textContent = originalLabel;
|
||||
} );
|
||||
} );
|
||||
} )();
|
||||
Reference in New Issue
Block a user