[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/ -> edit-form-blocks.php (source)

   1  <?php
   2  /**
   3   * The block editor page.
   4   *
   5   * @since 5.0.0
   6   *
   7   * @package WordPress
   8   * @subpackage Administration
   9   */
  10  
  11  // Don't load directly.
  12  if ( ! defined( 'ABSPATH' ) ) {
  13      exit;
  14  }
  15  
  16  /**
  17   * @global string       $post_type        Global post type.
  18   * @global WP_Post_Type $post_type_object Global post type object.
  19   * @global WP_Post      $post             Global post object.
  20   * @global string       $title            The title of the current screen.
  21   * @global array        $wp_meta_boxes    Global meta box state.
  22   */
  23  global $post_type, $post_type_object, $post, $title, $wp_meta_boxes;
  24  
  25  $block_editor_context = new WP_Block_Editor_Context( array( 'post' => $post ) );
  26  
  27  // Flag that we're loading the block editor.
  28  $current_screen = get_current_screen();
  29  $current_screen->is_block_editor( true );
  30  
  31  // Default to is-fullscreen-mode to avoid jumps in the UI.
  32  add_filter(
  33      'admin_body_class',
  34      static function ( $classes ) {
  35          return "$classes is-fullscreen-mode";
  36      }
  37  );
  38  
  39  /*
  40   * Emoji replacement is disabled for now, until it plays nicely with React.
  41   */
  42  remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
  43  
  44  /*
  45   * Block editor implements its own Options menu for toggling Document Panels.
  46   */
  47  add_filter( 'screen_options_show_screen', '__return_false' );
  48  
  49  wp_enqueue_script( 'heartbeat' );
  50  wp_enqueue_script( 'wp-edit-post' );
  51  
  52  $rest_path = rest_get_route_for_post( $post );
  53  
  54  $active_theme                   = get_stylesheet();
  55  $global_styles_endpoint_context = current_user_can( 'edit_theme_options' ) ? 'edit' : 'view';
  56  $template_lookup_slug           = 'page' === $post->post_type ? 'page' : 'single-' . $post->post_type;
  57  if ( ! empty( $post->post_name ) ) {
  58      $template_lookup_slug .= '-' . $post->post_name;
  59  }
  60  // Preload common data.
  61  $preload_paths = array(
  62      '/wp/v2/types?context=view',
  63      '/wp/v2/taxonomies?context=view',
  64      add_query_arg( 'context', 'edit', $rest_path ),
  65      sprintf( '/wp/v2/types/%s?context=edit', $post_type ),
  66      '/wp/v2/users/me',
  67      array( rest_get_route_for_post_type_items( 'attachment' ), 'OPTIONS' ),
  68      array( rest_get_route_for_post_type_items( 'page' ), 'OPTIONS' ),
  69      array( rest_get_route_for_post_type_items( 'wp_block' ), 'OPTIONS' ),
  70      array( rest_get_route_for_post_type_items( 'wp_template' ), 'OPTIONS' ),
  71      sprintf( '%s/autosaves?context=edit', $rest_path ),
  72      '/wp/v2/settings',
  73      array( '/wp/v2/settings', 'OPTIONS' ),
  74      '/wp/v2/global-styles/themes/' . $active_theme . '?context=view',
  75      '/wp/v2/global-styles/themes/' . $active_theme . '/variations?context=view',
  76      '/wp/v2/themes?context=edit&status=active',
  77      array( '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver::get_user_global_styles_post_id(), 'OPTIONS' ),
  78      /*
  79       * Preload the global styles path with the correct context based on user caps.
  80       * NOTE: There is an equivalent conditional check in the client-side code to fetch
  81       * the global styles entity using the appropriate context value.
  82       * See the call to `canUser()`, under `useGlobalStylesUserConfig()` in `packages/edit-site/src/components/use-global-styles-user-config/index.js`.
  83       * Please ensure that the equivalent check is kept in sync with this preload path.
  84       */
  85      '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver::get_user_global_styles_post_id() . '?context=' . $global_styles_endpoint_context,
  86      // Used by getBlockPatternCategories in useBlockEditorSettings.
  87      '/wp/v2/block-patterns/categories',
  88      /**
  89       * The preloaded URL must exactly match the request the client makes,
  90       * including the field order.
  91       * @link https://github.com/WordPress/gutenberg/blob/trunk/packages/core-data/src/entities.js
  92       */
  93      '/?_fields=' . implode(
  94          ',',
  95          array(
  96              'description',
  97              'generate_animated_image_subsizes',
  98              'gmt_offset',
  99              'home',
 100              'image_max_bit_depth',
 101              'image_sizes',
 102              'image_size_threshold',
 103              'image_strip_meta',
 104              'name',
 105              'site_icon',
 106              'site_icon_url',
 107              'site_logo',
 108              'timezone_string',
 109              'url',
 110              'page_for_posts',
 111              'page_on_front',
 112              'show_on_front',
 113          )
 114      ),
 115      add_query_arg(
 116          'slug',
 117          // @link https://github.com/WordPress/gutenberg/blob/e093fefd041eb6cc4a4e7f67b92ab54fd75c8858/packages/core-data/src/private-selectors.ts#L244-L254
 118          $template_lookup_slug,
 119          '/wp/v2/templates/lookup'
 120      ),
 121      '/wp/v2/templates/lookup?slug=front-page',
 122      '/wp/v2/taxonomies?context=edit',
 123      array( rest_get_route_for_post_type_items( $post_type ), 'OPTIONS' ),
 124  );
 125  
 126  if ( post_type_supports( $post_type, 'author' ) && $post->post_author > 0 ) {
 127      $preload_paths[] = sprintf(
 128          '/wp/v2/users/%d?context=view&_fields=id,name',
 129          (int) $post->post_author
 130      );
 131  }
 132  
 133  block_editor_rest_api_preload( $preload_paths, $block_editor_context );
 134  
 135  wp_add_inline_script(
 136      'wp-blocks',
 137      sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $post ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ),
 138      'after'
 139  );
 140  
 141  /*
 142   * Assign initial edits, if applicable. These are not initially assigned to the persisted post,
 143   * but should be included in its save payload.
 144   */
 145  $initial_edits = array();
 146  $is_new_post   = false;
 147  if ( 'auto-draft' === $post->post_status ) {
 148      $is_new_post = true;
 149      // Override "(Auto Draft)" new post default title with empty string, or filtered value.
 150      if ( post_type_supports( $post->post_type, 'title' ) ) {
 151          $initial_edits['title'] = $post->post_title;
 152      }
 153  
 154      if ( post_type_supports( $post->post_type, 'editor' ) ) {
 155          $initial_edits['content'] = $post->post_content;
 156      }
 157  
 158      if ( post_type_supports( $post->post_type, 'excerpt' ) ) {
 159          $initial_edits['excerpt'] = $post->post_excerpt;
 160      }
 161  }
 162  
 163  // Preload server-registered block schemas.
 164  wp_add_inline_script(
 165      'wp-blocks',
 166      'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings(), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ');'
 167  );
 168  
 169  // Preload server-registered block bindings sources.
 170  $registered_sources = get_all_registered_block_bindings_sources();
 171  if ( ! empty( $registered_sources ) ) {
 172      $filtered_sources = array();
 173      foreach ( $registered_sources as $source ) {
 174          $filtered_sources[] = array(
 175              'name'        => $source->name,
 176              'label'       => $source->label,
 177              'usesContext' => $source->uses_context,
 178          );
 179      }
 180      $script = sprintf( 'for ( const source of %s ) { wp.blocks.registerBlockBindingsSource( source ); }', wp_json_encode( $filtered_sources, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) );
 181      wp_add_inline_script(
 182          'wp-blocks',
 183          $script
 184      );
 185  }
 186  
 187  // Get admin url for handling meta boxes.
 188  $meta_box_url = admin_url( 'post.php' );
 189  $meta_box_url = add_query_arg(
 190      array(
 191          'post'                  => $post->ID,
 192          'action'                => 'edit',
 193          'meta-box-loader'       => true,
 194          'meta-box-loader-nonce' => wp_create_nonce( 'meta-box-loader' ),
 195      ),
 196      $meta_box_url
 197  );
 198  wp_add_inline_script(
 199      'wp-editor',
 200      sprintf( 'var _wpMetaBoxUrl = %s;', wp_json_encode( $meta_box_url, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ),
 201      'before'
 202  );
 203  
 204  // Set Heartbeat interval to 10 seconds, used to refresh post locks.
 205  wp_add_inline_script(
 206      'heartbeat',
 207      'jQuery( function() {
 208          wp.heartbeat.interval( 10 );
 209      } );',
 210      'after'
 211  );
 212  
 213  /*
 214   * Get all available templates for the post/page attributes meta-box.
 215   * The "Default template" array element should only be added if the array is
 216   * not empty so we do not trigger the template select element without any options
 217   * besides the default value.
 218   */
 219  $available_templates = wp_get_theme()->get_page_templates( get_post( $post->ID ) );
 220  $available_templates = ! empty( $available_templates ) ? array_replace(
 221      array(
 222          /** This filter is documented in wp-admin/includes/meta-boxes.php */
 223          '' => apply_filters( 'default_page_template_title', __( 'Default template' ), 'rest-api' ),
 224      ),
 225      $available_templates
 226  ) : $available_templates;
 227  
 228  // Lock settings.
 229  $user_id = wp_check_post_lock( $post->ID );
 230  if ( $user_id ) {
 231      $locked = false;
 232  
 233      /** This filter is documented in wp-admin/includes/post.php */
 234      if ( apply_filters( 'show_post_locked_dialog', true, $post, $user_id ) ) {
 235          $locked = true;
 236      }
 237  
 238      $user_details = null;
 239      if ( $locked ) {
 240          $user         = get_userdata( $user_id );
 241          $user_details = array(
 242              'name' => $user->display_name,
 243          );
 244  
 245          if ( get_option( 'show_avatars' ) ) {
 246              $user_details['avatar'] = get_avatar_url( $user_id, array( 'size' => 128 ) );
 247          }
 248      }
 249  
 250      $lock_details = array(
 251          'isLocked' => $locked,
 252          'user'     => $user_details,
 253      );
 254  } else {
 255      // Lock the post.
 256      $active_post_lock = wp_set_post_lock( $post->ID );
 257      if ( $active_post_lock ) {
 258          $active_post_lock = esc_attr( implode( ':', $active_post_lock ) );
 259      }
 260  
 261      $lock_details = array(
 262          'isLocked'       => false,
 263          'activePostLock' => $active_post_lock,
 264      );
 265  }
 266  
 267  /**
 268   * Filters the body placeholder text.
 269   *
 270   * @since 5.0.0
 271   * @since 5.8.0 Changed the default placeholder text.
 272   *
 273   * @param string  $text Placeholder text. Default 'Type / to choose a block'.
 274   * @param WP_Post $post Post object.
 275   */
 276  $body_placeholder = apply_filters( 'write_your_story', __( 'Type / to choose a block' ), $post );
 277  
 278  $editor_settings = array(
 279      'availableTemplates'   => $available_templates,
 280      'disablePostFormats'   => ! current_theme_supports( 'post-formats' ),
 281      /** This filter is documented in wp-admin/edit-form-advanced.php */
 282      'titlePlaceholder'     => apply_filters( 'enter_title_here', __( 'Add title' ), $post ),
 283      'bodyPlaceholder'      => $body_placeholder,
 284      'autosaveInterval'     => AUTOSAVE_INTERVAL,
 285      'richEditingEnabled'   => user_can_richedit(),
 286      'postLock'             => $lock_details,
 287      'postLockUtils'        => array(
 288          'nonce'       => wp_create_nonce( 'lock-post_' . $post->ID ),
 289          'unlockNonce' => wp_create_nonce( 'update-post_' . $post->ID ),
 290          'ajaxUrl'     => admin_url( 'admin-ajax.php' ),
 291      ),
 292      'supportsLayout'       => wp_theme_has_theme_json(),
 293      'supportsTemplateMode' => current_theme_supports( 'block-templates' ),
 294  
 295      // Whether or not to load the 'postcustom' meta box is stored as a user meta
 296      // field so that we're not always loading its assets.
 297      'enableCustomFields'   => (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true ),
 298  );
 299  
 300  // Add additional back-compat patterns registered by `current_screen` et al.
 301  $editor_settings['__experimentalAdditionalBlockPatterns']          = WP_Block_Patterns_Registry::get_instance()->get_all_registered( true );
 302  $editor_settings['__experimentalAdditionalBlockPatternCategories'] = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered( true );
 303  
 304  $autosave = wp_get_post_autosave( $post->ID );
 305  if ( $autosave ) {
 306      if ( mysql2date( 'U', $autosave->post_modified_gmt, false ) > mysql2date( 'U', $post->post_modified_gmt, false ) ) {
 307          $editor_settings['autosave'] = array(
 308              'editLink' => get_edit_post_link( $autosave->ID ),
 309          );
 310      } else {
 311          wp_delete_post_revision( $autosave->ID );
 312      }
 313  }
 314  
 315  if ( ! empty( $post_type_object->template ) ) {
 316      $editor_settings['template']     = $post_type_object->template;
 317      $editor_settings['templateLock'] = ! empty( $post_type_object->template_lock ) ? $post_type_object->template_lock : false;
 318  }
 319  
 320  // If there's no template set on a new post, use the post format, instead.
 321  if ( $is_new_post && ! isset( $editor_settings['template'] ) && 'post' === $post->post_type ) {
 322      $post_format = get_post_format( $post );
 323      if ( in_array( $post_format, array( 'audio', 'gallery', 'image', 'quote', 'video' ), true ) ) {
 324          $editor_settings['template'] = array( array( "core/$post_format" ) );
 325      }
 326  }
 327  
 328  if ( wp_is_block_theme() && $editor_settings['supportsTemplateMode'] ) {
 329      $editor_settings['defaultTemplatePartAreas'] = get_allowed_block_template_part_areas();
 330  }
 331  
 332  /**
 333   * Scripts
 334   */
 335  wp_enqueue_media(
 336      array(
 337          'post' => $post->ID,
 338      )
 339  );
 340  wp_tinymce_inline_scripts();
 341  wp_enqueue_editor();
 342  
 343  /**
 344   * Styles
 345   */
 346  // Prefetched for the block editor by wp_prefetch_admin_assets(), which needs updating if this changes.
 347  wp_enqueue_style( 'wp-edit-post' );
 348  
 349  /**
 350   * Fires after block assets have been enqueued for the editing interface.
 351   *
 352   * Call `add_action` on any hook before 'admin_enqueue_scripts'.
 353   *
 354   * In the function call you supply, simply use `wp_enqueue_script` and
 355   * `wp_enqueue_style` to add your functionality to the block editor.
 356   *
 357   * @since 5.0.0
 358   */
 359  do_action( 'enqueue_block_editor_assets' );
 360  
 361  // In order to duplicate classic meta box behavior, we need to run the classic meta box actions.
 362  require_once  ABSPATH . 'wp-admin/includes/meta-boxes.php';
 363  register_and_do_post_meta_boxes( $post );
 364  
 365  // Check if the Custom Fields meta box has been removed at some point.
 366  $core_meta_boxes = $wp_meta_boxes[ $current_screen->id ]['normal']['core'];
 367  if ( ! isset( $core_meta_boxes['postcustom'] ) || ! $core_meta_boxes['postcustom'] ) {
 368      unset( $editor_settings['enableCustomFields'] );
 369  }
 370  
 371  $editor_settings = get_block_editor_settings( $editor_settings, $block_editor_context );
 372  
 373  $init_script = <<<JS
 374  ( function() {
 375      window._wpLoadBlockEditor = new Promise( function( resolve ) {
 376          wp.domReady( function() {
 377              resolve( wp.editPost.initializeEditor( 'editor', "%s", %d, %s, %s ) );
 378          } );
 379      } );
 380  } )();
 381  JS;
 382  
 383  $script = sprintf(
 384      $init_script,
 385      $post->post_type,
 386      $post->ID,
 387      wp_json_encode( $editor_settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
 388      wp_json_encode( $initial_edits, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES )
 389  );
 390  wp_add_inline_script( 'wp-edit-post', $script );
 391  
 392  if ( (int) get_option( 'page_for_posts' ) === $post->ID ) {
 393      add_action( 'admin_enqueue_scripts', '_wp_block_editor_posts_page_notice' );
 394  }
 395  
 396  require_once  ABSPATH . 'wp-admin/admin-header.php';
 397  ?>
 398  
 399  <div class="block-editor">
 400      <h1 class="screen-reader-text hide-if-no-js"><?php echo esc_html( $title ); ?></h1>
 401      <div id="editor" class="block-editor__container hide-if-no-js"></div>
 402      <div id="metaboxes" class="hidden">
 403          <?php the_block_editor_meta_boxes(); ?>
 404      </div>
 405  
 406      <?php // JavaScript is disabled. ?>
 407      <div class="wrap hide-if-js block-editor-no-js">
 408          <h1 class="wp-heading-inline"><?php echo esc_html( $title ); ?></h1>
 409          <?php
 410          if ( file_exists( WP_PLUGIN_DIR . '/classic-editor/classic-editor.php' ) ) {
 411              // If Classic Editor is already installed, provide a link to activate the plugin.
 412              $installed           = true;
 413              $plugin_activate_url = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=classic-editor/classic-editor.php', 'activate-plugin_classic-editor/classic-editor.php' );
 414              $message             = sprintf(
 415                  /* translators: %s: Link to activate the Classic Editor plugin. */
 416                  __( 'The block editor requires JavaScript. Please enable JavaScript in your browser settings, or activate the <a href="%s">Classic Editor plugin</a>.' ),
 417                  esc_url( $plugin_activate_url )
 418              );
 419          } else {
 420              // If Classic Editor is not installed, provide a link to install it.
 421              $installed          = false;
 422              $plugin_install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=classic-editor' ), 'install-plugin_classic-editor' );
 423              $message            = sprintf(
 424                  /* translators: %s: Link to install the Classic Editor plugin. */
 425                  __( 'The block editor requires JavaScript. Please enable JavaScript in your browser settings, or install the <a href="%s">Classic Editor plugin</a>.' ),
 426                  esc_url( $plugin_install_url )
 427              );
 428          }
 429  
 430          /**
 431           * Filters the message displayed in the block editor interface when JavaScript is
 432           * not enabled in the browser.
 433           *
 434           * @since 5.0.3
 435           * @since 6.4.0 Added `$installed` parameter.
 436           *
 437           * @param string  $message   The message being displayed.
 438           * @param WP_Post $post      The post being edited.
 439           * @param bool    $installed Whether the classic editor is installed.
 440           */
 441          $message = apply_filters( 'block_editor_no_javascript_message', $message, $post, $installed );
 442          wp_admin_notice(
 443              $message,
 444              array(
 445                  'type' => 'error',
 446              )
 447          );
 448          ?>
 449      </div>
 450  </div>


Generated : Fri Oct 23 08:20:34 2026 Cross-referenced by PHPXref