You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
WordPress Multisite → Multi-company Odoo — Full multisite support: each site in a WordPress network syncs with a specific Odoo company (res.company). Migration 7 adds blog_id column to wp4odoo_entity_map, wp4odoo_sync_queue, and wp4odoo_logs tables. Repository layer (Entity_Map_Repository, Sync_Queue_Repository, Logger) scopes all queries by blog_id. Odoo_Client injects allowed_company_ids into kwargs context when company_id > 0. Network activation iterates all sites, wp_initialize_site hook provisions new sites. Backward compatible: DEFAULT 1 ensures single-site installs are unaffected
Network Admin page — Centralized settings page in the WordPress network admin for shared Odoo connection (URL, DB, user, API key, protocol, timeout) and site → company_id mapping. Individual sites inherit the network connection by default but can override with their own connection in Settings > Odoo Connector
JetBooking module — New booking module for JetBooking (Crocoblock) 3.0+. Extends Booking_Module_Base. Syncs services → product.product (bidirectional), bookings → calendar.event (push). Hybrid data access: CPT for services, custom table jet_apartment_bookings for bookings. Hooks: jet-abaf/db/booking/after-insert, jet-abaf/db/booking/after-update, save_post_{service_cpt}
WP ERP CRM module — New CRM module for WP ERP 1.6+. Syncs contacts → crm.lead (bidirectional), activities → mail.activity (push). Custom table access (erp_peoples, erp_crm_customer_activities). Activity type resolution via mail.activity.type (cached). Cross-module partner linking with existing CRM module via email lookup. Life stage mapping: subscriber/lead → lead, opportunity → opportunity, customer → won
JetEngine Meta-Module — New meta-module for JetEngine (Crocoblock) 3.0+. Enriches other modules' sync pipelines with JetEngine meta-fields (pattern identical to ACF meta-module). Admin-configured mappings: target_module, entity_type, jet_field, odoo_field, type. Registers wp4odoo_map_to_odoo_*, wp4odoo_map_from_odoo_*, and wp4odoo_after_save_* filters at boot. No own entity types
JetFormBuilder support — 8th form plugin in the Forms module. Hooks into jet-form-builder/form-handler/after-send. Key-value data extraction via strategy pattern (same as Fluent Forms). Detection: JET_FORM_BUILDER_VERSION constant
Odoo_Model enum additions — 2 new cases: MailActivity, MailActivityType
WP-CLI --blog_id parameter — wp wp4odoo sync run --blog_id=3 and wp wp4odoo reconcile crm contact --blog_id=3 target a specific site in multisite (switches blog context, flushes credential cache)
Added (Architecture)
Migration 8 — Stale recovery index — New composite index idx_stale_recovery (blog_id, status, processed_at) on wp4odoo_sync_queue for efficient stale job recovery queries. Idempotent (checks SHOW INDEX before ALTER)
Migration 9 — Rebuild indexes with blog_id prefix — Rebuilds idx_dedup_odoo on wp4odoo_sync_queue and idx_poll_detection on wp4odoo_entity_map with blog_id as leading column for correct multisite index scoping. Idempotent (checks SHOW INDEX before DROP)
Migration 10 — Logs cleanup index + drop obsolete index — Adds idx_blog_cleanup (blog_id, created_at) on wp4odoo_logs for efficient multisite log cleanup. Drops obsolete idx_dedup_composite from wp4odoo_sync_queue (redundant since migration 7 added blog_id to dedup indexes)
Logger::for_channel() factory — New static factory method creates Logger instances with a shared Settings_Repository (avoids repeated get_option() calls when multiple loggers are created in the same request). All 12 direct new Logger() callsites migrated to Logger::for_channel() (Sync_Engine, Queue_Manager, Module_Base, Webhook_Handler, Partner_Service, Odoo_Client, Odoo_Transport_Base, Odoo_Auth, CLI, Ajax_Monitor_Handlers, Translation_Service)
Module_Base::register_hook() / teardown() — New hook lifecycle methods. register_hook() wraps add_action() with safe_callback() and tracks registered hooks. teardown() removes all tracked hooks via remove_action(). Called automatically when a module is disabled via the admin toggle. Designed for gradual adoption by new modules
Queue_Manager injectable Logger — Constructor accepts optional ?Logger $logger parameter. When provided (e.g. by Sync_Engine), queue depth alerts share the caller's Logger and its correlation ID. Falls back to Logger::for_channel('queue_manager') when null
Removed
exclusive_priority dead code — Removed $exclusive_priority property and get_exclusive_priority() getter from Module_Base and 17 module classes. Module_Registry::register() never read this value — exclusive groups use first-registered-wins based on registration order, not priority
Fixed (Architecture)
Blog-scoped transients — Sync_Engine stale recovery transient (wp4odoo_last_stale_recovery) and Queue_Manager depth check cooldown now include get_current_blog_id() in their transient keys, preventing multisite sites from sharing cooldown state
Webhook token auto-migration — Settings_Repository::get_webhook_token() now auto-encrypts plaintext tokens on first read (backward-compat fallback path). Subsequent reads return the encrypted-then-decrypted value, eliminating the plaintext storage after first access
Multisite index scoping — idx_dedup_odoo and idx_poll_detection indexes were missing blog_id as leading column, causing full-index scans in multisite installations. Migration 9 rebuilds both with correct blog_id prefix
SSRF protection on Network Admin — Network_Admin URL input now passes through Settings_Validator::is_safe_url() (same SSRF check as Settings_Page), rejecting private/internal IP addresses. is_safe_url() and is_private_ip() extracted from Settings_Page to shared Settings_Validator
Encryption key empty salt — Odoo_Auth::get_encryption_key() now throws RuntimeException when both AUTH_KEY and SECURE_AUTH_KEY are empty, instead of silently deriving a predictable key from SHA256('')
Batch JSON error classification — Batch_Create_Processor now classifies invalid JSON payloads as Error_Type::Transient (retryable) instead of Permanent, consistent with Sync_Engine::process_job() behavior
AJAX exception message sanitization — Ajax_Data_Handlers (fetch_odoo_taxes, fetch_odoo_carriers) no longer exposes raw exception messages to the browser. Errors are logged via Logger::for_channel('admin') and a generic translated message is returned to the client
Changed
Settings_Repository multisite support — New methods: get_effective_connection() (local → network fallback), get_network_connection(), save_network_connection(), get_site_company_id(), get_network_site_companies(), save_network_site_companies(), is_using_network_connection(). New constants: OPT_NETWORK_CONNECTION, OPT_NETWORK_SITE_COMPANIES. company_id added to DEFAULTS_CONNECTION
Odoo_Auth multisite credential resolution — get_credentials() falls back to network-level shared connection when site has no local URL configured. Applies site-specific company_id from network mapping. save_credentials() preserves company_id
Sync_Engine lock scoping — Advisory lock names include blog_id: wp4odoo_sync_{blog_id} and wp4odoo_sync_{blog_id}_{module} for multisite isolation
Connection tab UI — Shows "Using network connection" indicator when site inherits from network. New Company ID input field after Timeout