register(); $shortcode = new Dadan_Shortcode(); $shortcode->register(); $settings = new Dadan_Settings(); $settings->register(); $instances = new Dadan_Instance(); $instances->register(); $recorder = new Dadan_Recorder(); $recorder->register(); $record_shortcode = new Dadan_Record_Shortcode(); $record_shortcode->register(); // Elementor widgets when Elementor is active (optional). require_once DADAN_VIDEO_PATH . 'includes/class-dadan-elementor.php'; Dadan_Elementor::register(); add_action( 'init', array( $this, 'register_block' ) ); add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) ); // Priority 20: after wp_filter_post_kses (10) so smuggled block names are normalized first (NEW-1). add_filter( 'content_save_pre', array( $this, 'strip_privileged_record_block_attrs' ), 20, 1 ); } /** * Suggest privacy policy text (Dadan is a third-party service). */ public function add_privacy_policy_content() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } $content = '

' . esc_html__( 'This site may embed Dadan video players and/or recording buttons. When those features are used, the visitor’s browser communicates with Dadan’s servers (app.dadan.io) to play video, load the Record studio script, and upload recordings.', 'dadan' ) . '

'; $content .= '

' . esc_html__( 'Finished recordings are uploaded to Dadan’s upload service (upload-direct.dadan.io). The browser may temporarily keep an unfinished recording in IndexedDB (so an interrupted take can be restored) and upload-resume keys in localStorage.', 'dadan' ) . '

'; $content .= '

' . esc_html__( 'WordPress stores only the site’s public App ID and display settings. Recording media and related session data are processed by Dadan under Dadan’s own terms and privacy policy.', 'dadan' ) . ' ' . esc_html__( 'Dadan Terms', 'dadan' ) . '

'; wp_add_privacy_policy_content( __( 'Dadan', 'dadan' ), wp_kses_post( $content ) ); } /** * Register Gutenberg blocks and attach script translations (W2). */ public function register_block() { $lang = DADAN_VIDEO_PATH . 'languages'; // DADAN-34: one handle for public-record.css (block.json + shortcode share it). wp_register_style( 'dadan-video-public-record', DADAN_VIDEO_URL . 'assets/public-record.css', array(), DADAN_VIDEO_VERSION ); $video_dir = DADAN_VIDEO_PATH . 'blocks/dadan-video'; if ( file_exists( $video_dir . '/block.json' ) ) { register_block_type( $video_dir ); wp_set_script_translations( 'dadan-video-editor-script', 'dadan', $lang ); } $record_dir = DADAN_VIDEO_PATH . 'blocks/dadan-record'; if ( file_exists( $record_dir . '/block.json' ) ) { register_block_type( $record_dir ); wp_set_script_translations( 'dadan-record-editor-script', 'dadan', $lang ); } } /** * Non-admins cannot persist privileged Record block attrs. * * Runs on content_save_pre (priority 20, after kses) with SLASHED content — * must unslash before parse_blocks / serialize_blocks or every block loses attrs (DADAN-01). * After-kses ordering closes the `wp:dadan/record` smuggle (NEW-1). * * @param string $content Post content (slashed). * @return string */ public function strip_privileged_record_block_attrs( $content ) { if ( current_user_can( 'manage_options' ) ) { return $content; } if ( ! is_string( $content ) || '' === $content ) { return $content; } // has_block() is unreliable on slashed content; cheap needle check first. if ( false === strpos( $content, 'wp:dadan/record' ) ) { return $content; } if ( ! function_exists( 'parse_blocks' ) || ! function_exists( 'serialize_blocks' ) ) { return $content; } $raw = wp_unslash( $content ); $blocks = $this->map_record_blocks_for_non_admin( parse_blocks( $raw ) ); return wp_slash( serialize_blocks( $blocks ) ); } /** * @param array> $blocks Blocks. * @return array> */ private function map_record_blocks_for_non_admin( $blocks ) { $default = class_exists( 'Dadan_Instance' ) ? (int) Dadan_Instance::default_id() : 0; foreach ( $blocks as &$block ) { if ( ! empty( $block['blockName'] ) && 'dadan/record' === $block['blockName'] ) { $attrs = isset( $block['attrs'] ) && is_array( $block['attrs'] ) ? $block['attrs'] : array(); $attrs['publicAppId'] = ''; $attrs['folderId'] = ''; $attrs['teamId'] = ''; $attrs['frontRecordAccess'] = ''; $iid = isset( $attrs['instanceId'] ) ? absint( $attrs['instanceId'] ) : 0; if ( ! $iid && $default ) { $attrs['instanceId'] = $default; } $block['attrs'] = $attrs; } if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) { $block['innerBlocks'] = $this->map_record_blocks_for_non_admin( $block['innerBlocks'] ); } } unset( $block ); return $blocks; } /** * Front-end CSS for shortcodes (block styles load via block.json). */ public function enqueue_frontend_assets() { wp_register_style( 'dadan-video-frontend', DADAN_VIDEO_URL . 'assets/frontend.css', array(), DADAN_VIDEO_VERSION ); wp_enqueue_style( 'dadan-video-frontend' ); } }