<?php
/**
 * WordPress 7.0 compatibility functions for the Gutenberg
 * editor plugin changes related to REST API.
 *
 * @package gutenberg
 */

/**
 * Registers the Block Patterns REST API routes.
 */
function gutenberg_register_block_patterns_controller_endpoints() {
	$block_patterns_controller = new Gutenberg_REST_Block_Patterns_Controller_7_0();
	$block_patterns_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_block_patterns_controller_endpoints' );

/**
 * Registers the Registered Templates REST API routes.
 * The template activation experiment registers its own routes, so we only register the registered templates controller if the experiment is not enabled.
 * See: lib/compat/wordpress-7.0/template-activate.php
 *
 * @see Gutenberg_REST_Registered_Templates_Controller
 * @see Gutenberg_REST_Templates_Controller_7_0
 */
if ( ! gutenberg_is_experiment_enabled( 'active_templates' ) ) {
	function gutenberg_modify_wp_template_post_type_args_7_0( $args ) {
		$args['rest_controller_class']   = 'Gutenberg_REST_Templates_Controller_7_0';
		$args['late_route_registration'] = true;
		return $args;
	}
	add_filter( 'register_wp_template_post_type_args', 'gutenberg_modify_wp_template_post_type_args_7_0' );
}

/**
 * Registers the Registered Templates Parts REST API routes.
 * The template activation experiment does not, however, register the routes for the wp_template_part post type,
 * so we need to register the routes for that post type here.
 * See: lib/compat/wordpress-7.0/template-activate.php
 *
 * @see Gutenberg_REST_Registered_Templates_Controller
 * @see Gutenberg_REST_Templates_Controller_7_0
 */
function gutenberg_modify_wp_template_part_post_type_args_7_0( $args ) {
	$args['rest_controller_class']   = 'Gutenberg_REST_Templates_Controller_7_0';
	$args['late_route_registration'] = true;
	return $args;
}
add_filter( 'register_wp_template_part_post_type_args', 'gutenberg_modify_wp_template_part_post_type_args_7_0' );

/**
 * Registers the 'navigation-overlay' template part area.
 *
 * @param array $areas Array of template part area definitions.
 * @return array Modified array of template part area definitions.
 */
function gutenberg_register_overlay_template_part_area( $areas ) {
	foreach ( $areas as $area ) {
		if ( isset( $area['area'] ) && 'navigation-overlay' === $area['area'] ) {
			return $areas;
		}
	}

	$areas[] = array(
		'area'        => 'navigation-overlay',
		'label'       => __( 'Navigation Overlay', 'gutenberg' ),
		'description' => __(
			'The Navigation Overlay template defines an overlay area that typically contains navigation links and can be toggled open and closed.'
		),
		'icon'        => 'navigation-overlay',
		'area_tag'    => 'div',
	);

	return $areas;
}
add_filter( 'default_wp_template_part_areas', 'gutenberg_register_overlay_template_part_area' );

/**
 * Adds user global styles link relation to all theme responses.
 *
 * This ensures that all themes (including classic themes) have access to the
 * wp:user-global-styles link, which is required for the font library to function.
 *
 * WordPress core only adds this link for block themes with theme.json support.
 * This filter extends that functionality to all themes.
 *
 * @param WP_REST_Response $response The response object.
 * @param WP_Theme         $theme    Theme object used to create response.
 * @return WP_REST_Response Modified response object.
 */
function gutenberg_rest_theme_global_styles_link_rel_7_0( $response, $theme ) {
	// Only add the link for the active theme to match WordPress core behavior.
	if ( $theme->get_stylesheet() !== get_stylesheet() ) {
		return $response;
	}

	// Check if the link already exists (WordPress core adds it for block themes).
	$all_links = $response->get_links();
	if ( isset( $all_links['https://api.w.org/user-global-styles'] ) ) {
		return $response;
	}

	// Get or create the global styles post ID for this theme.
	// Now that we've removed the theme.json check, this works for all themes.
	$global_styles_id = WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id();
	if ( ! $global_styles_id ) {
		return $response;
	}

	// Add the wp:user-global-styles link.
	$response->add_link(
		'https://api.w.org/user-global-styles',
		rest_url( 'wp/v2/global-styles/' . $global_styles_id )
	);

	return $response;
}
add_filter( 'rest_prepare_theme', 'gutenberg_rest_theme_global_styles_link_rel_7_0', 10, 2 );

/**
 * Overrides the default REST controller for autosaves to fix real-time
 * collaboration on draft posts.
 *
 * When RTC is enabled, draft autosaves from all users update the post directly
 * instead of creating per-user autosave revisions depending on post lock and
 * assigned author.
 *
 * Only overrides when autosave_rest_controller_class is not explicitly set,
 * i.e. when WP_REST_Autosaves_Controller would be used by default. Post types
 * with their own specialized autosave controller (e.g. templates) are left alone.
 */
function gutenberg_override_autosaves_rest_controller( $args ) {
	if ( empty( $args['autosave_rest_controller_class'] ) ) {
		$args['autosave_rest_controller_class'] = 'Gutenberg_REST_Autosaves_Controller';
	}
	return $args;
}

add_filter( 'register_post_type_args', 'gutenberg_override_autosaves_rest_controller', 10, 1 );

/**
 * Overrides the default REST controller for revisions to support nested
 * _fields parameters (e.g. content.raw without content.rendered).
 *
 * The core WP_REST_Revisions_Controller uses in_array() checks for content,
 * title, excerpt, and guid fields, which prevents sub-field filtering via
 * the _fields parameter. The Gutenberg override uses rest_is_field_included()
 * so that clients can avoid expensive server-side rendering when only raw
 * data is needed.
 *
 * Only overrides when revisions_rest_controller_class is not explicitly set.
 */
function gutenberg_override_revisions_rest_controller( $args ) {
	if ( empty( $args['revisions_rest_controller_class'] ) ) {
		$args['revisions_rest_controller_class'] = 'Gutenberg_REST_Revisions_Controller';
	}
	return $args;
}

add_filter( 'register_post_type_args', 'gutenberg_override_revisions_rest_controller', 10, 1 );
