[ 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              'gmt_offset',
  98              'home',
  99              'image_max_bit_depth',
 100              'image_sizes',
 101              'image_size_threshold',
 102              'image_strip_meta',
 103              'name',
 104              'site_icon',
 105              'site_icon_url',
 106              'site_logo',
 107              'timezone_string',
 108              'url',
 109              'page_for_posts',
 110              'page_on_front',
 111              'show_on_front',
 112          )
 113      ),
 114      add_query_arg(
 115          'slug',
 116          // @link https://github.com/WordPress/gutenberg/blob/e093fefd041eb6cc4a4e7f67b92ab54fd75c8858/packages/core-data/src/private-selectors.ts#L244-L254
 117          $template_lookup_slug,
 118          '/wp/v2/templates/lookup'
 119      ),
 120      '/wp/v2/templates/lookup?slug=front-page',
 121      '/wp/v2/taxonomies?context=edit',
 122      array( rest_get_route_for_post_type_items( $post_type ), 'OPTIONS' ),
 123  );
 124  
 125  if ( post_type_supports( $post_type, 'author' ) && $post->post_author > 0 ) {
 126      $preload_paths[] = sprintf(
 127          '/wp/v2/users/%d?context=view&_fields=id,name',
 128          (int) $post->post_author
 129      );
 130  }
 131  
 132  block_editor_rest_api_preload( $preload_paths, $block_editor_context );
 133  
 134  wp_add_inline_script(
 135      'wp-blocks',
 136      sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $post ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ),
 137      'after'
 138  );
 139  
 140  /*
 141   * Assign initial edits, if applicable. These are not initially assigned to the persisted post,
 142   * but should be included in its save payload.
 143   */
 144  $initial_edits = array();
 145  $is_new_post   = false;
 146  if ( 'auto-draft' === $post->post_status ) {
 147      $is_new_post = true;
 148      // Override "(Auto Draft)" new post default title with empty string, or filtered value.
 149      if ( post_type_supports( $post->post_type, 'title' ) ) {
 150          $initial_edits['title'] = $post->post_title;
 151      }
 152  
 153      if ( post_type_supports( $post->post_type, 'editor' ) ) {
 154          $initial_edits['content'] = $post->post_content;
 155      }
 156  
 157      if ( post_type_supports( $post->post_type, 'excerpt' ) ) {
 158          $initial_edits['excerpt'] = $post->post_excerpt;
 159      }
 160  }
 161  
 162  // Preload server-registered block schemas.
 163  wp_add_inline_script(
 164      'wp-blocks',
 165      'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings(), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ');'
 166  );
 167  
 168  // Preload server-registered block bindings sources.
 169  $registered_sources = get_all_registered_block_bindings_sources();
 170  if ( ! empty( $registered_sources ) ) {
 171      $filtered_sources = array();
 172      foreach ( $registered_sources as $source ) {
 173          $filtered_sources[] = array(
 174              'name'        => $source->name,
 175              'label'       => $source->label,
 176              'usesContext' => $source->uses_context,
 177          );
 178      }
 179      $script = sprintf( 'for ( const source of %s ) { wp.blocks.registerBlockBindingsSource( source ); }', wp_json_encode( $filtered_sources, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) );
 180      wp_add_inline_script(
 181          'wp-blocks',
 182          $script
 183      );
 184  }
 185  
 186  // Get admin url for handling meta boxes.
 187  $meta_box_url = admin_url( 'post.php' );
 188  $meta_box_url = add_query_arg(
 189      array(
 190          'post'                  => $post->ID,
 191          'action'                => 'edit',
 192          'meta-box-loader'       => true,
 193          'meta-box-loader-nonce' => wp_create_nonce( 'meta-box-loader' ),
 194      ),
 195      $meta_box_url
 196  );
 197  wp_add_inline_script(
 198      'wp-editor',
 199      sprintf( 'var _wpMetaBoxUrl = %s;', wp_json_encode( $meta_box_url, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ),
 200      'before'
 201  );
 202  
 203  // Set Heartbeat interval to 10 seconds, used to refresh post locks.
 204  wp_add_inline_script(
 205      'heartbeat',
 206      'jQuery( function() {
 207          wp.heartbeat.interval( 10 );
 208      } );',
 209      'after'
 210  );
 211  
 212  /*
 213   * Get all available templates for the post/page attributes meta-box.
 214   * The "Default template" array element should only be added if the array is
 215   * not empty so we do not trigger the template select element without any options
 216   * besides the default value.
 217   */
 218  $available_templates = wp_get_theme()->get_page_templates( get_post( $post->ID ) );
 219  $available_templates = ! empty( $available_templates ) ? array_replace(
 220      array(
 221          /** This filter is documented in wp-admin/includes/meta-boxes.php */
 222          '' => apply_filters( 'default_page_template_title', __( 'Default template' ), 'rest-api' ),
 223      ),
 224      $available_templates
 225  ) : $available_templates;
 226  
 227  // Lock settings.
 228  $user_id = wp_check_post_lock( $post->ID );
 229  if ( $user_id ) {
 230      $locked = false;
 231  
 232      /** This filter is documented in wp-admin/includes/post.php */
 233      if ( apply_filters( 'show_post_locked_dialog', true, $post, $user_id ) ) {
 234          $locked = true;
 235      }
 236  
 237      $user_details = null;
 238      if ( $locked ) {
 239          $user         = get_userdata( $user_id );
 240          $user_details = array(
 241              'name' => $user->display_name,
 242          );
 243  
 244          if ( get_option( 'show_avatars' ) ) {
 245              $user_details['avatar'] = get_avatar_url( $user_id, array( 'size' => 128 ) );
 246          }
 247      }
 248  
 249      $lock_details = array(
 250          'isLocked' => $locked,
 251          'user'     => $user_details,
 252      );
 253  } else {
 254      // Lock the post.
 255      $active_post_lock = wp_set_post_lock( $post->ID );
 256      if ( $active_post_lock ) {
 257          $active_post_lock = esc_attr( implode( ':', $active_post_lock ) );
 258      }
 259  
 260      $lock_details = array(
 261          'isLocked'       => false,
 262          'activePostLock' => $active_post_lock,
 263      );
 264  }
 265  
 266  /**
 267   * Filters the body placeholder text.
 268   *
 269   * @since 5.0.0
 270   * @since 5.8.0 Changed the default placeholder text.
 271   *
 272   * @param string  $text Placeholder text. Default 'Type / to choose a block'.
 273   * @param WP_Post $post Post object.
 274   */
 275  $body_placeholder = apply_filters( 'write_your_story', __( 'Type / to choose a block' ), $post );
 276  
 277  $editor_settings = array(
 278      'availableTemplates'   => $available_templates,
 279      'disablePostFormats'   => ! current_theme_supports( 'post-formats' ),
 280      /** This filter is documented in wp-admin/edit-form-advanced.php */
 281      'titlePlaceholder'     => apply_filters( 'enter_title_here', __( 'Add title' ), $post ),
 282      'bodyPlaceholder'      => $body_placeholder,
 283      'autosaveInterval'     => AUTOSAVE_INTERVAL,
 284      'richEditingEnabled'   => user_can_richedit(),
 285      'postLock'             => $lock_details,
 286      'postLockUtils'        => array(
 287          'nonce'       => wp_create_nonce( 'lock-post_' . $post->ID ),
 288          'unlockNonce' => wp_create_nonce( 'update-post_' . $post->ID ),
 289          'ajaxUrl'     => admin_url( 'admin-ajax.php' ),
 290      ),
 291      'supportsLayout'       => wp_theme_has_theme_json(),
 292      'supportsTemplateMode' => current_theme_supports( 'block-templates' ),
 293  
 294      // Whether or not to load the 'postcustom' meta box is stored as a user meta
 295      // field so that we're not always loading its assets.
 296      'enableCustomFields'   => (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true ),
 297  );
 298  
 299  // Add additional back-compat patterns registered by `current_screen` et al.
 300  $editor_settings['__experimentalAdditionalBlockPatterns']          = WP_Block_Patterns_Registry::get_instance()->get_all_registered( true );
 301  $editor_settings['__experimentalAdditionalBlockPatternCategories'] = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered( true );
 302  
 303  $autosave = wp_get_post_autosave( $post->ID );
 304  if ( $autosave ) {
 305      if ( mysql2date( 'U', $autosave->post_modified_gmt, false ) > mysql2date( 'U', $post->post_modified_gmt, false ) ) {
 306          $editor_settings['autosave'] = array(
 307              'editLink' => get_edit_post_link( $autosave->ID ),
 308          );
 309      } else {
 310          wp_delete_post_revision( $autosave->ID );
 311      }
 312  }
 313  
 314  if ( ! empty( $post_type_object->template ) ) {
 315      $editor_settings['template']     = $post_type_object->template;
 316      $editor_settings['templateLock'] = ! empty( $post_type_object->template_lock ) ? $post_type_object->template_lock : false;
 317  }
 318  
 319  // If there's no template set on a new post, use the post format, instead.
 320  if ( $is_new_post && ! isset( $editor_settings['template'] ) && 'post' === $post->post_type ) {
 321      $post_format = get_post_format( $post );
 322      if ( in_array( $post_format, array( 'audio', 'gallery', 'image', 'quote', 'video' ), true ) ) {
 323          $editor_settings['template'] = array( array( "core/$post_format" ) );
 324      }
 325  }
 326  
 327  if ( wp_is_block_theme() && $editor_settings['supportsTemplateMode'] ) {
 328      $editor_settings['defaultTemplatePartAreas'] = get_allowed_block_template_part_areas();
 329  }
 330  
 331  /**
 332   * Scripts
 333   */
 334  wp_enqueue_media(
 335      array(
 336          'post' => $post->ID,
 337      )
 338  );
 339  wp_tinymce_inline_scripts();
 340  wp_enqueue_editor();
 341  
 342  /**
 343   * Styles
 344   */
 345  wp_enqueue_style( 'wp-edit-post' );
 346  
 347  /**
 348   * Fires after block assets have been enqueued for the editing interface.
 349   *
 350   * Call `add_action` on any hook before 'admin_enqueue_scripts'.
 351   *
 352   * In the function call you supply, simply use `wp_enqueue_script` and
 353   * `wp_enqueue_style` to add your functionality to the block editor.
 354   *
 355   * @since 5.0.0
 356   */
 357  do_action( 'enqueue_block_editor_assets' );
 358  
 359  // In order to duplicate classic meta box behavior, we need to run the classic meta box actions.
 360  require_once  ABSPATH . 'wp-admin/includes/meta-boxes.php';
 361  register_and_do_post_meta_boxes( $post );
 362  
 363  // Check if the Custom Fields meta box has been removed at some point.
 364  $core_meta_boxes = $wp_meta_boxes[ $current_screen->id ]['normal']['core'];
 365  if ( ! isset( $core_meta_boxes['postcustom'] ) || ! $core_meta_boxes['postcustom'] ) {
 366      unset( $editor_settings['enableCustomFields'] );
 367  }
 368  
 369  $editor_settings = get_block_editor_settings( $editor_settings, $block_editor_context );
 370  
 371  $init_script = <<<JS
 372  ( function() {
 373      window._wpLoadBlockEditor = new Promise( function( resolve ) {
 374          wp.domReady( function() {
 375              resolve( wp.editPost.initializeEditor( 'editor', "%s", %d, %s, %s ) );
 376          } );
 377      } );
 378  } )();
 379  JS;
 380  
 381  $script = sprintf(
 382      $init_script,
 383      $post->post_type,
 384      $post->ID,
 385      wp_json_encode( $editor_settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
 386      wp_json_encode( $initial_edits, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES )
 387  );
 388  wp_add_inline_script( 'wp-edit-post', $script );
 389  
 390  if ( (int) get_option( 'page_for_posts' ) === $post->ID ) {
 391      add_action( 'admin_enqueue_scripts', '_wp_block_editor_posts_page_notice' );
 392  }
 393  
 394  require_once  ABSPATH . 'wp-admin/admin-header.php';
 395  ?>
 396  
 397  <div class="block-editor">
 398      <h1 class="screen-reader-text hide-if-no-js"><?php echo esc_html( $title ); ?></h1>
 399      <div id="editor" class="block-editor__container hide-if-no-js"></div>
 400      <div id="metaboxes" class="hidden">
 401          <?php the_block_editor_meta_boxes(); ?>
 402      </div>
 403  
 404      <?php // JavaScript is disabled. ?>
 405      <div class="wrap hide-if-js block-editor-no-js">
 406          <h1 class="wp-heading-inline"><?php echo esc_html( $title ); ?></h1>
 407          <?php
 408          if ( file_exists( WP_PLUGIN_DIR . '/classic-editor/classic-editor.php' ) ) {
 409              // If Classic Editor is already installed, provide a link to activate the plugin.
 410              $installed           = true;
 411              $plugin_activate_url = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=classic-editor/classic-editor.php', 'activate-plugin_classic-editor/classic-editor.php' );
 412              $message             = sprintf(
 413                  /* translators: %s: Link to activate the Classic Editor plugin. */
 414                  __( 'The block editor requires JavaScript. Please enable JavaScript in your browser settings, or activate the <a href="%s">Classic Editor plugin</a>.' ),
 415                  esc_url( $plugin_activate_url )
 416              );
 417          } else {
 418              // If Classic Editor is not installed, provide a link to install it.
 419              $installed          = false;
 420              $plugin_install_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=classic-editor' ), 'install-plugin_classic-editor' );
 421              $message            = sprintf(
 422                  /* translators: %s: Link to install the Classic Editor plugin. */
 423                  __( 'The block editor requires JavaScript. Please enable JavaScript in your browser settings, or install the <a href="%s">Classic Editor plugin</a>.' ),
 424                  esc_url( $plugin_install_url )
 425              );
 426          }
 427  
 428          /**
 429           * Filters the message displayed in the block editor interface when JavaScript is
 430           * not enabled in the browser.
 431           *
 432           * @since 5.0.3
 433           * @since 6.4.0 Added `$installed` parameter.
 434           *
 435           * @param string  $message   The message being displayed.
 436           * @param WP_Post $post      The post being edited.
 437           * @param bool    $installed Whether the classic editor is installed.
 438           */
 439          $message = apply_filters( 'block_editor_no_javascript_message', $message, $post, $installed );
 440          wp_admin_notice(
 441              $message,
 442              array(
 443                  'type' => 'error',
 444              )
 445          );
 446          ?>
 447      </div>
 448  </div>


Generated : Tue Aug 4 08:20:20 2026 Cross-referenced by PHPXref