Make WordPress Core

Changeset 44717


Ignore:
Timestamp:
01/30/2019 11:00:30 AM (8 years ago)
Author:
flixos90
Message:

Bootstrap/Load: Revert fatal error recovery mechanism from 5.1 to polish for 5.2.

Due to the high number of follow-up tickets and associated security concerns, it was decided to reschedule the fatal error recovery feature for WordPress 5.2, in order to address these issues properly. The feature will continue to be developed, with iterations being merged into trunk early in the 5.2 release cycle.

Fixes #46141. See #44458, #45932, #45940, #46038, #46047, #46068.

Location:
trunk
Files:
3 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/list-tables.css

    r44646 r44717  
    13021302}
    13031303
    1304 .plugins tr.paused th.check-column {
    1305         border-left: 4px solid #d54e21;
    1306 }
    1307 
    1308 .plugins tr.paused th,
    1309 .plugins tr.paused td {
    1310         background-color: #fef7f1;
    1311 }
    1312 
    1313 .plugins tr.paused .plugin-title,
    1314 .plugins .paused .dashicons-warning {
    1315         color: #dc3232;
    1316 }
    1317 
    1318 .plugins .paused .error-display p,
    1319 .plugins .paused .error-display code {
    1320         font-size: 90%;
    1321         font-style: italic;
    1322         color: rgb( 0, 0, 0, 0.7 );
    1323 }
    1324 
    1325 .plugins .resume-link {
    1326         color: #dc3232;
    1327 }
    1328 
    13291304.plugin-card .update-now:before {
    13301305        color: #f56e28;
  • trunk/src/wp-admin/includes/admin-filters.php

    r44647 r44717  
    118118
    119119add_action( 'admin_notices', 'update_nag', 3 );
    120 add_action( 'admin_notices', 'paused_plugins_notice', 5 );
    121 add_action( 'admin_notices', 'paused_themes_notice', 5 );
    122120add_action( 'admin_notices', 'maintenance_nag', 10 );
    123121
  • trunk/src/wp-admin/includes/class-wp-plugins-list-table.php

    r44541 r44717  
    4141
    4242                $status = 'all';
    43                 if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused' ) ) ) {
     43                if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) ) {
    4444                        $status = $_REQUEST['plugin_status'];
    4545                }
     
    100100                        'mustuse'            => array(),
    101101                        'dropins'            => array(),
    102                         'paused'             => array(),
    103102                );
    104103
     
    211210                                        // On the non-network screen, show network-active plugins if allowed
    212211                                        $plugins['active'][ $plugin_file ] = $plugin_data;
    213                                         if ( is_plugin_paused( $plugin_file ) ) {
    214                                                 $plugins['paused'][ $plugin_file ] = $plugin_data;
    215                                         }
    216212                                } else {
    217213                                        // On the non-network screen, filter out network-active plugins
     
    223219                                // On the network-admin screen, populate the active list with plugins that are network activated
    224220                                $plugins['active'][ $plugin_file ] = $plugin_data;
    225                                 if ( is_plugin_paused( $plugin_file ) ) {
    226                                         $plugins['paused'][ $plugin_file ] = $plugin_data;
    227                                 }
    228221                        } else {
    229222                                if ( isset( $recently_activated[ $plugin_file ] ) ) {
     
    453446                                        $text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
    454447                                        break;
    455                                 case 'paused':
    456                                         /* translators: %s: plugin count */
    457                                         $text = _n( 'Paused <span class="count">(%s)</span>', 'Paused <span class="count">(%s)</span>', $count );
    458                                         break;
    459448                                case 'upgrade':
    460449                                        /* translators: %s: plugin count */
     
    645634                                                $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Deactivate' ) . '</a>';
    646635                                        }
    647                                         if ( current_user_can( 'manage_network_plugins' ) && count_paused_plugin_sites_for_network( $plugin_file ) ) {
    648                                                 /* translators: %s: plugin name */
    649                                                 $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Resume' ) . '</a>';
    650                                         }
    651636                                } else {
    652637                                        if ( current_user_can( 'manage_network_plugins' ) ) {
    653638                                                /* translators: %s: plugin name */
    654639                                                $actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Activate' ) . '</a>';
    655                                         }
    656                                         if ( current_user_can( 'manage_network_plugins' ) && count_paused_plugin_sites_for_network( $plugin_file ) ) {
    657                                                 /* translators: %s: plugin name */
    658                                                 $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Resume' ) . '</a>';
    659640                                        }
    660641                                        if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
     
    668649                                                'network_active' => __( 'Network Active' ),
    669650                                        );
    670                                         if ( ! $restrict_network_only && current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
    671                                                 /* translators: %s: plugin name */
    672                                                 $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Resume' ) . '</a>';
    673                                         }
    674651                                } elseif ( $restrict_network_only ) {
    675652                                        $actions = array(
     
    681658                                                $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
    682659                                        }
    683                                         if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
    684                                                 /* translators: %s: plugin name */
    685                                                 $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Resume' ) . '</a>';
    686                                         }
    687660                                } else {
    688661                                        if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
     
    790763                if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) ) {
    791764                        $class .= ' update';
    792                 }
    793 
    794                 $paused                        = is_plugin_paused( $plugin_file );
    795                 $paused_on_network_sites_count = $screen->in_admin( 'network' ) ? count_paused_plugin_sites_for_network( $plugin_file ) : 0;
    796                 if ( $paused || $paused_on_network_sites_count ) {
    797                         $class .= ' paused';
    798765                }
    799766
     
    879846                                         * @param string   $status      Status of the plugin. Defaults are 'All', 'Active',
    880847                                         *                              'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    881                                          *                              'Drop-ins', 'Search', 'Paused'.
     848                                         *                              'Drop-ins', 'Search'.
    882849                                         */
    883850                                        $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
     
    885852
    886853                                        echo '</div>';
    887 
    888                                         if ( $paused || $paused_on_network_sites_count ) {
    889                                                 $notice_text = __( 'This plugin failed to load properly and was paused within the admin backend.' );
    890                                                 if ( $screen->in_admin( 'network' ) && $paused_on_network_sites_count ) {
    891                                                         $notice_text = sprintf(
    892                                                                 /* translators: %s: number of sites */
    893                                                                 _n( 'This plugin failed to load properly and was paused within the admin backend for %s site.', 'This plugin failed to load properly and was paused within the admin backend for %s sites.', $paused_on_network_sites_count ),
    894                                                                 number_format_i18n( $paused_on_network_sites_count )
    895                                                         );
    896                                                 }
    897 
    898                                                 printf( '<p><span class="dashicons dashicons-warning"></span> <strong>%s</strong></p>', $notice_text );
    899 
    900                                                 $error = wp_get_plugin_error( $plugin_file );
    901 
    902                                                 if ( false !== $error ) {
    903                                                         $constants = get_defined_constants( true );
    904                                                         $constants = isset( $constants['Core'] ) ? $constants['Core'] : $constants['internal'];
    905 
    906                                                         foreach ( $constants as $constant => $value ) {
    907                                                                 if ( 0 === strpos( $constant, 'E_' ) ) {
    908                                                                         $core_errors[ $value ] = $constant;
    909                                                                 }
    910                                                         }
    911 
    912                                                         $error['type'] = $core_errors[ $error['type'] ];
    913 
    914                                                         printf(
    915                                                                 '<div class="error-display"><p>%s</p></div>',
    916                                                                 sprintf(
    917                                                                         /* translators: 1: error type, 2: error line number, 3: error file name, 4: error message */
    918                                                                         __( 'The plugin caused an error of type %1$s in line %2$s of the file %3$s. Error message: %4$s' ),
    919                                                                         "<code>{$error['type']}</code>",
    920                                                                         "<code>{$error['line']}</code>",
    921                                                                         "<code>{$error['file']}</code>",
    922                                                                         "<code>{$error['message']}</code>"
    923                                                                 )
    924                                                         );
    925                                                 }
    926                                         }
    927854
    928855                                        echo '</td>';
     
    959886                 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    960887                 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    961                  *                            'Drop-ins', 'Search', 'Paused'.
     888                 *                            'Drop-ins', 'Search'.
    962889                 */
    963890                do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
     
    975902                 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    976903                 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    977                  *                            'Drop-ins', 'Search', 'Paused'.
     904                 *                            'Drop-ins', 'Search'.
    978905                 */
    979906                do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
  • trunk/src/wp-admin/includes/plugin.php

    r44675 r44717  
    469469function _get_dropins() {
    470470        $dropins = array(
    471                 'advanced-cache.php'      => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
    472                 'db.php'                  => array( __( 'Custom database class.' ), true ), // auto on load
    473                 'db-error.php'            => array( __( 'Custom database error message.' ), true ), // auto on error
    474                 'install.php'             => array( __( 'Custom installation script.' ), true ), // auto on installation
    475                 'maintenance.php'         => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
    476                 'object-cache.php'        => array( __( 'External object cache.' ), true ), // auto on load
    477                 'php-error.php'           => array( __( 'Custom PHP error message.' ), true ), // auto on error
    478                 'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // auto on error
     471                'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
     472                'db.php'             => array( __( 'Custom database class.' ), true ), // auto on load
     473                'db-error.php'       => array( __( 'Custom database error message.' ), true ), // auto on error
     474                'install.php'        => array( __( 'Custom installation script.' ), true ), // auto on installation
     475                'maintenance.php'    => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
     476                'object-cache.php'   => array( __( 'External object cache.' ), true ), // auto on load
    479477        );
    480478
     
    527525function is_plugin_inactive( $plugin ) {
    528526        return ! is_plugin_active( $plugin );
    529 }
    530 
    531 /**
    532  * Determines whether a plugin is technically active but was paused while
    533  * loading.
    534  *
    535  * For more information on this and similar theme functions, check out
    536  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
    537  * Conditional Tags} article in the Theme Developer Handbook.
    538  *
    539  * @since 5.1.0
    540  *
    541  * @param string $plugin Path to the plugin file relative to the plugins directory.
    542  * @return bool True, if in the list of paused plugins. False, not in the list.
    543  */
    544 function is_plugin_paused( $plugin ) {
    545         if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    546                 return false;
    547         }
    548 
    549         if ( ! is_plugin_active( $plugin ) && ! is_plugin_active_for_network( $plugin ) ) {
    550                 return false;
    551         }
    552 
    553         list( $plugin ) = explode( '/', $plugin );
    554 
    555         return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
    556 }
    557 
    558 /**
    559  * Gets the error that was recorded for a paused plugin.
    560  *
    561  * @since 5.1.0
    562  *
    563  * @param string $plugin Path to the plugin file relative to the plugins
    564  *                       directory.
    565  * @return array|false Array of error information as it was returned by
    566  *                     `error_get_last()`, or false if none was recorded.
    567  */
    568 function wp_get_plugin_error( $plugin ) {
    569         if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    570                 return false;
    571         }
    572 
    573         list( $plugin ) = explode( '/', $plugin );
    574 
    575         if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
    576                 return false;
    577         }
    578 
    579         return $GLOBALS['_paused_plugins'][ $plugin ];
    580 }
    581 
    582 /**
    583  * Gets the number of sites on which a specific plugin is paused.
    584  *
    585  * @since 5.1.0
    586  *
    587  * @param string $plugin Path to the plugin file relative to the plugins directory.
    588  * @return int Site count.
    589  */
    590 function count_paused_plugin_sites_for_network( $plugin ) {
    591         if ( ! is_multisite() ) {
    592                 return is_plugin_paused( $plugin ) ? 1 : 0;
    593         }
    594 
    595         list( $plugin ) = explode( '/', $plugin );
    596 
    597         $query_args = array(
    598                 'count'      => true,
    599                 'number'     => 0,
    600                 'network_id' => get_current_network_id(),
    601                 'meta_query' => array(
    602                         wp_paused_plugins()->get_site_meta_query_clause( $plugin ),
    603                 ),
    604         );
    605 
    606         return get_sites( $query_args );
    607527}
    608528
     
    802722                if ( ! is_plugin_active( $plugin ) ) {
    803723                        continue;
    804                 }
    805 
    806                 // Clean up the database before deactivating the plugin.
    807                 if ( is_plugin_paused( $plugin ) ) {
    808                         resume_plugin( $plugin );
    809724                }
    810725
     
    1003918                }
    1004919
    1005                 // Clean up the database before removing the plugin.
    1006                 if ( is_plugin_paused( $plugin_file ) ) {
    1007                         resume_plugin( $plugin_file );
    1008                 }
    1009 
    1010920                /**
    1011921                 * Fires immediately before a plugin deletion attempt.
     
    1080990
    1081991                return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
    1082         }
    1083 
    1084         return true;
    1085 }
    1086 
    1087 /**
    1088  * Tries to resume a single plugin.
    1089  *
    1090  * If a redirect was provided, we first ensure the plugin does not throw fatal
    1091  * errors anymore.
    1092  *
    1093  * The way it works is by setting the redirection to the error before trying to
    1094  * include the plugin file. If the plugin fails, then the redirection will not
    1095  * be overwritten with the success message and the plugin will not be resumed.
    1096  *
    1097  * @since 5.1.0
    1098  *
    1099  * @param string $plugin       Single plugin to resume.
    1100  * @param string $redirect     Optional. URL to redirect to. Default empty string.
    1101  * @param bool   $network_wide Optional. Whether to resume the plugin for the entire
    1102  *                             network. Default false.
    1103  * @return bool|WP_Error True on success, false if `$plugin` was not paused,
    1104  *                       `WP_Error` on failure.
    1105  */
    1106 function resume_plugin( $plugin, $redirect = '', $network_wide = false ) {
    1107         /*
    1108          * We'll override this later if the plugin could be included without
    1109          * creating a fatal error.
    1110          */
    1111         if ( ! empty( $redirect ) ) {
    1112                 wp_redirect(
    1113                         add_query_arg(
    1114                                 '_error_nonce',
    1115                                 wp_create_nonce( 'plugin-resume-error_' . $plugin ),
    1116                                 $redirect
    1117                         )
    1118                 );
    1119 
    1120                 // Load the plugin to test whether it throws a fatal error.
    1121                 ob_start();
    1122                 plugin_sandbox_scrape( $plugin );
    1123                 ob_clean();
    1124         }
    1125 
    1126         $result = wp_forget_extension_error( 'plugins', $plugin, $network_wide );
    1127 
    1128         if ( ! $result ) {
    1129                 return new WP_Error(
    1130                         'could_not_resume_plugin',
    1131                         __( 'Could not resume the plugin.' )
    1132                 );
    1133992        }
    1134993
     
    22432102        WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
    22442103}
    2245 
    2246 /**
    2247  * Renders an admin notice in case some plugins have been paused due to errors.
    2248  *
    2249  * @since 5.1.0
    2250  */
    2251 function paused_plugins_notice() {
    2252         if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
    2253                 return;
    2254         }
    2255 
    2256         if ( ! current_user_can( 'deactivate_plugins' ) ) {
    2257                 return;
    2258         }
    2259 
    2260         if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) {
    2261                 return;
    2262         }
    2263 
    2264         printf(
    2265                 '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p>%s</p></div>',
    2266                 __( 'One or more plugins failed to load properly.' ),
    2267                 __( 'You can find more details and make changes on the Plugins screen.' ),
    2268                 sprintf(
    2269                         '<a href="%s">%s</a>',
    2270                         admin_url( 'plugins.php?plugin_status=paused' ),
    2271                         'Go to the Plugins screen'
    2272                 )
    2273         );
    2274 }
  • trunk/src/wp-admin/includes/theme.php

    r44675 r44717  
    769769        <?php
    770770}
    771 
    772 /**
    773  * Determines whether a theme is technically active but was paused while
    774  * loading.
    775  *
    776  * For more information on this and similar theme functions, check out
    777  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
    778  * Conditional Tags} article in the Theme Developer Handbook.
    779  *
    780  * @since 5.1.0
    781  *
    782  * @param string $theme Path to the theme directory relative to the themes directory.
    783  * @return bool True, if in the list of paused themes. False, not in the list.
    784  */
    785 function is_theme_paused( $theme ) {
    786         if ( ! isset( $GLOBALS['_paused_themes'] ) ) {
    787                 return false;
    788         }
    789 
    790         if ( $theme !== get_stylesheet() && $theme !== get_template() ) {
    791                 return false;
    792         }
    793 
    794         return array_key_exists( $theme, $GLOBALS['_paused_themes'] );
    795 }
    796 
    797 /**
    798  * Gets the error that was recorded for a paused theme.
    799  *
    800  * @since 5.1.0
    801  *
    802  * @param string $theme Path to the theme directory relative to the themes
    803  *                      directory.
    804  * @return array|false Array of error information as it was returned by
    805  *                     `error_get_last()`, or false if none was recorded.
    806  */
    807 function wp_get_theme_error( $theme ) {
    808         if ( ! isset( $GLOBALS['_paused_themes'] ) ) {
    809                 return false;
    810         }
    811 
    812         if ( ! array_key_exists( $theme, $GLOBALS['_paused_themes'] ) ) {
    813                 return false;
    814         }
    815 
    816         return $GLOBALS['_paused_themes'][ $theme ];
    817 }
    818 
    819 /**
    820  * Gets the number of sites on which a specific theme is paused.
    821  *
    822  * @since 5.1.0
    823  *
    824  * @param string $theme Path to the theme directory relative to the themes directory.
    825  * @return int Site count.
    826  */
    827 function count_paused_theme_sites_for_network( $theme ) {
    828         if ( ! is_multisite() ) {
    829                 return is_theme_paused( $theme ) ? 1 : 0;
    830         }
    831 
    832         $query_args = array(
    833                 'count'      => true,
    834                 'number'     => 0,
    835                 'network_id' => get_current_network_id(),
    836                 'meta_query' => array(
    837                         wp_paused_themes()->get_site_meta_query_clause( $theme ),
    838                 ),
    839         );
    840 
    841         return get_sites( $query_args );
    842 }
    843 
    844 /**
    845  * Tries to resume a single theme.
    846  *
    847  * @since 5.1.0
    848  *
    849  * @param string $theme Single theme to resume.
    850  * @return bool|WP_Error True on success, false if `$theme` was not paused,
    851  *                       `WP_Error` on failure.
    852  */
    853 function resume_theme( $theme ) {
    854         $result = wp_forget_extension_error( 'themes', $theme );
    855 
    856         if ( ! $result ) {
    857                 return new WP_Error(
    858                         'could_not_resume_theme',
    859                         __( 'Could not resume the theme.' )
    860                 );
    861         }
    862 
    863         return true;
    864 }
    865 
    866 /**
    867  * Renders an admin notice in case some themes have been paused due to errors.
    868  *
    869  * @since 5.1.0
    870  */
    871 function paused_themes_notice() {
    872         if ( 'themes.php' === $GLOBALS['pagenow'] ) {
    873                 return;
    874         }
    875 
    876         if ( ! current_user_can( 'switch_themes' ) ) {
    877                 return;
    878         }
    879 
    880         if ( ! isset( $GLOBALS['_paused_themes'] ) || empty( $GLOBALS['_paused_themes'] ) ) {
    881                 return;
    882         }
    883 
    884         printf(
    885                 '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p>%s</p></div>',
    886                 __( 'One or more themes failed to load properly.' ),
    887                 __( 'You can find more details and make changes on the Themes screen.' ),
    888                 sprintf(
    889                         '<a href="%s">%s</a>',
    890                         admin_url( 'themes.php' ),
    891                         'Go to the Themes screen'
    892                 )
    893         );
    894 }
  • trunk/src/wp-admin/plugins.php

    r44524 r44717  
    390390                        break;
    391391
    392                 case 'resume':
    393                         if ( ! current_user_can( 'resume_plugin', $plugin ) ) {
    394                                 wp_die( __( 'Sorry, you are not allowed to resume this plugin.' ) );
    395                         }
    396 
    397                         if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) {
    398                                 wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    399                                 exit;
    400                         }
    401 
    402                         check_admin_referer( 'resume-plugin_' . $plugin );
    403 
    404                         $result = resume_plugin( $plugin, self_admin_url( 'plugins.php?error=resuming' ), is_network_admin() );
    405 
    406                         if ( is_wp_error( $result ) ) {
    407                                 wp_die( $result );
    408                         }
    409 
    410                         wp_redirect( self_admin_url( "plugins.php?resume=true&plugin_status=$status&paged=$page&s=$s" ) );
    411                         exit;
    412 
    413392                default:
    414393                        if ( isset( $_POST['checked'] ) ) {
     
    510489                );
    511490                $errmsg .= ' ' . __( 'If you notice &#8220;headers already sent&#8221; messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.' );
    512         } elseif ( 'resuming' === $_GET['error'] ) {
    513                 $errmsg = __( 'Plugin could not be resumed because it triggered a <strong>fatal error</strong>.' );
    514491        } else {
    515492                $errmsg = __( 'Plugin could not be activated because it triggered a <strong>fatal error</strong>.' );
     
    565542<?php elseif ( 'update-selected' == $action ) : ?>
    566543        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'All selected plugins are up to date.' ); ?></p></div>
    567 <?php elseif ( isset( $_GET['resume'] ) ) : ?>
    568         <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin <strong>resumed</strong>.' ); ?></p></div>
    569544<?php endif; ?>
    570545
  • trunk/src/wp-admin/themes.php

    r44524 r44717  
    3333                switch_theme( $theme->get_stylesheet() );
    3434                wp_redirect( admin_url( 'themes.php?activated=true' ) );
    35                 exit;
    36         } elseif ( 'resume' === $_GET['action'] ) {
    37                 check_admin_referer( 'resume-theme_' . $_GET['stylesheet'] );
    38                 $theme = wp_get_theme( $_GET['stylesheet'] );
    39 
    40                 if ( ! current_user_can( 'resume_themes' ) ) {
    41                         wp_die(
    42                                 '<h1>' . __( 'You need a higher level of permission.' ) . '</h1>' .
    43                                 '<p>' . __( 'Sorry, you are not allowed to resume this theme.' ) . '</p>',
    44                                 403
    45                         );
    46                 }
    47 
    48                 $result = resume_theme( $theme->get_stylesheet() );
    49 
    50                 if ( is_wp_error( $result ) ) {
    51                         wp_die( $result );
    52                 }
    53 
    54                 wp_redirect( admin_url( 'themes.php?resumed=true' ) );
    5535                exit;
    5636        } elseif ( 'delete' == $_GET['action'] ) {
     
    216196        <div id="message4" class="error"><p><?php _e( 'You cannot delete a theme while it has an active child theme.' ); ?></p></div>
    217197        <?php
    218 } elseif ( isset( $_GET['resumed'] ) ) {
    219         ?>
    220         <div id="message5" class="updated notice is-dismissible"><p><?php _e( 'Theme resumed.' ); ?></p></div>
    221         <?php
    222198}
    223199
     
    373349
    374350        <?php
    375         $can_resume  = current_user_can( 'resume_themes' );
    376351        $can_delete  = current_user_can( 'delete_themes' );
    377352        $can_install = current_user_can( 'install_themes' );
     
    381356                <th><?php _ex( 'Name', 'theme name' ); ?></th>
    382357                <th><?php _e( 'Description' ); ?></th>
    383                 <?php if ( $can_resume ) { ?>
    384                         <td></td>
    385                 <?php } ?>
    386358                <?php if ( $can_delete ) { ?>
    387359                        <td></td>
     
    396368                        <td><?php echo $broken_theme->errors()->get_error_message(); ?></td>
    397369                        <?php
    398                         if ( $can_resume ) {
    399                                 if ( 'theme_paused' === $broken_theme->errors()->get_error_code() ) {
    400                                         $stylesheet = $broken_theme->get_stylesheet();
    401                                         $resume_url = add_query_arg(
    402                                                 array(
    403                                                         'action'     => 'resume',
    404                                                         'stylesheet' => urlencode( $stylesheet ),
    405                                                 ),
    406                                                 admin_url( 'themes.php' )
    407                                         );
    408                                         $resume_url = wp_nonce_url( $resume_url, 'resume-theme_' . $stylesheet );
    409                                         ?>
    410                                         <td><a href="<?php echo esc_url( $resume_url ); ?>" class="button resume-theme"><?php _e( 'Resume' ); ?></a></td>
    411                                         <?php
    412                                 } else {
    413                                         ?>
    414                                         <td></td>
    415                                         <?php
    416                                 }
    417                         }
    418 
    419370                        if ( $can_delete ) {
    420371                                $stylesheet = $broken_theme->get_stylesheet();
  • trunk/src/wp-includes/capabilities.php

    r44524 r44717  
    465465                        }
    466466                        break;
    467                 case 'resume_plugin':
    468                         // Even in a multisite, regular administrators should be able to resume a plugin.
    469                         $caps[] = 'activate_plugins';
    470                         break;
    471                 case 'resume_themes':
    472                         // Even in a multisite, regular administrators should be able to resume a theme.
    473                         $caps[] = 'switch_themes';
    474                         break;
    475467                case 'delete_user':
    476468                case 'delete_users':
  • trunk/src/wp-includes/class-wp-theme.php

    r44562 r44717  
    370370                        // Set the parent. Pass the current instance so we can do the crazy checks above and assess errors.
    371371                        $this->parent = new WP_Theme( $this->template, isset( $theme_root_template ) ? $theme_root_template : $this->theme_root, $this );
    372                 }
    373 
    374                 if ( wp_paused_themes()->get( $this->stylesheet ) && ( ! is_wp_error( $this->errors ) || ! isset( $this->errors->errors['theme_paused'] ) ) ) {
    375                         $this->errors = new WP_Error( 'theme_paused', __( 'This theme failed to load properly and was paused within the admin backend.' ) );
    376372                }
    377373
  • trunk/src/wp-includes/load.php

    r44566 r44717  
    698698        }
    699699
    700         /*
    701          * Remove plugins from the list of active plugins when we're on an endpoint
    702          * that should be protected against WSODs and the plugin is paused.
    703          */
    704         if ( is_protected_endpoint() ) {
    705                 $plugins = wp_skip_paused_plugins( $plugins );
    706         }
    707 
    708         return $plugins;
    709 }
    710 
    711 /**
    712  * Filters a given list of plugins, removing any paused plugins from it.
    713  *
    714  * @since 5.1.0
    715  *
    716  * @param array $plugins List of absolute plugin main file paths.
    717  * @return array Filtered value of $plugins, without any paused plugins.
    718  */
    719 function wp_skip_paused_plugins( array $plugins ) {
    720         $paused_plugins = wp_paused_plugins()->get_all();
    721 
    722         if ( empty( $paused_plugins ) ) {
    723                 return $plugins;
    724         }
    725 
    726         foreach ( $plugins as $index => $plugin ) {
    727                 list( $plugin ) = explode( '/', plugin_basename( $plugin ) );
    728 
    729                 if ( array_key_exists( $plugin, $paused_plugins ) ) {
    730                         unset( $plugins[ $index ] );
    731 
    732                         // Store list of paused plugins for displaying an admin notice.
    733                         $GLOBALS['_paused_plugins'][ $plugin ] = $paused_plugins[ $plugin ];
    734                 }
    735         }
    736 
    737700        return $plugins;
    738701}
     
    762725
    763726        $themes[] = TEMPLATEPATH;
    764 
    765         /*
    766          * Remove themes from the list of active themes when we're on an endpoint
    767          * that should be protected against WSODs and the theme is paused.
    768          */
    769         if ( is_protected_endpoint() ) {
    770                 $themes = wp_skip_paused_themes( $themes );
    771 
    772                 // If no active and valid themes exist, skip loading themes.
    773                 if ( empty( $themes ) ) {
    774                         add_filter( 'wp_using_themes', '__return_false' );
    775                 }
    776         }
    777 
    778         return $themes;
    779 }
    780 
    781 /**
    782  * Filters a given list of themes, removing any paused themes from it.
    783  *
    784  * @since 5.1.0
    785  *
    786  * @param array $themes List of absolute theme directory paths.
    787  * @return array Filtered value of $themes, without any paused themes.
    788  */
    789 function wp_skip_paused_themes( array $themes ) {
    790         $paused_themes = wp_paused_themes()->get_all();
    791 
    792         if ( empty( $paused_themes ) ) {
    793                 return $themes;
    794         }
    795 
    796         foreach ( $themes as $index => $theme ) {
    797                 $theme = basename( $theme );
    798 
    799                 if ( array_key_exists( $theme, $paused_themes ) ) {
    800                         unset( $themes[ $index ] );
    801 
    802                         // Store list of paused themes for displaying an admin notice.
    803                         $GLOBALS['_paused_themes'][ $theme ] = $paused_themes[ $theme ];
    804                 }
    805         }
    806727
    807728        return $themes;
     
    12911212
    12921213/**
    1293  * Determines whether we are currently on an endpoint that should be protected against WSODs.
    1294  *
    1295  * @since 5.1.0
    1296  *
    1297  * @return bool True if the current endpoint should be protected.
    1298  */
    1299 function is_protected_endpoint() {
    1300         // Protect login pages.
    1301         if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
    1302                 return true;
    1303         }
    1304 
    1305         // Protect the admin backend.
    1306         if ( is_admin() && ! wp_doing_ajax() ) {
    1307                 return true;
    1308         }
    1309 
    1310         // Protect AJAX actions that could help resolve a fatal error should be available.
    1311         if ( is_protected_ajax_action() ) {
    1312                 return true;
    1313         }
    1314 
    1315         /**
    1316          * Filters whether the current request is against a protected endpoint.
    1317          *
    1318          * This filter is only fired when an endpoint is requested which is not already protected by
    1319          * WordPress core. As such, it exclusively allows providing further protected endpoints in
    1320          * addition to the admin backend, login pages and protected AJAX actions.
    1321          *
    1322          * @since 5.1.0
    1323          *
    1324          * @param bool $is_protected_endpoint Whether the currently requested endpoint is protected. Default false.
    1325          */
    1326         return (bool) apply_filters( 'is_protected_endpoint', false );
    1327 }
    1328 
    1329 /**
    1330  * Determines whether we are currently handling an AJAX action that should be protected against WSODs.
    1331  *
    1332  * @since 5.1.0
    1333  *
    1334  * @return bool True if the current AJAX action should be protected.
    1335  */
    1336 function is_protected_ajax_action() {
    1337         if ( ! wp_doing_ajax() ) {
    1338                 return false;
    1339         }
    1340 
    1341         if ( ! isset( $_REQUEST['action'] ) ) {
    1342                 return false;
    1343         }
    1344 
    1345         $actions_to_protect = array(
    1346                 'edit-theme-plugin-file', // Saving changes in the core code editor.
    1347                 'heartbeat',              // Keep the heart beating.
    1348                 'install-plugin',         // Installing a new plugin.
    1349                 'install-theme',          // Installing a new theme.
    1350                 'search-plugins',         // Searching in the list of plugins.
    1351                 'search-install-plugins', // Searching for a plugin in the plugin install screen.
    1352                 'update-plugin',          // Update an existing plugin.
    1353                 'update-theme',           // Update an existing theme.
    1354         );
    1355 
    1356         /**
    1357          * Filters the array of protected AJAX actions.
    1358          *
    1359          * This filter is only fired when doing AJAX and the AJAX request has an 'action' property.
    1360          *
    1361          * @since 5.1.0
    1362          *
    1363          * @param array $actions_to_protect Array of strings with AJAX actions to protect.
    1364          */
    1365         $actions_to_protect = (array) apply_filters( 'wp_protected_ajax_actions', $actions_to_protect );
    1366 
    1367         if ( ! in_array( $_REQUEST['action'], $actions_to_protect, true ) ) {
    1368                 return false;
    1369         }
    1370 
    1371         return true;
    1372 }
    1373 
    1374 /**
    13751214 * Determines whether the current request is a WordPress cron request.
    13761215 *
  • trunk/src/wp-includes/ms-load.php

    r44524 r44717  
    5252                        $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
    5353                }
    54         }
    55 
    56         /*
    57          * Remove plugins from the list of active plugins when we're on an endpoint
    58          * that should be protected against WSODs and the plugin is paused.
    59          */
    60         if ( is_protected_endpoint() ) {
    61                 $plugins = wp_skip_paused_plugins( $plugins );
    6254        }
    6355
  • trunk/src/wp-settings.php

    r44692 r44717  
    1818// Include files required for initialization.
    1919require( ABSPATH . WPINC . '/load.php' );
    20 require( ABSPATH . WPINC . '/class-wp-paused-extensions-storage.php' );
    21 require( ABSPATH . WPINC . '/class-wp-fatal-error-handler.php' );
    22 require( ABSPATH . WPINC . '/error-protection.php' );
    2320require( ABSPATH . WPINC . '/default-constants.php' );
    2421require_once( ABSPATH . WPINC . '/plugin.php' );
    25 
    26 // Make sure we register the shutdown handler for fatal errors as soon as possible.
    27 wp_register_fatal_error_handler();
    2822
    2923/*
     
    531525 */
    532526do_action( 'wp_loaded' );
    533 
    534 /*
    535  * Store the fact that we could successfully execute the entire WordPress
    536  * lifecycle. This is used to skip the premature shutdown handler, as it cannot
    537  * be unregistered.
    538  */
    539 if ( ! defined( 'WP_EXECUTION_SUCCEEDED' ) ) {
    540         define( 'WP_EXECUTION_SUCCEEDED', true );
    541 }
  • trunk/tests/phpunit/tests/user/capabilities.php

    r44525 r44717  
    258258                        'erase_others_personal_data'  => array( 'administrator' ),
    259259                        'manage_privacy_options'      => array( 'administrator' ),
    260                         'resume_themes'               => array( 'administrator' ),
    261260
    262261                        'edit_categories'             => array( 'administrator', 'editor' ),
     
    298297                        'delete_site'                 => array( 'administrator' ),
    299298                        'add_users'                   => array( 'administrator' ),
    300                         'resume_themes'               => array( 'administrator' ),
    301299
    302300                        'edit_categories'             => array( 'administrator', 'editor' ),
     
    457455                        $expected['activate_plugin'],
    458456                        $expected['deactivate_plugin'],
    459                         $expected['resume_plugin'],
    460457                        $expected['remove_user'],
    461458                        $expected['promote_user'],
Note: See TracChangeset for help on using the changeset viewer.