register_routes(); } /** * Register the internal `td_webhook` custom post type. * * This CPT is not exposed in the UI; it persists webhook configurations. * * @return void */ public static function register_cpt() { $labels = [ 'name' => __( 'Webhooks', 'thrive-dash' ), 'singular_name' => __( 'Webhook', 'thrive-dash' ), ]; $args = [ 'labels' => $labels, 'public' => false, 'show_ui' => false, 'show_in_menu' => false, 'exclude_from_search' => true, 'show_in_nav_menus' => false, 'supports' => [ 'title' ], 'capability_type' => 'post', 'map_meta_cap' => true, 'rewrite' => false, ]; register_post_type( 'td_webhook', $args ); // Exclude from Thrive index add_filter( 'tve_dash_exclude_post_types_from_index', static function( $post_types ) { $post_types[] = 'td_webhook'; return $post_types; } ); } /** * Add the Webhooks submenu under the Thrive Dashboard section. * * @return void */ public static function register_menu() { // Only expose the Webhooks admin UI when TVE_DEBUG is enabled if ( defined( 'TVE_DEBUG' ) && TVE_DEBUG ) { add_submenu_page( 'tve_dash_section', __( 'Webhooks', 'thrive-dash' ), __( 'Webhooks', 'thrive-dash' ), TVE_DASH_CAPABILITY, 'td_webhooks', [ __CLASS__, 'render_admin_page' ] ); } } /** * Render the admin page wrapper. The concrete UI is delegated to TD_Webhooks_Admin. * * @return void */ public static function render_admin_page() { TD_Webhooks_Admin::render(); } /** * Initialize default options for Webhooks settings and logs storage. * * - td_webhooks_settings: module settings (timeout, retention, TTL, allow/deny lists) * - td_webhooks_logs: per-webhook execution logs * * @return void */ public static function init_options() { // Do not create settings option unconditionally; defaults are provided via TD_Webhooks_Settings. if ( get_option( 'td_webhooks_logs', null ) === null ) { add_option( 'td_webhooks_logs', [], '', 'no' ); } } /** * Hook into the editor content pre-save pipeline to persist any webhook drafts coming from TCB. */ public static function hook_content_pre_save() { add_filter( 'tcb.content_pre_save', static function ( $response, $post_data ) { // Expect an array of { form_identifier, webhook_id, draft } under 'webhooks' if ( empty( $post_data['webhooks'] ) || ! is_array( $post_data['webhooks'] ) ) { return $response; } $result = []; foreach ( $post_data['webhooks'] as $item ) { $draft = isset( $item['draft'] ) && is_array( $item['draft'] ) ? $item['draft'] : []; $form_identifier = isset( $item['form_identifier'] ) ? sanitize_text_field( $item['form_identifier'] ) : ''; $form_id = isset( $item['form_id'] ) ? sanitize_text_field( $item['form_id'] ) : ''; $existing_id = isset( $item['webhook_id'] ) ? (int) $item['webhook_id'] : 0; $delete_id = isset( $item['delete'] ) ? (int) $item['delete'] : 0; // If deletion was requested, delete and return mapping only if ( $delete_id > 0 && get_post_type( $delete_id ) === TD_Webhooks_Repository::POST_TYPE ) { TD_Webhooks_Repository::delete( $delete_id ); $result[] = [ 'id' => 0, 'name' => __( 'Deleted', 'thrive-dash' ), 'form_identifier' => $form_identifier, 'form_id' => $form_id, 'deleted' => $delete_id, ]; continue; } // Otherwise create or update based on presence of existing_id if ( $existing_id > 0 && get_post_type( $existing_id ) === TD_Webhooks_Repository::POST_TYPE ) { // ID Exists, Update the webhook. TD_Webhooks_Repository::update( $existing_id, $draft ); $saved_id = $existing_id; } else { // ID Does Not Exist, Create the webhook. $saved_id = TD_Webhooks_Repository::create( $draft ); } if ( $saved_id ) { $saved = TD_Webhooks_Repository::read( (int) $saved_id ); $result[] = [ 'id' => (int) $saved_id, 'name' => isset( $saved['name'] ) ? $saved['name'] : '', 'form_identifier' => $form_identifier, 'form_id' => $form_id, 'deleted' => 0, ]; } } if ( ! empty( $result ) ) { $response['webhooks'] = $result; } return $response; }, 10, 2 ); } }