[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ -> kses.php (source)

   1  <?php
   2  /**
   3   * kses 0.2.2 - HTML/XHTML filter that only allows some elements and attributes
   4   * Copyright (C) 2002, 2003, 2005  Ulf Harnhammar
   5   *
   6   * This program is free software and open source software; you can redistribute
   7   * it and/or modify it under the terms of the GNU General Public License as
   8   * published by the Free Software Foundation; either version 2 of the License,
   9   * or (at your option) any later version.
  10   *
  11   * This program is distributed in the hope that it will be useful, but WITHOUT
  12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14   * more details.
  15   *
  16   * You should have received a copy of the GNU General Public License along
  17   * with this program; if not, write to the Free Software Foundation, Inc.,
  18   * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19   * http://www.gnu.org/licenses/gpl.html
  20   *
  21   * [kses strips evil scripts!]
  22   *
  23   * Added wp_ prefix to avoid conflicts with existing kses users
  24   *
  25   * @version 0.2.2
  26   * @copyright (C) 2002, 2003, 2005
  27   * @author Ulf Harnhammar <http://advogato.org/person/metaur/>
  28   *
  29   * @package External
  30   * @subpackage KSES
  31   */
  32  
  33  /**
  34   * Specifies the default allowable HTML tags.
  35   *
  36   * Using `CUSTOM_TAGS` is not recommended and should be considered deprecated. The
  37   * {@see 'wp_kses_allowed_html'} filter is more powerful and supplies context.
  38   *
  39   * @see wp_kses_allowed_html()
  40   * @since 1.2.0
  41   *
  42   * @var array[]|bool Array of default allowable HTML tags, or false to use the defaults.
  43   */
  44  if ( ! defined( 'CUSTOM_TAGS' ) ) {
  45      define( 'CUSTOM_TAGS', false );
  46  }
  47  
  48  // Ensure that these variables are added to the global namespace
  49  // (e.g. if using namespaces / autoload in the current PHP environment).
  50  global $allowedposttags, $allowedtags, $allowedentitynames;
  51  
  52  if ( ! CUSTOM_TAGS ) {
  53      /**
  54       * KSES global for default allowable HTML tags.
  55       *
  56       * Can be overridden with the `CUSTOM_TAGS` constant.
  57       *
  58       * @var array[] $allowedposttags Array of default allowable HTML tags.
  59       * @since 2.0.0
  60       */
  61      $allowedposttags = array(
  62          'address'    => array(),
  63          'a'          => array(
  64              'href'     => true,
  65              'rel'      => true,
  66              'rev'      => true,
  67              'name'     => true,
  68              'target'   => true,
  69              'download' => array(
  70                  'valueless' => 'y',
  71              ),
  72          ),
  73          'abbr'       => array(),
  74          'acronym'    => array(),
  75          'area'       => array(
  76              'alt'    => true,
  77              'coords' => true,
  78              'href'   => true,
  79              'nohref' => true,
  80              'shape'  => true,
  81              'target' => true,
  82          ),
  83          'article'    => array(
  84              'align'    => true,
  85              'dir'      => true,
  86              'lang'     => true,
  87              'xml:lang' => true,
  88          ),
  89          'aside'      => array(
  90              'align'    => true,
  91              'dir'      => true,
  92              'lang'     => true,
  93              'xml:lang' => true,
  94          ),
  95          'audio'      => array(
  96              'autoplay' => true,
  97              'controls' => true,
  98              'loop'     => true,
  99              'muted'    => true,
 100              'preload'  => true,
 101              'src'      => true,
 102          ),
 103          'b'          => array(),
 104          'bdo'        => array(
 105              'dir' => true,
 106          ),
 107          'big'        => array(),
 108          'blockquote' => array(
 109              'cite'     => true,
 110              'lang'     => true,
 111              'xml:lang' => true,
 112          ),
 113          'br'         => array(),
 114          'button'     => array(
 115              'disabled' => true,
 116              'name'     => true,
 117              'type'     => true,
 118              'value'    => true,
 119          ),
 120          'caption'    => array(
 121              'align' => true,
 122          ),
 123          'cite'       => array(
 124              'dir'  => true,
 125              'lang' => true,
 126          ),
 127          'code'       => array(),
 128          'col'        => array(
 129              'align'   => true,
 130              'char'    => true,
 131              'charoff' => true,
 132              'span'    => true,
 133              'dir'     => true,
 134              'valign'  => true,
 135              'width'   => true,
 136          ),
 137          'colgroup'   => array(
 138              'align'   => true,
 139              'char'    => true,
 140              'charoff' => true,
 141              'span'    => true,
 142              'valign'  => true,
 143              'width'   => true,
 144          ),
 145          'del'        => array(
 146              'datetime' => true,
 147          ),
 148          'dd'         => array(),
 149          'dfn'        => array(),
 150          'details'    => array(
 151              'align'    => true,
 152              'dir'      => true,
 153              'lang'     => true,
 154              'open'     => true,
 155              'xml:lang' => true,
 156          ),
 157          'div'        => array(
 158              'align'    => true,
 159              'dir'      => true,
 160              'lang'     => true,
 161              'xml:lang' => true,
 162          ),
 163          'dl'         => array(),
 164          'dt'         => array(),
 165          'em'         => array(),
 166          'fieldset'   => array(),
 167          'figure'     => array(
 168              'align'    => true,
 169              'dir'      => true,
 170              'lang'     => true,
 171              'xml:lang' => true,
 172          ),
 173          'figcaption' => array(
 174              'align'    => true,
 175              'dir'      => true,
 176              'lang'     => true,
 177              'xml:lang' => true,
 178          ),
 179          'font'       => array(
 180              'color' => true,
 181              'face'  => true,
 182              'size'  => true,
 183          ),
 184          'footer'     => array(
 185              'align'    => true,
 186              'dir'      => true,
 187              'lang'     => true,
 188              'xml:lang' => true,
 189          ),
 190          'h1'         => array(
 191              'align' => true,
 192          ),
 193          'h2'         => array(
 194              'align' => true,
 195          ),
 196          'h3'         => array(
 197              'align' => true,
 198          ),
 199          'h4'         => array(
 200              'align' => true,
 201          ),
 202          'h5'         => array(
 203              'align' => true,
 204          ),
 205          'h6'         => array(
 206              'align' => true,
 207          ),
 208          'header'     => array(
 209              'align'    => true,
 210              'dir'      => true,
 211              'lang'     => true,
 212              'xml:lang' => true,
 213          ),
 214          'hgroup'     => array(
 215              'align'    => true,
 216              'dir'      => true,
 217              'lang'     => true,
 218              'xml:lang' => true,
 219          ),
 220          'hr'         => array(
 221              'align'   => true,
 222              'noshade' => true,
 223              'size'    => true,
 224              'width'   => true,
 225          ),
 226          'i'          => array(),
 227          'img'        => array(
 228              'alt'      => true,
 229              'align'    => true,
 230              'border'   => true,
 231              'height'   => true,
 232              'hspace'   => true,
 233              'longdesc' => true,
 234              'vspace'   => true,
 235              'src'      => true,
 236              'usemap'   => true,
 237              'width'    => true,
 238          ),
 239          'ins'        => array(
 240              'datetime' => true,
 241              'cite'     => true,
 242          ),
 243          'kbd'        => array(),
 244          'label'      => array(
 245              'for' => true,
 246          ),
 247          'legend'     => array(
 248              'align' => true,
 249          ),
 250          'li'         => array(
 251              'align' => true,
 252              'value' => true,
 253          ),
 254          'map'        => array(
 255              'name' => true,
 256          ),
 257          'mark'       => array(),
 258          'menu'       => array(
 259              'type' => true,
 260          ),
 261          'nav'        => array(
 262              'align'    => true,
 263              'dir'      => true,
 264              'lang'     => true,
 265              'xml:lang' => true,
 266          ),
 267          'p'          => array(
 268              'align'    => true,
 269              'dir'      => true,
 270              'lang'     => true,
 271              'xml:lang' => true,
 272          ),
 273          'pre'        => array(
 274              'width' => true,
 275          ),
 276          'q'          => array(
 277              'cite' => true,
 278          ),
 279          's'          => array(),
 280          'samp'       => array(),
 281          'span'       => array(
 282              'dir'      => true,
 283              'align'    => true,
 284              'lang'     => true,
 285              'xml:lang' => true,
 286          ),
 287          'section'    => array(
 288              'align'    => true,
 289              'dir'      => true,
 290              'lang'     => true,
 291              'xml:lang' => true,
 292          ),
 293          'small'      => array(),
 294          'strike'     => array(),
 295          'strong'     => array(),
 296          'sub'        => array(),
 297          'summary'    => array(
 298              'align'    => true,
 299              'dir'      => true,
 300              'lang'     => true,
 301              'xml:lang' => true,
 302          ),
 303          'sup'        => array(),
 304          'table'      => array(
 305              'align'       => true,
 306              'bgcolor'     => true,
 307              'border'      => true,
 308              'cellpadding' => true,
 309              'cellspacing' => true,
 310              'dir'         => true,
 311              'rules'       => true,
 312              'summary'     => true,
 313              'width'       => true,
 314          ),
 315          'tbody'      => array(
 316              'align'   => true,
 317              'char'    => true,
 318              'charoff' => true,
 319              'valign'  => true,
 320          ),
 321          'td'         => array(
 322              'abbr'    => true,
 323              'align'   => true,
 324              'axis'    => true,
 325              'bgcolor' => true,
 326              'char'    => true,
 327              'charoff' => true,
 328              'colspan' => true,
 329              'dir'     => true,
 330              'headers' => true,
 331              'height'  => true,
 332              'nowrap'  => true,
 333              'rowspan' => true,
 334              'scope'   => true,
 335              'valign'  => true,
 336              'width'   => true,
 337          ),
 338          'textarea'   => array(
 339              'cols'     => true,
 340              'rows'     => true,
 341              'disabled' => true,
 342              'name'     => true,
 343              'readonly' => true,
 344          ),
 345          'tfoot'      => array(
 346              'align'   => true,
 347              'char'    => true,
 348              'charoff' => true,
 349              'valign'  => true,
 350          ),
 351          'th'         => array(
 352              'abbr'    => true,
 353              'align'   => true,
 354              'axis'    => true,
 355              'bgcolor' => true,
 356              'char'    => true,
 357              'charoff' => true,
 358              'colspan' => true,
 359              'headers' => true,
 360              'height'  => true,
 361              'nowrap'  => true,
 362              'rowspan' => true,
 363              'scope'   => true,
 364              'valign'  => true,
 365              'width'   => true,
 366          ),
 367          'thead'      => array(
 368              'align'   => true,
 369              'char'    => true,
 370              'charoff' => true,
 371              'valign'  => true,
 372          ),
 373          'title'      => array(),
 374          'tr'         => array(
 375              'align'   => true,
 376              'bgcolor' => true,
 377              'char'    => true,
 378              'charoff' => true,
 379              'valign'  => true,
 380          ),
 381          'track'      => array(
 382              'default' => true,
 383              'kind'    => true,
 384              'label'   => true,
 385              'src'     => true,
 386              'srclang' => true,
 387          ),
 388          'tt'         => array(),
 389          'u'          => array(),
 390          'ul'         => array(
 391              'type' => true,
 392          ),
 393          'ol'         => array(
 394              'start'    => true,
 395              'type'     => true,
 396              'reversed' => true,
 397          ),
 398          'var'        => array(),
 399          'video'      => array(
 400              'autoplay' => true,
 401              'controls' => true,
 402              'height'   => true,
 403              'loop'     => true,
 404              'muted'    => true,
 405              'poster'   => true,
 406              'preload'  => true,
 407              'src'      => true,
 408              'width'    => true,
 409          ),
 410      );
 411  
 412      /**
 413       * @var array[] $allowedtags Array of KSES allowed HTML elements.
 414       * @since 1.0.0
 415       */
 416      $allowedtags = array(
 417          'a'          => array(
 418              'href'  => true,
 419              'title' => true,
 420          ),
 421          'abbr'       => array(
 422              'title' => true,
 423          ),
 424          'acronym'    => array(
 425              'title' => true,
 426          ),
 427          'b'          => array(),
 428          'blockquote' => array(
 429              'cite' => true,
 430          ),
 431          'cite'       => array(),
 432          'code'       => array(),
 433          'del'        => array(
 434              'datetime' => true,
 435          ),
 436          'em'         => array(),
 437          'i'          => array(),
 438          'q'          => array(
 439              'cite' => true,
 440          ),
 441          's'          => array(),
 442          'strike'     => array(),
 443          'strong'     => array(),
 444      );
 445  
 446      /**
 447       * @var string[] $allowedentitynames Array of KSES allowed HTML entitity names.
 448       * @since 1.0.0
 449       */
 450      $allowedentitynames = array(
 451          'nbsp',
 452          'iexcl',
 453          'cent',
 454          'pound',
 455          'curren',
 456          'yen',
 457          'brvbar',
 458          'sect',
 459          'uml',
 460          'copy',
 461          'ordf',
 462          'laquo',
 463          'not',
 464          'shy',
 465          'reg',
 466          'macr',
 467          'deg',
 468          'plusmn',
 469          'acute',
 470          'micro',
 471          'para',
 472          'middot',
 473          'cedil',
 474          'ordm',
 475          'raquo',
 476          'iquest',
 477          'Agrave',
 478          'Aacute',
 479          'Acirc',
 480          'Atilde',
 481          'Auml',
 482          'Aring',
 483          'AElig',
 484          'Ccedil',
 485          'Egrave',
 486          'Eacute',
 487          'Ecirc',
 488          'Euml',
 489          'Igrave',
 490          'Iacute',
 491          'Icirc',
 492          'Iuml',
 493          'ETH',
 494          'Ntilde',
 495          'Ograve',
 496          'Oacute',
 497          'Ocirc',
 498          'Otilde',
 499          'Ouml',
 500          'times',
 501          'Oslash',
 502          'Ugrave',
 503          'Uacute',
 504          'Ucirc',
 505          'Uuml',
 506          'Yacute',
 507          'THORN',
 508          'szlig',
 509          'agrave',
 510          'aacute',
 511          'acirc',
 512          'atilde',
 513          'auml',
 514          'aring',
 515          'aelig',
 516          'ccedil',
 517          'egrave',
 518          'eacute',
 519          'ecirc',
 520          'euml',
 521          'igrave',
 522          'iacute',
 523          'icirc',
 524          'iuml',
 525          'eth',
 526          'ntilde',
 527          'ograve',
 528          'oacute',
 529          'ocirc',
 530          'otilde',
 531          'ouml',
 532          'divide',
 533          'oslash',
 534          'ugrave',
 535          'uacute',
 536          'ucirc',
 537          'uuml',
 538          'yacute',
 539          'thorn',
 540          'yuml',
 541          'quot',
 542          'amp',
 543          'lt',
 544          'gt',
 545          'apos',
 546          'OElig',
 547          'oelig',
 548          'Scaron',
 549          'scaron',
 550          'Yuml',
 551          'circ',
 552          'tilde',
 553          'ensp',
 554          'emsp',
 555          'thinsp',
 556          'zwnj',
 557          'zwj',
 558          'lrm',
 559          'rlm',
 560          'ndash',
 561          'mdash',
 562          'lsquo',
 563          'rsquo',
 564          'sbquo',
 565          'ldquo',
 566          'rdquo',
 567          'bdquo',
 568          'dagger',
 569          'Dagger',
 570          'permil',
 571          'lsaquo',
 572          'rsaquo',
 573          'euro',
 574          'fnof',
 575          'Alpha',
 576          'Beta',
 577          'Gamma',
 578          'Delta',
 579          'Epsilon',
 580          'Zeta',
 581          'Eta',
 582          'Theta',
 583          'Iota',
 584          'Kappa',
 585          'Lambda',
 586          'Mu',
 587          'Nu',
 588          'Xi',
 589          'Omicron',
 590          'Pi',
 591          'Rho',
 592          'Sigma',
 593          'Tau',
 594          'Upsilon',
 595          'Phi',
 596          'Chi',
 597          'Psi',
 598          'Omega',
 599          'alpha',
 600          'beta',
 601          'gamma',
 602          'delta',
 603          'epsilon',
 604          'zeta',
 605          'eta',
 606          'theta',
 607          'iota',
 608          'kappa',
 609          'lambda',
 610          'mu',
 611          'nu',
 612          'xi',
 613          'omicron',
 614          'pi',
 615          'rho',
 616          'sigmaf',
 617          'sigma',
 618          'tau',
 619          'upsilon',
 620          'phi',
 621          'chi',
 622          'psi',
 623          'omega',
 624          'thetasym',
 625          'upsih',
 626          'piv',
 627          'bull',
 628          'hellip',
 629          'prime',
 630          'Prime',
 631          'oline',
 632          'frasl',
 633          'weierp',
 634          'image',
 635          'real',
 636          'trade',
 637          'alefsym',
 638          'larr',
 639          'uarr',
 640          'rarr',
 641          'darr',
 642          'harr',
 643          'crarr',
 644          'lArr',
 645          'uArr',
 646          'rArr',
 647          'dArr',
 648          'hArr',
 649          'forall',
 650          'part',
 651          'exist',
 652          'empty',
 653          'nabla',
 654          'isin',
 655          'notin',
 656          'ni',
 657          'prod',
 658          'sum',
 659          'minus',
 660          'lowast',
 661          'radic',
 662          'prop',
 663          'infin',
 664          'ang',
 665          'and',
 666          'or',
 667          'cap',
 668          'cup',
 669          'int',
 670          'sim',
 671          'cong',
 672          'asymp',
 673          'ne',
 674          'equiv',
 675          'le',
 676          'ge',
 677          'sub',
 678          'sup',
 679          'nsub',
 680          'sube',
 681          'supe',
 682          'oplus',
 683          'otimes',
 684          'perp',
 685          'sdot',
 686          'lceil',
 687          'rceil',
 688          'lfloor',
 689          'rfloor',
 690          'lang',
 691          'rang',
 692          'loz',
 693          'spades',
 694          'clubs',
 695          'hearts',
 696          'diams',
 697          'sup1',
 698          'sup2',
 699          'sup3',
 700          'frac14',
 701          'frac12',
 702          'frac34',
 703          'there4',
 704      );
 705  
 706      $allowedposttags = array_map( '_wp_add_global_attributes', $allowedposttags );
 707  } else {
 708      $allowedtags     = wp_kses_array_lc( $allowedtags );
 709      $allowedposttags = wp_kses_array_lc( $allowedposttags );
 710  }
 711  
 712  /**
 713   * Filters text content and strips out disallowed HTML.
 714   *
 715   * This function makes sure that only the allowed HTML element names, attribute
 716   * names, attribute values, and HTML entities will occur in the given text string.
 717   *
 718   * This function expects unslashed data.
 719   *
 720   * @see wp_kses_post() for specifically filtering post content and fields.
 721   * @see wp_allowed_protocols() for the default allowed protocols in link URLs.
 722   *
 723   * @since 1.0.0
 724   *
 725   * @param string         $string            Text content to filter.
 726   * @param array[]|string $allowed_html      An array of allowed HTML elements and attributes, or a
 727   *                                          context name such as 'post'.
 728   * @param string[]       $allowed_protocols Array of allowed URL protocols.
 729   * @return string Filtered content containing only the allowed HTML.
 730   */
 731  function wp_kses( $string, $allowed_html, $allowed_protocols = array() ) {
 732      if ( empty( $allowed_protocols ) ) {
 733          $allowed_protocols = wp_allowed_protocols();
 734      }
 735      $string = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) );
 736      $string = wp_kses_normalize_entities( $string );
 737      $string = wp_kses_hook( $string, $allowed_html, $allowed_protocols );
 738      return wp_kses_split( $string, $allowed_html, $allowed_protocols );
 739  }
 740  
 741  /**
 742   * Filters one HTML attribute and ensures its value is allowed.
 743   *
 744   * This function can escape data in some situations where `wp_kses()` must strip the whole attribute.
 745   *
 746   * @since 4.2.3
 747   *
 748   * @param string $string  The 'whole' attribute, including name and value.
 749   * @param string $element The HTML element name to which the attribute belongs.
 750   * @return string Filtered attribute.
 751   */
 752  function wp_kses_one_attr( $string, $element ) {
 753      $uris              = wp_kses_uri_attributes();
 754      $allowed_html      = wp_kses_allowed_html( 'post' );
 755      $allowed_protocols = wp_allowed_protocols();
 756      $string            = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) );
 757  
 758      // Preserve leading and trailing whitespace.
 759      $matches = array();
 760      preg_match( '/^\s*/', $string, $matches );
 761      $lead = $matches[0];
 762      preg_match( '/\s*$/', $string, $matches );
 763      $trail = $matches[0];
 764      if ( empty( $trail ) ) {
 765          $string = substr( $string, strlen( $lead ) );
 766      } else {
 767          $string = substr( $string, strlen( $lead ), -strlen( $trail ) );
 768      }
 769  
 770      // Parse attribute name and value from input.
 771      $split = preg_split( '/\s*=\s*/', $string, 2 );
 772      $name  = $split[0];
 773      if ( count( $split ) == 2 ) {
 774          $value = $split[1];
 775  
 776          // Remove quotes surrounding $value.
 777          // Also guarantee correct quoting in $string for this one attribute.
 778          if ( '' == $value ) {
 779              $quote = '';
 780          } else {
 781              $quote = $value[0];
 782          }
 783          if ( '"' == $quote || "'" == $quote ) {
 784              if ( substr( $value, -1 ) != $quote ) {
 785                  return '';
 786              }
 787              $value = substr( $value, 1, -1 );
 788          } else {
 789              $quote = '"';
 790          }
 791  
 792          // Sanitize quotes, angle braces, and entities.
 793          $value = esc_attr( $value );
 794  
 795          // Sanitize URI values.
 796          if ( in_array( strtolower( $name ), $uris ) ) {
 797              $value = wp_kses_bad_protocol( $value, $allowed_protocols );
 798          }
 799  
 800          $string = "$name=$quote$value$quote";
 801          $vless  = 'n';
 802      } else {
 803          $value = '';
 804          $vless = 'y';
 805      }
 806  
 807      // Sanitize attribute by name.
 808      wp_kses_attr_check( $name, $value, $string, $vless, $element, $allowed_html );
 809  
 810      // Restore whitespace.
 811      return $lead . $string . $trail;
 812  }
 813  
 814  /**
 815   * Returns an array of allowed HTML tags and attributes for a given context.
 816   *
 817   * @since 3.5.0
 818   * @since 5.0.1 `form` removed as allowable HTML tag.
 819   *
 820   * @global array $allowedposttags
 821   * @global array $allowedtags
 822   * @global array $allowedentitynames
 823   *
 824   * @param string|array $context The context for which to retrieve tags. Allowed values are 'post',
 825   *                              'strip', 'data', 'entities', or the name of a field filter such as
 826   *                              'pre_user_description'.
 827   * @return array Array of allowed HTML tags and their allowed attributes.
 828   */
 829  function wp_kses_allowed_html( $context = '' ) {
 830      global $allowedposttags, $allowedtags, $allowedentitynames;
 831  
 832      if ( is_array( $context ) ) {
 833          /**
 834           * Filters the HTML that is allowed for a given context.
 835           *
 836           * @since 3.5.0
 837           *
 838           * @param array[]|string $context      Context to judge allowed tags by.
 839           * @param string         $context_type Context name.
 840           */
 841          return apply_filters( 'wp_kses_allowed_html', $context, 'explicit' );
 842      }
 843  
 844      switch ( $context ) {
 845          case 'post':
 846              /** This filter is documented in wp-includes/kses.php */
 847              $tags = apply_filters( 'wp_kses_allowed_html', $allowedposttags, $context );
 848  
 849              // 5.0.1 removed the `<form>` tag, allow it if a filter is allowing it's sub-elements `<input>` or `<select>`.
 850              if ( ! CUSTOM_TAGS && ! isset( $tags['form'] ) && ( isset( $tags['input'] ) || isset( $tags['select'] ) ) ) {
 851                  $tags = $allowedposttags;
 852  
 853                  $tags['form'] = array(
 854                      'action'         => true,
 855                      'accept'         => true,
 856                      'accept-charset' => true,
 857                      'enctype'        => true,
 858                      'method'         => true,
 859                      'name'           => true,
 860                      'target'         => true,
 861                  );
 862  
 863                  /** This filter is documented in wp-includes/kses.php */
 864                  $tags = apply_filters( 'wp_kses_allowed_html', $tags, $context );
 865              }
 866  
 867              return $tags;
 868  
 869          case 'user_description':
 870          case 'pre_user_description':
 871              $tags             = $allowedtags;
 872              $tags['a']['rel'] = true;
 873              /** This filter is documented in wp-includes/kses.php */
 874              return apply_filters( 'wp_kses_allowed_html', $tags, $context );
 875  
 876          case 'strip':
 877              /** This filter is documented in wp-includes/kses.php */
 878              return apply_filters( 'wp_kses_allowed_html', array(), $context );
 879  
 880          case 'entities':
 881              /** This filter is documented in wp-includes/kses.php */
 882              return apply_filters( 'wp_kses_allowed_html', $allowedentitynames, $context );
 883  
 884          case 'data':
 885          default:
 886              /** This filter is documented in wp-includes/kses.php */
 887              return apply_filters( 'wp_kses_allowed_html', $allowedtags, $context );
 888      }
 889  }
 890  
 891  /**
 892   * You add any KSES hooks here.
 893   *
 894   * There is currently only one KSES WordPress hook, {@see 'pre_kses'}, and it is called here.
 895   * All parameters are passed to the hooks and expected to receive a string.
 896   *
 897   * @since 1.0.0
 898   *
 899   * @param string          $string            Content to filter through KSES.
 900   * @param array[]|string  $allowed_html      List of allowed HTML elements.
 901   * @param string[]        $allowed_protocols Array of allowed URL protocols.
 902   * @return string Filtered content through {@see 'pre_kses'} hook.
 903   */
 904  function wp_kses_hook( $string, $allowed_html, $allowed_protocols ) {
 905      /**
 906       * Filters content to be run through kses.
 907       *
 908       * @since 2.3.0
 909       *
 910       * @param string          $string            Content to run through KSES.
 911       * @param array[]|string  $allowed_html      Allowed HTML elements.
 912       * @param string[]        $allowed_protocols Array of allowed URL protocols.
 913       */
 914      return apply_filters( 'pre_kses', $string, $allowed_html, $allowed_protocols );
 915  }
 916  
 917  /**
 918   * Returns the version number of KSES.
 919   *
 920   * @since 1.0.0
 921   *
 922   * @return string KSES version number.
 923   */
 924  function wp_kses_version() {
 925      return '0.2.2';
 926  }
 927  
 928  /**
 929   * Searches for HTML tags, no matter how malformed.
 930   *
 931   * It also matches stray `>` characters.
 932   *
 933   * @since 1.0.0
 934   *
 935   * @global array $pass_allowed_html
 936   * @global array $pass_allowed_protocols
 937   *
 938   * @param string   $string            Content to filter.
 939   * @param array    $allowed_html      Allowed HTML elements.
 940   * @param string[] $allowed_protocols Array of allowed URL protocols.
 941   * @return string Content with fixed HTML tags
 942   */
 943  function wp_kses_split( $string, $allowed_html, $allowed_protocols ) {
 944      global $pass_allowed_html, $pass_allowed_protocols;
 945      $pass_allowed_html      = $allowed_html;
 946      $pass_allowed_protocols = $allowed_protocols;
 947      return preg_replace_callback( '%(<!--.*?(-->|$))|(<[^>]*(>|$)|>)%', '_wp_kses_split_callback', $string );
 948  }
 949  
 950  /**
 951   * Helper function listing HTML attributes containing a URL.
 952   *
 953   * This function returns a list of all HTML attributes that must contain
 954   * a URL according to the HTML specification.
 955   *
 956   * This list includes URI attributes both allowed and disallowed by KSES.
 957   *
 958   * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
 959   *
 960   * @since 5.0.1
 961   *
 962   * @return array HTML attributes that must include a URL.
 963   */
 964  function wp_kses_uri_attributes() {
 965      $uri_attributes = array(
 966          'action',
 967          'archive',
 968          'background',
 969          'cite',
 970          'classid',
 971          'codebase',
 972          'data',
 973          'formaction',
 974          'href',
 975          'icon',
 976          'longdesc',
 977          'manifest',
 978          'poster',
 979          'profile',
 980          'src',
 981          'usemap',
 982          'xmlns',
 983      );
 984  
 985      /**
 986       * Filters the list of attributes that are required to contain a URL.
 987       *
 988       * Use this filter to add any `data-` attributes that are required to be
 989       * validated as a URL.
 990       *
 991       * @since 5.0.1
 992       *
 993       * @param array $uri_attributes HTML attributes requiring validation as a URL.
 994       */
 995      $uri_attributes = apply_filters( 'wp_kses_uri_attributes', $uri_attributes );
 996  
 997      return $uri_attributes;
 998  }
 999  
1000  /**
1001   * Callback for `wp_kses_split()`.
1002   *
1003   * @since 3.1.0
1004   * @access private
1005   * @ignore
1006   *
1007   * @global array $pass_allowed_html
1008   * @global array $pass_allowed_protocols
1009   *
1010   * @return string
1011   */
1012  function _wp_kses_split_callback( $match ) {
1013      global $pass_allowed_html, $pass_allowed_protocols;
1014      return wp_kses_split2( $match[0], $pass_allowed_html, $pass_allowed_protocols );
1015  }
1016  
1017  /**
1018   * Callback for `wp_kses_split()` for fixing malformed HTML tags.
1019   *
1020   * This function does a lot of work. It rejects some very malformed things like
1021   * `<:::>`. It returns an empty string, if the element isn't allowed (look ma, no
1022   * `strip_tags()`!). Otherwise it splits the tag into an element and an attribute
1023   * list.
1024   *
1025   * After the tag is split into an element and an attribute list, it is run
1026   * through another filter which will remove illegal attributes and once that is
1027   * completed, will be returned.
1028   *
1029   * @access private
1030   * @ignore
1031   * @since 1.0.0
1032   *
1033   * @param string   $string            Content to filter.
1034   * @param array    $allowed_html      Allowed HTML elements.
1035   * @param string[] $allowed_protocols Array of allowed URL protocols.
1036   * @return string Fixed HTML element
1037   */
1038  function wp_kses_split2( $string, $allowed_html, $allowed_protocols ) {
1039      $string = wp_kses_stripslashes( $string );
1040  
1041      // It matched a ">" character.
1042      if ( substr( $string, 0, 1 ) != '<' ) {
1043          return '&gt;';
1044      }
1045  
1046      // Allow HTML comments.
1047      if ( '<!--' == substr( $string, 0, 4 ) ) {
1048          $string = str_replace( array( '<!--', '-->' ), '', $string );
1049          while ( $string != ( $newstring = wp_kses( $string, $allowed_html, $allowed_protocols ) ) ) {
1050              $string = $newstring;
1051          }
1052          if ( $string == '' ) {
1053              return '';
1054          }
1055          // prevent multiple dashes in comments
1056          $string = preg_replace( '/--+/', '-', $string );
1057          // prevent three dashes closing a comment
1058          $string = preg_replace( '/-$/', '', $string );
1059          return "<!--{$string}-->";
1060      }
1061  
1062      // It's seriously malformed.
1063      if ( ! preg_match( '%^<\s*(/\s*)?([a-zA-Z0-9-]+)([^>]*)>?$%', $string, $matches ) ) {
1064          return '';
1065      }
1066  
1067      $slash    = trim( $matches[1] );
1068      $elem     = $matches[2];
1069      $attrlist = $matches[3];
1070  
1071      if ( ! is_array( $allowed_html ) ) {
1072          $allowed_html = wp_kses_allowed_html( $allowed_html );
1073      }
1074  
1075      // They are using a not allowed HTML element.
1076      if ( ! isset( $allowed_html[ strtolower( $elem ) ] ) ) {
1077          return '';
1078      }
1079  
1080      // No attributes are allowed for closing elements.
1081      if ( $slash != '' ) {
1082          return "</$elem>";
1083      }
1084  
1085      return wp_kses_attr( $elem, $attrlist, $allowed_html, $allowed_protocols );
1086  }
1087  
1088  /**
1089   * Removes all attributes, if none are allowed for this element.
1090   *
1091   * If some are allowed it calls `wp_kses_hair()` to split them further, and then
1092   * it builds up new HTML code from the data that `kses_hair()` returns. It also
1093   * removes `<` and `>` characters, if there are any left. One more thing it does
1094   * is to check if the tag has a closing XHTML slash, and if it does, it puts one
1095   * in the returned code as well.
1096   *
1097   * @since 1.0.0
1098   *
1099   * @param string   $element           HTML element/tag.
1100   * @param string   $attr              HTML attributes from HTML element to closing HTML element tag.
1101   * @param array    $allowed_html      Allowed HTML elements.
1102   * @param string[] $allowed_protocols Array of allowed URL protocols.
1103   * @return string Sanitized HTML element.
1104   */
1105  function wp_kses_attr( $element, $attr, $allowed_html, $allowed_protocols ) {
1106      if ( ! is_array( $allowed_html ) ) {
1107          $allowed_html = wp_kses_allowed_html( $allowed_html );
1108      }
1109  
1110      // Is there a closing XHTML slash at the end of the attributes?
1111      $xhtml_slash = '';
1112      if ( preg_match( '%\s*/\s*$%', $attr ) ) {
1113          $xhtml_slash = ' /';
1114      }
1115  
1116      // Are any attributes allowed at all for this element?
1117      $element_low = strtolower( $element );
1118      if ( empty( $allowed_html[ $element_low ] ) || true === $allowed_html[ $element_low ] ) {
1119          return "<$element$xhtml_slash>";
1120      }
1121  
1122      // Split it
1123      $attrarr = wp_kses_hair( $attr, $allowed_protocols );
1124  
1125      // Go through $attrarr, and save the allowed attributes for this element
1126      // in $attr2
1127      $attr2 = '';
1128      foreach ( $attrarr as $arreach ) {
1129          if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) {
1130              $attr2 .= ' ' . $arreach['whole'];
1131          }
1132      }
1133  
1134      // Remove any "<" or ">" characters
1135      $attr2 = preg_replace( '/[<>]/', '', $attr2 );
1136  
1137      return "<$element$attr2$xhtml_slash>";
1138  }
1139  
1140  /**
1141   * Determines whether an attribute is allowed.
1142   *
1143   * @since 4.2.3
1144   * @since 5.0.0 Add support for `data-*` wildcard attributes.
1145   *
1146   * @param string $name         The attribute name. Passed by reference. Returns empty string when not allowed.
1147   * @param string $value        The attribute value. Passed by reference. Returns a filtered value.
1148   * @param string $whole        The `name=value` input. Passed by reference. Returns filtered input.
1149   * @param string $vless        Whether the attribute is valueless. Use 'y' or 'n'.
1150   * @param string $element      The name of the element to which this attribute belongs.
1151   * @param array  $allowed_html The full list of allowed elements and attributes.
1152   * @return bool Whether or not the attribute is allowed.
1153   */
1154  function wp_kses_attr_check( &$name, &$value, &$whole, $vless, $element, $allowed_html ) {
1155      $allowed_attr = $allowed_html[ strtolower( $element ) ];
1156  
1157      $name_low = strtolower( $name );
1158      if ( ! isset( $allowed_attr[ $name_low ] ) || '' == $allowed_attr[ $name_low ] ) {
1159          /*
1160           * Allow `data-*` attributes.
1161           *
1162           * When specifying `$allowed_html`, the attribute name should be set as
1163           * `data-*` (not to be mixed with the HTML 4.0 `data` attribute, see
1164           * https://www.w3.org/TR/html40/struct/objects.html#adef-data).
1165           *
1166           * Note: the attribute name should only contain `A-Za-z0-9_-` chars,
1167           * double hyphens `--` are not accepted by WordPress.
1168           */
1169          if ( strpos( $name_low, 'data-' ) === 0 && ! empty( $allowed_attr['data-*'] ) && preg_match( '/^data(?:-[a-z0-9_]+)+$/', $name_low, $match ) ) {
1170              /*
1171               * Add the whole attribute name to the allowed attributes and set any restrictions
1172               * for the `data-*` attribute values for the current element.
1173               */
1174              $allowed_attr[ $match[0] ] = $allowed_attr['data-*'];
1175          } else {
1176              $name  = '';
1177              $value = '';
1178              $whole = '';
1179              return false;
1180          }
1181      }
1182  
1183      if ( 'style' == $name_low ) {
1184          $new_value = safecss_filter_attr( $value );
1185  
1186          if ( empty( $new_value ) ) {
1187              $name  = '';
1188              $value = '';
1189              $whole = '';
1190              return false;
1191          }
1192  
1193          $whole = str_replace( $value, $new_value, $whole );
1194          $value = $new_value;
1195      }
1196  
1197      if ( is_array( $allowed_attr[ $name_low ] ) ) {
1198          // there are some checks
1199          foreach ( $allowed_attr[ $name_low ] as $currkey => $currval ) {
1200              if ( ! wp_kses_check_attr_val( $value, $vless, $currkey, $currval ) ) {
1201                  $name  = '';
1202                  $value = '';
1203                  $whole = '';
1204                  return false;
1205              }
1206          }
1207      }
1208  
1209      return true;
1210  }
1211  
1212  /**
1213   * Builds an attribute list from string containing attributes.
1214   *
1215   * This function does a lot of work. It parses an attribute list into an array
1216   * with attribute data, and tries to do the right thing even if it gets weird
1217   * input. It will add quotes around attribute values that don't have any quotes
1218   * or apostrophes around them, to make it easier to produce HTML code that will
1219   * conform to W3C's HTML specification. It will also remove bad URL protocols
1220   * from attribute values. It also reduces duplicate attributes by using the
1221   * attribute defined first (`foo='bar' foo='baz'` will result in `foo='bar'`).
1222   *
1223   * @since 1.0.0
1224   *
1225   * @param string   $attr              Attribute list from HTML element to closing HTML element tag.
1226   * @param string[] $allowed_protocols Array of allowed URL protocols.
1227   * @return array[] Array of attribute information after parsing.
1228   */
1229  function wp_kses_hair( $attr, $allowed_protocols ) {
1230      $attrarr  = array();
1231      $mode     = 0;
1232      $attrname = '';
1233      $uris     = wp_kses_uri_attributes();
1234  
1235      // Loop through the whole attribute list
1236  
1237      while ( strlen( $attr ) != 0 ) {
1238          $working = 0; // Was the last operation successful?
1239  
1240          switch ( $mode ) {
1241              case 0:
1242                  if ( preg_match( '/^([-a-zA-Z:]+)/', $attr, $match ) ) {
1243                      $attrname = $match[1];
1244                      $working  = 1;
1245                      $mode     = 1;
1246                      $attr     = preg_replace( '/^[-a-zA-Z:]+/', '', $attr );
1247                  }
1248  
1249                  break;
1250  
1251              case 1:
1252                  if ( preg_match( '/^\s*=\s*/', $attr ) ) { // equals sign
1253                      $working = 1;
1254                      $mode    = 2;
1255                      $attr    = preg_replace( '/^\s*=\s*/', '', $attr );
1256                      break;
1257                  }
1258  
1259                  if ( preg_match( '/^\s+/', $attr ) ) { // valueless
1260                      $working = 1;
1261                      $mode    = 0;
1262                      if ( false === array_key_exists( $attrname, $attrarr ) ) {
1263                          $attrarr[ $attrname ] = array(
1264                              'name'  => $attrname,
1265                              'value' => '',
1266                              'whole' => $attrname,
1267                              'vless' => 'y',
1268                          );
1269                      }
1270                      $attr = preg_replace( '/^\s+/', '', $attr );
1271                  }
1272  
1273                  break;
1274  
1275              case 2:
1276                  if ( preg_match( '%^"([^"]*)"(\s+|/?$)%', $attr, $match ) ) {
1277                      // "value"
1278                      $thisval = $match[1];
1279                      if ( in_array( strtolower( $attrname ), $uris ) ) {
1280                          $thisval = wp_kses_bad_protocol( $thisval, $allowed_protocols );
1281                      }
1282  
1283                      if ( false === array_key_exists( $attrname, $attrarr ) ) {
1284                          $attrarr[ $attrname ] = array(
1285                              'name'  => $attrname,
1286                              'value' => $thisval,
1287                              'whole' => "$attrname=\"$thisval\"",
1288                              'vless' => 'n',
1289                          );
1290                      }
1291                      $working = 1;
1292                      $mode    = 0;
1293                      $attr    = preg_replace( '/^"[^"]*"(\s+|$)/', '', $attr );
1294                      break;
1295                  }
1296  
1297                  if ( preg_match( "%^'([^']*)'(\s+|/?$)%", $attr, $match ) ) {
1298                      // 'value'
1299                      $thisval = $match[1];
1300                      if ( in_array( strtolower( $attrname ), $uris ) ) {
1301                          $thisval = wp_kses_bad_protocol( $thisval, $allowed_protocols );
1302                      }
1303  
1304                      if ( false === array_key_exists( $attrname, $attrarr ) ) {
1305                          $attrarr[ $attrname ] = array(
1306                              'name'  => $attrname,
1307                              'value' => $thisval,
1308                              'whole' => "$attrname='$thisval'",
1309                              'vless' => 'n',
1310                          );
1311                      }
1312                      $working = 1;
1313                      $mode    = 0;
1314                      $attr    = preg_replace( "/^'[^']*'(\s+|$)/", '', $attr );
1315                      break;
1316                  }
1317  
1318                  if ( preg_match( "%^([^\s\"']+)(\s+|/?$)%", $attr, $match ) ) {
1319                      // value
1320                      $thisval = $match[1];
1321                      if ( in_array( strtolower( $attrname ), $uris ) ) {
1322                          $thisval = wp_kses_bad_protocol( $thisval, $allowed_protocols );
1323                      }
1324  
1325                      if ( false === array_key_exists( $attrname, $attrarr ) ) {
1326                          $attrarr[ $attrname ] = array(
1327                              'name'  => $attrname,
1328                              'value' => $thisval,
1329                              'whole' => "$attrname=\"$thisval\"",
1330                              'vless' => 'n',
1331                          );
1332                      }
1333                      // We add quotes to conform to W3C's HTML spec.
1334                      $working = 1;
1335                      $mode    = 0;
1336                      $attr    = preg_replace( "%^[^\s\"']+(\s+|$)%", '', $attr );
1337                  }
1338  
1339                  break;
1340          } // switch
1341  
1342          if ( $working == 0 ) { // not well formed, remove and try again
1343              $attr = wp_kses_html_error( $attr );
1344              $mode = 0;
1345          }
1346      } // while
1347  
1348      if ( $mode == 1 && false === array_key_exists( $attrname, $attrarr ) ) {
1349          // special case, for when the attribute list ends with a valueless
1350          // attribute like "selected"
1351          $attrarr[ $attrname ] = array(
1352              'name'  => $attrname,
1353              'value' => '',
1354              'whole' => $attrname,
1355              'vless' => 'y',
1356          );
1357      }
1358  
1359      return $attrarr;
1360  }
1361  
1362  /**
1363   * Finds all attributes of an HTML element.
1364   *
1365   * Does not modify input.  May return "evil" output.
1366   *
1367   * Based on `wp_kses_split2()` and `wp_kses_attr()`.
1368   *
1369   * @since 4.2.3
1370   *
1371   * @param string $element HTML element.
1372   * @return array|bool List of attributes found in the element. Returns false on failure.
1373   */
1374  function wp_kses_attr_parse( $element ) {
1375      $valid = preg_match( '%^(<\s*)(/\s*)?([a-zA-Z0-9]+\s*)([^>]*)(>?)$%', $element, $matches );
1376      if ( 1 !== $valid ) {
1377          return false;
1378      }
1379  
1380      $begin  = $matches[1];
1381      $slash  = $matches[2];
1382      $elname = $matches[3];
1383      $attr   = $matches[4];
1384      $end    = $matches[5];
1385  
1386      if ( '' !== $slash ) {
1387          // Closing elements do not get parsed.
1388          return false;
1389      }
1390  
1391      // Is there a closing XHTML slash at the end of the attributes?
1392      if ( 1 === preg_match( '%\s*/\s*$%', $attr, $matches ) ) {
1393          $xhtml_slash = $matches[0];
1394          $attr        = substr( $attr, 0, -strlen( $xhtml_slash ) );
1395      } else {
1396          $xhtml_slash = '';
1397      }
1398  
1399      // Split it
1400      $attrarr = wp_kses_hair_parse( $attr );
1401      if ( false === $attrarr ) {
1402          return false;
1403      }
1404  
1405      // Make sure all input is returned by adding front and back matter.
1406      array_unshift( $attrarr, $begin . $slash . $elname );
1407      array_push( $attrarr, $xhtml_slash . $end );
1408  
1409      return $attrarr;
1410  }
1411  
1412  /**
1413   * Builds an attribute list from string containing attributes.
1414   *
1415   * Does not modify input.  May return "evil" output.
1416   * In case of unexpected input, returns false instead of stripping things.
1417   *
1418   * Based on `wp_kses_hair()` but does not return a multi-dimensional array.
1419   *
1420   * @since 4.2.3
1421   *
1422   * @param string $attr Attribute list from HTML element to closing HTML element tag.
1423   * @return array|bool List of attributes found in $attr. Returns false on failure.
1424   */
1425  function wp_kses_hair_parse( $attr ) {
1426      if ( '' === $attr ) {
1427          return array();
1428      }
1429  
1430      // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
1431      $regex =
1432      '(?:'
1433      .     '[-a-zA-Z:]+'   // Attribute name.
1434      . '|'
1435      .     '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html.
1436      . ')'
1437      . '(?:'               // Attribute value.
1438      .     '\s*=\s*'       // All values begin with '='
1439      .     '(?:'
1440      .         '"[^"]*"'   // Double-quoted
1441      .     '|'
1442      .         "'[^']*'"   // Single-quoted
1443      .     '|'
1444      .         '[^\s"\']+' // Non-quoted
1445      .         '(?:\s|$)'  // Must have a space
1446      .     ')'
1447      . '|'
1448      .     '(?:\s|$)'      // If attribute has no value, space is required.
1449      . ')'
1450      . '\s*';              // Trailing space is optional except as mentioned above.
1451      // phpcs:enable
1452  
1453      // Although it is possible to reduce this procedure to a single regexp,
1454      // we must run that regexp twice to get exactly the expected result.
1455  
1456      $validation = "%^($regex)+$%";
1457      $extraction = "%$regex%";
1458  
1459      if ( 1 === preg_match( $validation, $attr ) ) {
1460          preg_match_all( $extraction, $attr, $attrarr );
1461          return $attrarr[0];
1462      } else {
1463          return false;
1464      }
1465  }
1466  
1467  /**
1468   * Performs different checks for attribute values.
1469   *
1470   * The currently implemented checks are "maxlen", "minlen", "maxval", "minval",
1471   * and "valueless".
1472   *
1473   * @since 1.0.0
1474   *
1475   * @param string $value      Attribute value.
1476   * @param string $vless      Whether the attribute is valueless. Use 'y' or 'n'.
1477   * @param string $checkname  What $checkvalue is checking for.
1478   * @param mixed  $checkvalue What constraint the value should pass.
1479   * @return bool Whether check passes.
1480   */
1481  function wp_kses_check_attr_val( $value, $vless, $checkname, $checkvalue ) {
1482      $ok = true;
1483  
1484      switch ( strtolower( $checkname ) ) {
1485          case 'maxlen':
1486              // The maxlen check makes sure that the attribute value has a length not
1487              // greater than the given value. This can be used to avoid Buffer Overflows
1488              // in WWW clients and various Internet servers.
1489  
1490              if ( strlen( $value ) > $checkvalue ) {
1491                  $ok = false;
1492              }
1493              break;
1494  
1495          case 'minlen':
1496              // The minlen check makes sure that the attribute value has a length not
1497              // smaller than the given value.
1498  
1499              if ( strlen( $value ) < $checkvalue ) {
1500                  $ok = false;
1501              }
1502              break;
1503  
1504          case 'maxval':
1505              // The maxval check does two things: it checks that the attribute value is
1506              // an integer from 0 and up, without an excessive amount of zeroes or
1507              // whitespace (to avoid Buffer Overflows). It also checks that the attribute
1508              // value is not greater than the given value.
1509              // This check can be used to avoid Denial of Service attacks.
1510  
1511              if ( ! preg_match( '/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value ) ) {
1512                  $ok = false;
1513              }
1514              if ( $value > $checkvalue ) {
1515                  $ok = false;
1516              }
1517              break;
1518  
1519          case 'minval':
1520              // The minval check makes sure that the attribute value is a positive integer,
1521              // and that it is not smaller than the given value.
1522  
1523              if ( ! preg_match( '/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value ) ) {
1524                  $ok = false;
1525              }
1526              if ( $value < $checkvalue ) {
1527                  $ok = false;
1528              }
1529              break;
1530  
1531          case 'valueless':
1532              // The valueless check makes sure if the attribute has a value
1533              // (like `<a href="blah">`) or not (`<option selected>`). If the given value
1534              // is a "y" or a "Y", the attribute must not have a value.
1535              // If the given value is an "n" or an "N", the attribute must have a value.
1536  
1537              if ( strtolower( $checkvalue ) != $vless ) {
1538                  $ok = false;
1539              }
1540              break;
1541      } // switch
1542  
1543      return $ok;
1544  }
1545  
1546  /**
1547   * Sanitizes a string and removed disallowed URL protocols.
1548   *
1549   * This function removes all non-allowed protocols from the beginning of the
1550   * string. It ignores whitespace and the case of the letters, and it does
1551   * understand HTML entities. It does its work recursively, so it won't be
1552   * fooled by a string like `javascript:javascript:alert(57)`.
1553   *
1554   * @since 1.0.0
1555   *
1556   * @param string   $string            Content to filter bad protocols from.
1557   * @param string[] $allowed_protocols Array of allowed URL protocols.
1558   * @return string Filtered content.
1559   */
1560  function wp_kses_bad_protocol( $string, $allowed_protocols ) {
1561      $string     = wp_kses_no_null( $string );
1562      $iterations = 0;
1563  
1564      do {
1565          $original_string = $string;
1566          $string          = wp_kses_bad_protocol_once( $string, $allowed_protocols );
1567      } while ( $original_string != $string && ++$iterations < 6 );
1568  
1569      if ( $original_string != $string ) {
1570          return '';
1571      }
1572  
1573      return $string;
1574  }
1575  
1576  /**
1577   * Removes any invalid control characters in a text string.
1578   *
1579   * Also removes any instance of the `\0` string.
1580   *
1581   * @since 1.0.0
1582   *
1583   * @param string $string  Content to filter null characters from.
1584   * @param array  $options Set 'slash_zero' => 'keep' when '\0' is allowed. Default is 'remove'.
1585   * @return string Filtered content.
1586   */
1587  function wp_kses_no_null( $string, $options = null ) {
1588      if ( ! isset( $options['slash_zero'] ) ) {
1589          $options = array( 'slash_zero' => 'remove' );
1590      }
1591  
1592      $string = preg_replace( '/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $string );
1593      if ( 'remove' == $options['slash_zero'] ) {
1594          $string = preg_replace( '/\\\\+0+/', '', $string );
1595      }
1596  
1597      return $string;
1598  }
1599  
1600  /**
1601   * Strips slashes from in front of quotes.
1602   *
1603   * This function changes the character sequence `\"` to just `"`. It leaves all other
1604   * slashes alone. The quoting from `preg_replace(//e)` requires this.
1605   *
1606   * @since 1.0.0
1607   *
1608   * @param string $string String to strip slashes from.
1609   * @return string Fixed string with quoted slashes.
1610   */
1611  function wp_kses_stripslashes( $string ) {
1612      return preg_replace( '%\\\\"%', '"', $string );
1613  }
1614  
1615  /**
1616   * Converts the keys of an array to lowercase.
1617   *
1618   * @since 1.0.0
1619   *
1620   * @param array $inarray Unfiltered array.
1621   * @return array Fixed array with all lowercase keys.
1622   */
1623  function wp_kses_array_lc( $inarray ) {
1624      $outarray = array();
1625  
1626      foreach ( (array) $inarray as $inkey => $inval ) {
1627          $outkey              = strtolower( $inkey );
1628          $outarray[ $outkey ] = array();
1629  
1630          foreach ( (array) $inval as $inkey2 => $inval2 ) {
1631              $outkey2                         = strtolower( $inkey2 );
1632              $outarray[ $outkey ][ $outkey2 ] = $inval2;
1633          }
1634      }
1635  
1636      return $outarray;
1637  }
1638  
1639  /**
1640   * Handles parsing errors in `wp_kses_hair()`.
1641   *
1642   * The general plan is to remove everything to and including some whitespace,
1643   * but it deals with quotes and apostrophes as well.
1644   *
1645   * @since 1.0.0
1646   *
1647   * @param string $string
1648   * @return string
1649   */
1650  function wp_kses_html_error( $string ) {
1651      return preg_replace( '/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string );
1652  }
1653  
1654  /**
1655   * Sanitizes content from bad protocols and other characters.
1656   *
1657   * This function searches for URL protocols at the beginning of the string, while
1658   * handling whitespace and HTML entities.
1659   *
1660   * @since 1.0.0
1661   *
1662   * @param string   $string            Content to check for bad protocols.
1663   * @param string[] $allowed_protocols Array of allowed URL protocols.
1664   * @return string Sanitized content.
1665   */
1666  function wp_kses_bad_protocol_once( $string, $allowed_protocols, $count = 1 ) {
1667      $string  = preg_replace( '/(&#0*58(?![;0-9])|&#x0*3a(?![;a-f0-9]))/i', '$1;', $string );
1668      $string2 = preg_split( '/:|&#0*58;|&#x0*3a;/i', $string, 2 );
1669      if ( isset( $string2[1] ) && ! preg_match( '%/\?%', $string2[0] ) ) {
1670          $string   = trim( $string2[1] );
1671          $protocol = wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols );
1672          if ( 'feed:' == $protocol ) {
1673              if ( $count > 2 ) {
1674                  return '';
1675              }
1676              $string = wp_kses_bad_protocol_once( $string, $allowed_protocols, ++$count );
1677              if ( empty( $string ) ) {
1678                  return $string;
1679              }
1680          }
1681          $string = $protocol . $string;
1682      }
1683  
1684      return $string;
1685  }
1686  
1687  /**
1688   * Callback for `wp_kses_bad_protocol_once()` regular expression.
1689   *
1690   * This function processes URL protocols, checks to see if they're in the
1691   * whitelist or not, and returns different data depending on the answer.
1692   *
1693   * @access private
1694   * @ignore
1695   * @since 1.0.0
1696   *
1697   * @param string   $string            URI scheme to check against the whitelist.
1698   * @param string[] $allowed_protocols Array of allowed URL protocols.
1699   * @return string Sanitized content.
1700   */
1701  function wp_kses_bad_protocol_once2( $string, $allowed_protocols ) {
1702      $string2 = wp_kses_decode_entities( $string );
1703      $string2 = preg_replace( '/\s/', '', $string2 );
1704      $string2 = wp_kses_no_null( $string2 );
1705      $string2 = strtolower( $string2 );
1706  
1707      $allowed = false;
1708      foreach ( (array) $allowed_protocols as $one_protocol ) {
1709          if ( strtolower( $one_protocol ) == $string2 ) {
1710              $allowed = true;
1711              break;
1712          }
1713      }
1714  
1715      if ( $allowed ) {
1716          return "$string2:";
1717      } else {
1718          return '';
1719      }
1720  }
1721  
1722  /**
1723   * Converts and fixes HTML entities.
1724   *
1725   * This function normalizes HTML entities. It will convert `AT&T` to the correct
1726   * `AT&amp;T`, `&#00058;` to `&#58;`, `&#XYZZY;` to `&amp;#XYZZY;` and so on.
1727   *
1728   * @since 1.0.0
1729   *
1730   * @param string $string Content to normalize entities.
1731   * @return string Content with normalized entities.
1732   */
1733  function wp_kses_normalize_entities( $string ) {
1734      // Disarm all entities by converting & to &amp;
1735      $string = str_replace( '&', '&amp;', $string );
1736  
1737      // Change back the allowed entities in our entity whitelist
1738      $string = preg_replace_callback( '/&amp;([A-Za-z]{2,8}[0-9]{0,2});/', 'wp_kses_named_entities', $string );
1739      $string = preg_replace_callback( '/&amp;#(0*[0-9]{1,7});/', 'wp_kses_normalize_entities2', $string );
1740      $string = preg_replace_callback( '/&amp;#[Xx](0*[0-9A-Fa-f]{1,6});/', 'wp_kses_normalize_entities3', $string );
1741  
1742      return $string;
1743  }
1744  
1745  /**
1746   * Callback for `wp_kses_normalize_entities()` regular expression.
1747   *
1748   * This function only accepts valid named entity references, which are finite,
1749   * case-sensitive, and highly scrutinized by HTML and XML validators.
1750   *
1751   * @since 3.0.0
1752   *
1753   * @global array $allowedentitynames
1754   *
1755   * @param array $matches preg_replace_callback() matches array.
1756   * @return string Correctly encoded entity.
1757   */
1758  function wp_kses_named_entities( $matches ) {
1759      global $allowedentitynames;
1760  
1761      if ( empty( $matches[1] ) ) {
1762          return '';
1763      }
1764  
1765      $i = $matches[1];
1766      return ( ! in_array( $i, $allowedentitynames ) ) ? "&amp;$i;" : "&$i;";
1767  }
1768  
1769  /**
1770   * Callback for `wp_kses_normalize_entities()` regular expression.
1771   *
1772   * This function helps `wp_kses_normalize_entities()` to only accept 16-bit
1773   * values and nothing more for `&#number;` entities.
1774   *
1775   * @access private
1776   * @ignore
1777   * @since 1.0.0
1778   *
1779   * @param array $matches `preg_replace_callback()` matches array.
1780   * @return string Correctly encoded entity.
1781   */
1782  function wp_kses_normalize_entities2( $matches ) {
1783      if ( empty( $matches[1] ) ) {
1784          return '';
1785      }
1786  
1787      $i = $matches[1];
1788      if ( valid_unicode( $i ) ) {
1789          $i = str_pad( ltrim( $i, '0' ), 3, '0', STR_PAD_LEFT );
1790          $i = "&#$i;";
1791      } else {
1792          $i = "&amp;#$i;";
1793      }
1794  
1795      return $i;
1796  }
1797  
1798  /**
1799   * Callback for `wp_kses_normalize_entities()` for regular expression.
1800   *
1801   * This function helps `wp_kses_normalize_entities()` to only accept valid Unicode
1802   * numeric entities in hex form.
1803   *
1804   * @since 2.7.0
1805   * @access private
1806   * @ignore
1807   *
1808   * @param array $matches `preg_replace_callback()` matches array.
1809   * @return string Correctly encoded entity.
1810   */
1811  function wp_kses_normalize_entities3( $matches ) {
1812      if ( empty( $matches[1] ) ) {
1813          return '';
1814      }
1815  
1816      $hexchars = $matches[1];
1817      return ( ! valid_unicode( hexdec( $hexchars ) ) ) ? "&amp;#x$hexchars;" : '&#x' . ltrim( $hexchars, '0' ) . ';';
1818  }
1819  
1820  /**
1821   * Determines if a Unicode codepoint is valid.
1822   *
1823   * @since 2.7.0
1824   *
1825   * @param int $i Unicode codepoint.
1826   * @return bool Whether or not the codepoint is a valid Unicode codepoint.
1827   */
1828  function valid_unicode( $i ) {
1829      return ( $i == 0x9 || $i == 0xa || $i == 0xd ||
1830              ( $i >= 0x20 && $i <= 0xd7ff ) ||
1831              ( $i >= 0xe000 && $i <= 0xfffd ) ||
1832              ( $i >= 0x10000 && $i <= 0x10ffff ) );
1833  }
1834  
1835  /**
1836   * Converts all numeric HTML entities to their named counterparts.
1837   *
1838   * This function decodes numeric HTML entities (`&#65;` and `&#x41;`).
1839   * It doesn't do anything with named entities like `&auml;`, but we don't
1840   * need them in the URL protocol whitelisting system anyway.
1841   *
1842   * @since 1.0.0
1843   *
1844   * @param string $string Content to change entities.
1845   * @return string Content after decoded entities.
1846   */
1847  function wp_kses_decode_entities( $string ) {
1848      $string = preg_replace_callback( '/&#([0-9]+);/', '_wp_kses_decode_entities_chr', $string );
1849      $string = preg_replace_callback( '/&#[Xx]([0-9A-Fa-f]+);/', '_wp_kses_decode_entities_chr_hexdec', $string );
1850  
1851      return $string;
1852  }
1853  
1854  /**
1855   * Regex callback for `wp_kses_decode_entities()`.
1856   *
1857   * @since 2.9.0
1858   * @access private
1859   * @ignore
1860   *
1861   * @param array $match preg match
1862   * @return string
1863   */
1864  function _wp_kses_decode_entities_chr( $match ) {
1865      return chr( $match[1] );
1866  }
1867  
1868  /**
1869   * Regex callback for `wp_kses_decode_entities()`.
1870   *
1871   * @since 2.9.0
1872   * @access private
1873   * @ignore
1874   *
1875   * @param array $match preg match
1876   * @return string
1877   */
1878  function _wp_kses_decode_entities_chr_hexdec( $match ) {
1879      return chr( hexdec( $match[1] ) );
1880  }
1881  
1882  /**
1883   * Sanitize content with allowed HTML KSES rules.
1884   *
1885   * This function expects slashed data.
1886   *
1887   * @since 1.0.0
1888   *
1889   * @param string $data Content to filter, expected to be escaped with slashes.
1890   * @return string Filtered content.
1891   */
1892  function wp_filter_kses( $data ) {
1893      return addslashes( wp_kses( stripslashes( $data ), current_filter() ) );
1894  }
1895  
1896  /**
1897   * Sanitize content with allowed HTML KSES rules.
1898   *
1899   * This function expects unslashed data.
1900   *
1901   * @since 2.9.0
1902   *
1903   * @param string $data Content to filter, expected to not be escaped.
1904   * @return string Filtered content.
1905   */
1906  function wp_kses_data( $data ) {
1907      return wp_kses( $data, current_filter() );
1908  }
1909  
1910  /**
1911   * Sanitizes content for allowed HTML tags for post content.
1912   *
1913   * Post content refers to the page contents of the 'post' type and not `$_POST`
1914   * data from forms.
1915   *
1916   * This function expects slashed data.
1917   *
1918   * @since 2.0.0
1919   *
1920   * @param string $data Post content to filter, expected to be escaped with slashes.
1921   * @return string Filtered post content with allowed HTML tags and attributes intact.
1922   */
1923  function wp_filter_post_kses( $data ) {
1924      return addslashes( wp_kses( stripslashes( $data ), 'post' ) );
1925  }
1926  
1927  /**
1928   * Sanitizes content for allowed HTML tags for post content.
1929   *
1930   * Post content refers to the page contents of the 'post' type and not `$_POST`
1931   * data from forms.
1932   *
1933   * This function expects unslashed data.
1934   *
1935   * @since 2.9.0
1936   *
1937   * @param string $data Post content to filter.
1938   * @return string Filtered post content with allowed HTML tags and attributes intact.
1939   */
1940  function wp_kses_post( $data ) {
1941      return wp_kses( $data, 'post' );
1942  }
1943  
1944  /**
1945   * Navigates through an array, object, or scalar, and sanitizes content for
1946   * allowed HTML tags for post content.
1947   *
1948   * @since 4.4.2
1949   *
1950   * @see map_deep()
1951   *
1952   * @param mixed $data The array, object, or scalar value to inspect.
1953   * @return mixed The filtered content.
1954   */
1955  function wp_kses_post_deep( $data ) {
1956      return map_deep( $data, 'wp_kses_post' );
1957  }
1958  
1959  /**
1960   * Strips all HTML from a text string.
1961   *
1962   * This function expects slashed data.
1963   *
1964   * @since 2.1.0
1965   *
1966   * @param string $data Content to strip all HTML from.
1967   * @return string Filtered content without any HTML.
1968   */
1969  function wp_filter_nohtml_kses( $data ) {
1970      return addslashes( wp_kses( stripslashes( $data ), 'strip' ) );
1971  }
1972  
1973  /**
1974   * Adds all KSES input form content filters.
1975   *
1976   * All hooks have default priority. The `wp_filter_kses()` function is added to
1977   * the 'pre_comment_content' and 'title_save_pre' hooks.
1978   *
1979   * The `wp_filter_post_kses()` function is added to the 'content_save_pre',
1980   * 'excerpt_save_pre', and 'content_filtered_save_pre' hooks.
1981   *
1982   * @since 2.0.0
1983   */
1984  function kses_init_filters() {
1985      // Normal filtering
1986      add_filter( 'title_save_pre', 'wp_filter_kses' );
1987  
1988      // Comment filtering
1989      if ( current_user_can( 'unfiltered_html' ) ) {
1990          add_filter( 'pre_comment_content', 'wp_filter_post_kses' );
1991      } else {
1992          add_filter( 'pre_comment_content', 'wp_filter_kses' );
1993      }
1994  
1995      // Post filtering
1996      add_filter( 'content_save_pre', 'wp_filter_post_kses' );
1997      add_filter( 'excerpt_save_pre', 'wp_filter_post_kses' );
1998      add_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
1999  }
2000  
2001  /**
2002   * Removes all KSES input form content filters.
2003   *
2004   * A quick procedural method to removing all of the filters that KSES uses for
2005   * content in WordPress Loop.
2006   *
2007   * Does not remove the `kses_init()` function from {@see 'init'} hook (priority is
2008   * default). Also does not remove `kses_init()` function from {@see 'set_current_user'}
2009   * hook (priority is also default).
2010   *
2011   * @since 2.0.6
2012   */
2013  function kses_remove_filters() {
2014      // Normal filtering
2015      remove_filter( 'title_save_pre', 'wp_filter_kses' );
2016  
2017      // Comment filtering
2018      remove_filter( 'pre_comment_content', 'wp_filter_post_kses' );
2019      remove_filter( 'pre_comment_content', 'wp_filter_kses' );
2020  
2021      // Post filtering
2022      remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
2023      remove_filter( 'excerpt_save_pre', 'wp_filter_post_kses' );
2024      remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
2025  }
2026  
2027  /**
2028   * Sets up most of the KSES filters for input form content.
2029   *
2030   * First removes all of the KSES filters in case the current user does not need
2031   * to have KSES filter the content. If the user does not have `unfiltered_html`
2032   * capability, then KSES filters are added.
2033   *
2034   * @since 2.0.0
2035   */
2036  function kses_init() {
2037      kses_remove_filters();
2038  
2039      if ( ! current_user_can( 'unfiltered_html' ) ) {
2040          kses_init_filters();
2041      }
2042  }
2043  
2044  /**
2045   * Filters an inline style attribute and removes disallowed rules.
2046   *
2047   * @since 2.8.1
2048   *
2049   * @param string $css        A string of CSS rules.
2050   * @param string $deprecated Not used.
2051   * @return string Filtered string of CSS rules.
2052   */
2053  function safecss_filter_attr( $css, $deprecated = '' ) {
2054      if ( ! empty( $deprecated ) ) {
2055          _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented
2056      }
2057  
2058      $css = wp_kses_no_null( $css );
2059      $css = str_replace( array( "\n", "\r", "\t" ), '', $css );
2060  
2061      $allowed_protocols = wp_allowed_protocols();
2062  
2063      $css_array = explode( ';', trim( $css ) );
2064  
2065      /**
2066       * Filters list of allowed CSS attributes.
2067       *
2068       * @since 2.8.1
2069       * @since 4.4.0 Added support for `min-height`, `max-height`, `min-width`, and `max-width`.
2070       * @since 4.6.0 Added support for `list-style-type`.
2071       * @since 5.0.0 Added support for `background-image`.
2072       * @since 5.1.0 Added support for `text-transform`.
2073       * @since 5.2.0 Added support for `background-position` and `grid-template-columns`
2074       * @since 5.3.0 Added support for `grid`, `flex` and `column` layout properties.
2075       *              Extend `background-*` support of individual properties.
2076       *
2077       * @param string[] $attr Array of allowed CSS attributes.
2078       */
2079      $allowed_attr = apply_filters(
2080          'safe_style_css',
2081          array(
2082              'background',
2083              'background-color',
2084              'background-image',
2085              'background-position',
2086              'background-size',
2087              'background-attachment',
2088              'background-blend-mode',
2089  
2090              'border',
2091              'border-radius',
2092              'border-width',
2093              'border-color',
2094              'border-style',
2095              'border-right',
2096              'border-right-color',
2097              'border-right-style',
2098              'border-right-width',
2099              'border-bottom',
2100              'border-bottom-color',
2101              'border-bottom-style',
2102              'border-bottom-width',
2103              'border-left',
2104              'border-left-color',
2105              'border-left-style',
2106              'border-left-width',
2107              'border-top',
2108              'border-top-color',
2109              'border-top-style',
2110              'border-top-width',
2111  
2112              'border-spacing',
2113              'border-collapse',
2114              'caption-side',
2115  
2116              'columns',
2117              'column-count',
2118              'column-fill',
2119              'column-gap',
2120              'column-rule',
2121              'column-span',
2122              'column-width',
2123  
2124              'color',
2125              'font',
2126              'font-family',
2127              'font-size',
2128              'font-style',
2129              'font-variant',
2130              'font-weight',
2131              'letter-spacing',
2132              'line-height',
2133              'text-align',
2134              'text-decoration',
2135              'text-indent',
2136              'text-transform',
2137  
2138              'height',
2139              'min-height',
2140              'max-height',
2141  
2142              'width',
2143              'min-width',
2144              'max-width',
2145  
2146              'margin',
2147              'margin-right',
2148              'margin-bottom',
2149              'margin-left',
2150              'margin-top',
2151  
2152              'padding',
2153              'padding-right',
2154              'padding-bottom',
2155              'padding-left',
2156              'padding-top',
2157  
2158              'flex',
2159              'flex-basis',
2160              'flex-direction',
2161              'flex-flow',
2162              'flex-grow',
2163              'flex-shrink',
2164  
2165              'grid-template-columns',
2166              'grid-auto-columns',
2167              'grid-column-start',
2168              'grid-column-end',
2169              'grid-column-gap',
2170              'grid-template-rows',
2171              'grid-auto-rows',
2172              'grid-row-start',
2173              'grid-row-end',
2174              'grid-row-gap',
2175              'grid-gap',
2176  
2177              'justify-content',
2178              'justify-items',
2179              'justify-self',
2180              'align-content',
2181              'align-items',
2182              'align-self',
2183  
2184              'clear',
2185              'cursor',
2186              'direction',
2187              'float',
2188              'overflow',
2189              'vertical-align',
2190              'list-style-type',
2191          )
2192      );
2193  
2194      /*
2195       * CSS attributes that accept URL data types.
2196       *
2197       * This is in accordance to the CSS spec and unrelated to
2198       * the sub-set of supported attributes above.
2199       *
2200       * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url
2201       */
2202      $css_url_data_types = array(
2203          'background',
2204          'background-image',
2205  
2206          'cursor',
2207  
2208          'list-style',
2209          'list-style-image',
2210      );
2211  
2212      if ( empty( $allowed_attr ) ) {
2213          return $css;
2214      }
2215  
2216      $css = '';
2217      foreach ( $css_array as $css_item ) {
2218          if ( $css_item == '' ) {
2219              continue;
2220          }
2221  
2222          $css_item        = trim( $css_item );
2223          $css_test_string = $css_item;
2224          $found           = false;
2225          $url_attr        = false;
2226  
2227          if ( strpos( $css_item, ':' ) === false ) {
2228              $found = true;
2229          } else {
2230              $parts        = explode( ':', $css_item, 2 );
2231              $css_selector = trim( $parts[0] );
2232  
2233              if ( in_array( $css_selector, $allowed_attr, true ) ) {
2234                  $found    = true;
2235                  $url_attr = in_array( $css_selector, $css_url_data_types, true );
2236              }
2237          }
2238  
2239          if ( $found && $url_attr ) {
2240              // Simplified: matches the sequence `url(*)`.
2241              preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches );
2242  
2243              foreach ( $url_matches[0] as $url_match ) {
2244                  // Clean up the URL from each of the matches above.
2245                  preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces );
2246  
2247                  if ( empty( $url_pieces[2] ) ) {
2248                      $found = false;
2249                      break;
2250                  }
2251  
2252                  $url = trim( $url_pieces[2] );
2253  
2254                  if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url, $allowed_protocols ) ) {
2255                      $found = false;
2256                      break;
2257                  } else {
2258                      // Remove the whole `url(*)` bit that was matched above from the CSS.
2259                      $css_test_string = str_replace( $url_match, '', $css_test_string );
2260                  }
2261              }
2262          }
2263  
2264          // Remove any CSS containing containing \ ( & } = or comments, except for url() useage checked above.
2265          if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) {
2266              if ( $css != '' ) {
2267                  $css .= ';';
2268              }
2269  
2270              $css .= $css_item;
2271          }
2272      }
2273  
2274      return $css;
2275  }
2276  
2277  /**
2278   * Helper function to add global attributes to a tag in the allowed html list.
2279   *
2280   * @since 3.5.0
2281   * @since 5.0.0 Add support for `data-*` wildcard attributes.
2282   * @access private
2283   * @ignore
2284   *
2285   * @param array $value An array of attributes.
2286   * @return array The array of attributes with global attributes added.
2287   */
2288  function _wp_add_global_attributes( $value ) {
2289      $global_attributes = array(
2290          'aria-describedby' => true,
2291          'aria-details'     => true,
2292          'aria-label'       => true,
2293          'aria-labelledby'  => true,
2294          'aria-hidden'      => true,
2295          'class'            => true,
2296          'id'               => true,
2297          'style'            => true,
2298          'title'            => true,
2299          'role'             => true,
2300          'data-*'           => true,
2301      );
2302  
2303      if ( true === $value ) {
2304          $value = array();
2305      }
2306  
2307      if ( is_array( $value ) ) {
2308          return array_merge( $value, $global_attributes );
2309      }
2310  
2311      return $value;
2312  }


Generated: Fri Oct 25 08:20:01 2019 Cross-referenced by PHPXref 0.7