[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-content/themes/twentytwentyone/ -> functions.php (source)

   1  <?php
   2  /**
   3   * Functions and definitions
   4   *
   5   * @link https://developer.wordpress.org/themes/basics/theme-functions/
   6   *
   7   * @package WordPress
   8   * @subpackage Twenty_Twenty_One
   9   * @since Twenty Twenty-One 1.0
  10   */
  11  
  12  // This theme requires WordPress 5.3 or later.
  13  if ( version_compare( $GLOBALS['wp_version'], '5.3', '<' ) ) {
  14      require get_template_directory() . '/inc/back-compat.php';
  15  }
  16  
  17  if ( ! function_exists( 'twenty_twenty_one_setup' ) ) {
  18      /**
  19       * Sets up theme defaults and registers support for various WordPress features.
  20       *
  21       * Note that this function is hooked into the after_setup_theme hook, which
  22       * runs before the init hook. The init hook is too late for some features, such
  23       * as indicating support for post thumbnails.
  24       *
  25       * @since Twenty Twenty-One 1.0
  26       *
  27       * @return void
  28       */
  29  	function twenty_twenty_one_setup() {
  30          /*
  31           * Make theme available for translation.
  32           * Translations can be filed in the /languages/ directory.
  33           * If you're building a theme based on Twenty Twenty-One, use a find and replace
  34           * to change 'twentytwentyone' to the name of your theme in all the template files.
  35           */
  36          load_theme_textdomain( 'twentytwentyone', get_template_directory() . '/languages' );
  37  
  38          // Add default posts and comments RSS feed links to head.
  39          add_theme_support( 'automatic-feed-links' );
  40  
  41          /*
  42           * Let WordPress manage the document title.
  43           * This theme does not use a hard-coded <title> tag in the document head,
  44           * WordPress will provide it for us.
  45           */
  46          add_theme_support( 'title-tag' );
  47  
  48          /**
  49           * Add post-formats support.
  50           */
  51          add_theme_support(
  52              'post-formats',
  53              array(
  54                  'link',
  55                  'aside',
  56                  'gallery',
  57                  'image',
  58                  'quote',
  59                  'status',
  60                  'video',
  61                  'audio',
  62                  'chat',
  63              )
  64          );
  65  
  66          /*
  67           * Enable support for Post Thumbnails on posts and pages.
  68           *
  69           * @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
  70           */
  71          add_theme_support( 'post-thumbnails' );
  72          set_post_thumbnail_size( 1568, 9999 );
  73  
  74          register_nav_menus(
  75              array(
  76                  'primary' => esc_html__( 'Primary menu', 'twentytwentyone' ),
  77                  'footer'  => __( 'Secondary menu', 'twentytwentyone' ),
  78              )
  79          );
  80  
  81          /*
  82           * Switch default core markup for search form, comment form, and comments
  83           * to output valid HTML5.
  84           */
  85          add_theme_support(
  86              'html5',
  87              array(
  88                  'comment-form',
  89                  'comment-list',
  90                  'gallery',
  91                  'caption',
  92                  'style',
  93                  'script',
  94                  'navigation-widgets',
  95              )
  96          );
  97  
  98          /**
  99           * Add support for core custom logo.
 100           *
 101           * @link https://codex.wordpress.org/Theme_Logo
 102           */
 103          $logo_width  = 300;
 104          $logo_height = 100;
 105  
 106          add_theme_support(
 107              'custom-logo',
 108              array(
 109                  'height'               => $logo_height,
 110                  'width'                => $logo_width,
 111                  'flex-width'           => true,
 112                  'flex-height'          => true,
 113                  'unlink-homepage-logo' => true,
 114              )
 115          );
 116  
 117          // Add theme support for selective refresh for widgets.
 118          add_theme_support( 'customize-selective-refresh-widgets' );
 119  
 120          // Add support for Block Styles.
 121          add_theme_support( 'wp-block-styles' );
 122  
 123          // Add support for full and wide align images.
 124          add_theme_support( 'align-wide' );
 125  
 126          // Add support for editor styles.
 127          add_theme_support( 'editor-styles' );
 128          $background_color = get_theme_mod( 'background_color', 'D1E4DD' );
 129          if ( 127 > Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) ) {
 130              add_theme_support( 'dark-editor-style' );
 131          }
 132  
 133          $editor_stylesheet_path = './assets/css/style-editor.css';
 134  
 135          // Note, the is_IE global variable is defined by WordPress and is used
 136          // to detect if the current browser is internet explorer.
 137          global $is_IE;
 138          if ( $is_IE ) {
 139              $editor_stylesheet_path = './assets/css/ie-editor.css';
 140          }
 141  
 142          // Enqueue editor styles.
 143          add_editor_style( $editor_stylesheet_path );
 144  
 145          // Add custom editor font sizes.
 146          add_theme_support(
 147              'editor-font-sizes',
 148              array(
 149                  array(
 150                      'name'      => esc_html__( 'Extra small', 'twentytwentyone' ),
 151                      'shortName' => esc_html_x( 'XS', 'Font size', 'twentytwentyone' ),
 152                      'size'      => 16,
 153                      'slug'      => 'extra-small',
 154                  ),
 155                  array(
 156                      'name'      => esc_html__( 'Small', 'twentytwentyone' ),
 157                      'shortName' => esc_html_x( 'S', 'Font size', 'twentytwentyone' ),
 158                      'size'      => 18,
 159                      'slug'      => 'small',
 160                  ),
 161                  array(
 162                      'name'      => esc_html__( 'Normal', 'twentytwentyone' ),
 163                      'shortName' => esc_html_x( 'M', 'Font size', 'twentytwentyone' ),
 164                      'size'      => 20,
 165                      'slug'      => 'normal',
 166                  ),
 167                  array(
 168                      'name'      => esc_html__( 'Large', 'twentytwentyone' ),
 169                      'shortName' => esc_html_x( 'L', 'Font size', 'twentytwentyone' ),
 170                      'size'      => 24,
 171                      'slug'      => 'large',
 172                  ),
 173                  array(
 174                      'name'      => esc_html__( 'Extra large', 'twentytwentyone' ),
 175                      'shortName' => esc_html_x( 'XL', 'Font size', 'twentytwentyone' ),
 176                      'size'      => 40,
 177                      'slug'      => 'extra-large',
 178                  ),
 179                  array(
 180                      'name'      => esc_html__( 'Huge', 'twentytwentyone' ),
 181                      'shortName' => esc_html_x( 'XXL', 'Font size', 'twentytwentyone' ),
 182                      'size'      => 96,
 183                      'slug'      => 'huge',
 184                  ),
 185                  array(
 186                      'name'      => esc_html__( 'Gigantic', 'twentytwentyone' ),
 187                      'shortName' => esc_html_x( 'XXXL', 'Font size', 'twentytwentyone' ),
 188                      'size'      => 144,
 189                      'slug'      => 'gigantic',
 190                  ),
 191              )
 192          );
 193  
 194          // Custom background color.
 195          add_theme_support(
 196              'custom-background',
 197              array(
 198                  'default-color' => 'd1e4dd',
 199              )
 200          );
 201  
 202          // Editor color palette.
 203          $black     = '#000000';
 204          $dark_gray = '#28303D';
 205          $gray      = '#39414D';
 206          $green     = '#D1E4DD';
 207          $blue      = '#D1DFE4';
 208          $purple    = '#D1D1E4';
 209          $red       = '#E4D1D1';
 210          $orange    = '#E4DAD1';
 211          $yellow    = '#EEEADD';
 212          $white     = '#FFFFFF';
 213  
 214          add_theme_support(
 215              'editor-color-palette',
 216              array(
 217                  array(
 218                      'name'  => esc_html__( 'Black', 'twentytwentyone' ),
 219                      'slug'  => 'black',
 220                      'color' => $black,
 221                  ),
 222                  array(
 223                      'name'  => esc_html__( 'Dark gray', 'twentytwentyone' ),
 224                      'slug'  => 'dark-gray',
 225                      'color' => $dark_gray,
 226                  ),
 227                  array(
 228                      'name'  => esc_html__( 'Gray', 'twentytwentyone' ),
 229                      'slug'  => 'gray',
 230                      'color' => $gray,
 231                  ),
 232                  array(
 233                      'name'  => esc_html__( 'Green', 'twentytwentyone' ),
 234                      'slug'  => 'green',
 235                      'color' => $green,
 236                  ),
 237                  array(
 238                      'name'  => esc_html__( 'Blue', 'twentytwentyone' ),
 239                      'slug'  => 'blue',
 240                      'color' => $blue,
 241                  ),
 242                  array(
 243                      'name'  => esc_html__( 'Purple', 'twentytwentyone' ),
 244                      'slug'  => 'purple',
 245                      'color' => $purple,
 246                  ),
 247                  array(
 248                      'name'  => esc_html__( 'Red', 'twentytwentyone' ),
 249                      'slug'  => 'red',
 250                      'color' => $red,
 251                  ),
 252                  array(
 253                      'name'  => esc_html__( 'Orange', 'twentytwentyone' ),
 254                      'slug'  => 'orange',
 255                      'color' => $orange,
 256                  ),
 257                  array(
 258                      'name'  => esc_html__( 'Yellow', 'twentytwentyone' ),
 259                      'slug'  => 'yellow',
 260                      'color' => $yellow,
 261                  ),
 262                  array(
 263                      'name'  => esc_html__( 'White', 'twentytwentyone' ),
 264                      'slug'  => 'white',
 265                      'color' => $white,
 266                  ),
 267              )
 268          );
 269  
 270          add_theme_support(
 271              'editor-gradient-presets',
 272              array(
 273                  array(
 274                      'name'     => esc_html__( 'Purple to yellow', 'twentytwentyone' ),
 275                      'gradient' => 'linear-gradient(160deg, ' . $purple . ' 0%, ' . $yellow . ' 100%)',
 276                      'slug'     => 'purple-to-yellow',
 277                  ),
 278                  array(
 279                      'name'     => esc_html__( 'Yellow to purple', 'twentytwentyone' ),
 280                      'gradient' => 'linear-gradient(160deg, ' . $yellow . ' 0%, ' . $purple . ' 100%)',
 281                      'slug'     => 'yellow-to-purple',
 282                  ),
 283                  array(
 284                      'name'     => esc_html__( 'Green to yellow', 'twentytwentyone' ),
 285                      'gradient' => 'linear-gradient(160deg, ' . $green . ' 0%, ' . $yellow . ' 100%)',
 286                      'slug'     => 'green-to-yellow',
 287                  ),
 288                  array(
 289                      'name'     => esc_html__( 'Yellow to green', 'twentytwentyone' ),
 290                      'gradient' => 'linear-gradient(160deg, ' . $yellow . ' 0%, ' . $green . ' 100%)',
 291                      'slug'     => 'yellow-to-green',
 292                  ),
 293                  array(
 294                      'name'     => esc_html__( 'Red to yellow', 'twentytwentyone' ),
 295                      'gradient' => 'linear-gradient(160deg, ' . $red . ' 0%, ' . $yellow . ' 100%)',
 296                      'slug'     => 'red-to-yellow',
 297                  ),
 298                  array(
 299                      'name'     => esc_html__( 'Yellow to red', 'twentytwentyone' ),
 300                      'gradient' => 'linear-gradient(160deg, ' . $yellow . ' 0%, ' . $red . ' 100%)',
 301                      'slug'     => 'yellow-to-red',
 302                  ),
 303                  array(
 304                      'name'     => esc_html__( 'Purple to red', 'twentytwentyone' ),
 305                      'gradient' => 'linear-gradient(160deg, ' . $purple . ' 0%, ' . $red . ' 100%)',
 306                      'slug'     => 'purple-to-red',
 307                  ),
 308                  array(
 309                      'name'     => esc_html__( 'Red to purple', 'twentytwentyone' ),
 310                      'gradient' => 'linear-gradient(160deg, ' . $red . ' 0%, ' . $purple . ' 100%)',
 311                      'slug'     => 'red-to-purple',
 312                  ),
 313              )
 314          );
 315  
 316          /*
 317          * Adds starter content to highlight the theme on fresh sites.
 318          * This is done conditionally to avoid loading the starter content on every
 319          * page load, as it is a one-off operation only needed once in the customizer.
 320          */
 321          if ( is_customize_preview() ) {
 322              require get_template_directory() . '/inc/starter-content.php';
 323              add_theme_support( 'starter-content', twenty_twenty_one_get_starter_content() );
 324          }
 325  
 326          // Add support for responsive embedded content.
 327          add_theme_support( 'responsive-embeds' );
 328  
 329          // Add support for custom line height controls.
 330          add_theme_support( 'custom-line-height' );
 331  
 332          // Add support for experimental link color control.
 333          add_theme_support( 'experimental-link-color' );
 334  
 335          // Add support for experimental cover block spacing.
 336          add_theme_support( 'custom-spacing' );
 337  
 338          // Add support for custom units.
 339          // This was removed in WordPress 5.6 but is still required to properly support WP 5.5.
 340          add_theme_support( 'custom-units' );
 341      }
 342  }
 343  add_action( 'after_setup_theme', 'twenty_twenty_one_setup' );
 344  
 345  /**
 346   * Register widget area.
 347   *
 348   * @since Twenty Twenty-One 1.0
 349   *
 350   * @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
 351   *
 352   * @return void
 353   */
 354  function twenty_twenty_one_widgets_init() {
 355  
 356      register_sidebar(
 357          array(
 358              'name'          => esc_html__( 'Footer', 'twentytwentyone' ),
 359              'id'            => 'sidebar-1',
 360              'description'   => esc_html__( 'Add widgets here to appear in your footer.', 'twentytwentyone' ),
 361              'before_widget' => '<section id="%1$s" class="widget %2$s">',
 362              'after_widget'  => '</section>',
 363              'before_title'  => '<h2 class="widget-title">',
 364              'after_title'   => '</h2>',
 365          )
 366      );
 367  }
 368  add_action( 'widgets_init', 'twenty_twenty_one_widgets_init' );
 369  
 370  /**
 371   * Set the content width in pixels, based on the theme's design and stylesheet.
 372   *
 373   * Priority 0 to make it available to lower priority callbacks.
 374   *
 375   * @since Twenty Twenty-One 1.0
 376   *
 377   * @global int $content_width Content width.
 378   *
 379   * @return void
 380   */
 381  function twenty_twenty_one_content_width() {
 382      // This variable is intended to be overruled from themes.
 383      // Open WPCS issue: {@link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/1043}.
 384      // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
 385      $GLOBALS['content_width'] = apply_filters( 'twenty_twenty_one_content_width', 750 );
 386  }
 387  add_action( 'after_setup_theme', 'twenty_twenty_one_content_width', 0 );
 388  
 389  /**
 390   * Enqueue scripts and styles.
 391   *
 392   * @since Twenty Twenty-One 1.0
 393   *
 394   * @return void
 395   */
 396  function twenty_twenty_one_scripts() {
 397      // Note, the is_IE global variable is defined by WordPress and is used
 398      // to detect if the current browser is internet explorer.
 399      global $is_IE, $wp_scripts;
 400      if ( $is_IE ) {
 401          // If IE 11 or below, use a flattened stylesheet with static values replacing CSS Variables.
 402          wp_enqueue_style( 'twenty-twenty-one-style', get_template_directory_uri() . '/assets/css/ie.css', array(), wp_get_theme()->get( 'Version' ) );
 403      } else {
 404          // If not IE, use the standard stylesheet.
 405          wp_enqueue_style( 'twenty-twenty-one-style', get_template_directory_uri() . '/style.css', array(), wp_get_theme()->get( 'Version' ) );
 406      }
 407  
 408      // RTL styles.
 409      wp_style_add_data( 'twenty-twenty-one-style', 'rtl', 'replace' );
 410  
 411      // Print styles.
 412      wp_enqueue_style( 'twenty-twenty-one-print-style', get_template_directory_uri() . '/assets/css/print.css', array(), wp_get_theme()->get( 'Version' ), 'print' );
 413  
 414      // Threaded comment reply styles.
 415      if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
 416          wp_enqueue_script( 'comment-reply' );
 417      }
 418  
 419      // Register the IE11 polyfill file.
 420      wp_register_script(
 421          'twenty-twenty-one-ie11-polyfills-asset',
 422          get_template_directory_uri() . '/assets/js/polyfills.js',
 423          array(),
 424          wp_get_theme()->get( 'Version' ),
 425          true
 426      );
 427  
 428      // Register the IE11 polyfill loader.
 429      wp_register_script(
 430          'twenty-twenty-one-ie11-polyfills',
 431          null,
 432          array(),
 433          wp_get_theme()->get( 'Version' ),
 434          true
 435      );
 436      wp_add_inline_script(
 437          'twenty-twenty-one-ie11-polyfills',
 438          wp_get_script_polyfill(
 439              $wp_scripts,
 440              array(
 441                  'Element.prototype.matches && Element.prototype.closest && window.NodeList && NodeList.prototype.forEach' => 'twenty-twenty-one-ie11-polyfills-asset',
 442              )
 443          )
 444      );
 445  
 446      // Main navigation scripts.
 447      if ( has_nav_menu( 'primary' ) ) {
 448          wp_enqueue_script(
 449              'twenty-twenty-one-primary-navigation-script',
 450              get_template_directory_uri() . '/assets/js/primary-navigation.js',
 451              array( 'twenty-twenty-one-ie11-polyfills' ),
 452              wp_get_theme()->get( 'Version' ),
 453              true
 454          );
 455      }
 456  
 457      // Responsive embeds script.
 458      wp_enqueue_script(
 459          'twenty-twenty-one-responsive-embeds-script',
 460          get_template_directory_uri() . '/assets/js/responsive-embeds.js',
 461          array( 'twenty-twenty-one-ie11-polyfills' ),
 462          wp_get_theme()->get( 'Version' ),
 463          true
 464      );
 465  }
 466  add_action( 'wp_enqueue_scripts', 'twenty_twenty_one_scripts' );
 467  
 468  /**
 469   * Enqueue block editor script.
 470   *
 471   * @since Twenty Twenty-One 1.0
 472   *
 473   * @return void
 474   */
 475  function twentytwentyone_block_editor_script() {
 476  
 477      wp_enqueue_script( 'twentytwentyone-editor', get_theme_file_uri( '/assets/js/editor.js' ), array( 'wp-blocks', 'wp-dom' ), wp_get_theme()->get( 'Version' ), true );
 478  }
 479  
 480  add_action( 'enqueue_block_editor_assets', 'twentytwentyone_block_editor_script' );
 481  
 482  /**
 483   * Fix skip link focus in IE11.
 484   *
 485   * This does not enqueue the script because it is tiny and because it is only for IE11,
 486   * thus it does not warrant having an entire dedicated blocking script being loaded.
 487   *
 488   * @link https://git.io/vWdr2
 489   */
 490  function twenty_twenty_one_skip_link_focus_fix() {
 491  
 492      // If SCRIPT_DEBUG is defined and true, print the unminified file.
 493      if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
 494          echo '<script>';
 495          include get_template_directory() . '/assets/js/skip-link-focus-fix.js';
 496          echo '</script>';
 497      }
 498  
 499      // The following is minified via `npx terser --compress --mangle -- assets/js/skip-link-focus-fix.js`.
 500      ?>
 501      <script>
 502      /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",(function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())}),!1);
 503      </script>
 504      <?php
 505  }
 506  add_action( 'wp_print_footer_scripts', 'twenty_twenty_one_skip_link_focus_fix' );
 507  
 508  /** Enqueue non-latin language styles
 509   *
 510   * @since Twenty Twenty-One 1.0
 511   *
 512   * @return void
 513   */
 514  function twenty_twenty_one_non_latin_languages() {
 515      $custom_css = twenty_twenty_one_get_non_latin_css( 'front-end' );
 516  
 517      if ( $custom_css ) {
 518          wp_add_inline_style( 'twenty-twenty-one-style', $custom_css );
 519      }
 520  }
 521  add_action( 'wp_enqueue_scripts', 'twenty_twenty_one_non_latin_languages' );
 522  
 523  // SVG Icons class.
 524  require get_template_directory() . '/classes/class-twenty-twenty-one-svg-icons.php';
 525  
 526  // Custom color classes.
 527  require get_template_directory() . '/classes/class-twenty-twenty-one-custom-colors.php';
 528  new Twenty_Twenty_One_Custom_Colors();
 529  
 530  // Enhance the theme by hooking into WordPress.
 531  require get_template_directory() . '/inc/template-functions.php';
 532  
 533  // Menu functions and filters.
 534  require get_template_directory() . '/inc/menu-functions.php';
 535  
 536  // Custom template tags for the theme.
 537  require get_template_directory() . '/inc/template-tags.php';
 538  
 539  // Customizer additions.
 540  require get_template_directory() . '/classes/class-twenty-twenty-one-customize.php';
 541  new Twenty_Twenty_One_Customize();
 542  
 543  // Block Patterns.
 544  require get_template_directory() . '/inc/block-patterns.php';
 545  
 546  // Block Styles.
 547  require get_template_directory() . '/inc/block-styles.php';
 548  
 549  // Dark Mode.
 550  require_once get_template_directory() . '/classes/class-twenty-twenty-one-dark-mode.php';
 551  new Twenty_Twenty_One_Dark_Mode();
 552  
 553  /**
 554   * Enqueue scripts for the customizer preview.
 555   *
 556   * @since Twenty Twenty-One 1.0
 557   *
 558   * @return void
 559   */
 560  function twentytwentyone_customize_preview_init() {
 561      wp_enqueue_script(
 562          'twentytwentyone-customize-helpers',
 563          get_theme_file_uri( '/assets/js/customize-helpers.js' ),
 564          array(),
 565          wp_get_theme()->get( 'Version' ),
 566          true
 567      );
 568  
 569      wp_enqueue_script(
 570          'twentytwentyone-customize-preview',
 571          get_theme_file_uri( '/assets/js/customize-preview.js' ),
 572          array( 'customize-preview', 'customize-selective-refresh', 'jquery', 'twentytwentyone-customize-helpers' ),
 573          wp_get_theme()->get( 'Version' ),
 574          true
 575      );
 576  }
 577  add_action( 'customize_preview_init', 'twentytwentyone_customize_preview_init' );
 578  
 579  /**
 580   * Enqueue scripts for the customizer.
 581   *
 582   * @since Twenty Twenty-One 1.0
 583   *
 584   * @return void
 585   */
 586  function twentytwentyone_customize_controls_enqueue_scripts() {
 587  
 588      wp_enqueue_script(
 589          'twentytwentyone-customize-helpers',
 590          get_theme_file_uri( '/assets/js/customize-helpers.js' ),
 591          array(),
 592          wp_get_theme()->get( 'Version' ),
 593          true
 594      );
 595  }
 596  add_action( 'customize_controls_enqueue_scripts', 'twentytwentyone_customize_controls_enqueue_scripts' );
 597  
 598  /**
 599   * Calculate classes for the main <html> element.
 600   *
 601   * @since Twenty Twenty-One 1.0
 602   *
 603   * @return void
 604   */
 605  function twentytwentyone_the_html_classes() {
 606      $classes = apply_filters( 'twentytwentyone_html_classes', '' );
 607      if ( ! $classes ) {
 608          return;
 609      }
 610      echo 'class="' . esc_attr( $classes ) . '"';
 611  }
 612  
 613  /**
 614   * Add "is-IE" class to body if the user is on Internet Explorer.
 615   *
 616   * @since Twenty Twenty-One 1.0
 617   *
 618   * @return void
 619   */
 620  function twentytwentyone_add_ie_class() {
 621      ?>
 622      <script>
 623      if ( -1 !== navigator.userAgent.indexOf( 'MSIE' ) || -1 !== navigator.appVersion.indexOf( 'Trident/' ) ) {
 624          document.body.classList.add( 'is-IE' );
 625      }
 626      </script>
 627      <?php
 628  }
 629  add_action( 'wp_footer', 'twentytwentyone_add_ie_class' );


Generated: Wed Apr 21 01:00:05 2021 Cross-referenced by PHPXref 0.7.1