[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/block-supports/ -> position.php (source)

   1  <?php
   2  /**
   3   * Position block support flag.
   4   *
   5   * @package WordPress
   6   * @since 6.2.0
   7   */
   8  
   9  /**
  10   * Registers the style block attribute for block types that support it.
  11   *
  12   * @since 6.2.0
  13   * @access private
  14   *
  15   * @param WP_Block_Type $block_type Block Type.
  16   */
  17  function wp_register_position_support( $block_type ) {
  18      $has_position_support = block_has_support( $block_type, 'position', false );
  19  
  20      // Set up attributes and styles within that if needed.
  21      if ( ! $block_type->attributes ) {
  22          $block_type->attributes = array();
  23      }
  24  
  25      if ( $has_position_support && ! array_key_exists( 'style', $block_type->attributes ) ) {
  26          $block_type->attributes['style'] = array(
  27              'type' => 'object',
  28          );
  29      }
  30  }
  31  
  32  /**
  33   * Returns the CSS rules for a position style configuration.
  34   *
  35   * @since 7.2.0
  36   *
  37   * @param string $selector               CSS selector to scope the rules to.
  38   * @param mixed  $position               Position style configuration.
  39   * @param array  $allowed_position_types Position types the theme supports.
  40   * @return array CSS rules, or an empty array when the configuration is not allowed.
  41   */
  42  function wp_get_position_support_styles( $selector, $position, $allowed_position_types ) {
  43      $styles = array();
  44  
  45      if ( ! is_array( $position ) || ! is_string( $position['type'] ?? null ) ) {
  46          return $styles;
  47      }
  48  
  49      $position_type = $position['type'];
  50  
  51      if ( ! in_array( $position_type, $allowed_position_types, true ) ) {
  52          return $styles;
  53      }
  54  
  55      $sides = array( 'top', 'right', 'bottom', 'left' );
  56  
  57      foreach ( $sides as $side ) {
  58          $side_value = $position[ $side ] ?? null;
  59          if ( null !== $side_value ) {
  60              /*
  61               * For fixed or sticky top positions,
  62               * ensure the value includes an offset for the logged in admin bar.
  63               */
  64              if ( 'top' === $side ) {
  65                  // Ensure 0 values can be used in `calc()` calculations.
  66                  if ( '0' === $side_value || 0 === $side_value ) {
  67                      $side_value = '0px';
  68                  }
  69  
  70                  // Ensure current side value also factors in the height of the logged in admin bar.
  71                  $side_value = "calc($side_value + var(--wp-admin--admin-bar--position-offset, 0px))";
  72              }
  73  
  74              $styles[] = array(
  75                  'selector'     => $selector,
  76                  'declarations' => array(
  77                      $side => $side_value,
  78                  ),
  79              );
  80          }
  81      }
  82  
  83      $styles[] = array(
  84          'selector'     => $selector,
  85          'declarations' => array(
  86              'position' => $position_type,
  87              'z-index'  => '10',
  88          ),
  89      );
  90  
  91      return $styles;
  92  }
  93  
  94  /**
  95   * Renders position styles to the block wrapper.
  96   *
  97   * @since 6.2.0
  98   * @since 7.2.0 Added support for viewport states.
  99   * @access private
 100   *
 101   * @param string $block_content Rendered block content.
 102   * @param array  $block         Block object.
 103   * @return string Filtered block content.
 104   */
 105  function wp_render_position_support( $block_content, $block ) {
 106      $block_type           = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
 107      $has_position_support = block_has_support( $block_type, 'position', false );
 108      $style_attribute      = $block['attrs']['style'] ?? null;
 109  
 110      if ( ! $has_position_support || ! is_array( $style_attribute ) ) {
 111          return $block_content;
 112      }
 113  
 114      /*
 115       * Position styles can exist in either the default state or a viewport state.
 116       */
 117      $has_position_style = ! empty( $style_attribute['position'] );
 118      if ( ! $has_position_style ) {
 119          foreach ( $style_attribute as $key => $style ) {
 120              if (
 121                  is_string( $key ) &&
 122                  str_starts_with( $key, '@' ) &&
 123                  is_array( $style ) &&
 124                  ! empty( $style['position'] )
 125              ) {
 126                  $has_position_style = true;
 127                  break;
 128              }
 129          }
 130      }
 131  
 132      if ( ! $has_position_style ) {
 133          return $block_content;
 134      }
 135  
 136      $global_settings          = wp_get_global_settings();
 137      $theme_has_sticky_support = $global_settings['position']['sticky'] ?? false;
 138      $theme_has_fixed_support  = $global_settings['position']['fixed'] ?? false;
 139  
 140      // Only allow output for position types that the theme supports.
 141      $allowed_position_types = array();
 142      if ( true === $theme_has_sticky_support ) {
 143          $allowed_position_types[] = 'sticky';
 144      }
 145      if ( true === $theme_has_fixed_support ) {
 146          $allowed_position_types[] = 'fixed';
 147      }
 148  
 149      $viewport_settings        = $global_settings['viewport'] ?? null;
 150      $responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings );
 151      $class_name               = wp_unique_id( 'wp-container-' );
 152      $selector                 = ".$class_name";
 153      $position_styles          = array();
 154      $wrapper_classes          = array();
 155      $base_position            = $style_attribute['position'] ?? null;
 156  
 157      // Default viewport (base) position styles.
 158      $base_styles = wp_get_position_support_styles(
 159          $selector,
 160          $base_position,
 161          $allowed_position_types
 162      );
 163  
 164      if ( ! empty( $base_styles ) ) {
 165          $position_styles   = $base_styles;
 166          $wrapper_classes[] = 'is-position-' . $base_position['type'];
 167      }
 168  
 169      /*
 170       * Responsive viewport state styles. A viewport state inherits any values
 171       * it does not set from the default state, so a state that only overrides
 172       * e.g. the `top` offset keeps the base position type.
 173       */
 174      foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
 175          $viewport_position_style = $style_attribute[ $breakpoint ]['position'] ?? null;
 176  
 177          if ( empty( $viewport_position_style ) || ! is_array( $viewport_position_style ) ) {
 178              continue;
 179          }
 180  
 181          $viewport_position = is_array( $base_position )
 182              ? array_replace( $base_position, $viewport_position_style )
 183              : $viewport_position_style;
 184  
 185          $viewport_styles = wp_get_position_support_styles(
 186              $selector,
 187              $viewport_position,
 188              $allowed_position_types
 189          );
 190  
 191          if ( ! empty( $viewport_styles ) ) {
 192              $wrapper_classes[] = 'is-position-' . $viewport_position['type'];
 193          } elseif ( ! empty( $base_styles ) ) {
 194              /*
 195               * The viewport state can explicitly clear the position type inherited from the
 196               * default state.
 197               */
 198              $viewport_styles = array(
 199                  array(
 200                      'selector'     => $selector,
 201                      'declarations' => array( 'position' => 'static' ),
 202                  ),
 203              );
 204          } else {
 205              continue;
 206          }
 207  
 208          foreach ( $viewport_styles as $index => $rule ) {
 209              $viewport_styles[ $index ]['rules_group'] = $media_query;
 210          }
 211  
 212          $position_styles = array_merge( $position_styles, $viewport_styles );
 213      }
 214  
 215      if ( ! empty( $position_styles ) ) {
 216          /*
 217           * Add to the style engine store to enqueue and render position styles.
 218           */
 219          wp_style_engine_get_stylesheet_from_css_rules(
 220              $position_styles,
 221              array(
 222                  'context'  => 'block-supports',
 223                  'prettify' => false,
 224              )
 225          );
 226  
 227          // Inject class name to block container markup.
 228          $content = new WP_HTML_Tag_Processor( $block_content );
 229          $content->next_tag();
 230          $content->add_class( $class_name );
 231          foreach ( array_unique( $wrapper_classes ) as $class ) {
 232              $content->add_class( $class );
 233          }
 234          return (string) $content;
 235      }
 236  
 237      return $block_content;
 238  }
 239  
 240  // Register the block support.
 241  WP_Block_Supports::get_instance()->register(
 242      'position',
 243      array(
 244          'register_attribute' => 'wp_register_position_support',
 245      )
 246  );
 247  add_filter( 'render_block', 'wp_render_position_support', 10, 2 );


Generated : Wed Oct 7 08:20:33 2026 Cross-referenced by PHPXref