[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ -> class-wp-recovery-mode-email-service.php (source)

   1  <?php
   2  /**
   3   * Error Protection API: WP_Recovery_Mode_Email_Link class
   4   *
   5   * @package WordPress
   6   * @since   5.2.0
   7   */
   8  
   9  /**
  10   * Core class used to send an email with a link to begin Recovery Mode.
  11   *
  12   * @since 5.2.0
  13   */
  14  final class WP_Recovery_Mode_Email_Service {
  15  
  16      const RATE_LIMIT_OPTION = 'recovery_mode_email_last_sent';
  17  
  18      /**
  19       * Service to generate recovery mode URLs.
  20       *
  21       * @since 5.2.0
  22       * @var WP_Recovery_Mode_Link_Service
  23       */
  24      private $link_service;
  25  
  26      /**
  27       * WP_Recovery_Mode_Email_Service constructor.
  28       *
  29       * @since 5.2.0
  30       *
  31       * @param WP_Recovery_Mode_Link_Service $link_service
  32       */
  33  	public function __construct( WP_Recovery_Mode_Link_Service $link_service ) {
  34          $this->link_service = $link_service;
  35      }
  36  
  37      /**
  38       * Sends the recovery mode email if the rate limit has not been sent.
  39       *
  40       * @since 5.2.0
  41       *
  42       * @param int   $rate_limit Number of seconds before another email can be sent.
  43       * @param array $error      Error details from {@see error_get_last()}
  44       * @param array $extension  The extension that caused the error. {
  45       *      @type string $slug The extension slug. The plugin or theme's directory.
  46       *      @type string $type The extension type. Either 'plugin' or 'theme'.
  47       * }
  48       * @return true|WP_Error True if email sent, WP_Error otherwise.
  49       */
  50  	public function maybe_send_recovery_mode_email( $rate_limit, $error, $extension ) {
  51  
  52          $last_sent = get_option( self::RATE_LIMIT_OPTION );
  53  
  54          if ( ! $last_sent || time() > $last_sent + $rate_limit ) {
  55              if ( ! update_option( self::RATE_LIMIT_OPTION, time() ) ) {
  56                  return new WP_Error( 'storage_error', __( 'Could not update the email last sent time.' ) );
  57              }
  58  
  59              $sent = $this->send_recovery_mode_email( $rate_limit, $error, $extension );
  60  
  61              if ( $sent ) {
  62                  return true;
  63              }
  64  
  65              return new WP_Error(
  66                  'email_failed',
  67                  sprintf(
  68                      /* translators: %s: mail() */
  69                      __( 'The email could not be sent. Possible reason: your host may have disabled the %s function.' ),
  70                      'mail()'
  71                  )
  72              );
  73          }
  74  
  75          $err_message = sprintf(
  76              /* translators: 1. Last sent as a human time diff 2. Wait time as a human time diff. */
  77              __( 'A recovery link was already sent %1$s ago. Please wait another %2$s before requesting a new email.' ),
  78              human_time_diff( $last_sent ),
  79              human_time_diff( $last_sent + $rate_limit )
  80          );
  81  
  82          return new WP_Error( 'email_sent_already', $err_message );
  83      }
  84  
  85      /**
  86       * Clears the rate limit, allowing a new recovery mode email to be sent immediately.
  87       *
  88       * @since 5.2.0
  89       *
  90       * @return bool True on success, false on failure.
  91       */
  92  	public function clear_rate_limit() {
  93          return delete_option( self::RATE_LIMIT_OPTION );
  94      }
  95  
  96      /**
  97       * Sends the Recovery Mode email to the site admin email address.
  98       *
  99       * @since 5.2.0
 100       *
 101       * @param int   $rate_limit Number of seconds before another email can be sent.
 102       * @param array $error      Error details from {@see error_get_last()}
 103       * @param array $extension  Extension that caused the error.
 104       *
 105       * @return bool Whether the email was sent successfully.
 106       */
 107  	private function send_recovery_mode_email( $rate_limit, $error, $extension ) {
 108  
 109          $url      = $this->link_service->generate_url();
 110          $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
 111  
 112          $switched_locale = false;
 113  
 114          // The switch_to_locale() function is loaded before it can actually be used.
 115          if ( function_exists( 'switch_to_locale' ) && isset( $GLOBALS['wp_locale_switcher'] ) ) {
 116              $switched_locale = switch_to_locale( get_locale() );
 117          }
 118  
 119          if ( $extension ) {
 120              $cause   = $this->get_cause( $extension );
 121              $details = wp_strip_all_tags( wp_get_extension_error_description( $error ) );
 122  
 123              if ( $details ) {
 124                  $header  = __( 'Error Details' );
 125                  $details = "\n\n" . $header . "\n" . str_pad( '', strlen( $header ), '=' ) . "\n" . $details;
 126              }
 127          } else {
 128              $cause   = '';
 129              $details = '';
 130          }
 131  
 132          /**
 133           * Filters the support message sent with the the fatal error protection email.
 134           *
 135           * @since 5.2.0
 136           *
 137           * @param $message string The Message to include in the email.
 138           */
 139          $support = apply_filters( 'recovery_email_support_info', __( 'Please contact your host for assistance with investigating this issue further.' ) );
 140  
 141          /* translators: Do not translate LINK, EXPIRES, CAUSE, DETAILS, SITEURL, PAGEURL, SUPPORT: those are placeholders. */
 142          $message = __(
 143              'Howdy!
 144  
 145  Since WordPress 5.2 there is a built-in feature that detects when a plugin or theme causes a fatal error on your site, and notifies you with this automated email.
 146  ###CAUSE###
 147  First, visit your website (###SITEURL###) and check for any visible issues. Next, visit the page where the error was caught (###PAGEURL###) and check for any visible issues.
 148  
 149  ###SUPPORT###
 150  
 151  If your site appears broken and you can\'t access your dashboard normally, WordPress now has a special "recovery mode". This lets you safely login to your dashboard and investigate further.
 152  
 153  ###LINK###
 154  
 155  To keep your site safe, this link will expire in ###EXPIRES###. Don\'t worry about that, though: a new link will be emailed to you if the error occurs again after it expires.
 156  
 157  ###DETAILS###'
 158          );
 159          $message = str_replace(
 160              array(
 161                  '###LINK###',
 162                  '###EXPIRES###',
 163                  '###CAUSE###',
 164                  '###DETAILS###',
 165                  '###SITEURL###',
 166                  '###PAGEURL###',
 167                  '###SUPPORT###',
 168              ),
 169              array(
 170                  $url,
 171                  human_time_diff( time() + $rate_limit ),
 172                  $cause ? "\n{$cause}\n" : "\n",
 173                  $details,
 174                  home_url( '/' ),
 175                  home_url( $_SERVER['REQUEST_URI'] ),
 176                  $support,
 177              ),
 178              $message
 179          );
 180  
 181          $email = array(
 182              'to'      => $this->get_recovery_mode_email_address(),
 183              /* translators: %s: site name */
 184              'subject' => __( '[%s] Your Site is Experiencing a Technical Issue' ),
 185              'message' => $message,
 186              'headers' => '',
 187          );
 188  
 189          /**
 190           * Filter the contents of the Recovery Mode email.
 191           *
 192           * @since 5.2.0
 193           *
 194           * @param array  $email Used to build wp_mail().
 195           * @param string $url   URL to enter recovery mode.
 196           */
 197          $email = apply_filters( 'recovery_mode_email', $email, $url );
 198  
 199          $sent = wp_mail(
 200              $email['to'],
 201              wp_specialchars_decode( sprintf( $email['subject'], $blogname ) ),
 202              $email['message'],
 203              $email['headers']
 204          );
 205  
 206          if ( $switched_locale ) {
 207              restore_previous_locale();
 208          }
 209  
 210          return $sent;
 211      }
 212  
 213      /**
 214       * Gets the email address to send the recovery mode link to.
 215       *
 216       * @since 5.2.0
 217       *
 218       * @return string Email address to send recovery mode link to.
 219       */
 220  	private function get_recovery_mode_email_address() {
 221          if ( defined( 'RECOVERY_MODE_EMAIL' ) && is_email( RECOVERY_MODE_EMAIL ) ) {
 222              return RECOVERY_MODE_EMAIL;
 223          }
 224  
 225          return get_option( 'admin_email' );
 226      }
 227  
 228      /**
 229       * Gets the description indicating the possible cause for the error.
 230       *
 231       * @since 5.2.0
 232       *
 233       * @param array $extension The extension that caused the error.
 234       * @return string Message about which extension caused the error.
 235       */
 236  	private function get_cause( $extension ) {
 237  
 238          if ( 'plugin' === $extension['type'] ) {
 239              if ( ! function_exists( 'get_plugins' ) ) {
 240                  require_once  ABSPATH . 'wp-admin/includes/plugin.php';
 241              }
 242  
 243              $plugins = get_plugins();
 244  
 245              $name = '';
 246  
 247              // Assume plugin main file name first since it is a common convention.
 248              if ( isset( $plugins[ "{$extension['slug']}/{$extension['slug']}.php" ] ) ) {
 249                  $name = $plugins[ "{$extension['slug']}/{$extension['slug']}.php" ]['Name'];
 250              } else {
 251                  foreach ( $plugins as $file => $plugin_data ) {
 252                      if ( 0 === strpos( $file, "{$extension['slug']}/" ) || $file === $extension['slug'] ) {
 253                          $name = $plugin_data['Name'];
 254                          break;
 255                      }
 256                  }
 257              }
 258  
 259              if ( empty( $name ) ) {
 260                  $name = $extension['slug'];
 261              }
 262  
 263              /* translators: %s: plugin name */
 264              $cause = sprintf( __( 'In this case, WordPress caught an error with one of your plugins, %s.' ), $name );
 265          } else {
 266              $theme = wp_get_theme( $extension['slug'] );
 267              $name  = $theme->exists() ? $theme->display( 'Name' ) : $extension['slug'];
 268  
 269              /* translators: %s: theme name */
 270              $cause = sprintf( __( 'In this case, WordPress caught an error with your theme, %s.' ), $name );
 271          }
 272  
 273          return $cause;
 274      }
 275  }


Generated: Tue Aug 20 08:20:01 2019 Cross-referenced by PHPXref 0.7