[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/blocks/ -> post-time-to-read.php (source)

   1  <?php
   2  /**
   3   * Server-side rendering of the `core/post-time-to-read` block.
   4   *
   5   * @package WordPress
   6   */
   7  
   8  /**
   9   * Counts words or characters in a provided text string.
  10   *
  11   * This function currently employs an array of regular expressions
  12   * to parse HTML and count words, which may result in inaccurate
  13   * word counts. However, it is designed primarily to agree with the
  14   * corresponding JavaScript function.
  15   *
  16   * Any improvements in the word counting, for example with the HTML API
  17   * and {@see \IntlBreakIterator::createWordInstance()} should coordinate
  18   * with changes to the JavaScript implementation to ensure consistency
  19   * between the editor and the rendered page.
  20   *
  21   * @since 6.9.0
  22   *
  23   * @param string $text Text to count elements in.
  24   * @param string $type The type of count. Accepts 'words', 'characters_excluding_spaces', or 'characters_including_spaces'.
  25   *
  26   * @return string The rendered word count.
  27   */
  28  function block_core_post_time_to_read_word_count( $text, $type ) {
  29      $settings = array(
  30          'html_regexp'                        => '/<\/?[a-z][^>]*?>/i',
  31          'html_comment_regexp'                => '/<!--[\s\S]*?-->/',
  32          'space_regexp'                       => '/&nbsp;|&#160;/i',
  33          'html_entity_regexp'                 => '/&\S+?;/',
  34          'connector_regexp'                   => "/--|\x{2014}/u",
  35          'remove_regexp'                      => "/[\x{0021}-\x{0040}\x{005B}-\x{0060}\x{007B}-\x{007E}\x{0080}-\x{00BF}\x{00D7}\x{00F7}\x{2000}-\x{2BFF}\x{2E00}-\x{2E7F}]/u",
  36          'astral_regexp'                      => "/[\x{010000}-\x{10FFFF}]/u",
  37          'words_regexp'                       => '/\S\s+/u',
  38          'characters_excluding_spaces_regexp' => '/\S/u',
  39          'characters_including_spaces_regexp' => "/[^\f\n\r\t\v\x{00AD}\x{2028}\x{2029}]/u",
  40      );
  41  
  42      $count = 0;
  43  
  44      if ( '' === trim( $text ) ) {
  45          return $count;
  46      }
  47  
  48      // Sanitize type to one of three possibilities: 'words', 'characters_excluding_spaces' or 'characters_including_spaces'.
  49      if ( 'characters_excluding_spaces' !== $type && 'characters_including_spaces' !== $type ) {
  50          $type = 'words';
  51      }
  52  
  53      $text .= "\n";
  54  
  55      // Replace all HTML with a new-line.
  56      $text = preg_replace( $settings['html_regexp'], "\n", $text );
  57  
  58      // Remove all HTML comments.
  59      $text = preg_replace( $settings['html_comment_regexp'], '', $text );
  60  
  61      // If a shortcode regular expression has been provided use it to remove shortcodes.
  62      if ( ! empty( $settings['shortcodes_regexp'] ) ) {
  63          $text = preg_replace( $settings['shortcodes_regexp'], "\n", $text );
  64      }
  65  
  66      // Normalize non-breaking space to a normal space.
  67      $text = preg_replace( $settings['space_regexp'], ' ', $text );
  68  
  69      if ( 'words' === $type ) {
  70          // Remove HTML Entities.
  71          $text = preg_replace( $settings['html_entity_regexp'], '', $text );
  72  
  73          // Convert connectors to spaces to count attached text as words.
  74          $text = preg_replace( $settings['connector_regexp'], ' ', $text );
  75  
  76          // Remove unwanted characters.
  77          $text = preg_replace( $settings['remove_regexp'], '', $text );
  78      } else {
  79          // Convert HTML Entities to "a".
  80          $text = preg_replace( $settings['html_entity_regexp'], 'a', $text );
  81  
  82          // Remove surrogate points.
  83          $text = preg_replace( $settings['astral_regexp'], 'a', $text );
  84      }
  85  
  86      // Match with the selected type regular expression to count the items.
  87      return (int) preg_match_all( $settings[ $type . '_regexp' ], $text );
  88  }
  89  
  90  /**
  91   * Renders the `core/post-time-to-read` block on the server.
  92   *
  93   * @since 6.9.0
  94   *
  95   * @param  array    $attributes Block attributes.
  96   * @param  string   $content    Block default content.
  97   * @param  WP_Block $block      Block instance.
  98   * @return string Returns the rendered post author name block.
  99   */
 100  function render_block_core_post_time_to_read( $attributes, $content, $block ) {
 101      if ( ! isset( $block->context['postId'] ) ) {
 102          return '';
 103      }
 104  
 105      $content              = get_the_content();
 106      $average_reading_rate = isset( $attributes['averageReadingSpeed'] ) ? $attributes['averageReadingSpeed'] : 189;
 107  
 108      $display_mode = isset( $attributes['displayMode'] ) ? $attributes['displayMode'] : 'time';
 109  
 110      $word_count_type = wp_get_word_count_type();
 111      $total_words     = block_core_post_time_to_read_word_count( $content, $word_count_type );
 112  
 113      $parts = array();
 114  
 115      // Add "time to read" part, if enabled.
 116      if ( 'time' === $display_mode ) {
 117          if ( ! empty( $attributes['displayAsRange'] ) ) {
 118              // Calculate faster reading rate with 20% speed = lower minutes,
 119              // and slower reading rate with 20% speed = higher minutes.
 120              $min_minutes = max( 1, (int) round( $total_words / $average_reading_rate * 0.8 ) );
 121              $max_minutes = max( 1, (int) round( $total_words / $average_reading_rate * 1.2 ) );
 122              if ( $min_minutes === $max_minutes ) {
 123                  $max_minutes = $min_minutes + 1;
 124              }
 125              /* translators: 1: minimum minutes, 2: maximum minutes to read the post. */
 126              $time_string = sprintf(
 127                  /* translators: 1: minimum minutes, 2: maximum minutes to read the post. */
 128                  _x( '%1$s–%2$s minutes', 'Range of minutes to read' ),
 129                  $min_minutes,
 130                  $max_minutes
 131              );
 132          } else {
 133              $minutes_to_read = max( 1, (int) round( $total_words / $average_reading_rate ) );
 134              $time_string     = sprintf(
 135                  /* translators: %s: the number of minutes to read the post. */
 136                  _n( '%s minute', '%s minutes', $minutes_to_read ),
 137                  $minutes_to_read
 138              );
 139          }
 140          $parts[] = $time_string;
 141      }
 142  
 143      // Add "word count" part, if enabled.
 144      if ( 'words' === $display_mode ) {
 145          $word_count_string = 'words' === $word_count_type ? sprintf(
 146              /* translators: %s: the number of words in the post. */
 147              _n( '%s word', '%s words', $total_words ),
 148              number_format_i18n( $total_words )
 149          ) : sprintf(
 150              /* translators: %s: the number of characters in the post. */
 151              _n( '%s character', '%s characters', $total_words ),
 152              number_format_i18n( $total_words )
 153          );
 154          $parts[] = $word_count_string;
 155      }
 156  
 157      $display_string = implode( '<br>', $parts );
 158  
 159      $align_class_name = empty( $attributes['textAlign'] ) ? '' : "has-text-align-{$attributes['textAlign']}";
 160  
 161      $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $align_class_name ) );
 162  
 163      return sprintf(
 164          '<div %1$s>%2$s</div>',
 165          $wrapper_attributes,
 166          $display_string
 167      );
 168  }
 169  
 170  
 171  /**
 172   * Registers the `core/post-time-to-read` block on the server.
 173   *
 174   * @since 6.9.0
 175   */
 176  function register_block_core_post_time_to_read() {
 177      register_block_type_from_metadata(
 178          __DIR__ . '/post-time-to-read',
 179          array(
 180              'render_callback' => 'render_block_core_post_time_to_read',
 181          )
 182      );
 183  }
 184  
 185  add_action( 'init', 'register_block_core_post_time_to_read' );


Generated : Wed Oct 22 08:20:04 2025 Cross-referenced by PHPXref