array( __CLASS__, 'render_callback' ), ) ); } /** * Render callback for the module. * * @since 4.0.0 * * @param array $attrs Module attributes. * @param string $content Module content. * @param \WP_Block $block Block object. * @param ModuleElements $elements ModuleElements instance. * @return string Rendered HTML. */ public static function render_callback( $attrs, $content, $block, $elements ) { // Extract template_id from nested attrs structure. $template_id = '0'; if ( isset( $attrs['templateId']['innerContent']['desktop']['value'] ) ) { $template_id = $attrs['templateId']['innerContent']['desktop']['value']; } // Convert to integer for comparison. $template_id = absint( $template_id ); if ( empty( $template_id ) || 0 === $template_id ) { $template_html = self::error_message( esc_html__( 'Please Select a Saved Template', 'post-carousel' ) ); } else { // Check if template exists and is published. $template_post = get_post( $template_id ); if ( ! $template_post || 'publish' !== $template_post->post_status ) { $template_html = self::error_message( esc_html__( 'Template not found or not published.', 'post-carousel' ) ); } elseif ( empty( $template_post->post_content ) ) { $template_html = self::error_message( esc_html__( 'Template content is empty.', 'post-carousel' ) ); } else { // Render the shortcode. $template_html = do_shortcode( '[smart_post id="' . absint( $template_id ) . '"]' ); } } // Check if in Divi 5 editor mode for CSS. $is_editor = self::is_divi5_builder_editor(); if ( $is_editor && $template_id > 0 ) { // Enqueue CSS for the template in builder mode. self::enqueue_template_dynamic_css( $template_id ); } // Use Module::render() for proper Divi 5 rendering in both frontend and visual builder. return Module::render( array( // Frontend only params. 'orderIndex' => $block->parsed_block['orderIndex'] ?? 0, 'storeInstance' => $block->parsed_block['storeInstance'] ?? '', // Visual builder params. 'attrs' => $attrs, 'elements' => $elements, 'id' => $block->parsed_block['id'] ?? '', 'moduleClassName' => 'spsp_divi5_smart_post_show', 'name' => $block->block_type->name ?? 'spsp/divi5-smart-post-show', 'classnamesFunction' => array( __CLASS__, 'module_classnames' ), 'moduleCategory' => $block->block_type->category ?? 'module', 'children' => self::render_module_inner( $template_html, $template_id ), ) ); } /** * Render module inner content. * * @since 4.0.0 * * @param string $template_html Rendered template HTML. * @param int $template_id Template ID. * @return string Module inner HTML. */ private static function render_module_inner( $template_html, $template_id ) { // Module inner container. return sprintf( '
%s
', esc_attr( $template_id ), $template_html ); } /** * Module classnames callback. * * @since 4.0.0 * * @param array $args Callback arguments. * @return void */ public static function module_classnames( $args ) { $classnames_instance = $args['classnamesInstance'] ?? null; $attrs = $args['attrs'] ?? array(); if ( $classnames_instance && method_exists( $classnames_instance, 'add' ) ) { // Add element classnames. $classnames_instance->add( 'spsp_divi5_smart_post_show' ); } } /** * Check if the current request is for Divi 5 Builder. * * @since 4.0.0 * * @return bool True if in Divi 5 builder context. */ protected static function is_divi5_builder_editor() { // Check Divi Frontend Builder. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce not required for builder context check. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- isset() check only, value not used. if ( isset( $_GET['et_fb'] ) ) { return true; } // Check if Divi is enabled. if ( function_exists( 'et_core_is_fb_enabled' ) && et_core_is_fb_enabled() ) { return true; } // Check Divi AJAX requests. if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && 0 === strpos( sanitize_key( wp_unslash( $_REQUEST['action'] ) ), 'et_' ) ) { return true; } return false; } /** * Enqueue CSS for template in Divi 5 builder. * Follows the same pattern as Elementor and Oxygen integrations. * * @since 4.0.0 * * @param int $template_id Template post ID. * @return void */ protected static function enqueue_template_dynamic_css( $template_id ) { // Prevent duplicate CSS generation for the same template in current request. static $generated_templates = array(); if ( isset( $generated_templates[ $template_id ] ) ) { return; } // Mark this template as processed. $generated_templates[ $template_id ] = true; $upload_dir = wp_upload_dir(); $css_file = $upload_dir['basedir'] . '/smart-post-show/static/sp-post-' . $template_id . '.css'; $css_url = $upload_dir['baseurl'] . '/smart-post-show/static/sp-post-' . $template_id . '.css'; // Enqueue CSS file if exists (same pattern as Elementor/Oxygen). if ( file_exists( $css_file ) ) { echo ''; // phpcs:ignore -- WordPress.Security.EscapeOutput.OutputNotEscaped } // Get and output dynamic CSS from meta (same pattern as Elementor/Oxygen). $dynamic_css = get_post_meta( $template_id, '_sp_smart_css', true ); if ( ! empty( $dynamic_css ) ) { echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } // Echo Google Fonts directly. $font_lists = get_post_meta( $template_id, '_sp_smart_fonts', true ); if ( ! empty( $font_lists ) && is_array( $font_lists ) ) { $font_lists = array_unique( $font_lists ); foreach ( $font_lists as $font ) { if ( ! empty( $font ) ) { echo ''; // phpcs:ignore -- WordPress.Security.EscapeOutput.OutputNotEscaped } } } } /** * Generate error message HTML. * * @since 4.0.0 * * @param string $message Error message. * @return string Error HTML. */ protected static function error_message( $message ) { return sprintf( '
%s
', esc_html( $message ) ); } } D5SmartPostShowProModule::get_instance()->load();