'https://wordpress.org/support/plugin/hookbird/',
'review' => 'https://wordpress.org/support/plugin/hookbird/reviews/#new-post',
'faq' => 'https://wordpress.org/plugins/hookbird/#faq',
);
}
/**
* Reasons offered in the deactivation form, each with an optional self-help hint.
*
* @return array key => [ label, hint, link, link_label, ask ].
*/
public static function reasons() {
$help = admin_url( 'admin.php?page=hookbird-help' );
return array(
'setup' => array(
'label' => __( 'I could not get it set up', 'hookbird' ),
'hint' => __( 'Help & Setup has a step-by-step guide for every destination, and each one ends with a test.', 'hookbird' ),
'link' => $help . '#guides',
'link_label' => __( 'Open the setup guides', 'hookbird' ),
'ask' => __( 'Which destination were you connecting?', 'hookbird' ),
),
'delivery' => array(
'label' => __( 'Messages did not arrive, or arrived late', 'hookbird' ),
'hint' => __( 'The delivery log shows the exact response each destination sent back. Low-traffic sites may also need a real cron job.', 'hookbird' ),
'link' => $help . '#status',
'link_label' => __( 'Run the system check', 'hookbird' ),
'ask' => __( 'What did the delivery log show?', 'hookbird' ),
),
'feature' => array(
'label' => __( 'It is missing a feature I need', 'hookbird' ),
'hint' => '',
'link' => '',
'link_label' => '',
'ask' => __( 'Which feature would have kept you?', 'hookbird' ),
),
'better' => array(
'label' => __( 'I found a better plugin', 'hookbird' ),
'hint' => '',
'link' => '',
'link_label' => '',
'ask' => __( 'Which plugin, and what does it do better?', 'hookbird' ),
),
'temporary' => array(
'label' => __( 'It is only temporary, I am debugging', 'hookbird' ),
'hint' => __( 'Your endpoints, settings and log are kept while the plugin is deactivated.', 'hookbird' ),
'link' => '',
'link_label' => '',
'ask' => '',
),
'other' => array(
'label' => __( 'Something else', 'hookbird' ),
'hint' => '',
'link' => '',
'link_label' => '',
'ask' => __( 'Tell us a little more', 'hookbird' ),
),
);
}
/**
* Load the small form assets on the Plugins screen only.
*
* @param string $hook Admin page hook.
*/
public function assets( $hook ) {
if ( 'plugins.php' !== $hook || ! current_user_can( 'activate_plugins' ) ) {
return;
}
wp_enqueue_style( 'hookbird-deactivate', HOOKBIRD_URL . 'assets/deactivate.css', array(), Admin::asset_version( 'deactivate.css' ) );
wp_enqueue_script( 'hookbird-deactivate', HOOKBIRD_URL . 'assets/deactivate.js', array(), Admin::asset_version( 'deactivate.js' ), true );
wp_localize_script(
'hookbird-deactivate',
'hookbirdDeactivate',
array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( self::NONCE ),
'sends' => '' !== self::support_email(),
'plugin' => plugin_basename( HOOKBIRD_FILE ),
)
);
}
/**
* Print the deactivation dialog on the Plugins screen.
*/
public function modal() {
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
if ( ! $screen || ! in_array( $screen->id, array( 'plugins', 'plugins-network' ), true ) || ! current_user_can( 'activate_plugins' ) ) {
return;
}
$sends = '' !== self::support_email();
$links = self::links();
?>
false ) );
}
$reasons = self::reasons();
$reason = isset( $_POST['reason'] ) ? sanitize_key( wp_unslash( $_POST['reason'] ) ) : '';
if ( ! isset( $reasons[ $reason ] ) ) {
wp_send_json_error( array( 'message' => 'invalid reason' ), 400 );
}
$details = isset( $_POST['details'] ) ? sanitize_textarea_field( wp_unslash( $_POST['details'] ) ) : '';
$details = mb_substr( $details, 0, 1000 );
$contact = ! empty( $_POST['contact'] );
global $wp_version;
$lines = array(
'Reason: ' . $reasons[ $reason ]['label'] . ' (' . $reason . ')',
'Details: ' . ( '' !== $details ? $details : '-' ),
'',
'Hookbird: ' . HOOKBIRD_VERSION,
'WordPress: ' . $wp_version,
'PHP: ' . PHP_VERSION,
'Locale: ' . get_locale(),
);
$headers = array();
if ( $contact ) {
$email = sanitize_email( (string) get_option( 'admin_email' ) );
$lines[] = 'Reply to: ' . $email;
$lines[] = 'Site: ' . home_url( '/' );
if ( is_email( $email ) ) {
$headers[] = 'Reply-To: ' . $email;
}
}
$sent = wp_mail( $to, '[Hookbird feedback] ' . $reasons[ $reason ]['label'], implode( "\n", $lines ), $headers );
wp_send_json_success( array( 'sent' => (bool) $sent ) );
}
/**
* Plain-text system report for support requests. Contains no URLs, secrets or personal data.
*
* @return string
*/
public static function system_report() {
global $wp_version;
$endpoints = Endpoints::all();
$formats = array();
$states = array(
'active' => 0,
'paused' => 0,
'disabled' => 0,
);
foreach ( $endpoints as $endpoint ) {
$key = isset( $endpoint['options']['preset'] ) ? $endpoint['options']['preset'] : $endpoint['format'];
$formats[ $key ] = isset( $formats[ $key ] ) ? $formats[ $key ] + 1 : 1;
if ( ! $endpoint['active'] ) {
++$states['disabled'];
} elseif ( $endpoint['paused_at'] ) {
++$states['paused'];
} else {
++$states['active'];
}
}
$format_list = array();
foreach ( $formats as $key => $count ) {
$format_list[] = $key . ' x' . $count;
}
$settings = Settings::all();
$last_run = (int) get_option( 'hookbird_last_queue_run' );
$next = wp_next_scheduled( Installer::CRON_PROCESS );
$errors = array();
$recent = Deliveries::query(
array(
'status' => 'failed',
'per_page' => 5,
)
);
foreach ( $recent['items'] as $item ) {
$errors[] = ' ' . $item['created_at'] . ' UTC ' . $item['event'] . ' ' . ( $item['response_code'] ? 'HTTP ' . $item['response_code'] : Formatter::truncate( preg_replace( '#https?://\S+#', '[url]', $item['error'] ), 120 ) );
}
$lines = array();
$lines[] = '### Hookbird system report ###';
$lines[] = 'Hookbird: ' . HOOKBIRD_VERSION . ' (db ' . get_option( 'hookbird_db_version' ) . ')';
$lines[] = 'WordPress: ' . $wp_version . ( is_multisite() ? ' (multisite)' : '' );
$lines[] = 'PHP: ' . PHP_VERSION;
$lines[] = 'Locale: ' . get_locale();
$lines[] = 'WooCommerce: ' . ( defined( 'WC_VERSION' ) ? WC_VERSION : 'not active' );
$lines[] = 'WP-Cron: ' . ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ? 'disabled (DISABLE_WP_CRON)' : 'enabled' );
$lines[] = 'Last queue run: ' . ( $last_run ? human_time_diff( $last_run ) . ' ago' : 'never' );
$lines[] = 'Next queue run: ' . ( $next ? gmdate( 'Y-m-d H:i:s', $next ) . ' UTC' : 'not scheduled' );
$lines[] = 'Safety sweep: ' . ( wp_next_scheduled( Installer::CRON_SWEEP ) ? 'scheduled' : 'missing' );
$lines[] = 'Endpoints: ' . count( $endpoints ) . ' (' . $states['active'] . ' active, ' . $states['paused'] . ' paused, ' . $states['disabled'] . ' disabled)' . ( $format_list ? ' ' . implode( ', ', $format_list ) : '' );
$lines[] = 'Queue: ' . Deliveries::count( 'pending' ) . ' pending, ' . Deliveries::count( 'processing' ) . ' processing, ' . Deliveries::count( 'failed' ) . ' failed, ' . Deliveries::count( 'success' ) . ' delivered';
$lines[] = 'Settings: attempts ' . $settings['max_attempts'] . ', timeout ' . $settings['timeout'] . 's, batch ' . $settings['batch_size'] . ', retention ' . $settings['retention_days'] . 'd, pause after ' . $settings['circuit_threshold'] . ', local URLs ' . ( $settings['allow_local_urls'] ? 'allowed' : 'blocked' );
foreach ( Onboarding::status_checks() as $check ) {
if ( in_array( $check['status'], array( 'warn', 'fail' ), true ) ) {
$lines[] = 'Check (' . $check['status'] . '): ' . $check['label'] . ' - ' . $check['detail'];
}
}
$lines[] = 'Recent failures:' . ( $errors ? "\n" . implode( "\n", $errors ) : ' none' );
$lines[] = '### End of report ###';
return implode( "\n", $lines );
}
}