sanitizer = $sanitizer; $this->evaluator = $evaluator; } /** * Registers hooks. * * @return void */ public function register(): void { add_filter( 'register_block_type_args', array( $this, 'add_attribute' ), 10, 2 ); add_filter( 'render_block', array( $this, 'render' ), 10, 2 ); } /** * Block types that can't have a rule. Every other block can. * * @return array */ public function excluded_block_types(): array { /** * Filters the block types that don't get the Visibility panel and rule attribute. * * @param array $block_types Block names, e.g. "core/freeform". */ return array_values( array_map( 'strval', (array) apply_filters( 'yangra_conditional_visibility_excluded_block_types', self::EXCLUDED ) ) ); } /** * Whether a block type can have a rule. * * @param string $block_type Block name. * @return bool */ public function supports( string $block_type ): bool { return '' !== $block_type && ! in_array( $block_type, $this->excluded_block_types(), true ); } /** * Adds the rule and schedule attributes to blocks registered on the server. Blocks * registered only in JS get it from the editor script, and the front end * reads it from the saved markup either way. * * @param mixed $args Block type arguments. * @param string $block_type Block name. * @return mixed */ public function add_attribute( $args, $block_type ) { if ( ! is_array( $args ) || ! $this->supports( (string) $block_type ) ) { return $args; } $args['attributes'] = isset( $args['attributes'] ) && is_array( $args['attributes'] ) ? $args['attributes'] : array(); $args['attributes'][ self::ATTRIBUTE ] = array( 'type' => 'object' ); $args['attributes'][ self::SCHEDULE_ATTRIBUTE ] = array( 'type' => 'object' ); return $args; } /** * Returns an empty string for hidden blocks on the front end. * * @param mixed $block_content Rendered block. * @param mixed $block Parsed block. * @return mixed */ public function render( $block_content, $block ) { if ( ! is_array( $block ) || ! $this->applies() ) { return $block_content; } return $this->is_hidden( $block ) ? '' : $block_content; } /** * Whether a parsed block has a rule that hides it for the current request. * Blocks without a rule, and excluded blocks, are never hidden. * * @param array $block Parsed block. * @return bool */ public function is_hidden( array $block ): bool { $name = isset( $block['blockName'] ) && is_string( $block['blockName'] ) ? $block['blockName'] : ''; if ( ! isset( $block['attrs'][ self::ATTRIBUTE ] ) || ! $this->supports( $name ) ) { return false; } $rule = $this->sanitizer->sanitize( $block['attrs'][ self::ATTRIBUTE ] ); return ! $this->evaluator->is_visible( $rule ); } /** * Rules only apply on the front end: never in the admin, and never in the * block renderer the editor uses for previews. * * @return bool */ public function applies(): bool { if ( is_admin() ) { return false; } if ( wp_is_serving_rest_request() ) { $route = isset( $GLOBALS['wp']->query_vars['rest_route'] ) ? (string) $GLOBALS['wp']->query_vars['rest_route'] : ''; if ( 0 === strpos( $route, '/wp/v2/block-renderer' ) ) { return false; } } return true; } }