Plugin Directory

Changeset 3446569


Ignore:
Timestamp:
01/25/2026 02:47:56 PM (4 weeks ago)
Author:
blaminhor
Message:
  1. 1.1.1
Location:
blaminhor-essentials
Files:
77 added
14 edited

Legend:

Unmodified
Added
Removed
  • blaminhor-essentials/trunk/assets/css/admin.css

    r3445838 r3446569  
    550550}
    551551
     552/* Card wrapper (for modules without tabs) */
     553.blaminhor-essentials-card {
     554    background: #fff;
     555    border: 1px solid #c3c4c7;
     556    border-radius: var(--ap-border-radius);
     557    box-shadow: var(--ap-shadow);
     558    padding: 20px;
     559}
     560
    552561/* Tabs */
    553562.blaminhor-essentials-tabs-wrapper {
  • blaminhor-essentials/trunk/assets/css/admin.min.css

    r3445838 r3446569  
    550550}
    551551
     552/* Card wrapper (for modules without tabs) */
     553.blaminhor-essentials-card {
     554    background: #fff;
     555    border: 1px solid #c3c4c7;
     556    border-radius: var(--ap-border-radius);
     557    box-shadow: var(--ap-shadow);
     558    padding: 20px;
     559}
     560
    552561/* Tabs */
    553562.blaminhor-essentials-tabs-wrapper {
  • blaminhor-essentials/trunk/assets/js/modules.js

    r3445615 r3446569  
    22192219                    if (response.success) {
    22202220                        $result.html('<div class="blaminhor-essentials-notice success">' + response.data.message + '</div>');
     2221                        // If logging is enabled, switch to log tab after delay
     2222                        if (response.data.logging_enabled) {
     2223                            setTimeout(function() {
     2224                                var $logTab = $('[data-tab="log"]');
     2225                                if ($logTab.length) {
     2226                                    $logTab.trigger('click');
     2227                                }
     2228                            }, 1500);
     2229                        }
    22212230                    } else {
    22222231                        $result.html('<div class="blaminhor-essentials-notice error">' + response.data.message + '</div>');
  • blaminhor-essentials/trunk/blaminhor-essentials.php

    r3445838 r3446569  
    44 * Plugin URI:        https://wp.blaminhor.com/
    55 * Description:       A modular toolkit for WordPress with activatable features. Lightweight, secure, and reliable.
    6  * Version:           1.1.0
     6 * Version:           1.1.1
    77 * Requires at least: 6.2
    88 * Requires PHP:      7.4
     
    2323
    2424// Plugin constants
    25 define('BLAMINHOR_ESSENTIALS_VERSION', '1.1.0');
     25define('BLAMINHOR_ESSENTIALS_VERSION', '1.1.1');
    2626define('BLAMINHOR_ESSENTIALS_PLUGIN_FILE', __FILE__);
    2727define('BLAMINHOR_ESSENTIALS_PLUGIN_DIR', plugin_dir_path(__FILE__));
     
    826826    // Flush rewrite rules
    827827    flush_rewrite_rules();
     828
     829    // Set transient for redirect to dashboard (single site only)
     830    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just checking activation context.
     831    if ( ! is_network_admin() && ! isset( $_GET['activate-multi'] ) ) {
     832        set_transient( 'blaminhor_essentials_activation_redirect', true, 30 );
     833    }
    828834});
    829835
  • blaminhor-essentials/trunk/includes/class-blaminhor-essentials-admin.php

    r3445838 r3446569  
    3333        $this->plugin = $plugin;
    3434        $this->register_ajax_handlers();
     35
     36        // Add plugin action links (Settings link in plugins list)
     37        add_filter( 'plugin_action_links_' . BLAMINHOR_ESSENTIALS_PLUGIN_BASENAME, array( $this, 'add_plugin_action_links' ) );
     38
     39        // Check for activation redirect
     40        add_action( 'admin_init', array( $this, 'maybe_redirect_after_activation' ) );
     41    }
     42
     43    /**
     44     * Redirect to plugin dashboard after activation
     45     */
     46    public function maybe_redirect_after_activation() {
     47        if ( get_transient( 'blaminhor_essentials_activation_redirect' ) ) {
     48            delete_transient( 'blaminhor_essentials_activation_redirect' );
     49            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Not processing form data, just checking activation context.
     50            if ( ! isset( $_GET['activate-multi'] ) ) {
     51                wp_safe_redirect( admin_url( 'admin.php?page=blaminhor-essentials' ) );
     52                exit;
     53            }
     54        }
     55    }
     56
     57    /**
     58     * Add Settings link to plugin action links
     59     *
     60     * @param array $links Existing plugin action links.
     61     * @return array
     62     */
     63    public function add_plugin_action_links( $links ) {
     64        $settings_link = sprintf(
     65            '<a href="%s">%s</a>',
     66            esc_url( admin_url( 'admin.php?page=blaminhor-essentials' ) ),
     67            esc_html__( 'Settings', 'blaminhor-essentials' )
     68        );
     69        // Insert after 'deactivate' link if it exists, otherwise at end
     70        if ( isset( $links['deactivate'] ) ) {
     71            $new_links = array();
     72            foreach ( $links as $key => $link ) {
     73                $new_links[ $key ] = $link;
     74                if ( 'deactivate' === $key ) {
     75                    $new_links['settings'] = $settings_link;
     76                }
     77            }
     78            return $new_links;
     79        }
     80        $links['settings'] = $settings_link;
     81        return $links;
    3582    }
    3683
  • blaminhor-essentials/trunk/languages/blaminhor-essentials-de_DE.po

    r3445838 r3446569  
    11msgid ""
    22msgstr ""
    3 "Project-Id-Version: Blaminhor Essentials 1.1.0\n"
     3"Project-Id-Version: Blaminhor Essentials 1.1.1\n"
    44"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/blaminhor-essentials\n"
    55"Last-Translator: \n"
     
    18521852msgid "If using cPanel, check <strong>Email Accounts</strong> → <strong>Connect Devices</strong>"
    18531853msgstr "Wenn Sie cPanel verwenden, prüfen Sie <strong>E-Mail-Konten</strong> → <strong>Geräte verbinden</strong>"
     1854
     1855# =====================================================
     1856# Version 1.1.1 - New translations
     1857# =====================================================
     1858
     1859msgid "Leave empty to use the post title"
     1860msgstr "Leer lassen, um den Beitragstitel zu verwenden"
     1861
     1862msgid "Email Notification"
     1863msgstr "E-Mail-Benachrichtigung"
     1864
     1865msgid "Send email notification when fatal error is detected"
     1866msgstr "E-Mail-Benachrichtigung bei fatalem Fehler senden"
     1867
     1868msgid "When enabled, an email with the recovery URL will be sent to the admin email when a fatal error caused by a plugin is detected."
     1869msgstr "Wenn aktiviert, wird bei einem durch ein Plugin verursachten fatalen Fehler eine E-Mail mit der Wiederherstellungs-URL an die Admin-E-Mail gesendet."
     1870
     1871msgid "[%s] Fatal Error Detected - Recovery Link"
     1872msgstr "[%s] Fataler Fehler erkannt - Wiederherstellungslink"
     1873
     1874msgid "Unknown"
     1875msgstr "Unbekannt"
  • blaminhor-essentials/trunk/languages/blaminhor-essentials-fr_FR.po

    r3445838 r3446569  
    11msgid ""
    22msgstr ""
    3 "Project-Id-Version: Blaminhor Essentials 1.1.0\n"
     3"Project-Id-Version: Blaminhor Essentials 1.1.1\n"
    44"Report-Msgid-Bugs-To: https://wp.blaminhor.com\n"
    55"POT-Creation-Date: 2026-01-20 10:00+0000\n"
     
    30243024msgid "If using cPanel, check <strong>Email Accounts</strong> → <strong>Connect Devices</strong>"
    30253025msgstr "Si vous utilisez cPanel, vérifiez <strong>Comptes de messagerie</strong> → <strong>Connecter des appareils</strong>"
     3026
     3027# =====================================================
     3028# Version 1.1.1 - New translations
     3029# =====================================================
     3030
     3031msgid "Leave empty to use the post title"
     3032msgstr "Laisser vide pour utiliser le titre de l'article"
     3033
     3034msgid "Email Notification"
     3035msgstr "Notification par email"
     3036
     3037msgid "Send email notification when fatal error is detected"
     3038msgstr "Envoyer une notification par email en cas d'erreur fatale"
     3039
     3040msgid "When enabled, an email with the recovery URL will be sent to the admin email when a fatal error caused by a plugin is detected."
     3041msgstr "Si activé, un email avec l'URL de récupération sera envoyé à l'email de l'administrateur lorsqu'une erreur fatale causée par un plugin est détectée."
     3042
     3043msgid "[%s] Fatal Error Detected - Recovery Link"
     3044msgstr "[%s] Erreur fatale détectée - Lien de récupération"
     3045
     3046msgid "Unknown"
     3047msgstr "Inconnu"
  • blaminhor-essentials/trunk/modules/fatal-error-recovery/class-module-fatal-error-recovery.php

    r3445838 r3446569  
    5858    protected function get_default_settings() {
    5959        return array(
    60             'recovery_key'       => '',
    61             'show_admin_bar'     => true,
    62             'email_notification' => true,
     60            'recovery_key'          => '',
     61            'show_admin_bar'        => true,
     62            'email_notification'    => true,
     63            'last_error_email_hash' => '',
    6364        );
    6465    }
     
    7980        // Admin hooks.
    8081        add_action( 'admin_init', array( $this, 'handle_settings_submission' ) );
     82        add_action( 'admin_init', array( $this, 'maybe_send_pending_error_email' ) );
    8183
    8284        // Admin bar indicator.
     
    246248    private function log_fatal_error( $error ) {
    247249        $error_data = array(
    248             'type'      => $error['type'],
    249             'message'   => $error['message'],
    250             'file'      => $error['file'],
    251             'line'      => $error['line'],
    252             'time'      => time(),
    253             'plugin'    => $this->detect_plugin_from_error( $error ),
    254             'url'       => isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '',
     250            'type'          => $error['type'],
     251            'message'       => $error['message'],
     252            'file'          => $error['file'],
     253            'line'          => $error['line'],
     254            'time'          => time(),
     255            'plugin'        => $this->detect_plugin_from_error( $error ),
     256            'url'           => isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '',
     257            'email_pending' => true,
    255258        );
    256259
     
    287290
    288291        return null;
     292    }
     293
     294    /**
     295     * Check for pending error emails and send them
     296     */
     297    public function maybe_send_pending_error_email() {
     298        $error_data = $this->get_last_error();
     299
     300        if ( $error_data && ! empty( $error_data['email_pending'] ) && ! empty( $error_data['plugin'] ) ) {
     301            $this->send_recovery_email( $error_data );
     302        }
     303    }
     304
     305    /**
     306     * Send recovery email notification
     307     *
     308     * @param array $error_data Error details.
     309     */
     310    private function send_recovery_email( $error_data ) {
     311        if ( ! $this->get_setting( 'email_notification', true ) ) {
     312            return;
     313        }
     314
     315        // Create hash of this error to avoid duplicate emails.
     316        $error_hash = md5( $error_data['file'] . $error_data['line'] . $error_data['message'] );
     317
     318        // Check if we already sent an email for this exact error.
     319        if ( $this->get_setting( 'last_error_email_hash', '' ) === $error_hash ) {
     320            return;
     321        }
     322
     323        $recovery_key = $this->get_setting( 'recovery_key', '' );
     324        if ( empty( $recovery_key ) ) {
     325            $recovery_key = $this->get_recovery_key_from_file();
     326        }
     327
     328        $recovery_url = add_query_arg( 'ap_recovery', $recovery_key, home_url( '/' ) );
     329        $admin_email  = get_option( 'admin_email' );
     330        $site_name    = get_bloginfo( 'name' );
     331
     332        $subject = sprintf(
     333            /* translators: %s: site name */
     334            __( '[%s] Fatal Error Detected - Recovery Link', 'blaminhor-essentials' ),
     335            $site_name
     336        );
     337
     338        $message = sprintf(
     339            /* translators: 1: site name, 2: error message, 3: file path, 4: line number, 5: plugin name, 6: recovery URL */
     340            __( "A fatal error was detected on %1\$s.\n\nError: %2\$s\n\nFile: %3\$s (line %4\$d)\n\nSuspected Plugin: %5\$s\n\nRecovery URL:\n%6\$s\n\nUse this link to disable problematic plugins and recover access to your site.\n\nIMPORTANT: Keep this URL secret! Anyone with this link can disable plugins.\n\n--\nBlaminhor Essentials - Fatal Error Recovery", 'blaminhor-essentials' ),
     341            $site_name,
     342            $error_data['message'],
     343            $error_data['file'],
     344            $error_data['line'],
     345            $error_data['plugin'] ? $error_data['plugin'] : __( 'Unknown', 'blaminhor-essentials' ),
     346            $recovery_url
     347        );
     348
     349        $sent = wp_mail( $admin_email, $subject, $message );
     350
     351        if ( $sent ) {
     352            // Save the hash to prevent duplicate emails.
     353            $settings = $this->settings;
     354            $settings['last_error_email_hash'] = $error_hash;
     355            $this->save_settings( $settings );
     356
     357            // Clear the pending flag in error data.
     358            $error_data['email_pending'] = false;
     359            update_option( 'ap_fer_last_error', $error_data, false );
     360
     361            // Also update file.
     362            $upload_dir = wp_upload_dir();
     363            $error_file = $upload_dir['basedir'] . '/blaminhor-essentials/.last-error.json';
     364            if ( file_exists( $error_file ) ) {
     365                file_put_contents( $error_file, wp_json_encode( $error_data ) );
     366            }
     367        }
    289368    }
    290369
     
    10381117                            </td>
    10391118                        </tr>
     1119                        <tr>
     1120                            <th scope="row"><?php esc_html_e( 'Email Notification', 'blaminhor-essentials' ); ?></th>
     1121                            <td>
     1122                                <label>
     1123                                    <input type="checkbox" name="email_notification" <?php checked( $this->get_setting( 'email_notification', true ) ); ?>>
     1124                                    <?php esc_html_e( 'Send email notification when fatal error is detected', 'blaminhor-essentials' ); ?>
     1125                                </label>
     1126                                <p class="description"><?php esc_html_e( 'When enabled, an email with the recovery URL will be sent to the admin email when a fatal error caused by a plugin is detected.', 'blaminhor-essentials' ); ?></p>
     1127                            </td>
     1128                        </tr>
    10401129                    </table>
    10411130
  • blaminhor-essentials/trunk/modules/favicon/class-module-favicon.php

    r3445838 r3446569  
    399399        $theme_color = $this->get_setting( 'theme_color', '#ffffff' );
    400400        ?>
    401 <!-- Alfred Proteus Favicon -->
     401<!-- Blaminhor Essentials Favicon -->
    402402<link rel="icon" type="image/png" sizes="48x48" href="<?php echo esc_url( $favicon_url . 'favicon-48x48.png' ); ?>">
    403403<link rel="icon" type="image/png" sizes="32x32" href="<?php echo esc_url( $favicon_url . 'favicon-32x32.png' ); ?>">
     
    409409<meta name="msapplication-config" content="<?php echo esc_url( home_url( '/browserconfig.xml' ) ); ?>">
    410410<meta name="theme-color" content="<?php echo esc_attr( $theme_color ); ?>">
    411 <!-- End Alfred Proteus Favicon -->
     411<!-- End Blaminhor Essentials Favicon -->
    412412        <?php
    413413    }
  • blaminhor-essentials/trunk/modules/image-sizes/class-module-image-sizes.php

    r3445838 r3446569  
    777777                </div>
    778778                <div class="ap-notice-actions">
    779                     <button type="button" class="button button-primary" onclick="jQuery('[data-tab=regenerate]').click();">
     779                    <button type="button" class="button button-primary" onclick="jQuery('[data-tab=regenerate]').click(); setTimeout(function(){ document.querySelector('.ap-cleanup-options').scrollIntoView({behavior: 'smooth', block: 'start'}); }, 150);">
    780780                        <?php esc_html_e( 'Clean Up', 'blaminhor-essentials' ); ?>
    781781                    </button>
  • blaminhor-essentials/trunk/modules/smtp/class-module-smtp.php

    r3445615 r3446569  
    768768        if ( $result ) {
    769769            wp_send_json_success( array(
    770                 'message' => __( 'Test email sent successfully! Check your inbox.', 'blaminhor-essentials' ),
     770                'message'         => __( 'Test email sent successfully! Check your inbox.', 'blaminhor-essentials' ),
     771                'logging_enabled' => (bool) $this->get_setting( 'enable_logging', false ),
    771772            ) );
    772773        } else {
  • blaminhor-essentials/trunk/readme.txt

    r3445838 r3446569  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 1.1.0
     7Stable tag: 1.1.1
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    192192
    193193== Changelog ==
     194
     195= 1.1.1 =
     196* Added: Redirect to plugin dashboard after activation.
     197* Added: "Settings" link in the plugins list page.
     198* Added: Email log auto-refresh after successful test email in SMTP module.
     199* Added: Recovery email notification option in Fatal Error Recovery module.
     200* Fixed: Missing translation for SEO placeholder text.
     201* Fixed: "Alfred Proteus" references in Favicon module HTML comments.
     202* Fixed: Image Sizes cleanup button now scrolls to cleanup section.
     203* Fixed: Mute Core Emails design consistency (missing card styles).
    194204
    195205= 1.1.0 =
     
    211221== Upgrade Notice ==
    212222
     223= 1.1.1 =
     224UX improvements: Dashboard redirect on activation, settings link in plugins list, SMTP log auto-refresh, recovery email notifications, and design fixes.
     225
    213226= 1.1.0 =
    214227Major update: 13 new modules, complete SMTP translations, improved Fatal Error Recovery, and new Advanced Settings.
     
    225238This plugin allows you to optionally configure connections to external SMTP services for email delivery. **No data is sent to any external service unless you explicitly configure an SMTP relay.**
    226239
    227 When you configure the SMTP Mailer module, your emails will be sent through the service you choose. The following services have preset configurations available:
    228 
    229 = Gmail =
    230 * Service URL: smtp.gmail.com
    231 * Privacy Policy: [https://policies.google.com/privacy](https://policies.google.com/privacy)
    232 
    233 = Microsoft Outlook/Office 365 =
    234 * Service URL: smtp.office365.com
    235 * Privacy Policy: [https://privacy.microsoft.com/privacystatement](https://privacy.microsoft.com/privacystatement)
    236 
    237 = Brevo (formerly Sendinblue) =
    238 * Service URL: smtp-relay.brevo.com
    239 * Privacy Policy: [https://www.brevo.com/legal/privacypolicy/](https://www.brevo.com/legal/privacypolicy/)
    240 
    241 = SendGrid =
    242 * Service URL: smtp.sendgrid.net
    243 * Privacy Policy: [https://www.twilio.com/legal/privacy](https://www.twilio.com/legal/privacy)
    244 
    245 = Mailgun =
    246 * Service URL: smtp.mailgun.org
    247 * Privacy Policy: [https://www.mailgun.com/legal/privacy-policy/](https://www.mailgun.com/legal/privacy-policy/)
    248 
    249 = Amazon SES =
    250 * Service URL: email-smtp.[region].amazonaws.com
    251 * Privacy Policy: [https://aws.amazon.com/privacy/](https://aws.amazon.com/privacy/)
    252 
    253 = Postmark =
    254 * Service URL: smtp.postmarkapp.com
    255 * Privacy Policy: [https://postmarkapp.com/privacy-policy](https://postmarkapp.com/privacy-policy)
    256 
    257 = Elastic Email =
    258 * Service URL: smtp.elasticemail.com
    259 * Privacy Policy: [https://elasticemail.com/privacy-policy](https://elasticemail.com/privacy-policy)
    260 
    261 = SparkPost =
    262 * Service URL: smtp.sparkpostmail.com
    263 * Privacy Policy: [https://www.sparkpost.com/policies/privacy/](https://www.sparkpost.com/policies/privacy/)
    264 
    265 = Mailjet =
    266 * Service URL: in-v3.mailjet.com
    267 * Privacy Policy: [https://www.mailjet.com/legal/privacy-policy/](https://www.mailjet.com/legal/privacy-policy/)
    268 
    269 = SMTP2GO =
    270 * Service URL: mail.smtp2go.com
    271 * Privacy Policy: [https://www.smtp2go.com/privacy/](https://www.smtp2go.com/privacy/)
    272 
    273 = Zoho Mail =
    274 * Service URL: smtp.zoho.com
    275 * Privacy Policy: [https://www.zoho.com/privacy.html](https://www.zoho.com/privacy.html)
     240When you configure the SMTP Mailer module, your emails will be sent through the service you choose. The following services have preset configurations available: Gmail, Microsoft Outlook/Office 365, Brevo (formerly Sendinblue), SendGrid, Mailgun, Amazon SES, Postmark, Elastic Email, SparkPost, Mailjet, SMTP2GO, Zoho Mail.
    276241
    277242You can also configure any other SMTP server using the "Other" option. Please review the privacy policy of any third-party service you choose to use.
Note: See TracChangeset for help on using the changeset viewer.