1<?php
2/**
3 * Server-side rendering of the `core/legacy-widget` block.
4 *
5 * @package WordPress
6 */
7
8/**
9 * Renders the 'core/legacy-widget' block.
10 *
11 * @since 5.8.0
12 *
13 * @global WP_Widget_Factory $wp_widget_factory.
14 *
15 * @param array $attributes The block attributes.
16 *
17 * @return string Rendered block.
18 */
19function render_block_core_legacy_widget( $attributes ) {
20 global $wp_widget_factory;
21
22 if ( isset( $attributes['id'] ) ) {
23 $sidebar_id = wp_find_widgets_sidebar( $attributes['id'] );
24 return wp_render_widget( $attributes['id'], $sidebar_id );
25 }
26
27 if ( ! isset( $attributes['idBase'] ) ) {
28 return '';
29 }
30
31 $id_base = $attributes['idBase'];
32 $widget_key = $wp_widget_factory->get_widget_key( $id_base );
33 $widget_object = $wp_widget_factory->get_widget_object( $id_base );
34
35 if ( ! $widget_key || ! $widget_object ) {
36 return '';
37 }
38
39 if ( isset( $attributes['instance']['encoded'], $attributes['instance']['hash'] ) ) {
40 $serialized_instance = base64_decode( $attributes['instance']['encoded'] );
41 if ( ! hash_equals( wp_hash( $serialized_instance ), (string) $attributes['instance']['hash'] ) ) {
42 return '';
43 }
44 $instance = unserialize( $serialized_instance );
45 } else {
46 $instance = array();
47 }
48
49 $args = array(
50 'widget_id' => $widget_object->id,
51 'widget_name' => $widget_object->name,
52 );
53
54 ob_start();
55 the_widget( $widget_key, $instance, $args );
56 return ob_get_clean();
57}
58
59/**
60 * Registers the 'core/legacy-widget' block.
61 *
62 * @since 5.8.0
63 */
64function register_block_core_legacy_widget() {
65 register_block_type_from_metadata(
66 __DIR__ . '/legacy-widget',
67 array(
68 'render_callback' => 'render_block_core_legacy_widget',
69 )
70 );
71}
72
73add_action( 'init', 'register_block_core_legacy_widget' );
74
75/**
76 * Intercepts any request with legacy-widget-preview in the query param and, if
77 * set, renders a page containing a preview of the requested Legacy Widget
78 * block.
79 *
80 * @since 5.8.0
81 */
82function handle_legacy_widget_preview_iframe() {
83 if ( empty( $_GET['legacy-widget-preview'] ) ) {
84 return;
85 }
86
87 if ( ! current_user_can( 'edit_theme_options' ) ) {
88 return;
89 }
90
91 define( 'IFRAME_REQUEST', true );
92
93 ?>
94 <!doctype html>
95 <html <?php language_attributes(); ?>>
96 <head>
97 <meta charset="<?php bloginfo( 'charset' ); ?>" />
98 <meta name="viewport" content="width=device-width, initial-scale=1" />
99 <link rel="profile" href="https://gmpg.org/xfn/11" />
100 <?php wp_head(); ?>
101 <style>
102 /* Reset theme styles */
103 html, body, #page, #content {
104 padding: 0 !important;
105 margin: 0 !important;
106 }
107
108 /* Hide root level text nodes */
109 body {
110 font-size: 0 !important;
111 }
112
113 /* Hide non-widget elements */
114 body *:not(#page):not(#content):not(.widget):not(.widget *) {
115 display: none !important;
116 font-size: 0 !important;
117 height: 0 !important;
118 left: -9999px !important;
119 max-height: 0 !important;
120 max-width: 0 !important;
121 opacity: 0 !important;
122 pointer-events: none !important;
123 position: absolute !important;
124 top: -9999px !important;
125 transform: translate(-9999px, -9999px) !important;
126 visibility: hidden !important;
127 z-index: -999 !important;
128 }
129
130 /* Restore widget font-size */
131 .widget {
132 font-size: var(--global--font-size-base);
133 }
134 </style>
135 </head>
136 <body <?php body_class(); ?>>
137 <div id="page" class="site">
138 <div id="content" class="site-content">
139 <?php
140 $registry = WP_Block_Type_Registry::get_instance();
141 $block = $registry->get_registered( 'core/legacy-widget' );
142 echo $block->render( $_GET['legacy-widget-preview'] );
143 ?>
144 </div><!-- #content -->
145 </div><!-- #page -->
146 <?php wp_footer(); ?>
147 </body>
148 </html>
149 <?php
150
151 exit;
152}
153
154// Use admin_init instead of init to ensure get_current_screen function is already available.
155// This isn't strictly required, but enables better compatibility with existing plugins.
156// See: https://github.com/WordPress/gutenberg/issues/32624.
157add_action( 'admin_init', 'handle_legacy_widget_preview_iframe', 20 );
158