'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 ); } }