'show_if_user_logged_in', 'show_if_public_users' => 'show_if_user_not_logged_in', 'show_if_tag_exists' => 'show_if_tag_exist', 'show_if_tag_not_exists' => 'show_if_tag_not_exist', ]; public function register() { add_action('init', [$this, 'registerBlock']); add_action('enqueue_block_editor_assets', [$this, 'enqueueEditorAssets']); } /** * Register the block with a render callback. * The JS save() still writes HTML into post_content for storage, * but the render_callback fully controls frontend output. */ public function registerBlock() { if (!function_exists('register_block_type')) { return; } register_block_type(self::BLOCK_NAME, [ 'api_version' => 3, 'editor_script' => 'fluent-crm-conditional-content-block', 'attributes' => [ 'condition_type' => [ 'type' => 'string', 'default' => self::DEFAULT_CONDITION, ], 'tag_ids' => [ 'type' => 'array', 'default' => [], ], ], 'supports' => [ 'align' => ['wide', 'full'], 'anchor' => true, 'html' => false, ], 'render_callback' => [$this, 'renderBlock'], ]); } public function enqueueEditorAssets() { // The iframe editor already registers its own conditional block implementation. if (isset($_REQUEST['fluent_crm_block_editor'])) { return; } $handle = 'fluent-crm-conditional-content-block'; wp_register_script( $handle, fluentCrmMix('public/conditional-content-block.js'), ['wp-blocks', 'wp-block-editor', 'wp-components', 'wp-element', 'wp-i18n'], FLUENTCRM_PLUGIN_VERSION, true ); $tags = Tag::select(['id', 'title'])->orderBy('title', 'ASC')->get(); wp_localize_script($handle, 'fcrmConditionalContentConfig', [ 'hasPro' => defined('FLUENTCAMPAIGN'), 'tags' => $tags ]); wp_set_script_translations($handle, 'fluent-crm'); } /** * Render callback. Receives block attributes, the rendered inner blocks * as $content, and the WP_Block instance. * * @param array $attributes * @param string $content Inner blocks already rendered. * @param \WP_Block $block * @return string */ public function renderBlock($attributes, $content, $block) { if (!$this->passesCondition($attributes)) { return ''; } // no inner blocks placed at all — nothing to render. // Checking $block->inner_blocks (parsed block data) is the authoritative source of truth // and avoids inspecting the rendered HTML string, which loses semantic information. if (count($block->inner_blocks) === 0) { return ''; } // inner blocks exist but all rendered to nothing — for example a Query Loop // with no results, a dynamic block gated by its own conditions, or a plugin-restricted // block. Avoids outputting an empty wrapper div in those cases. // trim() on the raw HTML string is intentional: any real element (iframe, video, image, // paragraph, etc.) produces a non-empty string. wp_strip_all_tags() is deliberately // avoided here because it removes HTML tags and would incorrectly treat media-only // content (iframes, videos, images) as empty. if (trim($content) === '') { return ''; } $wrapperAttributes = get_block_wrapper_attributes([ 'class' => 'fc-cond-section', ]); return sprintf( '