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


Generated : Wed Jul 15 08:20:16 2026 Cross-referenced by PHPXref