Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save xlplugins/302ae514c0b318acef5859009783fffb to your computer and use it in GitHub Desktop.

Select an option

Save xlplugins/302ae514c0b318acef5859009783fffb to your computer and use it in GitHub Desktop.
FunnelKit Stripe — Webhook Health Admin Notice
<?php
/**
* Plugin Name: FunnelKit Stripe — Webhook Health Admin Notice
* Description: Shows a WordPress admin notice when the Stripe webhook appears broken:
* (a) the last webhook delivery failed, (b) a webhook is configured but has
* been silent for over a day, or (c) the live webhook endpoint in Stripe is
* missing / disabled / pointing to a different URL — verified through the
* plugin's own fkwcs_check_live_webhook_url ajax, throttled to every 12h.
* The notice clears automatically once the webhook works again.
*/
defined( 'ABSPATH' ) || exit;
const FKWCS_WHN_PROBE_RESULT = 'fkwcs_whn_probe_result'; // option: '' = ok, string = problem found by probe
const FKWCS_WHN_PROBE_LOCK = 'fkwcs_whn_probe_lock'; // transient: probe throttle
/**
* 1) The admin notice — combines the plugin's passive webhook-health options with the
* last active probe result.
*/
add_action( 'admin_notices', function () {
if ( ! defined( 'FKWCS_VERSION' ) || ! current_user_can( 'manage_woocommerce' ) ) {
return;
}
$mode = ( 'test' === get_option( 'fkwcs_mode', 'test' ) ) ? 'test' : 'live';
$success = (int) get_option( "fkwcs_{$mode}_webhook_last_success_at" );
$failure = (int) get_option( "fkwcs_{$mode}_webhook_last_failure_at" );
$began = (int) get_option( "fkwcs_{$mode}_webhook_began_at" );
$error = get_option( "fkwcs_{$mode}_webhook_last_error" );
$problems = array();
if ( $failure && $failure >= $success ) {
$problems[] = sprintf(
'The last Stripe webhook call failed %1$s ago.%2$s',
human_time_diff( $failure ),
$error ? ' Error: <b>' . esc_html( $error ) . '</b>.' : ''
);
} elseif ( ! $success && $began && ( time() - $began ) > DAY_IN_SECONDS ) {
$problems[] = sprintf(
'No Stripe webhook has been received for %s, although a webhook secret is configured.',
human_time_diff( $began )
);
}
$probe = get_option( FKWCS_WHN_PROBE_RESULT, '' );
if ( '' !== $probe && is_string( $probe ) ) {
$problems[] = esc_html( $probe );
}
if ( empty( $problems ) ) {
return;
}
printf(
'<div class="notice notice-error"><p><b>%s</b> %s %s <a href="%s">%s</a></p></div>',
'FunnelKit Stripe webhook problem:',
wp_kses_post( implode( ' ', $problems ) ),
'Payments may succeed in Stripe without the WooCommerce order updating.',
esc_url( admin_url( 'admin.php?page=wc-settings&tab=fkwcs_api_settings' ) ),
'Review webhook settings &rarr;'
);
} );
/**
* 2) Active probe using the plugin's own fkwcs_check_live_webhook_url ajax.
* Runs at most every 12h — except on FunnelKit Stripe settings screens, where it always
* runs so a repaired webhook clears the notice immediately.
*/
add_action( 'admin_footer', function () {
if ( ! defined( 'FKWCS_VERSION' ) || ! current_user_can( 'manage_woocommerce' ) ) {
return;
}
$is_stripe_screen = isset( $_GET['tab'] ) && false !== strpos( sanitize_text_field( wp_unslash( $_GET['tab'] ) ), 'fkwcs' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! $is_stripe_screen && get_transient( FKWCS_WHN_PROBE_LOCK ) ) {
return;
}
$check_nonce = wp_create_nonce( 'fkwcs_admin_request' );
$save_nonce = wp_create_nonce( 'fkwcs_whn_save' );
?>
<script id="fkwcs-whn-probe">
(function () {
var url = window.ajaxurl || '<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>';
function save(problem) {
var d = new FormData();
d.append('action', 'fkwcs_whn_save_probe');
d.append('_security', '<?php echo esc_js( $save_nonce ); ?>');
d.append('problem', problem);
fetch(url, { method: 'POST', credentials: 'same-origin', body: d });
}
var f = new FormData();
f.append('action', 'fkwcs_check_live_webhook_url');
f.append('_security', '<?php echo esc_js( $check_nonce ); ?>');
fetch(url, { method: 'POST', credentials: 'same-origin', body: f })
.then(function (r) { return r.json(); })
.then(function (res) {
var d = (res && res.data) || {};
if (d.mismatch === true) {
save(d.actual_url
? 'The Stripe webhook endpoint does not point to this site (or is disabled) — endpoint found: ' + d.actual_url
: 'The Stripe webhook endpoint could not be found in your Stripe account' + (d.msg ? ' (' + d.msg + ')' : '') + '.');
} else {
save(''); // healthy or not verifiable — clear any previous probe alarm
}
})
.catch(function () { /* network hiccup — keep previous state */ });
})();
</script>
<?php
} );
/**
* 3) Store the probe result. Empty string clears the alarm; sets the 12h throttle.
*/
add_action( 'wp_ajax_fkwcs_whn_save_probe', function () {
check_ajax_referer( 'fkwcs_whn_save', '_security' );
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_send_json_error();
}
$problem = isset( $_POST['problem'] ) ? sanitize_text_field( wp_unslash( $_POST['problem'] ) ) : '';
update_option( FKWCS_WHN_PROBE_RESULT, $problem, false );
set_transient( FKWCS_WHN_PROBE_LOCK, 1, 12 * HOUR_IN_SECONDS );
wp_die();
} );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment