193 lines
7.2 KiB
PHP
193 lines
7.2 KiB
PHP
|
|
<?php
|
||
|
|
/**
|
||
|
|
* Plugin Name: Sirius Press Compatibility
|
||
|
|
* Plugin URI: https://code.silentmode.st/silentmode/sirius-press
|
||
|
|
* Description: Keeps plugins that hard-require an administrator email address installable and activatable on a site that has none.
|
||
|
|
* Version: 0.1.0
|
||
|
|
* Requires at least: 6.5
|
||
|
|
* Requires PHP: 7.4
|
||
|
|
* Requires Plugins: sirius-press-core
|
||
|
|
* Author: Silent Mode
|
||
|
|
* Author URI: https://silentmode.st
|
||
|
|
* License: GPL-2.0-or-later
|
||
|
|
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||
|
|
* Text Domain: sirius-press
|
||
|
|
*
|
||
|
|
* @package SiriusPress
|
||
|
|
*
|
||
|
|
* ---------------------------------------------------------------------------
|
||
|
|
*
|
||
|
|
* A large part of the WordPress ecosystem assumes `get_option('admin_email')`
|
||
|
|
* returns something, and a smaller but important part refuses to finish its
|
||
|
|
* setup wizard if it does not. WooCommerce wants a store address for order
|
||
|
|
* emails. Contact Form 7 defaults a form's "To" field to it. Yoast reads it
|
||
|
|
* while building schema. None of these are wrong to do so — they were written
|
||
|
|
* for a WordPress where that value always exists.
|
||
|
|
*
|
||
|
|
* Rather than patch each of them, this plugin makes the assumption true: the
|
||
|
|
* site always has an admin email, and it is permanently undeliverable. The
|
||
|
|
* `.invalid` top-level domain is reserved by RFC 2606 for exactly this — it
|
||
|
|
* is guaranteed never to resolve, anywhere, ever. So a plugin that stores it,
|
||
|
|
* validates it or puts it in a "From" header behaves normally, and a plugin
|
||
|
|
* that tries to *send* to it has its message caught by the Sirius Press inbox
|
||
|
|
* before it reaches a mail transport.
|
||
|
|
*
|
||
|
|
* What this plugin deliberately does NOT do is disable `wp_mail()`. A site
|
||
|
|
* owner who configures SMTP gets working contact forms and working order
|
||
|
|
* receipts, because those go to real addresses that real people gave. The
|
||
|
|
* fork's objection was never to email as a feature — only to email as an
|
||
|
|
* identity.
|
||
|
|
*/
|
||
|
|
|
||
|
|
defined( 'ABSPATH' ) || exit;
|
||
|
|
|
||
|
|
define( 'SIRIUS_PRESS_COMPAT_VERSION', '0.1.0' );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Supply a placeholder wherever WordPress or a plugin reads the admin email.
|
||
|
|
*
|
||
|
|
* Filtered rather than written to the database so that a site owner who does
|
||
|
|
* set a real address keeps it: the filter defers to any non-empty stored
|
||
|
|
* value and only fills a gap.
|
||
|
|
*/
|
||
|
|
function sirius_press_admin_email( $value ) {
|
||
|
|
if ( is_string( $value ) && '' !== trim( $value ) ) {
|
||
|
|
return $value;
|
||
|
|
}
|
||
|
|
return 'admin@' . SP_Settings::stub_email_domain();
|
||
|
|
}
|
||
|
|
add_filter( 'option_admin_email', 'sirius_press_admin_email' );
|
||
|
|
add_filter( 'default_option_admin_email', 'sirius_press_admin_email' );
|
||
|
|
add_filter( 'pre_option_new_admin_email', '__return_empty_string' );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fill a blank `user_email` on save rather than letting one persist.
|
||
|
|
*
|
||
|
|
* `$user->user_email` is read in thousands of places across the ecosystem,
|
||
|
|
* usually without a null check, so an account with an empty one leaves
|
||
|
|
* warnings and blank "From" headers scattered through other people's code.
|
||
|
|
* An account created before this fork was installed, or by a plugin calling
|
||
|
|
* `wp_insert_user()` directly, can have exactly that.
|
||
|
|
*
|
||
|
|
* Runs late so a plugin that supplies a real address wins.
|
||
|
|
*/
|
||
|
|
add_filter(
|
||
|
|
'wp_pre_insert_user_data',
|
||
|
|
function ( $data, $update, $user_id ) {
|
||
|
|
if ( ! class_exists( 'SP_Identity' ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
if ( ! empty( $data['user_email'] ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
$address = $user_id ? SP_Identity::address_of( (int) $user_id ) : '';
|
||
|
|
$data['user_email'] = SP_Identity::stub_email( $address );
|
||
|
|
return $data;
|
||
|
|
},
|
||
|
|
20,
|
||
|
|
3
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Stop core nagging about an unconfirmed administrator email change.
|
||
|
|
*
|
||
|
|
* The "Your admin email is still <x>, please confirm" prompt sends a
|
||
|
|
* confirmation link to an address that cannot receive it, which makes the
|
||
|
|
* prompt permanent and unactionable.
|
||
|
|
*/
|
||
|
|
add_filter( 'admin_email_check_interval', '__return_zero' );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* WooCommerce.
|
||
|
|
*
|
||
|
|
* Its setup wizard and its system-status report both read the store address
|
||
|
|
* out of `woocommerce_email_from_address`, and the onboarding profiler posts
|
||
|
|
* to a remote service with it. Supplying the placeholder lets the wizard
|
||
|
|
* finish; order emails to real customers are unaffected, because those use
|
||
|
|
* the address the customer typed at checkout.
|
||
|
|
*/
|
||
|
|
add_filter(
|
||
|
|
'pre_option_woocommerce_email_from_address',
|
||
|
|
function ( $value ) {
|
||
|
|
if ( ! empty( $value ) || ! class_exists( 'SP_Settings' ) ) {
|
||
|
|
return $value;
|
||
|
|
}
|
||
|
|
return 'shop@' . SP_Settings::stub_email_domain();
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Contact Form 7.
|
||
|
|
*
|
||
|
|
* CF7 validates a form's mail template on save and marks the form as
|
||
|
|
* misconfigured if the "To" address is empty, which it will be on a site with
|
||
|
|
* no admin email. The placeholder makes new forms save cleanly; a site owner
|
||
|
|
* who wants the form to actually deliver replaces it with a real address and
|
||
|
|
* configures SMTP, which is documented in docs/smtp.md.
|
||
|
|
*/
|
||
|
|
add_filter(
|
||
|
|
'wpcf7_default_template',
|
||
|
|
function ( $template, $prop ) {
|
||
|
|
if ( 'mail' !== $prop || ! is_array( $template ) || ! class_exists( 'SP_Settings' ) ) {
|
||
|
|
return $template;
|
||
|
|
}
|
||
|
|
if ( empty( $template['recipient'] ) ) {
|
||
|
|
$template['recipient'] = 'admin@' . SP_Settings::stub_email_domain();
|
||
|
|
}
|
||
|
|
return $template;
|
||
|
|
},
|
||
|
|
10,
|
||
|
|
2
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Plugins that check "is this a real email?" during their own setup.
|
||
|
|
*
|
||
|
|
* `is_email()` correctly rejects a `.invalid` address — the domain is
|
||
|
|
* reserved precisely so that it fails. That correctness is a problem for a
|
||
|
|
* setup wizard that refuses to advance, so `.invalid` addresses under *this
|
||
|
|
* site's own* placeholder domain are allowed through, and nothing else is.
|
||
|
|
* Narrowing it to our own domain matters: a contact form that accepts
|
||
|
|
* `someone@example.invalid` from a visitor would silently collect addresses
|
||
|
|
* that can never be replied to.
|
||
|
|
*/
|
||
|
|
add_filter(
|
||
|
|
'is_email',
|
||
|
|
function ( $is_email, $email ) {
|
||
|
|
if ( $is_email || ! class_exists( 'SP_Settings' ) ) {
|
||
|
|
return $is_email;
|
||
|
|
}
|
||
|
|
$domain = '@' . strtolower( SP_Settings::stub_email_domain() );
|
||
|
|
if ( substr( strtolower( (string) $email ), -strlen( $domain ) ) !== $domain ) {
|
||
|
|
return $is_email;
|
||
|
|
}
|
||
|
|
// Same local-part rules core applies, minus the domain check it fails.
|
||
|
|
$local = substr( (string) $email, 0, strlen( (string) $email ) - strlen( $domain ) );
|
||
|
|
return (bool) preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.\-]+$/', $local );
|
||
|
|
},
|
||
|
|
10,
|
||
|
|
2
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A short explanation on the plugins screen, next to anything known to want
|
||
|
|
* an address. Better a sentence here than a confused hour later.
|
||
|
|
*/
|
||
|
|
add_action(
|
||
|
|
'after_plugin_row',
|
||
|
|
function ( $plugin_file ) {
|
||
|
|
static $notes = array(
|
||
|
|
'woocommerce/woocommerce.php' => 'WooCommerce will work, including checkout. Order emails need SMTP — see docs/smtp.md.',
|
||
|
|
'contact-form-7/wp-contact-form-7.php' => 'Forms save and submit. Delivery needs SMTP and a real recipient address — see docs/smtp.md.',
|
||
|
|
'wordpress-seo/wp-seo.php' => 'Yoast works unchanged. Its sitemaps are exported to your name along with everything else.',
|
||
|
|
);
|
||
|
|
if ( ! isset( $notes[ $plugin_file ] ) || ! is_plugin_active( $plugin_file ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
printf(
|
||
|
|
'<tr class="plugin-update-tr active"><td colspan="4" class="plugin-update"><div class="update-message notice inline notice-info notice-alt"><p>%s</p></div></td></tr>',
|
||
|
|
esc_html( $notes[ $plugin_file ] )
|
||
|
|
);
|
||
|
|
}
|
||
|
|
);
|