Fix button roundtrip in editor, alignment persistence, and test email rendering

This commit is contained in:
Dwindi Ramadhana
2026-01-17 13:10:50 +07:00
parent 0e9ace902d
commit 6d2136d3b5
61 changed files with 8287 additions and 866 deletions

View File

@@ -5,7 +5,9 @@ use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WooNooW\Frontend\PlaceholderRenderer;
use WooNooW\Frontend\PageSSR;
use WooNooW\Templates\TemplateRegistry;
/**
* Pages Controller
@@ -19,6 +21,13 @@ class PagesController
public static function register_routes()
{
$namespace = 'woonoow/v1';
// Unset SPA Landing (Must be before generic slug route)
register_rest_route($namespace, '/pages/unset-spa-landing', [
'methods' => 'POST',
'callback' => [__CLASS__, 'unset_spa_landing'],
'permission_callback' => [__CLASS__, 'check_admin_permission'],
]);
// List all pages and templates
register_rest_route($namespace, '/pages', [
@@ -41,6 +50,13 @@ class PagesController
],
]);
// Get template presets (Must be before generic template cpt route)
register_rest_route($namespace, '/templates/presets', [
'methods' => 'GET',
'callback' => [__CLASS__, 'get_template_presets'],
'permission_callback' => '__return_true',
]);
// Get/Save CPT templates
register_rest_route($namespace, '/templates/(?P<cpt>[a-zA-Z0-9_-]+)', [
[
@@ -61,6 +77,8 @@ class PagesController
'callback' => [__CLASS__, 'get_content_with_template'],
'permission_callback' => '__return_true',
]);
// Create new page
register_rest_route($namespace, '/pages', [
@@ -82,6 +100,22 @@ class PagesController
'callback' => [__CLASS__, 'render_template_preview'],
'permission_callback' => [__CLASS__, 'check_admin_permission'],
]);
// Set page as SPA Landing (shown at SPA root route)
register_rest_route($namespace, '/pages/(?P<id>\d+)/set-as-spa-landing', [
'methods' => 'POST',
'callback' => [__CLASS__, 'set_as_spa_landing'],
'permission_callback' => [__CLASS__, 'check_admin_permission'],
]);
// Delete page
register_rest_route($namespace, '/pages/(?P<id>\d+)', [
'methods' => 'DELETE',
'callback' => [__CLASS__, 'delete_page'],
'permission_callback' => [__CLASS__, 'check_admin_permission'],
]);
}
/**
@@ -91,14 +125,26 @@ class PagesController
{
return current_user_can('manage_woocommerce');
}
/**
* Get available template presets
*/
public static function get_template_presets()
{
return new WP_REST_Response(TemplateRegistry::get_templates(), 200);
}
/**
* Get all pages and templates
* Get all editable pages (and templates)
*/
public static function get_pages(WP_REST_Request $request)
public static function get_pages()
{
$result = [];
// Get SPA settings
$settings = get_option('woonoow_appearance_settings', []);
$spa_frontpage_id = $settings['general']['spa_frontpage'] ?? 0;
// Get structural pages (pages with WooNooW structure)
$pages = get_posts([
'post_type' => 'page',
@@ -119,6 +165,7 @@ class PagesController
'title' => $page->post_title,
'url' => get_permalink($page),
'icon' => 'page',
'is_spa_frontpage' => (int)$page->ID === (int)$spa_frontpage_id,
];
}
@@ -155,6 +202,10 @@ class PagesController
$structure = get_post_meta($page->ID, '_wn_page_structure', true);
// Get SPA settings
$settings = get_option('woonoow_appearance_settings', []);
$spa_frontpage_id = $settings['general']['spa_frontpage'] ?? 0;
// Get SEO data (Yoast/Rank Math)
$seo = self::get_seo_data($page->ID);
@@ -163,8 +214,8 @@ class PagesController
'type' => 'page',
'slug' => $page->post_name,
'title' => $page->post_title,
'url' => get_permalink($page),
'seo' => $seo,
'is_spa_frontpage' => (int)$page->ID === (int)$spa_frontpage_id,
'structure' => $structure ?: ['sections' => []],
], 200);
}
@@ -198,6 +249,9 @@ class PagesController
update_post_meta($page->ID, '_wn_page_structure', $save_data);
// Invalidate SSR cache
delete_transient("wn_ssr_page_{$page->ID}");
return new WP_REST_Response([
'success' => true,
'page' => [
@@ -327,6 +381,53 @@ class PagesController
], 200);
}
/**
* Set page as SPA Landing (the page shown at SPA root route)
* This does NOT affect WordPress page_on_front setting.
*/
public static function set_as_spa_landing(WP_REST_Request $request) {
$id = (int)$request->get_param('id');
// Verify the page exists
$page = get_post($id);
if (!$page || $page->post_type !== 'page') {
return new WP_Error('invalid_page', 'Page not found', ['status' => 404]);
}
// Update WooNooW SPA settings - set this page as the SPA frontpage
$settings = get_option('woonoow_appearance_settings', []);
if (!isset($settings['general'])) {
$settings['general'] = [];
}
$settings['general']['spa_frontpage'] = $id;
update_option('woonoow_appearance_settings', $settings);
return new WP_REST_Response([
'success' => true,
'id' => $id,
'message' => 'SPA Landing page set successfully'
], 200);
}
/**
* Unset SPA Landing (the page shown at SPA root route)
* After unsetting, SPA will redirect to /shop or /checkout based on mode
*/
public static function unset_spa_landing(WP_REST_Request $request) {
// Update WooNooW SPA settings - clear the SPA frontpage
$settings = get_option('woonoow_appearance_settings', []);
if (isset($settings['general'])) {
$settings['general']['spa_frontpage'] = 0;
}
update_option('woonoow_appearance_settings', $settings);
return new WP_REST_Response([
'success' => true,
'message' => 'SPA Landing page unset. Root will now redirect to shop/checkout.'
], 200);
}
/**
* Create new page
*/
@@ -365,6 +466,15 @@ class PagesController
'created_at' => current_time('mysql'),
];
// Apply template if provided
$template_id = $body['templateId'] ?? null;
if ($template_id) {
$template = TemplateRegistry::get_template($template_id);
if ($template) {
$structure['sections'] = $template['sections'];
}
}
update_post_meta($page_id, '_wn_page_structure', $structure);
return new WP_REST_Response([
@@ -378,6 +488,42 @@ class PagesController
], 201);
}
/**
* Delete page
*/
public static function delete_page(WP_REST_Request $request) {
$id = (int)$request->get_param('id');
$page = get_post($id);
if (!$page || $page->post_type !== 'page') {
return new WP_Error('not_found', 'Page not found', ['status' => 404]);
}
// Check if it's the SPA front page
$settings = get_option('woonoow_appearance_settings', []);
$spa_frontpage_id = $settings['general']['spa_frontpage'] ?? 0;
if ((int)$id === (int)$spa_frontpage_id) {
// Unset SPA frontpage if deleting it
if (isset($settings['general'])) {
$settings['general']['spa_frontpage'] = 0;
update_option('woonoow_appearance_settings', $settings);
}
}
$deleted = wp_delete_post($id, true); // Force delete
if (!$deleted) {
return new WP_Error('delete_failed', 'Failed to delete page', ['status' => 500]);
}
return new WP_REST_Response([
'success' => true,
'id' => $id,
'message' => 'Page deleted successfully'
], 200);
}
// ========================================
// Helper Methods
// ========================================