( new Rest\Contract_Controller() )->register_routes() ); add_action( 'init', array( Lab\Pattern_Meta::class, 'register' ) ); add_filter( 'rest_pre_insert_wp_block', array( Lab\Pattern_Meta::class, 'validate_rest' ), 10, 2 ); add_filter( 'rest_wp_block_query', array( Lab\Pattern_Meta::class, 'hide_variants_in_rest' ) ); add_action( 'pre_get_posts', array( Lab\Pattern_Meta::class, 'hide_variants_in_admin' ) ); add_action( 'leitvia_studio_init', array( Lab\Token_Lint::class, 'register_check' ) ); add_action( 'save_post_wp_block', array( Lab\Token_Lint::class, 'store' ), 10, 2 ); add_action( 'save_post_wp_block', array( Lab\Status::class, 'flush' ) ); foreach ( array( 'added_post_meta', 'updated_post_meta', 'deleted_post_meta' ) as $hook ) { add_action( $hook, array( Lab\Status::class, 'flush_on_meta' ), 10, 3 ); } add_action( 'switch_blog', array( Lab\Status::class, 'flush' ) ); add_action( 'rest_api_init', static fn() => ( new Rest\Lab_Controller() )->register_routes() ); add_action( 'init', array( Tokens\Token_Sets::class, 'register' ) ); add_filter( 'map_meta_cap', array( Tokens\Token_Sets::class, 'map_meta_cap' ) ); add_filter( 'wp_insert_post_data', array( Tokens\Token_Sets::class, 'force_private' ) ); add_filter( 'rest_leitvia_tokens_collection_params', array( Tokens\Token_Sets::class, 'collection_params' ) ); add_action( 'deleted_post', array( Tokens\Compiler::class, 'forget' ) ); add_filter( 'get_edit_post_link', array( Tokens\Token_Sets::class, 'edit_link' ), 10, 3 ); add_action( 'rest_api_init', static fn() => ( new Rest\Tokens_Controller() )->register_routes() ); foreach ( array( 'before_delete_post', 'wp_trash_post', 'untrashed_post' ) as $hook ) { add_action( $hook, array( Lab\Pattern_Meta::class, 'follow_original' ) ); } foreach ( array( 'trashed_post', 'untrashed_post', 'deleted_post' ) as $hook ) { add_action( $hook, array( Lab\Status::class, 'flush' ) ); } add_filter( 'wp_count_posts', array( Lab\Pattern_Meta::class, 'count_originals' ), 10, 2 ); add_action( 'leitvia_studio_init', array( Tokens\Contrast::class, 'register_check' ) ); add_action( 'leitvia_studio_init', array( Tokens\Sources::class, 'register' ) ); add_filter( 'rest_pre_insert_leitvia_tokens', array( Tokens\Token_Sets::class, 'validate_rest' ), 10, 2 ); // Token set preview on any front-end address, see Tokens\Set_Preview. Tokens\Set_Preview::boot(); add_filter( 'wp_theme_json_data_user', array( Tokens\Overlays::class, 'apply' ), 20 ); add_filter( 'rest_pre_insert_leitvia_tokens', array( Tokens\Overlays::class, 'validate_rest' ), 10, 2 ); add_filter( 'wp_headers', array( Tokens\Overlays::class, 'headers' ) ); add_action( 'parse_request', array( Tokens\Overlays::class, 'refresh' ), PHP_INT_MAX ); foreach ( array( 'added_post_meta', 'updated_post_meta', 'deleted_post_meta' ) as $hook ) { add_action( $hook, array( Tokens\Overlays::class, 'forget_on_meta' ), 10, 3 ); } add_action( 'transition_post_status', array( Tokens\Overlays::class, 'forget' ), 10, 3 ); add_action( 'deleted_post', array( Tokens\Overlays::class, 'forget' ), 10, 2 ); add_filter( 'rest_request_before_callbacks', array( Tokens\Site_Editor_Guard::class, 'validate_rest' ), 10, 3 ); add_action( 'template_redirect', array( Lab\Preview::class, 'maybe_render' ), 0 ); add_action( 'leitvia_studio_init', array( Admin\Admin::class, 'register_panels' ) ); add_action( 'admin_menu', array( Admin\Admin::class, 'register_menu' ) ); add_action( 'admin_enqueue_scripts', array( Admin\Admin::class, 'enqueue' ), 20 ); add_action( 'init', array( Admin\Settings::class, 'register' ) ); // Core adds the admin hooks of the emoji loader after init, so admin_init removes those. add_action( 'init', array( Admin\Settings::class, 'remove_emoji_loader' ) ); add_action( 'admin_init', array( Admin\Settings::class, 'remove_emoji_loader' ) ); add_action( 'rest_api_init', array( Admin\Admin::class, 'register_routes' ) ); add_action( 'leitvia_studio_screen_notes', array( Admin\Admin::class, 'pro_note' ) ); Avatars\Avatars::boot(); add_action( 'init', array( Model\Registrar::class, 'register' ), 9 ); add_action( 'init', array( Model\Registrar::class, 'maybe_flush' ), 999 ); add_filter( 'wp_insert_post_data', array( Model\Registrar::class, 'force_inherit' ) ); add_action( 'enqueue_block_editor_assets', array( Model\Registrar::class, 'enqueue_editor' ) ); add_filter( 'render_block_context', array( Model\Registrar::class, 'query_namespace' ), 10, 3 ); add_filter( 'query_loop_block_query_vars', array( Model\Registrar::class, 'listed_query_vars' ), 9, 2 ); add_filter( 'rest_prepare_post_type', array( Model\Registrar::class, 'listed_in_editor' ), 10, 3 ); add_filter( 'query_loop_block_query_vars', array( Model\Registrar::class, 'children_query_vars' ), 10, 2 ); add_action( 'init', array( Model\Entry_View::class, 'register' ), 20 ); add_filter( 'query_loop_block_query_vars', array( Model\Entry_View::class, 'query_vars' ), 10, 2 ); add_filter( 'render_block_core/query', array( Model\Entry_View::class, 'hide_empty_more' ), 10, 2 ); add_filter( 'block_core_breadcrumbs_items', array( Model\Entry_View::class, 'breadcrumbs' ) ); add_filter( 'render_block_core/group', array( Model\Entry_View::class, 'facts' ), 10, 2 ); add_filter( 'render_block_core/group', array( Model\Entry_View::class, 'hide_empty_author' ), 10, 2 ); add_action( 'transition_post_status', array( Model\Registrar::class, 'follow_entry' ), 10, 3 ); add_action( 'before_delete_post', array( Model\Registrar::class, 'trash_children' ), 10, 2 ); add_filter( 'map_meta_cap', array( Model\Registrar::class, 'map_row_caps' ), 10, 4 ); add_action( 'switch_blog', array( Model\Model::class, 'forget' ) ); add_action( 'rest_api_init', static fn() => ( new Rest\Model_Controller() )->register_routes() ); add_action( 'rest_api_init', static fn() => ( new Rest\Recipes_Controller() )->register_routes() ); add_action( 'rest_api_init', static fn() => ( new Rest\Building_Blocks_Controller() )->register_routes() ); add_filter( 'render_block', array( Model\Building_Block_Views::class, 'hide_unmet' ), 10, 2 ); add_action( 'manage_posts_extra_tablenav', array( Model\Building_Block_Views::class, 'list_notice' ) ); add_action( 'admin_post_' . Model\Building_Block_Views::PAGE_ACTION, array( Model\Building_Block_Views::class, 'new_page' ) ); add_filter( 'rest_request_before_callbacks', array( Model\Building_Block_Views::class, 'pattern_request' ), 10, 3 ); add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_model_editor' ), 21 ); add_action( 'init', array( Model\Bindings::class, 'register' ) ); Model\Author_Name::boot(); add_filter( 'render_block_core/list', array( Model\Bindings::class, 'list_items' ), 10, 3 ); add_filter( 'get_block_type_uses_context', array( Model\Bindings::class, 'list_context' ), 10, 2 ); add_filter( 'block_bindings_source_value', array( Model\Bindings::class, 'core_post_meta' ), 10, 5 ); add_action( 'save_post', array( Lab\Usage_Index::class, 'index' ), 10, 2 ); add_action( 'init', array( Admin\Admin::class, 'register_status_column' ), 20 ); add_action( 'after_setup_theme', array( News\Image_Sizes::class, 'register' ) ); add_action( 'wp_head', array( News\Schema::class, 'print' ) ); add_action( 'wp_head', array( News\Head::class, 'print' ), 5 ); add_filter( 'pre_get_document_title', array( News\Head::class, 'title' ) ); add_filter( 'wp_robots', array( News\Head::class, 'robots' ) ); add_action( 'wp_head', array( Blocks\Schema_Nodes::class, 'print' ) ); add_action( 'wp_head', array( self::class, 'defer_modules' ), 1 ); add_filter( 'leitvia_editorial_url', static fn( $url ): string => '' !== (string) $url ? (string) $url : News\Schema::editorial_url() ); add_action( 'init', array( News\Sitemap::class, 'register' ) ); add_filter( 'query_vars', array( News\Sitemap::class, 'query_vars' ) ); // Before redirect_canonical, which could add a trailing slash to the address. add_action( 'template_redirect', array( News\Sitemap::class, 'maybe_render' ), 1 ); add_filter( 'robots_txt', array( News\Sitemap::class, 'robots' ), 20 ); add_action( 'transition_post_status', array( News\Sitemap::class, 'forget' ), 10, 3 ); add_action( 'leitvia_studio_init', array( Blocks\Blocks::class, 'register' ) ); add_filter( 'block_categories_all', array( Blocks\Blocks::class, 'category' ) ); add_filter( 'render_block_core/tabs', array( Blocks\Tabs::class, 'render_tabs' ) ); add_filter( 'render_block_core/tab-panel', array( Blocks\Tabs::class, 'render_panel' ), 10, 2 ); add_filter( 'render_block', array( Blocks\Blocks::class, 'highlight_style' ) ); add_action( 'enqueue_block_assets', array( Blocks\Blocks::class, 'editor_highlight_style' ) ); add_filter( 'register_block_type_args', array( Blocks\Animation::class, 'block_args' ), 10, 2 ); add_filter( 'render_block', array( Blocks\Animation::class, 'render' ), 10, 2 ); add_filter( 'render_block', array( Tokens\Compiler::class, 'ink_links' ), 10, 2 ); add_filter( 'body_class', array( Blocks\Animation::class, 'body_class' ) ); add_filter( 'render_block_data', array( Blocks\Marquee::class, 'state' ) ); add_filter( 'wp_kses_allowed_html', array( Blocks\Blocks::class, 'allow_inputs' ), 10, 2 ); add_filter( 'render_block_leitvia/pricing', array( Blocks\Blocks::class, 'unique_pricing_group' ) ); add_filter( 'render_block_leitvia/spotlight', array( Blocks\Blocks::class, 'spotlight_group' ) ); add_filter( 'render_block_leitvia/faq', array( Blocks\Faq::class, 'render' ), 10, 2 ); add_filter( 'leitvia_studio_schema_nodes', array( Blocks\Faq::class, 'merge' ) ); add_filter( 'render_block_core/image', array( Blocks\Blocks::class, 'pattern_image_size' ) ); add_filter( 'render_block_leitvia/announcement-bar', array( Blocks\Announcement_Bar::class, 'render' ) ); add_filter( 'register_block_type_args', array( Blocks\Product_Compare::class, 'block_args' ), 10, 2 ); add_action( 'init', array( Blocks\Blocks::class, 'patterns' ) ); add_action( 'init', array( Consent\Consent::class, 'register_module' ) ); add_filter( 'render_block_core/embed', array( Consent\Consent::class, 'filter_embed' ), 10, 2 ); add_filter( 'render_block_core/html', array( Consent\Consent::class, 'filter_iframes' ) ); add_filter( 'the_content', array( Consent\Consent::class, 'filter_iframes' ), 12 ); add_filter( 'render_block_leitvia/consent-settings', array( Consent\Consent::class, 'filter_settings_block' ) ); add_filter( 'wp_script_attributes', array( Consent\Scripts::class, 'script_attributes' ) ); add_filter( 'wp_inline_script_attributes', array( Consent\Scripts::class, 'inline_attributes' ), 10, 2 ); add_filter( 'script_loader_tag', array( Consent\Scripts::class, 'loader_tag' ), 999, 3 ); add_action( 'wp_enqueue_scripts', array( Consent\Scripts::class, 'enqueue' ) ); add_filter( 'wp_resource_hints', array( Consent\Scripts::class, 'resource_hints' ), 999 ); add_filter( 'wp_preload_resources', array( Consent\Scripts::class, 'resource_hints' ), 999 ); add_filter( 'render_block_data', array( Blocks\Table_Of_Contents::class, 'enter_content' ) ); add_filter( 'render_block_core/post-content', array( Blocks\Table_Of_Contents::class, 'leave_content' ) ); add_filter( 'render_block_core/heading', array( Blocks\Table_Of_Contents::class, 'add_id' ), 10, 2 ); add_action( 'init', array( Blocks\Code_Copy::class, 'register_module' ) ); add_filter( 'render_block_core/code', array( Blocks\Code_Copy::class, 'render' ), 10, 2 ); add_filter( 'render_block_core/group', array( Blocks\Blocks::class, 'list_group' ), 10, 2 ); add_action( 'init', array( Blocks\Lightbox_Focus::class, 'register_module' ) ); add_filter( 'render_block_core/image', array( Blocks\Lightbox_Focus::class, 'render' ), 20 ); add_action( 'init', array( Blocks\Sticky_Header::class, 'register_module' ) ); add_filter( 'render_block_core/group', array( Blocks\Sticky_Header::class, 'render' ), 10, 2 ); add_filter( 'default_wp_template_part_areas', array( Blocks\Mega_Menu::class, 'areas' ) ); add_filter( 'register_block_type_args', array( Blocks\Mega_Menu::class, 'block_args' ), 10, 2 ); add_filter( 'register_block_type_args', array( Blocks\Blocks::class, 'render_callbacks' ), 10, 2 ); add_action( 'enqueue_block_editor_assets', array( Blocks\Icon::class, 'editor_data' ) ); add_action( 'switch_blog', array( Blocks\Icon::class, 'flush' ) ); add_filter( 'render_block_core/navigation', array( Blocks\Mega_Menu::class, 'collapsible_overlay' ), 10, 2 ); add_filter( 'query_loop_block_query_vars', array( Blocks\Query_Filter::class, 'query_vars' ), 10, 2 ); add_filter( 'leitvia_studio_consent_services', array( Blocks\Map::class, 'service' ) ); add_filter( 'render_block_leitvia/map', array( Blocks\Map::class, 'render' ), 10, 2 ); add_filter( 'render_block_leitvia/wizard', array( Blocks\Wizard::class, 'render' ) ); add_filter( 'render_block_leitvia/form-errors', array( Blocks\Form_Errors::class, 'render' ) ); add_action( 'init', array( Easy_Language\Easy_Language::class, 'register' ) ); add_filter( 'render_block_leitvia/a11y-bar', array( Easy_Language\Easy_Language::class, 'render_bar' ) ); Gateway\Gateway::boot(); } /** * Moves the script modules of Leitvia behind everything the first paint needs, as core does for interactive blocks: * low priority, at the end of the body. Block modules are queued by now, a block theme renders before wp_head. */ public static function defer_modules(): void { $modules = wp_script_modules(); foreach ( $modules->get_queue() as $id ) { if ( str_contains( $id, 'leitvia' ) ) { $modules->set_fetchpriority( $id, 'low' ); $modules->set_in_footer( $id, true ); } } } /** * Loads the CodeMirror JSON editor of core on the Model screen; window.leitviaStudioCodeEditor holds its settings, * false when the user turned syntax highlighting off. */ public static function enqueue_model_editor(): void { if ( 'leitvia-studio-model' === Admin\Admin::current_screen() ) { $settings = wp_enqueue_code_editor( array( 'type' => 'application/json' ) ); wp_add_inline_script( 'leitvia-studio-admin', 'window.leitviaStudioCodeEditor = ' . wp_json_encode( $settings ) . ';', 'before' ); } } /** * Contract of the active theme. */ public static function contract(): Contract\Contract { self::$contract ??= Contract\Contract::for_active_theme(); return self::$contract; } /** * Drops the cached contract after a theme or site switch. */ public static function forget_contract(): void { self::$contract = null; } /** * The Extension API instance. */ public static function studio(): Extension\Studio { self::$studio ??= new Extension\Studio(); return self::$studio; } /** * Registers the leitvia-studio-api script (window.leitviaStudio). Studio screens enqueue it or depend on it. */ public static function register_api_script(): void { $asset_file = dirname( LEITVIA_STUDIO_FILE ) . '/build/api.asset.php'; if ( ! is_readable( $asset_file ) ) { return; } $asset = require $asset_file; wp_register_script( 'leitvia-studio-api', plugin_dir_url( LEITVIA_STUDIO_FILE ) . 'build/api.js', $asset['dependencies'], $asset['version'], true ); } }