| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WordPress Administration Update API 4 * 5 * @package WordPress 6 * @subpackage Administration 7 */ 8 9 /** 10 * Selects the first update version from the update_core option. 11 * 12 * @since 2.7.0 13 * 14 * @return object|array|false The response from the API on success, false on failure. 15 */ 16 function get_preferred_from_update_core() { 17 $updates = get_core_updates(); 18 19 if ( ! is_array( $updates ) ) { 20 return false; 21 } 22 23 if ( empty( $updates ) ) { 24 return (object) array( 'response' => 'latest' ); 25 } 26 27 return $updates[0]; 28 } 29 30 /** 31 * Gets available core updates. 32 * 33 * @since 2.7.0 34 * 35 * @param array $options Set $options['dismissed'] to true to show dismissed upgrades too, 36 * set $options['available'] to false to skip not-dismissed updates. 37 * @return array<object>|false Array of the update objects on success, false on failure. 38 */ 39 function get_core_updates( $options = array() ) { 40 $options = array_merge( 41 array( 42 'available' => true, 43 'dismissed' => false, 44 ), 45 $options 46 ); 47 48 $dismissed = get_site_option( 'dismissed_update_core' ); 49 50 if ( ! is_array( $dismissed ) ) { 51 $dismissed = array(); 52 } 53 54 $from_api = get_site_transient( 'update_core' ); 55 56 if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) { 57 return false; 58 } 59 60 $updates = $from_api->updates; 61 $result = array(); 62 63 foreach ( $updates as $update ) { 64 if ( 'autoupdate' === $update->response ) { 65 continue; 66 } 67 68 if ( array_key_exists( $update->current . '|' . $update->locale, $dismissed ) ) { 69 if ( $options['dismissed'] ) { 70 $update->dismissed = true; 71 $result[] = $update; 72 } 73 } else { 74 if ( $options['available'] ) { 75 $update->dismissed = false; 76 $result[] = $update; 77 } 78 } 79 } 80 81 return $result; 82 } 83 84 /** 85 * Gets the best available (and enabled) Auto-Update for WordPress core. 86 * 87 * If there's 1.2.3 and 1.3 on offer, it'll choose 1.3 if the installation allows it, else, 1.2.3. 88 * 89 * @since 3.7.0 90 * 91 * @return object|false The core update offering on success, false on failure. 92 */ 93 function find_core_auto_update() { 94 $updates = get_site_transient( 'update_core' ); 95 96 if ( ! $updates || empty( $updates->updates ) ) { 97 return false; 98 } 99 100 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; 101 102 $auto_update = false; 103 $upgrader = new WP_Automatic_Updater(); 104 105 foreach ( $updates->updates as $update ) { 106 if ( 'autoupdate' !== $update->response ) { 107 continue; 108 } 109 110 if ( ! $upgrader->should_update( 'core', $update, ABSPATH ) ) { 111 continue; 112 } 113 114 if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) ) { 115 $auto_update = $update; 116 } 117 } 118 119 return $auto_update; 120 } 121 122 /** 123 * Gets and caches the checksums for the given version of WordPress. 124 * 125 * @since 3.7.0 126 * 127 * @param string $version Version string to query. 128 * @param string $locale Locale to query. 129 * @return array<string, string>|false An array of checksums on success, false on failure. 130 */ 131 function get_core_checksums( $version, $locale ) { 132 $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), '', '&' ); 133 $url = $http_url; 134 135 $ssl = wp_http_supports( array( 'ssl' ) ); 136 137 if ( $ssl ) { 138 $url = set_url_scheme( $url, 'https' ); 139 } 140 141 $options = array( 142 'timeout' => wp_doing_cron() ? 30 : 3, 143 ); 144 145 $response = wp_remote_get( $url, $options ); 146 147 if ( $ssl && is_wp_error( $response ) ) { 148 wp_trigger_error( 149 __FUNCTION__, 150 sprintf( 151 /* translators: %s: Support forums URL. */ 152 __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), 153 __( 'https://wordpress.org/support/forums/' ) 154 ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), 155 headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE 156 ); 157 158 $response = wp_remote_get( $http_url, $options ); 159 } 160 161 if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { 162 return false; 163 } 164 165 $body = trim( wp_remote_retrieve_body( $response ) ); 166 $body = json_decode( $body, true ); 167 168 if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) { 169 return false; 170 } 171 172 return $body['checksums']; 173 } 174 175 /** 176 * Dismisses core update. 177 * 178 * @since 2.7.0 179 * 180 * @param object $update 181 * @return bool True if the option was updated, false otherwise. 182 */ 183 function dismiss_core_update( $update ) { 184 $dismissed = get_site_option( 'dismissed_update_core' ); 185 $dismissed[ $update->current . '|' . $update->locale ] = true; 186 187 return update_site_option( 'dismissed_update_core', $dismissed ); 188 } 189 190 /** 191 * Undismisses core update. 192 * 193 * @since 2.7.0 194 * 195 * @param string $version 196 * @param string $locale 197 * @return bool True if the option was updated, false otherwise. 198 */ 199 function undismiss_core_update( $version, $locale ) { 200 $dismissed = get_site_option( 'dismissed_update_core' ); 201 $key = $version . '|' . $locale; 202 203 if ( ! isset( $dismissed[ $key ] ) ) { 204 return false; 205 } 206 207 unset( $dismissed[ $key ] ); 208 209 return update_site_option( 'dismissed_update_core', $dismissed ); 210 } 211 212 /** 213 * Finds the available update for WordPress core. 214 * 215 * @since 2.7.0 216 * 217 * @param string $version Version string to find the update for. 218 * @param string $locale Locale to find the update for. 219 * @return object|false The core update offering on success, false on failure. 220 */ 221 function find_core_update( $version, $locale ) { 222 $from_api = get_site_transient( 'update_core' ); 223 224 if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) { 225 return false; 226 } 227 228 $updates = $from_api->updates; 229 230 foreach ( $updates as $update ) { 231 if ( $update->current === $version && $update->locale === $locale ) { 232 return $update; 233 } 234 } 235 236 return false; 237 } 238 239 /** 240 * Returns core update footer message. 241 * 242 * @since 2.3.0 243 * 244 * @param string $msg 245 * @return string The core update footer message. 246 */ 247 function core_update_footer( $msg = '' ) { 248 if ( ! current_user_can( 'update_core' ) ) { 249 /* translators: %s: WordPress version. */ 250 return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); 251 } 252 253 $cur = get_preferred_from_update_core(); 254 255 if ( ! is_object( $cur ) ) { 256 $cur = new stdClass(); 257 } 258 259 if ( ! isset( $cur->current ) ) { 260 $cur->current = ''; 261 } 262 263 if ( ! isset( $cur->response ) ) { 264 $cur->response = ''; 265 } 266 267 $is_development_version = preg_match( '/alpha|beta|RC/', wp_get_wp_version() ); 268 269 if ( $is_development_version ) { 270 return sprintf( 271 /* translators: 1: WordPress version number, 2: URL to WordPress Updates screen. */ 272 __( 'You are using a development version (%1$s). Cool! Please <a href="%2$s">stay updated</a>.' ), 273 get_bloginfo( 'version', 'display' ), 274 network_admin_url( 'update-core.php' ) 275 ); 276 } 277 278 switch ( $cur->response ) { 279 case 'upgrade': 280 return sprintf( 281 '<strong><a href="%s">%s</a></strong>', 282 network_admin_url( 'update-core.php' ), 283 /* translators: %s: WordPress version. */ 284 sprintf( __( 'Get Version %s' ), $cur->current ) 285 ); 286 287 case 'latest': 288 default: 289 /* translators: %s: WordPress version. */ 290 return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); 291 } 292 } 293 294 /** 295 * Returns core update notification message. 296 * 297 * @since 2.3.0 298 * 299 * @global string $pagenow The filename of the current screen. 300 * @return void|false Void on success, false if the update nag should not be displayed. 301 */ 302 function update_nag() { 303 global $pagenow; 304 305 if ( is_multisite() && ! current_user_can( 'update_core' ) ) { 306 return false; 307 } 308 309 if ( 'update-core.php' === $pagenow ) { 310 return; 311 } 312 313 $cur = get_preferred_from_update_core(); 314 315 if ( ! isset( $cur->response ) || 'upgrade' !== $cur->response ) { 316 return false; 317 } 318 319 $version_url = sprintf( 320 /* translators: %s: WordPress version. */ 321 esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ), 322 sanitize_title( $cur->current ) 323 ); 324 325 if ( current_user_can( 'update_core' ) ) { 326 $msg = sprintf( 327 /* translators: 1: URL to WordPress release notes, 2: New WordPress version, 3: URL to network admin, 4: Accessibility text. */ 328 __( '<a href="%1$s">WordPress %2$s</a> is available! <a href="%3$s" aria-label="%4$s">Please update now</a>.' ), 329 $version_url, 330 $cur->current, 331 network_admin_url( 'update-core.php' ), 332 esc_attr__( 'Please update WordPress now' ) 333 ); 334 } else { 335 $msg = sprintf( 336 /* translators: 1: URL to WordPress release notes, 2: New WordPress version. */ 337 __( '<a href="%1$s">WordPress %2$s</a> is available! Please notify the site administrator.' ), 338 $version_url, 339 $cur->current 340 ); 341 } 342 343 wp_admin_notice( 344 $msg, 345 array( 346 'type' => 'warning', 347 'additional_classes' => array( 'update-nag', 'inline' ), 348 'paragraph_wrap' => false, 349 ) 350 ); 351 } 352 353 /** 354 * Displays WordPress version and active theme in the 'At a Glance' dashboard widget. 355 * 356 * @since 2.5.0 357 */ 358 function update_right_now_message() { 359 $theme_name = wp_get_theme(); 360 361 if ( current_user_can( 'switch_themes' ) ) { 362 $theme_name = sprintf( '<a href="themes.php">%1$s</a>', $theme_name ); 363 } 364 365 /* translators: 1: Version number, 2: Theme name. */ 366 $content = __( 'WordPress %1$s running %2$s theme.' ); 367 368 /** 369 * Filters the text displayed in the 'At a Glance' dashboard widget. 370 * 371 * Prior to 3.8.0, the widget was named 'Right Now'. 372 * 373 * @since 4.4.0 374 * 375 * @param string $content Default text. 376 */ 377 $content = apply_filters( 'update_right_now_text', $content ); 378 379 $msg = sprintf( '<span id="wp-version">' . $content . '</span>', get_bloginfo( 'version', 'display' ), $theme_name ); 380 381 if ( current_user_can( 'update_core' ) ) { 382 $cur = get_preferred_from_update_core(); 383 384 if ( isset( $cur->response ) && 'upgrade' === $cur->response ) { 385 $msg .= sprintf( 386 '<a href="%s" class="button" aria-describedby="wp-version">%s</a>', 387 network_admin_url( 'update-core.php' ), 388 /* translators: %s: WordPress version number, or 'Latest' string. */ 389 sprintf( __( 'Update to %s' ), $cur->current ? $cur->current : __( 'Latest' ) ) 390 ); 391 } 392 } 393 394 echo "<p id='wp-version-message'>$msg</p>"; 395 } 396 397 /** 398 * Retrieves plugins with updates available. 399 * 400 * @since 2.9.0 401 * 402 * @return array<string, object> Array of plugin objects with available updates. 403 */ 404 function get_plugin_updates() { 405 $all_plugins = get_plugins(); 406 $upgrade_plugins = array(); 407 $current = get_site_transient( 'update_plugins' ); 408 409 foreach ( (array) $all_plugins as $plugin_file => $plugin_data ) { 410 if ( isset( $current->response[ $plugin_file ] ) ) { 411 $upgrade_plugins[ $plugin_file ] = (object) $plugin_data; 412 $upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ]; 413 } 414 } 415 416 return $upgrade_plugins; 417 } 418 419 /** 420 * Adds a callback to display update information for plugins with updates available. 421 * 422 * @since 2.9.0 423 */ 424 function wp_plugin_update_rows() { 425 if ( ! current_user_can( 'update_plugins' ) ) { 426 return; 427 } 428 429 $plugins = get_site_transient( 'update_plugins' ); 430 431 if ( isset( $plugins->response ) && is_array( $plugins->response ) ) { 432 $plugins = array_keys( $plugins->response ); 433 434 foreach ( $plugins as $plugin_file ) { 435 add_action( "after_plugin_row_{$plugin_file}", 'wp_plugin_update_row', 10, 2 ); 436 } 437 } 438 } 439 440 /** 441 * Displays update information for a plugin. 442 * 443 * @since 2.3.0 444 * 445 * @param string $file Plugin basename. 446 * @param array $plugin_data Plugin information. 447 * @return void|false Void on success, false if the plugin update is not available. 448 */ 449 function wp_plugin_update_row( $file, $plugin_data ) { 450 $current = get_site_transient( 'update_plugins' ); 451 452 if ( ! isset( $current->response[ $file ] ) ) { 453 return false; 454 } 455 456 $response = $current->response[ $file ]; 457 458 $plugins_allowedtags = array( 459 'a' => array( 460 'href' => array(), 461 'title' => array(), 462 ), 463 'abbr' => array( 'title' => array() ), 464 'acronym' => array( 'title' => array() ), 465 'code' => array(), 466 'em' => array(), 467 'strong' => array(), 468 ); 469 470 $plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags ); 471 $plugin_slug = $response->slug ?? $response->id; 472 473 if ( isset( $response->slug ) ) { 474 $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_slug . '§ion=changelog' ); 475 } elseif ( isset( $response->url ) ) { 476 $details_url = $response->url; 477 } else { 478 $details_url = $plugin_data['PluginURI']; 479 } 480 481 $details_url = add_query_arg( 482 array( 483 'TB_iframe' => 'true', 484 'width' => 600, 485 'height' => 800, 486 ), 487 $details_url 488 ); 489 490 /** @var WP_Plugins_List_Table $wp_list_table */ 491 $wp_list_table = _get_list_table( 492 'WP_Plugins_List_Table', 493 array( 494 'screen' => get_current_screen(), 495 ) 496 ); 497 498 if ( is_network_admin() || ! is_multisite() ) { 499 if ( is_network_admin() ) { 500 $active_class = is_plugin_active_for_network( $file ) ? ' active' : ''; 501 } else { 502 $active_class = is_plugin_active( $file ) ? ' active' : ''; 503 } 504 505 $requires_php = $response->requires_php ?? null; 506 $compatible_php = is_php_version_compatible( $requires_php ); 507 $notice_type = $compatible_php ? 'notice-warning' : 'notice-error'; 508 509 printf( 510 '<tr class="plugin-update-tr%s" id="%s" data-slug="%s" data-plugin="%s">' . 511 '<td colspan="%s" class="plugin-update colspanchange">' . 512 '<div class="update-message notice inline %s notice-alt"><p>', 513 $active_class, 514 esc_attr( $plugin_slug . '-update' ), 515 esc_attr( $plugin_slug ), 516 esc_attr( $file ), 517 esc_attr( $wp_list_table->get_column_count() ), 518 $notice_type 519 ); 520 521 if ( ! current_user_can( 'update_plugins' ) ) { 522 printf( 523 /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ 524 __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ), 525 $plugin_name, 526 esc_url( $details_url ), 527 sprintf( 528 'class="thickbox open-plugin-details-modal" aria-label="%s"', 529 /* translators: 1: Plugin name, 2: Version number. */ 530 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 531 ), 532 esc_attr( $response->new_version ) 533 ); 534 } elseif ( empty( $response->package ) ) { 535 printf( 536 /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ 537 __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>' ), 538 $plugin_name, 539 esc_url( $details_url ), 540 sprintf( 541 'class="thickbox open-plugin-details-modal" aria-label="%s"', 542 /* translators: 1: Plugin name, 2: Version number. */ 543 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 544 ), 545 esc_attr( $response->new_version ) 546 ); 547 } else { 548 if ( $compatible_php ) { 549 printf( 550 /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ 551 __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ), 552 $plugin_name, 553 esc_url( $details_url ), 554 sprintf( 555 'class="thickbox open-plugin-details-modal" aria-label="%s"', 556 /* translators: 1: Plugin name, 2: Version number. */ 557 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 558 ), 559 esc_attr( $response->new_version ), 560 wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ), 561 sprintf( 562 'class="update-link" aria-label="%s"', 563 /* translators: %s: Plugin name. */ 564 esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $plugin_name ) ) 565 ) 566 ); 567 } else { 568 printf( 569 /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number 5: URL to Update PHP page. */ 570 __( 'There is a new version of %1$s available, but it does not work with your version of PHP. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s">learn more about updating PHP</a>.' ), 571 $plugin_name, 572 esc_url( $details_url ), 573 sprintf( 574 'class="thickbox open-plugin-details-modal" aria-label="%s"', 575 /* translators: 1: Plugin name, 2: Version number. */ 576 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 577 ), 578 esc_attr( $response->new_version ), 579 esc_url( wp_get_update_php_url() ) 580 ); 581 wp_update_php_annotation( '<br><em>', '</em>' ); 582 } 583 } 584 585 /** 586 * Fires at the end of the update message container in each 587 * row of the plugins list table. 588 * 589 * The dynamic portion of the hook name, `$file`, refers to the path 590 * of the plugin's primary file relative to the plugins directory. 591 * 592 * @since 2.8.0 593 * 594 * @param array $plugin_data An array of plugin metadata. See get_plugin_data() 595 * and the {@see 'plugin_row_meta'} filter for the list 596 * of possible values. 597 * @param object $response { 598 * An object of metadata about the available plugin update. 599 * 600 * @type string $id Plugin ID, e.g. `w.org/plugins/[plugin-name]`. 601 * @type string $slug Plugin slug. 602 * @type string $plugin Plugin basename. 603 * @type string $new_version New plugin version. 604 * @type string $url Plugin URL. 605 * @type string $package Plugin update package URL. 606 * @type string[] $icons An array of plugin icon URLs. 607 * @type string[] $banners An array of plugin banner URLs. 608 * @type string[] $banners_rtl An array of plugin RTL banner URLs. 609 * @type string $requires The version of WordPress which the plugin requires. 610 * @type string $tested The version of WordPress the plugin is tested against. 611 * @type string $requires_php The version of PHP which the plugin requires. 612 * } 613 */ 614 do_action( "in_plugin_update_message-{$file}", $plugin_data, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores 615 616 echo '</p></div></td></tr>'; 617 } 618 } 619 620 /** 621 * Retrieves themes with updates available. 622 * 623 * @since 2.9.0 624 * 625 * @return array<string, WP_Theme> Array of theme objects with available updates. 626 */ 627 function get_theme_updates() { 628 $current = get_site_transient( 'update_themes' ); 629 630 if ( ! isset( $current->response ) ) { 631 return array(); 632 } 633 634 $update_themes = array(); 635 636 foreach ( $current->response as $stylesheet => $data ) { 637 $update_themes[ $stylesheet ] = wp_get_theme( $stylesheet ); 638 $update_themes[ $stylesheet ]->update = $data; 639 } 640 641 return $update_themes; 642 } 643 644 /** 645 * Gets plugin names for translation updates. 646 * 647 * @since 7.2.0 648 * 649 * @return string[] Plugin names keyed by plugin file, directory, basename, and slug. 650 */ 651 function wp_get_translation_update_plugin_names() { 652 require_once ABSPATH . 'wp-admin/includes/plugin.php'; 653 654 $plugin_names = array(); 655 $all_plugins = get_plugins(); 656 $plugin_update = get_site_transient( 'update_plugins' ); 657 658 if ( is_object( $plugin_update ) ) { 659 $plugin_updates = array(); 660 661 if ( ! empty( $plugin_update->response ) && is_array( $plugin_update->response ) ) { 662 $plugin_updates = array_merge( $plugin_updates, $plugin_update->response ); 663 } 664 665 if ( ! empty( $plugin_update->no_update ) && is_array( $plugin_update->no_update ) ) { 666 $plugin_updates = array_merge( $plugin_updates, $plugin_update->no_update ); 667 } 668 669 foreach ( $plugin_updates as $plugin_file => $plugin_data ) { 670 $plugin_data = (object) $plugin_data; 671 672 if ( ! empty( $plugin_data->slug ) && ! empty( $all_plugins[ $plugin_file ]['Name'] ) ) { 673 $plugin_names[ $plugin_data->slug ] = $all_plugins[ $plugin_file ]['Name']; 674 } 675 } 676 } 677 678 foreach ( $all_plugins as $plugin_file => $plugin_data ) { 679 $plugin_basename = dirname( $plugin_file ); 680 681 if ( isset( $plugin_data['Name'] ) ) { 682 $plugin_names[ $plugin_file ] = $plugin_data['Name']; 683 $plugin_names[ basename( $plugin_file, '.php' ) ] = $plugin_data['Name']; 684 685 if ( '.' !== $plugin_basename ) { 686 $plugin_names[ $plugin_basename ] = $plugin_data['Name']; 687 } 688 } 689 } 690 691 return $plugin_names; 692 } 693 694 /** 695 * Gets the display name for a translation update. 696 * 697 * @since 7.2.0 698 * 699 * @param object $update Translation update object. 700 * @param string[]|null $plugin_names Optional. Plugin names keyed by plugin file, directory, 701 * basename, and slug. Default null. 702 * @return string The translation update name. 703 */ 704 function wp_get_translation_update_name( $update, $plugin_names = null ) { 705 $type = isset( $update->type ) ? $update->type : ''; 706 $slug = isset( $update->slug ) ? $update->slug : ''; 707 708 switch ( $type ) { 709 case 'core': 710 return 'WordPress'; // Not translated. 711 712 case 'theme': 713 $theme = wp_get_theme( $slug ); 714 if ( $theme->exists() ) { 715 return $theme->get( 'Name' ); 716 } 717 break; 718 719 case 'plugin': 720 if ( null === $plugin_names ) { 721 $plugin_names = wp_get_translation_update_plugin_names(); 722 } 723 724 if ( ! empty( $plugin_names[ $slug ] ) ) { 725 return $plugin_names[ $slug ]; 726 } 727 break; 728 } 729 730 return $slug; 731 } 732 733 /** 734 * Gets the display language for a translation update. 735 * 736 * @since 7.2.0 737 * 738 * @param string $locale Translation update locale. 739 * @return string The translation update language. 740 */ 741 function wp_get_translation_update_language( $locale ) { 742 $translations = get_site_transient( 'available_translations' ); 743 744 if ( is_array( $translations ) && ! empty( $translations[ $locale ]['native_name'] ) ) { 745 return sprintf( 746 /* translators: 1: Native language name, 2: Locale. */ 747 __( '%1$s (%2$s)' ), 748 $translations[ $locale ]['native_name'], 749 $locale 750 ); 751 } 752 753 return $locale; 754 } 755 756 /** 757 * Gets display data for available translation updates. 758 * 759 * @since 7.2.0 760 * 761 * @return array[] { 762 * An array of translation update display data. 763 * 764 * @type bool $checked Whether the translation update is selected for installation. 765 * @type bool $deferred Whether the translation update has been deferred. 766 * @type string $id Translation update identifier. 767 * @type string $language Translation update language. 768 * @type string $language_code Translation update locale. 769 * @type string $name Translation update name. 770 * @type string $slug Translation update slug. 771 * @type string $type Translation update type. 772 * @type string $version Translation update version. 773 * } 774 */ 775 function wp_get_translation_update_data() { 776 $available_updates = wp_get_translation_updates(); 777 $deferred_translation_updates = wp_get_deferred_translation_updates( $available_updates ); 778 $plugin_names = null; 779 $translation_updates = array(); 780 781 foreach ( $available_updates as $update ) { 782 $translation_update_id = wp_get_translation_update_id( $update ); 783 $language = isset( $update->language ) ? $update->language : ''; 784 $type = isset( $update->type ) ? $update->type : ''; 785 $deferred = isset( $deferred_translation_updates[ $translation_update_id ] ); 786 787 if ( 'plugin' === $type && null === $plugin_names ) { 788 $plugin_names = wp_get_translation_update_plugin_names(); 789 } 790 791 $translation_updates[] = array( 792 'checked' => ! $deferred, 793 'deferred' => $deferred, 794 'id' => $translation_update_id, 795 'language' => wp_get_translation_update_language( $language ), 796 'language_code' => $language, 797 'name' => wp_get_translation_update_name( $update, $plugin_names ), 798 'slug' => isset( $update->slug ) ? $update->slug : '', 799 'type' => $type, 800 'version' => isset( $update->version ) ? $update->version : '', 801 ); 802 } 803 804 return $translation_updates; 805 } 806 807 /** 808 * Processes a translation update selection and stores the deferred updates. 809 * 810 * Only currently available updates included in the submitted form can be selected 811 * or deferred. Previously deferred updates outside the form remain deferred, while 812 * newly available updates outside the form are left unchanged. 813 * 814 * The caller must check capabilities and the nonce before calling this function. 815 * 816 * @since 7.2.0 817 * 818 * @param string[] $translation_update_ids Sanitized identifiers of updates included in the form. 819 * @param string[] $selected_translation_update_ids Sanitized identifiers of selected updates. 820 * @return object[]|false Selected current translation updates keyed by identifier, an empty array 821 * if all updates in the form were deferred, or false if the form contains 822 * no currently available updates. On false, stored deferrals are unchanged. 823 */ 824 function wp_process_translation_update_selection( $translation_update_ids, $selected_translation_update_ids ) { 825 if ( empty( $translation_update_ids ) ) { 826 return false; 827 } 828 829 $current_translation_updates = wp_get_translation_updates_by_id(); 830 $translation_updates = array_intersect_key( $current_translation_updates, array_flip( $translation_update_ids ) ); 831 832 if ( empty( $translation_updates ) ) { 833 return false; 834 } 835 836 $selected_translation_updates = array_intersect_key( $translation_updates, array_flip( $selected_translation_update_ids ) ); 837 $deferred_translation_updates = array_intersect_key( 838 $current_translation_updates, 839 wp_get_deferred_translation_updates() 840 ); 841 $deferred_translation_updates = array_diff_key( $deferred_translation_updates, $translation_updates ); 842 $deferred_translation_updates += array_diff_key( $translation_updates, $selected_translation_updates ); 843 844 wp_set_deferred_translation_updates( $deferred_translation_updates ); 845 846 return $selected_translation_updates; 847 } 848 849 /** 850 * Adds a callback to display update information for themes with updates available. 851 * 852 * @since 3.1.0 853 */ 854 function wp_theme_update_rows() { 855 if ( ! current_user_can( 'update_themes' ) ) { 856 return; 857 } 858 859 $themes = get_site_transient( 'update_themes' ); 860 861 if ( isset( $themes->response ) && is_array( $themes->response ) ) { 862 $themes = array_keys( $themes->response ); 863 864 foreach ( $themes as $theme ) { 865 add_action( "after_theme_row_{$theme}", 'wp_theme_update_row', 10, 2 ); 866 } 867 } 868 } 869 870 /** 871 * Displays update information for a theme. 872 * 873 * @since 3.1.0 874 * 875 * @param string $theme_key Theme stylesheet. 876 * @param WP_Theme $theme Theme object. 877 * @return void|false Void on success, false if the theme update is not available. 878 */ 879 function wp_theme_update_row( $theme_key, $theme ) { 880 $current = get_site_transient( 'update_themes' ); 881 882 if ( ! isset( $current->response[ $theme_key ] ) ) { 883 return false; 884 } 885 886 $response = $current->response[ $theme_key ]; 887 888 $details_url = add_query_arg( 889 array( 890 'TB_iframe' => 'true', 891 'width' => 1024, 892 'height' => 800, 893 ), 894 $current->response[ $theme_key ]['url'] 895 ); 896 897 /** @var WP_MS_Themes_List_Table $wp_list_table */ 898 $wp_list_table = _get_list_table( 'WP_MS_Themes_List_Table' ); 899 900 $active = $theme->is_allowed( 'network' ) ? ' active' : ''; 901 902 $requires_wp = $response['requires'] ?? null; 903 $requires_php = $response['requires_php'] ?? null; 904 905 $compatible_wp = is_wp_version_compatible( $requires_wp ); 906 $compatible_php = is_php_version_compatible( $requires_php ); 907 908 printf( 909 '<tr class="plugin-update-tr%s" id="%s" data-slug="%s">' . 910 '<td colspan="%s" class="plugin-update colspanchange">' . 911 '<div class="update-message notice inline notice-warning notice-alt"><p>', 912 $active, 913 esc_attr( $theme->get_stylesheet() . '-update' ), 914 esc_attr( $theme->get_stylesheet() ), 915 $wp_list_table->get_column_count() 916 ); 917 918 if ( $compatible_wp && $compatible_php ) { 919 if ( ! current_user_can( 'update_themes' ) ) { 920 printf( 921 /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ 922 __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ), 923 $theme['Name'], 924 esc_url( $details_url ), 925 sprintf( 926 'class="thickbox open-plugin-details-modal" aria-label="%s"', 927 /* translators: 1: Theme name, 2: Version number. */ 928 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) 929 ), 930 $response['new_version'] 931 ); 932 } elseif ( empty( $response['package'] ) ) { 933 printf( 934 /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number. */ 935 __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ), 936 $theme['Name'], 937 esc_url( $details_url ), 938 sprintf( 939 'class="thickbox open-plugin-details-modal" aria-label="%s"', 940 /* translators: 1: Theme name, 2: Version number. */ 941 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) 942 ), 943 $response['new_version'] 944 ); 945 } else { 946 printf( 947 /* translators: 1: Theme name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ 948 __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ), 949 $theme['Name'], 950 esc_url( $details_url ), 951 sprintf( 952 'class="thickbox open-plugin-details-modal" aria-label="%s"', 953 /* translators: 1: Theme name, 2: Version number. */ 954 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) 955 ), 956 $response['new_version'], 957 wp_nonce_url( self_admin_url( 'update.php?action=upgrade-theme&theme=' ) . $theme_key, 'upgrade-theme_' . $theme_key ), 958 sprintf( 959 'class="update-link" aria-label="%s"', 960 /* translators: %s: Theme name. */ 961 esc_attr( sprintf( _x( 'Update %s now', 'theme' ), $theme['Name'] ) ) 962 ) 963 ); 964 } 965 } else { 966 if ( ! $compatible_wp && ! $compatible_php ) { 967 printf( 968 /* translators: %s: Theme name. */ 969 __( 'There is a new version of %s available, but it does not work with your versions of WordPress and PHP.' ), 970 $theme['Name'] 971 ); 972 if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) { 973 printf( 974 /* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */ 975 ' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ), 976 self_admin_url( 'update-core.php' ), 977 esc_url( wp_get_update_php_url() ) 978 ); 979 wp_update_php_annotation( '</p><p><em>', '</em>' ); 980 } elseif ( current_user_can( 'update_core' ) ) { 981 printf( 982 /* translators: %s: URL to WordPress Updates screen. */ 983 ' ' . __( '<a href="%s">Please update WordPress</a>.' ), 984 self_admin_url( 'update-core.php' ) 985 ); 986 } elseif ( current_user_can( 'update_php' ) ) { 987 printf( 988 /* translators: %s: URL to Update PHP page. */ 989 ' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ), 990 esc_url( wp_get_update_php_url() ) 991 ); 992 wp_update_php_annotation( '</p><p><em>', '</em>' ); 993 } 994 } elseif ( ! $compatible_wp ) { 995 printf( 996 /* translators: %s: Theme name. */ 997 __( 'There is a new version of %s available, but it does not work with your version of WordPress.' ), 998 $theme['Name'] 999 ); 1000 if ( current_user_can( 'update_core' ) ) { 1001 printf( 1002 /* translators: %s: URL to WordPress Updates screen. */ 1003 ' ' . __( '<a href="%s">Please update WordPress</a>.' ), 1004 self_admin_url( 'update-core.php' ) 1005 ); 1006 } 1007 } elseif ( ! $compatible_php ) { 1008 printf( 1009 /* translators: %s: Theme name. */ 1010 __( 'There is a new version of %s available, but it does not work with your version of PHP.' ), 1011 $theme['Name'] 1012 ); 1013 if ( current_user_can( 'update_php' ) ) { 1014 printf( 1015 /* translators: %s: URL to Update PHP page. */ 1016 ' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ), 1017 esc_url( wp_get_update_php_url() ) 1018 ); 1019 wp_update_php_annotation( '</p><p><em>', '</em>' ); 1020 } 1021 } 1022 } 1023 1024 /** 1025 * Fires at the end of the update message container in each 1026 * row of the themes list table. 1027 * 1028 * The dynamic portion of the hook name, `$theme_key`, refers to 1029 * the theme slug as found in the WordPress.org themes repository. 1030 * 1031 * @since 3.1.0 1032 * 1033 * @param WP_Theme $theme The WP_Theme object. 1034 * @param array $response { 1035 * An array of metadata about the available theme update. 1036 * 1037 * @type string $new_version New theme version. 1038 * @type string $url Theme URL. 1039 * @type string $package Theme update package URL. 1040 * } 1041 */ 1042 do_action( "in_theme_update_message-{$theme_key}", $theme, $response ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores 1043 1044 echo '</p></div></td></tr>'; 1045 } 1046 1047 /** 1048 * Displays maintenance nag HTML message. 1049 * 1050 * @since 2.7.0 1051 * 1052 * @global int $upgrading 1053 * 1054 * @return void|false Void on success, false if the maintenance nag should not be displayed. 1055 */ 1056 function maintenance_nag() { 1057 global $upgrading; 1058 1059 $nag = isset( $upgrading ); 1060 1061 if ( ! $nag ) { 1062 $failed = get_site_option( 'auto_core_update_failed' ); 1063 /* 1064 * If an update failed critically, we may have copied over version.php but not other files. 1065 * In that case, if the installation claims we're running the version we attempted, nag. 1066 * This is serious enough to err on the side of nagging. 1067 * 1068 * If we simply failed to update before we tried to copy any files, then assume things are 1069 * OK if they are now running the latest. 1070 * 1071 * This flag is cleared whenever a successful update occurs using Core_Upgrader. 1072 */ 1073 $comparison = ! empty( $failed['critical'] ) ? '>=' : '>'; 1074 if ( isset( $failed['attempted'] ) && version_compare( $failed['attempted'], wp_get_wp_version(), $comparison ) ) { 1075 $nag = true; 1076 } 1077 } 1078 1079 if ( ! $nag ) { 1080 return false; 1081 } 1082 1083 if ( current_user_can( 'update_core' ) ) { 1084 $msg = sprintf( 1085 /* translators: %s: URL to WordPress Updates screen. */ 1086 __( 'An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.' ), 1087 'update-core.php' 1088 ); 1089 } else { 1090 $msg = __( 'An automated WordPress update has failed to complete! Please notify the site administrator.' ); 1091 } 1092 1093 wp_admin_notice( 1094 $msg, 1095 array( 1096 'type' => 'warning', 1097 'additional_classes' => array( 'update-nag', 'inline' ), 1098 'paragraph_wrap' => false, 1099 ) 1100 ); 1101 } 1102 1103 /** 1104 * Prints the JavaScript templates for update admin notices. 1105 * 1106 * @since 4.6.0 1107 * 1108 * Template takes one argument with four values: 1109 * 1110 * param {object} data { 1111 * Arguments for admin notice. 1112 * 1113 * @type string id ID of the notice. 1114 * @type string className Class names for the notice. 1115 * @type string message The notice's message. 1116 * @type string type The type of update the notice is for. Either 'plugin' or 'theme'. 1117 * } 1118 */ 1119 function wp_print_admin_notice_templates() { 1120 ?> 1121 <script id="tmpl-wp-updates-admin-notice" type="text/html"> 1122 <div <# if ( data.id ) { #>id="{{ data.id }}"<# } #> class="notice {{ data.className }}"><p>{{{ data.message }}}</p></div> 1123 </script> 1124 <script id="tmpl-wp-bulk-updates-admin-notice" type="text/html"> 1125 <div id="{{ data.id }}" class="{{ data.className }} notice <# if ( data.errorMessage ) { #>notice-error<# } else { #>notice-success<# } #>"> 1126 <p> 1127 <# if ( data.successMessage ) { #> 1128 {{{ data.successMessage }}} 1129 <# } #> 1130 <# if ( data.errorMessage ) { #> 1131 <button class="button-link bulk-action-errors-collapsed" aria-expanded="false"> 1132 {{{ data.errorMessage }}} 1133 <span class="screen-reader-text"> 1134 <?php 1135 /* translators: Hidden accessibility text. */ 1136 _e( 'Show more details' ); 1137 ?> 1138 </span> 1139 <span class="toggle-indicator" aria-hidden="true"></span> 1140 </button> 1141 <# } #> 1142 </p> 1143 <# if ( data.errorMessages ) { #> 1144 <ul class="bulk-action-errors hidden"> 1145 <# _.each( data.errorMessages, function( errorMessage ) { #> 1146 <li>{{ errorMessage }}</li> 1147 <# } ); #> 1148 </ul> 1149 <# } #> 1150 </div> 1151 </script> 1152 <?php 1153 } 1154 1155 /** 1156 * Prints the JavaScript templates for update and deletion rows in list tables. 1157 * 1158 * @since 4.6.0 1159 * 1160 * The update template takes one argument with four values: 1161 * 1162 * param {object} data { 1163 * Arguments for the update row 1164 * 1165 * @type string slug Plugin slug. 1166 * @type string plugin Plugin base name. 1167 * @type string colspan The number of table columns this row spans. 1168 * @type string content The row content. 1169 * } 1170 * 1171 * The delete template takes one argument with four values: 1172 * 1173 * param {object} data { 1174 * Arguments for the update row 1175 * 1176 * @type string slug Plugin slug. 1177 * @type string plugin Plugin base name. 1178 * @type string name Plugin name. 1179 * @type string colspan The number of table columns this row spans. 1180 * } 1181 */ 1182 function wp_print_update_row_templates() { 1183 ?> 1184 <script id="tmpl-item-update-row" type="text/template"> 1185 <tr class="plugin-update-tr update" id="{{ data.slug }}-update" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> 1186 <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> 1187 {{{ data.content }}} 1188 </td> 1189 </tr> 1190 </script> 1191 <script id="tmpl-item-deleted-row" type="text/template"> 1192 <tr class="plugin-deleted-tr inactive deleted" id="{{ data.slug }}-deleted" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> 1193 <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> 1194 <# if ( data.plugin ) { #> 1195 <?php 1196 printf( 1197 /* translators: %s: Plugin name. */ 1198 _x( '%s was successfully deleted.', 'plugin' ), 1199 '<strong>{{{ data.name }}}</strong>' 1200 ); 1201 ?> 1202 <# } else { #> 1203 <?php 1204 printf( 1205 /* translators: %s: Theme name. */ 1206 _x( '%s was successfully deleted.', 'theme' ), 1207 '<strong>{{{ data.name }}}</strong>' 1208 ); 1209 ?> 1210 <# } #> 1211 </td> 1212 </tr> 1213 </script> 1214 <?php 1215 } 1216 1217 /** 1218 * Displays a notice when the user is in recovery mode. 1219 * 1220 * @since 5.2.0 1221 */ 1222 function wp_recovery_mode_nag() { 1223 if ( ! wp_is_recovery_mode() ) { 1224 return; 1225 } 1226 1227 $url = wp_login_url(); 1228 $url = add_query_arg( 'action', WP_Recovery_Mode::EXIT_ACTION, $url ); 1229 $url = wp_nonce_url( $url, WP_Recovery_Mode::EXIT_ACTION ); 1230 1231 $message = sprintf( 1232 /* translators: %s: Recovery Mode exit link. */ 1233 __( 'You are in recovery mode. This means there may be an error with a theme or plugin. To exit recovery mode, log out or use the Exit button. <a href="%s">Exit Recovery Mode</a>' ), 1234 esc_url( $url ) 1235 ); 1236 wp_admin_notice( $message, array( 'type' => 'info' ) ); 1237 } 1238 1239 /** 1240 * Checks whether auto-updates are enabled. 1241 * 1242 * @since 5.5.0 1243 * 1244 * @param string $type The type of update being checked: Either 'theme' or 'plugin'. 1245 * @return bool True if auto-updates are enabled for `$type`, false otherwise. 1246 */ 1247 function wp_is_auto_update_enabled_for_type( $type ) { 1248 if ( ! class_exists( 'WP_Automatic_Updater' ) ) { 1249 require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php'; 1250 } 1251 1252 $updater = new WP_Automatic_Updater(); 1253 $enabled = ! $updater->is_disabled(); 1254 1255 switch ( $type ) { 1256 case 'plugin': 1257 /** 1258 * Filters whether plugins auto-update is enabled. 1259 * 1260 * @since 5.5.0 1261 * 1262 * @param bool $enabled True if plugins auto-update is enabled, false otherwise. 1263 */ 1264 return apply_filters( 'plugins_auto_update_enabled', $enabled ); 1265 case 'theme': 1266 /** 1267 * Filters whether themes auto-update is enabled. 1268 * 1269 * @since 5.5.0 1270 * 1271 * @param bool $enabled True if themes auto-update is enabled, false otherwise. 1272 */ 1273 return apply_filters( 'themes_auto_update_enabled', $enabled ); 1274 } 1275 1276 return false; 1277 } 1278 1279 /** 1280 * Checks whether auto-updates are forced for an item. 1281 * 1282 * @since 5.6.0 1283 * 1284 * @param string $type The type of update being checked: Either 'theme' or 'plugin'. 1285 * @param bool|null $update Whether to update. The value of null is internally used 1286 * to detect whether nothing has hooked into this filter. 1287 * @param object $item The update offer. 1288 * @return bool True if auto-updates are forced for `$item`, false otherwise. 1289 */ 1290 function wp_is_auto_update_forced_for_item( $type, $update, $item ) { 1291 /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */ 1292 return apply_filters( "auto_update_{$type}", $update, $item ); 1293 } 1294 1295 /** 1296 * Determines the appropriate auto-update message to be displayed. 1297 * 1298 * @since 5.5.0 1299 * @since 7.2.0 Added the `$type` parameter. A message is now returned when 1300 * automatic updates cannot run because the filesystem requires 1301 * credentials or the site appears to be under version control. 1302 * 1303 * @param string $type Optional. The type of update the message is for: 'plugin' or 'theme'. 1304 * Determines which directory is checked. Default empty, which checks ABSPATH. 1305 * @return string The update message to be shown. 1306 */ 1307 function wp_get_auto_update_message( $type = '' ) { 1308 // Loads Automatic_Upgrader_Skin and WP_Automatic_Updater. 1309 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; 1310 1311 if ( ! function_exists( 'request_filesystem_credentials' ) ) { 1312 require_once ABSPATH . 'wp-admin/includes/file.php'; 1313 } 1314 1315 switch ( $type ) { 1316 case 'plugin': 1317 $context = WP_PLUGIN_DIR; 1318 break; 1319 case 'theme': 1320 $context = get_theme_root(); 1321 break; 1322 default: 1323 $context = ABSPATH; 1324 } 1325 1326 /* 1327 * These mirror the checks in WP_Automatic_Updater::should_update(), which skips 1328 * the update regardless of the schedule if either one fails. 1329 */ 1330 $skin = new Automatic_Upgrader_Skin(); 1331 $updater = new WP_Automatic_Updater(); 1332 1333 $message = ''; 1334 if ( ! $skin->request_filesystem_credentials( false, $context ) ) { 1335 $message = __( 'Automatic update will not run because WordPress needs FTP credentials to update files.' ); 1336 } elseif ( $updater->is_vcs_checkout( $context ) ) { 1337 $message = __( 'Automatic update will not run because this site appears to be under version control.' ); 1338 } 1339 1340 if ( $message ) { 1341 if ( current_user_can( 'view_site_health_checks' ) ) { 1342 $message .= ' ' . sprintf( 1343 /* translators: %s: URL to the Site Health screen. */ 1344 __( '<a href="%s">Learn more in Site Health</a>.' ), 1345 esc_url( admin_url( 'site-health.php' ) ) 1346 ); 1347 } 1348 1349 return $message; 1350 } 1351 1352 $next_update_time = wp_next_scheduled( 'wp_version_check' ); 1353 1354 // Check if the event exists. 1355 if ( false === $next_update_time ) { 1356 $message = __( 'Automatic update not scheduled. There may be a problem with WP-Cron.' ); 1357 } else { 1358 $time_to_next_update = human_time_diff( (int) $next_update_time ); 1359 1360 // See if cron is overdue. 1361 $overdue = ( time() - $next_update_time ) > 0; 1362 1363 if ( $overdue ) { 1364 $message = sprintf( 1365 /* translators: %s: Duration that WP-Cron has been overdue. */ 1366 __( 'Automatic update overdue by %s. There may be a problem with WP-Cron.' ), 1367 $time_to_next_update 1368 ); 1369 } else { 1370 $message = sprintf( 1371 /* translators: %s: Time until the next update. */ 1372 __( 'Automatic update scheduled in %s.' ), 1373 $time_to_next_update 1374 ); 1375 } 1376 } 1377 1378 return $message; 1379 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Mon Nov 9 08:20:01 2026 | Cross-referenced by PHPXref |