[ Index ]

PHP Cross Reference of BBPress

title

Body

[close]

/src/includes/common/ -> formatting.php (source)

   1  <?php
   2  
   3  /**
   4   * bbPress Formatting
   5   *
   6   * @package bbPress
   7   * @subpackage Formatting
   8   */
   9  
  10  // Exit if accessed directly
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /** Kses **********************************************************************/
  14  
  15  /**
  16   * Custom allowed tags for forum topics and replies
  17   *
  18   * Allows all users to post links, quotes, code, formatting, lists, and images
  19   *
  20   * @since 2.3.0 bbPress (r4603)
  21   *
  22   * @return array Associative array of allowed tags and attributes
  23   */
  24  function bbp_kses_allowed_tags() {
  25  
  26      // Filter & return
  27      return (array) apply_filters( 'bbp_kses_allowed_tags', array(
  28  
  29          // Links
  30          'a' => array(
  31              'href'     => true,
  32              'title'    => true,
  33              'rel'      => true,
  34              'target'   => true
  35          ),
  36  
  37          // Quotes
  38          'blockquote'   => array(
  39              'cite'     => true
  40          ),
  41  
  42          // Code
  43          'code'         => array(),
  44          'pre'          => array(
  45              'class'    => true
  46          ),
  47  
  48          // Formatting
  49          'em'           => array(),
  50          'strong'       => array(),
  51          'del'          => array(
  52              'datetime' => true,
  53              'cite'     => true
  54          ),
  55          'ins' => array(
  56              'datetime' => true,
  57              'cite'     => true
  58          ),
  59  
  60          // Lists
  61          'ul'           => array(),
  62          'ol'           => array(
  63              'start'    => true,
  64          ),
  65          'li'           => array(),
  66  
  67          // Images
  68          'img'          => array(
  69              'src'      => true,
  70              'border'   => true,
  71              'alt'      => true,
  72              'height'   => true,
  73              'width'    => true,
  74          )
  75      ) );
  76  }
  77  
  78  /**
  79   * Custom kses filter for forum topics and replies, for filtering incoming data
  80   *
  81   * @since 2.3.0 bbPress (r4603)
  82   *
  83   * @param string $data Content to filter, expected to be escaped with slashes
  84   * @return string Filtered content
  85   */
  86  function bbp_filter_kses( $data = '' ) {
  87      return wp_slash( wp_kses( wp_unslash( $data ), bbp_kses_allowed_tags() ) );
  88  }
  89  
  90  /**
  91   * Custom kses filter for forum topics and replies, for raw data
  92   *
  93   * @since 2.3.0 bbPress (r4603)
  94   *
  95   * @param string $data Content to filter, expected to not be escaped
  96   * @return string Filtered content
  97   */
  98  function bbp_kses_data( $data = '' ) {
  99      return wp_kses( $data , bbp_kses_allowed_tags() );
 100  }
 101  
 102  /** Formatting ****************************************************************/
 103  
 104  /**
 105   * Filter the topic or reply content and output code and pre tags
 106   *
 107   * @since 2.3.0 bbPress (r4641)
 108   *
 109   * @param string $content Topic and reply content
 110   * @return string Partially encoded content
 111   */
 112  function bbp_code_trick( $content = '' ) {
 113      $content = str_replace( array( "\r\n", "\r" ), "\n", $content );
 114      $content = preg_replace_callback( "|(`)(.*?)`|",      'bbp_encode_callback', $content );
 115      $content = preg_replace_callback( "!(^|\n)`(.*?)`!s", 'bbp_encode_callback', $content );
 116  
 117      return $content;
 118  }
 119  
 120  /**
 121   * When editing a topic or reply, reverse the code trick so the textarea
 122   * contains the correct editable content.
 123   *
 124   * @since 2.3.0 bbPress (r4641)
 125   *
 126   * @param string $content Topic and reply content
 127   * @return string Partially encoded content
 128   */
 129  function bbp_code_trick_reverse( $content = '' ) {
 130  
 131      // Setup variables
 132      $openers = array( '<p>', '<br />' );
 133      $content = preg_replace_callback( "!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", 'bbp_decode_callback', $content );
 134  
 135      // Do the do
 136      $content = str_replace( $openers,       '',       $content );
 137      $content = str_replace( '</p>',         "\n",     $content );
 138      $content = str_replace( '<coded_br />', '<br />', $content );
 139      $content = str_replace( '<coded_p>',    '<p>',    $content );
 140      $content = str_replace( '</coded_p>',   '</p>',   $content );
 141  
 142      return $content;
 143  }
 144  
 145  /**
 146   * Filter the content and encode any bad HTML tags
 147   *
 148   * @since 2.3.0 bbPress (r4641)
 149   *
 150   * @param string $content Topic and reply content
 151   * @return string Partially encoded content
 152   */
 153  function bbp_encode_bad( $content = '' ) {
 154  
 155      // Setup variables
 156      $content = _wp_specialchars( $content, ENT_NOQUOTES );
 157      $content = preg_split( '@(`[^`]*`)@m', $content, -1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE );
 158      $allowed = bbp_kses_allowed_tags();
 159      $empty   = array(
 160          'br'    => true,
 161          'hr'    => true,
 162          'img'   => true,
 163          'input' => true,
 164          'param' => true,
 165          'area'  => true,
 166          'col'   => true,
 167          'embed' => true
 168      );
 169  
 170      // Loop through allowed tags and compare for empty and normal tags
 171      foreach ( $allowed as $tag => $args ) {
 172          $preg = $args ? "{$tag}(?:\s.*?)?" : $tag;
 173  
 174          // Which walker to use based on the tag and arguments
 175          if ( isset( $empty[ $tag ] ) ) {
 176              array_walk( $content, 'bbp_encode_empty_callback',  $preg );
 177          } else {
 178              array_walk( $content, 'bbp_encode_normal_callback', $preg );
 179          }
 180      }
 181  
 182      // Return the joined content array
 183      return implode( '', $content );
 184  }
 185  
 186  /** Code Callbacks ************************************************************/
 187  
 188  /**
 189   * Callback to encode the tags in topic or reply content
 190   *
 191   * @since 2.3.0 bbPress (r4641)
 192   *
 193   * @param array $matches
 194   * @return string
 195   */
 196  function bbp_encode_callback( $matches = array() ) {
 197  
 198      // Trim inline code, not pre blocks (to prevent removing indentation)
 199      if ( "`" === $matches[1] ) {
 200          $content = trim( $matches[2] );
 201      } else {
 202          $content = $matches[2];
 203      }
 204  
 205      // Do some replacing
 206      $content = htmlspecialchars( $content, ENT_QUOTES );
 207      $content = str_replace( array( "\r\n", "\r" ), "\n", $content );
 208      $content = preg_replace( "|\n\n\n+|", "\n\n", $content );
 209      $content = str_replace( '&amp;amp;', '&amp;', $content );
 210      $content = str_replace( '&amp;lt;',  '&lt;',  $content );
 211      $content = str_replace( '&amp;gt;',  '&gt;',  $content );
 212  
 213      // Wrap in code tags
 214      $content = '<code>' . $content . '</code>';
 215  
 216      // Wrap blocks in pre tags
 217      if ( "`" !== $matches[1] ) {
 218          $content = "\n<pre>" . $content . "</pre>\n";
 219      }
 220  
 221      return $content;
 222  }
 223  
 224  /**
 225   * Callback to decode the tags in topic or reply content
 226   *
 227   * @since 2.3.0 bbPress (r4641)
 228   *
 229   * @param array $matches
 230   * @todo Experiment with _wp_specialchars()
 231   * @return string
 232   */
 233  function bbp_decode_callback( $matches = array() ) {
 234  
 235      // Setup variables
 236      $trans_table = array_flip( get_html_translation_table( HTML_ENTITIES ) );
 237      $amps        = array( '&#38;','&#038;', '&amp;' );
 238      $single      = array( '&#39;','&#039;'          );
 239      $content     = $matches[2];
 240      $content     = strtr( $content, $trans_table );
 241  
 242      // Do the do
 243      $content = str_replace( '<br />', '<coded_br />', $content );
 244      $content = str_replace( '<p>',    '<coded_p>',    $content );
 245      $content = str_replace( '</p>',   '</coded_p>',   $content );
 246      $content = str_replace( $amps,    '&',            $content );
 247      $content = str_replace( $single,  "'",            $content );
 248  
 249      // Return content wrapped in code tags
 250      return '`' . $content . '`';
 251  }
 252  
 253  /**
 254   * Callback to replace empty HTML tags in a content string
 255   *
 256   * @since 2.3.0 bbPress (r4641)
 257   *
 258   * @internal Used by bbp_encode_bad()
 259   * @param string $content
 260   * @param string $key Not used
 261   * @param string $preg
 262   */
 263  function bbp_encode_empty_callback( &$content = '', $key = '', $preg = '' ) {
 264      if ( strpos( $content, '`' ) !== 0 ) {
 265          $content = preg_replace( "|&lt;({$preg})\s*?/*?&gt;|i", '<$1 />', $content );
 266      }
 267  }
 268  
 269  /**
 270   * Callback to replace normal HTML tags in a content string
 271   *
 272   * @since 2.3.0 bbPress (r4641)
 273   *
 274   * @internal Used by bbp_encode_bad()
 275   *
 276   * @param string $content
 277   * @param string $key
 278   * @param string $preg
 279   */
 280  function bbp_encode_normal_callback( &$content = '', $key = '', $preg = '') {
 281      if ( strpos( $content, '`' ) !== 0 ) {
 282          $content = preg_replace( "|&lt;(/?{$preg})&gt;|i", '<$1>', $content );
 283      }
 284  }
 285  
 286  /** No Follow *****************************************************************/
 287  
 288  /**
 289   * Catches links so rel=nofollow can be added (on output, not save)
 290   *
 291   * @since 2.3.0 bbPress (r4865)
 292   *
 293   * @param string $text Post text
 294   * @return string $text Text with rel=nofollow added to any links
 295   */
 296  function bbp_rel_nofollow( $text = '' ) {
 297      return preg_replace_callback( '|<a (.+?)>|i', 'bbp_rel_nofollow_callback', $text );
 298  }
 299  
 300  /**
 301   * Adds rel=nofollow to a link
 302   *
 303   * @since 2.3.0 bbPress (r4865)
 304   *
 305   * @param array $matches
 306   * @return string $text Link with rel=nofollow added
 307   */
 308  function bbp_rel_nofollow_callback( $matches = array() ) {
 309      $text     = $matches[1];
 310      $atts     = shortcode_parse_atts( $matches[1] );
 311      $rel      = 'nofollow';
 312      $home_url = home_url();
 313  
 314      // Bail on links that match the current domain
 315      if ( preg_match( '%href=["\'](' . preg_quote( set_url_scheme( $home_url, 'http'  ) ) . ')%i', $text ) ||
 316           preg_match( '%href=["\'](' . preg_quote( set_url_scheme( $home_url, 'https' ) ) . ')%i', $text )
 317      ) {
 318          return "<a {$text}>";
 319      }
 320  
 321      // Avoid collisions with existing "rel" attribute
 322      if ( ! empty( $atts['rel'] ) ) {
 323          $parts = array_map( 'trim', explode( ' ', $atts['rel'] ) );
 324          if ( false === array_search( 'nofollow', $parts ) ) {
 325              $parts[] = 'nofollow';
 326          }
 327  
 328          $rel = implode( ' ', $parts );
 329          unset( $atts['rel'] );
 330  
 331          $html = '';
 332          foreach ( $atts as $name => $value ) {
 333              $html .= "{$name}=\"{$value}\" ";
 334          }
 335  
 336          $text = trim( $html );
 337      }
 338  
 339      return "<a {$text} rel=\"{$rel}\">";
 340  }
 341  
 342  /** Make Clickable ************************************************************/
 343  
 344  /**
 345   * Convert plaintext URI to HTML links.
 346   *
 347   * Converts URI, www and ftp, and email addresses. Finishes by fixing links
 348   * within links.
 349   *
 350   * This custom version of WordPress's make_clickable() skips links inside of
 351   * pre and code tags.
 352   *
 353   * @since 2.4.0 bbPress (r4941)
 354   *
 355   * @param string $text Content to convert URIs.
 356   * @return string Content with converted URIs.
 357   */
 358  function bbp_make_clickable( $text = '' ) {
 359      $r               = '';
 360      $textarr         = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
 361      $nested_code_pre = 0; // Keep track of how many levels link is nested inside <pre> or <code>
 362  
 363      foreach ( $textarr as $piece ) {
 364  
 365          if ( preg_match( '|^<code[\s>]|i', $piece ) || preg_match( '|^<pre[\s>]|i', $piece ) || preg_match( '|^<script[\s>]|i', $piece ) || preg_match( '|^<style[\s>]|i', $piece ) ) {
 366              $nested_code_pre++;
 367          } elseif ( $nested_code_pre && ( '</code>' === strtolower( $piece ) || '</pre>' === strtolower( $piece ) || '</script>' === strtolower( $piece ) || '</style>' === strtolower( $piece ) ) ) {
 368              $nested_code_pre--;
 369          }
 370  
 371          if ( $nested_code_pre || empty( $piece ) || ( $piece[0] === '<' && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
 372              $r .= $piece;
 373              continue;
 374          }
 375  
 376          // Long strings might contain expensive edge cases ...
 377          if ( 10000 < strlen( $piece ) ) {
 378              // ... break it up
 379              foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
 380                  if ( 2101 < strlen( $chunk ) ) {
 381                      $r .= $chunk; // Too big, no whitespace: bail.
 382                  } else {
 383                      $r .= bbp_make_clickable( $chunk );
 384                  }
 385              }
 386          } else {
 387              $ret = " {$piece} "; // Pad with whitespace to simplify the regexes
 388              $ret = apply_filters( 'bbp_make_clickable', $ret, $text );
 389              $ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
 390              $r .= $ret;
 391          }
 392      }
 393  
 394      // Cleanup of accidental links within links
 395      return preg_replace( '#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a>([^<]*)</a>#i', "$1$3$4</a>", $r );
 396  }
 397  
 398  /**
 399   * Make URLs clickable in content areas
 400   *
 401   * @since 2.6.0 bbPress (r6014)
 402   *
 403   * @param  string $text
 404   * @return string
 405   */
 406  function bbp_make_urls_clickable( $text = '' ) {
 407      $url_clickable = '~
 408          ([\\s(<.,;:!?])                                # 1: Leading whitespace, or punctuation
 409          (                                              # 2: URL
 410              [\\w]{1,20}+://                            # Scheme and hier-part prefix
 411              (?=\S{1,2000}\s)                           # Limit to URLs less than about 2000 characters long
 412              [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+     # Non-punctuation URL character
 413              (?:                                        # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
 414                  [\'.,;:!?)]                            # Punctuation URL character
 415                  [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
 416              )*
 417          )
 418          (\)?)                                          # 3: Trailing closing parenthesis (for parethesis balancing post processing)
 419      ~xS';
 420  
 421      // The regex is a non-anchored pattern and does not have a single fixed starting character.
 422      // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
 423      return preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $text );
 424  }
 425  
 426  /**
 427   * Make FTP clickable in content areas
 428   *
 429   * @since 2.6.0 bbPress (r6014)
 430   *
 431   * @see make_clickable()
 432   *
 433   * @param  string $text
 434   * @return string
 435   */
 436  function bbp_make_ftps_clickable( $text = '' ) {
 437      return preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $text );
 438  }
 439  
 440  /**
 441   * Make emails clickable in content areas
 442   *
 443   * @since 2.6.0 bbPress (r6014)
 444   *
 445   * @see make_clickable()
 446   *
 447   * @param  string $text
 448   * @return string
 449   */
 450  function bbp_make_emails_clickable( $text = '' ) {
 451      return preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $text );
 452  }
 453  
 454  /**
 455   * Make mentions clickable in content areas
 456   *
 457   * @since 2.6.0 bbPress (r6014)
 458   *
 459   * @see make_clickable()
 460   *
 461   * @param  string $text
 462   * @return string
 463   */
 464  function bbp_make_mentions_clickable( $text = '' ) {
 465      return preg_replace_callback( '#@([0-9a-zA-Z-_]+)#i', 'bbp_make_mentions_clickable_callback', $text );
 466  }
 467  
 468  /**
 469   * Callback to convert mention matches to HTML A tag.
 470   *
 471   * @since 2.6.0 bbPress (r6014)
 472   *
 473   * @param array $matches Regular expression matches in the current text blob.
 474   *
 475   * @return string Original text if no user exists, or link to user profile.
 476   */
 477  function bbp_make_mentions_clickable_callback( $matches = array() ) {
 478  
 479      // Get user; bail if not found
 480      $user = get_user_by( 'slug', $matches[1] );
 481      if ( empty( $user ) || bbp_is_user_inactive( $user->ID ) ) {
 482          return $matches[0];
 483      }
 484  
 485      // Filter classes
 486      $classes = (array) apply_filters( 'bbp_make_mentions_clickable_classes', array(
 487          'bbp-user-id-' . $user->ID,
 488          'bbp-user-mention'
 489      ) );
 490  
 491      // Escape & implode if not empty, otherwise an empty string
 492      $class_str = ! empty( $classes )
 493          ? implode( ' ', array_map( 'sanitize_html_class', $classes ) )
 494          : '';
 495  
 496      // Create the link to the user's profile
 497      $url    = bbp_get_user_profile_url( $user->ID );
 498      $clicky = '<a href="%1$s" class="' . esc_attr( $class_str ) . '">%2$s</a>';
 499      $anchor = sprintf( $clicky, esc_url( $url ), esc_html( $matches[0] ) );
 500      $link   = bbp_rel_nofollow( $anchor );
 501  
 502      return $link;
 503  }
 504  
 505  /** Numbers *******************************************************************/
 506  
 507  /**
 508   * Never let a numeric value be less than zero.
 509   *
 510   * @since 2.6.0 bbPress (r6300)
 511   *
 512   * @param int $number
 513   */
 514  function bbp_number_not_negative( $number = 0 ) {
 515  
 516      // Protect against formatted strings
 517      if ( is_string( $number ) ) {
 518          $number = strip_tags( $number );                    // No HTML
 519          $number = preg_replace( '/[^0-9-]/', '', $number ); // No number-format
 520  
 521      // Protect against objects, arrays, scalars, etc...
 522      } elseif ( ! is_numeric( $number ) ) {
 523          $number = 0;
 524      }
 525  
 526      // Make the number an integer
 527      $int = intval( $number );
 528  
 529      // Pick the maximum value, never less than zero
 530      $not_less_than_zero = max( 0, $int );
 531  
 532      // Filter & return
 533      return (int) apply_filters( 'bbp_number_not_negative', $not_less_than_zero, $int, $number );
 534  }
 535  
 536  /**
 537   * A bbPress specific method of formatting numeric values
 538   *
 539   * @since 2.0.0 bbPress (r2486)
 540   *
 541   * @param string $number Number to format
 542   * @param string $decimals Optional. Display decimals
 543   *
 544   * @return string Formatted string
 545   */
 546  function bbp_number_format( $number = 0, $decimals = false, $dec_point = '.', $thousands_sep = ',' ) {
 547  
 548      // If empty, set $number to (int) 0
 549      if ( ! is_numeric( $number ) ) {
 550          $number = 0;
 551      }
 552  
 553      // Filter & return
 554      return apply_filters( 'bbp_number_format', number_format( $number, $decimals, $dec_point, $thousands_sep ), $number, $decimals, $dec_point, $thousands_sep );
 555  }
 556  
 557  /**
 558   * A bbPress specific method of formatting numeric values
 559   *
 560   * @since 2.1.0 bbPress (r3857)
 561   *
 562   * @param string $number Number to format
 563   * @param string $decimals Optional. Display decimals
 564   *
 565   * @return string Formatted string
 566   */
 567  function bbp_number_format_i18n( $number = 0, $decimals = false ) {
 568  
 569      // If empty, set $number to (int) 0
 570      if ( ! is_numeric( $number ) ) {
 571          $number = 0;
 572      }
 573  
 574      // Filter & return
 575      return apply_filters( 'bbp_number_format_i18n', number_format_i18n( $number, $decimals ), $number, $decimals );
 576  }
 577  
 578  /** Dates *********************************************************************/
 579  
 580  /**
 581   * Convert time supplied from database query into specified date format.
 582   *
 583   * @since 2.0.0 bbPress (r2544)
 584   *
 585   * @param string $time Time to convert
 586   * @param string $d Optional. Default is 'U'. Either 'G', 'U', or php date
 587   *                             format
 588   * @param bool $translate Optional. Default is false. Whether to translate the
 589   *
 590   * @return string Returns timestamp
 591   */
 592  function bbp_convert_date( $time, $d = 'U', $translate = false ) {
 593      $new_time = mysql2date( $d, $time, $translate );
 594  
 595      // Filter & return
 596      return apply_filters( 'bbp_convert_date', $new_time, $d, $translate, $time );
 597  }
 598  
 599  /**
 600   * Output formatted time to display human readable time difference.
 601   *
 602   * @since 2.0.0 bbPress (r2544)
 603   *
 604   * @param string $older_date Unix timestamp from which the difference begins.
 605   * @param string $newer_date Optional. Unix timestamp from which the
 606   *                            difference ends. False for current time.
 607   * @param int $gmt Optional. Whether to use GMT timezone. Default is false.
 608   */
 609  function bbp_time_since( $older_date, $newer_date = false, $gmt = false ) {
 610      echo bbp_get_time_since( $older_date, $newer_date, $gmt );
 611  }
 612      /**
 613       * Return formatted time to display human readable time difference.
 614       *
 615       * @since 2.0.0 bbPress (r2544)
 616       *
 617       * @param string $older_date Unix timestamp from which the difference begins.
 618       * @param string $newer_date Optional. Unix timestamp from which the
 619       *                            difference ends. False for current time.
 620       * @param int $gmt Optional. Whether to use GMT timezone. Default is false.
 621       *
 622       * @return string Formatted time
 623       */
 624  	function bbp_get_time_since( $older_date, $newer_date = false, $gmt = false ) {
 625  
 626          // Setup the strings
 627          $unknown_text   = apply_filters( 'bbp_core_time_since_unknown_text',   esc_html__( 'sometime',  'bbpress' ) );
 628          $right_now_text = apply_filters( 'bbp_core_time_since_right_now_text', esc_html__( 'right now', 'bbpress' ) );
 629          $ago_text       = apply_filters( 'bbp_core_time_since_ago_text',       esc_html__( '%s ago',    'bbpress' ) );
 630  
 631          // array of time period chunks
 632          $chunks = array(
 633              array( YEAR_IN_SECONDS,   _n_noop( '%s year',   '%s years',   'bbpress' ) ),
 634              array( MONTH_IN_SECONDS,  _n_noop( '%s month',  '%s months',  'bbpress' ) ),
 635              array( WEEK_IN_SECONDS,   _n_noop( '%s week',   '%s weeks',   'bbpress' ) ),
 636              array( DAY_IN_SECONDS,    _n_noop( '%s day',    '%s days',    'bbpress' ) ),
 637              array( HOUR_IN_SECONDS,   _n_noop( '%s hour',   '%s hours',   'bbpress' ) ),
 638              array( MINUTE_IN_SECONDS, _n_noop( '%s minute', '%s minutes', 'bbpress' ) ),
 639              array( 1,                 _n_noop( '%s second', '%s seconds', 'bbpress' ) ),
 640          );
 641  
 642          // Attempt to parse non-numeric older date
 643          if ( ! empty( $older_date ) && ! is_numeric( $older_date ) ) {
 644              $time_chunks = explode( ':', str_replace( ' ', ':', $older_date ) );
 645              $date_chunks = explode( '-', str_replace( ' ', '-', $older_date ) );
 646              $older_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
 647          }
 648  
 649          // Attempt to parse non-numeric newer date
 650          if ( ! empty( $newer_date ) && ! is_numeric( $newer_date ) ) {
 651              $time_chunks = explode( ':', str_replace( ' ', ':', $newer_date ) );
 652              $date_chunks = explode( '-', str_replace( ' ', '-', $newer_date ) );
 653              $newer_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
 654          }
 655  
 656          // Set newer date to current time
 657          if ( empty( $newer_date ) ) {
 658              $newer_date = strtotime( current_time( 'mysql', $gmt ) );
 659          }
 660  
 661          // Cast both dates to ints to avoid notices & errors with invalid values
 662          $newer_date = intval( $newer_date );
 663          $older_date = intval( $older_date );
 664  
 665          // Difference in seconds
 666          $since = intval( $newer_date - $older_date );
 667  
 668          // Something went wrong with date calculation and we ended up with a negative date.
 669          if ( 0 > $since ) {
 670              $output = $unknown_text;
 671  
 672          // We only want to output two chunks of time here, eg:
 673          //     x years, xx months
 674          //     x days, xx hours
 675          // so there's only two bits of calculation below:
 676          } else {
 677  
 678              // Step one: the first chunk
 679              for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) {
 680                  $seconds = $chunks[ $i ][0];
 681  
 682                  // Finding the biggest chunk (if the chunk fits, break)
 683                  $count = floor( $since / $seconds );
 684                  if ( 0 != $count ) {
 685                      break;
 686                  }
 687              }
 688  
 689              // If $i iterates all the way to $j, then the event happened 0 seconds ago
 690              if ( ! isset( $chunks[ $i ] ) ) {
 691                  $output = $right_now_text;
 692  
 693              } else {
 694  
 695                  // Set output var
 696                  $output = sprintf( translate_nooped_plural( $chunks[ $i ][1], $count, 'bbpress' ), bbp_number_format_i18n( $count ) );
 697  
 698                  // Step two: the second chunk
 699                  if ( $i + 2 < $j ) {
 700                      $seconds2 = $chunks[ $i + 1 ][0];
 701                      $count2   = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
 702  
 703                      // Add to output var
 704                      if ( 0 != $count2 ) {
 705                          $output .= _x( ',', 'Separator in time since', 'bbpress' ) . ' ';
 706                          $output .= sprintf( translate_nooped_plural( $chunks[ $i + 1 ][1], $count2, 'bbpress' ), bbp_number_format_i18n( $count2 ) );
 707                      }
 708                  }
 709  
 710                  // No output, so happened right now
 711                  if ( ! (int) trim( $output ) ) {
 712                      $output = $right_now_text;
 713                  }
 714              }
 715          }
 716  
 717          // Append 'ago' to the end of time-since if not 'right now'
 718          if ( $output != $right_now_text ) {
 719              $output = sprintf( $ago_text, $output );
 720          }
 721  
 722          // Filter & return
 723          return apply_filters( 'bbp_get_time_since', $output, $older_date, $newer_date );
 724      }
 725  
 726  /** Revisions *****************************************************************/
 727  
 728  /**
 729   * Formats the reason for editing the topic/reply.
 730   *
 731   * Does these things:
 732   *  - Trimming
 733   *  - Removing periods from the end of the string
 734   *  - Trimming again
 735   *
 736   * @since 2.0.0 bbPress (r2782)
 737   *
 738   * @param string $reason Optional. User submitted reason for editing.
 739   * @return string Status of topic
 740   */
 741  function bbp_format_revision_reason( $reason = '' ) {
 742      $reason = (string) $reason;
 743  
 744      // Bail if reason is empty
 745      if ( empty( $reason ) ) {
 746          return $reason;
 747      }
 748  
 749      // Trimming
 750      $reason = trim( $reason );
 751  
 752      // We add our own full stop.
 753      while ( substr( $reason, -1 ) === '.' ) {
 754          $reason = substr( $reason, 0, -1 );
 755      }
 756  
 757      // Trim again
 758      $reason = trim( $reason );
 759  
 760      return $reason;
 761  }


Generated: Sun Nov 17 01:01:25 2019 Cross-referenced by PHPXref 0.7.1