registry = $registry; $this->evaluator = $evaluator; $this->context_factory = $context_factory; } /** * Gets the condition registry. * * @return ConditionRegistry */ public function registry(): ConditionRegistry { return $this->registry; } /** * Gets the context factory. * * @return ContextFactory */ public function context_factory(): ContextFactory { return $this->context_factory; } /** * Determines whether a block should render for the current request. * * Fast-paths disabled or empty models, evaluates the conditions, and always * fails open (renders) on any error so content is never hidden by accident. * * @param array $model The visibility model. * @return bool True to render, false to hide. */ public function should_render( array $model ): bool { if ( empty( $model['enabled'] ) || empty( $model['conditions'] ) ) { return true; } try { $context = $this->context_factory->current(); $result = $this->evaluator->should_render( $model, $context ); } catch ( \Throwable $e ) { return true; } /** * Filters the final visibility result for a block. * * @param bool $result Whether the block should render. * @param array $model The visibility model. * @param Context $context The request context. */ return (bool) apply_filters( 'blocksieve_result', $result, $model, $context ); } /** * Reports whether every condition of a model has a registered type, i.e. * whether the model is enforced rather than failing open. * * @param array $model The visibility model. * @return bool */ public function is_valid( array $model ): bool { $conditions = $model['conditions'] ?? array(); if ( ! is_array( $conditions ) ) { return false; } try { $this->evaluator->validate( $conditions ); } catch ( \Throwable $e ) { return false; } return true; } /** * Evaluates a model for the current request without the result filter. * * For internal sub-evaluations (e.g. the non-device part of a model), so * `blocksieve_result` still runs exactly once per block with its real model. * Fails open like should_render(). * * @param array $model The visibility model. * @return bool */ public function matches( array $model ): bool { try { return $this->evaluator->should_render( $model, $this->context_factory->current() ); } catch ( \Throwable $e ) { return true; } } /** * Registers the built-in condition types, then fires the registration hook * so third-party types can be added. * * @return void */ public function register_conditions(): void { $this->register_builtin_conditions(); /** * Fires so additional condition types can be registered against the * registry after the built-in types are added. * * @param ConditionRegistry $registry The condition registry. */ try { do_action( 'blocksieve_register_conditions', $this->registry ); } catch ( ConditionException $e ) { // A duplicate or invalid third-party type must not take the whole site down. _doing_it_wrong( 'blocksieve_register_conditions', esc_html( $e->getMessage() ), esc_html( BLOCKSIEVE_VERSION ) ); } } /** * Registers the built-in condition types, if not already present. * * @return void */ private function register_builtin_conditions(): void { $conditions = array( new Definitions\LoggedInCondition(), new Definitions\LoggedOutCondition(), new Definitions\UserRoleCondition(), new Definitions\DateRangeCondition(), new Definitions\WeekdaysCondition(), new Definitions\TimeRangeCondition(), new Definitions\DeviceCondition(), new Definitions\PostTypeCondition(), new Definitions\PostSelectionCondition(), new Definitions\ArchiveCondition(), new Definitions\UrlContainsCondition(), new Definitions\QueryParameterCondition(), ); foreach ( $conditions as $condition ) { if ( ! $this->registry->has( $condition->id() ) ) { $this->registry->register( $condition ); } } } }