Skip to main content

Sync hooks & filters

Developer reference: This section is for theme and plugin developers.


Behaviour

  • Full sync loads remote units from the active provider (fetchRemoteUnits), then creates or updates Unit posts keyed by bec_external_id + bec_provider_slug.
  • Scheduled sync uses WP-Cron (bec_run_scheduled_sync). Interval is configured under Booking Engine → Sync & Import (bec_sync_interval_hours, default 6). On low-traffic sites, cron may run only after the next request (standard WP behaviour).
  • Manual full sync (wp-admin) uses AJAX batches (wp_ajax_bec_sync_start_all, wp_ajax_bec_sync_step_all) with progress stored per user + run id (SyncProgressReporter / SyncManualBatchState).
  • Lock — concurrent full sync is coordinated with transient bec_sync_running_lock:
    • TTL 7200 seconds (2 hours) per set_transient, refreshed on re-entry while work continues (SyncLock::refresh()).
    • Holder c — WP-Cron acquired the lock (SyncLock::acquireCron).
    • Holder m:{userId}:{runId} — batched manual sync (SyncLock::acquireManual), where runId is sanitised client UUID.
    • Cron cannot steal an active manual lock. Manual may preempt cron only when filter bec_sync_manual_may_preempt_cron_lock returns true (default false).
    • Same user starting a new manual run may clear a stale lock when the previous run’s batch state is gone, or after bec_sync_manual_lock_abandon_seconds (default 1800 = 30 minutes) without batch state updates.
    • SyncLock::forceReleaseAll() is used by Clear sync lock in admin; gated in UI by bec_sync_allow_admin_clear_lock (default true).
  • After each successful upsert, the plugin stores the normalised remote row as JSON in post meta bec_sync_payload (for inspection in the unit edit screen; hidden from REST by default).
  • Core fields: the active provider’s extractCoreUnitFields() maps each remote row into canonical bec_core_* meta (see Canonical unit fields). Overwritten each sync unless bec_sync_apply_core_unit_fields returns false.
  • Optional mapped fields: getUnitSyncFieldDefinitions() drives additional meta (client-specific). Overwritten each sync unless disabled via bec_sync_apply_mapped_unit_fields.
  • Unit categories: when the taxonomy is enabled, bec_after_unit_sync runs UnitCategorySync which upserts a term and assigns it using bec_sync_unit_category filtered descriptor data.

Actions

HookWhenArguments
bec_before_unit_syncBefore wp_insert_post / wp_update_post$post_id (0 if not yet created), $provider_slug, $remote_row
bec_after_unit_syncAfter meta updated$post_id, $provider_slug, $remote_row

Filters — core sync mapping

FilterPurpose
bec_sync_remote_unitNormalise each remote row before mapping ($row, $provider_slug)
bec_sync_unit_titlePost title ($title, $row, $provider_slug). Default is the canonical unit name from extractCoreUnitFields after bec_core_unit_fields (same as bec_core_name). Empty → Unit {external_id}. Duplicate titles are fine: WordPress keeps slugs unique.
bec_sync_unit_contentPost content ($content, $row, $provider_slug). Default is the canonical description (same as bec_core_description). Stored with wp_kses_post.
bec_sync_unit_post_datapost_data array for wp_insert_post / wp_update_post ($post_data, $row, $provider_slug, $post_id_or_null)
bec_provider_remote_unitsFinal list from Kross full sync ($rows, 'kross', $decoded_response)
bec_sync_apply_core_unit_fieldsSkip writing canonical bec_core_* meta (true / false, $post_id, $provider_slug, $remote_row)
bec_core_unit_fieldsAdjust core field array before save ($data, $provider_slug, $remote_row)
bec_core_unit_localeTwo-letter locale for name/description ($two, $wp_locale, $remote_row)
bec_provider_amenities_from_rowBuild amenities list ($items, $remote_row, $provider_slug)
bec_kross_amenities_from_rawKross-only: amenities from API raw ($items, $raw, $normalised_row)
bec_sync_unit_resolve_post_statusesPost statuses consulted when resolving an existing unit by external id ($statuses, $external_id, $provider_slug) — default publish, draft, pending, future, private

Posts with bec_sync_enabled = false are skipped in full sync but can still be updated via row action / bulk sync (manual refresh).


Filters — lock & manual sync (admin)

FilterPurpose
bec_sync_manual_lock_abandon_secondsIdle seconds before same user's orphaned manual run can release the lock ($default, $user_id, $old_run_id)
bec_sync_manual_may_preempt_cron_lockAllow manual sync to delete a c lock and replace it (false, $user_id, $sanitized_run_id)
bec_sync_allow_admin_clear_lockShow/allow Clear sync lock (true)
bec_sync_manual_gallery_batch_sizeGallery steps per manual sync batch (4, $user_id, $run_raw)

FilterPurpose
bec_sync_import_gallery_imagesSkip downloading gallery for this upsert (true, $parent_post_id, $urls)
bec_sync_gallery_ignore_hashIgnore stored order/hash dedupe for this pass (false, $parent_post_id, $urls, $order_hash)
bec_gallery_download_concurrencyParallel download limit (8, $parent_post_id, $urls)
bec_core_unit_gallery_before_saveAttachment ID list before save ($ids, $post_id)
bec_core_unit_gallery_remote_urlsRemote URL flat list before importer runs ($urls, $post_id, $value)

Filters — unit categories

FilterPurpose
bec_sync_unit_categoryReplace/suppress category descriptor after row normalisation ($descriptor, $row, $provider_slug, $post_id)
bec_unit_category_enabledEffective on/off for taxonomy registration without changing the saved option
bec_unit_category_rewrite_slugAdjust derived rewrite base slug
bec_unit_category_taxonomy_argsFinal register_taxonomy args ($args, 'bec_unit_category')

Kross mapping hooks (payload fragment → descriptor) include:

  • bec_kross_room_type_categories_payload
  • bec_kross_room_type_categories
  • bec_kross_room_type_category_from_row

Search form (front end)

FilterPurpose
bec_search_form_actionOverride the <form action> URL when SearchForm::render() did not receive an explicit action argument ($url, $context). Return empty string to keep built-in rules (archive / singular / home). The [bec_search] shortcode supplies action from redirect_url or the archive fallback—this filter applies mainly to PHP-rendered forms.

Other search UI filters (bec_search_form_fields, bec_search_form_preset, bec_search_guest_field_mode, etc.) remain documented alongside provider integration; see SearchForm and bec_search shortcode.


Filters — date range & money formatting

FilterPurpose
bec_search_form_daterange_formatPHP date_i18n() format for Enhanced calendar footer readout ($format, $context)
bec_daterange_moment_format_presetsMap preset slugs (iso, short, medium, …) to Moment.js format strings
bec_php_date_format_to_momentConvert a custom PHP date format to Moment.js ($moment, $phpFormat)
bec_search_form_popover_placementOverride popover placement (auto, top, bottom) for Enhanced search
bec_date_format_defaultsDefault format options for [bec_dates] shortcode
bec_shortcode_dates_format / bec_shortcode_dates_text / bec_shortcode_dates_htmlAdjust [bec_dates] output
bec_money_format_defaultsDefault currency/number options for [bec_quote] ($defaults, 'bec_quote')
bec_currency_symbolsMap ISO currency codes to display symbols
bec_format_moneyFinal formatted amount string before output

Filters — unit listing ([bec_unit_filters])

FilterPurpose
bec_unit_filter_definitionsAdd/replace built-in filter field definitions ($defs)
bec_unit_filters_preserve_query_keysExtra GET keys to keep when the filter form submits ($keys)
bec_unit_filter_query_appliedAction after filters are applied to a WP_Query ($query, $request)
bec_available_units_countOverride count returned by [bec_available_units_count] ($count, $loopQuery)
bec_shortcode_available_units_count_htmlAdjust count shortcode HTML ($html, $count, $atts, $ctx)
bec_elementor_unit_filter_query_idsElementor Loop Grid query ids that receive filter + availability logic ($ids)

Native bec_unit archive main queries are filtered via UnitFilterQueryHooks when bec_filter_* params are present.


FilterPurpose
bec_unit_url_structureEffective single-unit URL structure option (base, base_category, category_only)
bec_unit_category_url_structureCategory archive URL structure (category_base, unit_base, bare)
bec_unit_permalink_primary_termPick primary category term when multiple are assigned ($term, $candidates, $postId)
bec_unit_permalink_slug_conflicts_with_coreTreat a slug as conflicting with core WP content ($conflicts, $slug)

See user guide Permalinks and archive.


Custom REST, blocks, webhooks

The connector does not register its own register_rest_route surface for booking APIs. bec_unit uses WordPress CPT REST where show_in_rest is true; sensitive meta such as bec_sync_payload stays out of REST. There are no register_block_type Gutenberg blocks in the plugin PHP and no inbound webhooks—integrations are pull-based sync + front-end shortcodes/hooks.

Admin-only endpoints used for operations:

  • wp_ajax_bec_sync_progress_poll, bec_sync_run_all, bec_sync_start_all, bec_sync_step_all
  • admin_post_* actions for saving sync settings, clearing locks, per-unit sync, gallery rename, Kross engine refresh, etc.