Plugin Directory

Changeset 3419619


Ignore:
Timestamp:
12/15/2025 12:17:32 AM (4 months ago)
Author:
imgpro
Message:

Update to version 0.2.4

Location:
bandwidth-saver/trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • bandwidth-saver/trunk/admin/css/imgpro-cdn-admin.css

    r3411500 r3419619  
    271271}
    272272
    273 .imgpro-btn-primary:hover {
     273.imgpro-btn-primary:hover,
     274.imgpro-btn-primary:focus,
     275a.imgpro-btn-primary:hover,
     276a.imgpro-btn-primary:focus,
     277a.imgpro-btn-primary:visited {
    274278    background: var(--imgpro-primary-700);
    275279    border-color: var(--imgpro-primary-700);
    276280    box-shadow: 0 2px 8px rgba(0, 51, 255, 0.25);
     281    color: white;
    277282}
    278283
     
    10211026    gap: var(--imgpro-space-6);
    10221027    padding: var(--imgpro-space-5) var(--imgpro-space-6);
     1028    margin-bottom: var(--imgpro-space-4);
    10231029    background: var(--imgpro-bg);
    10241030    border: 1px solid var(--imgpro-border);
  • bandwidth-saver/trunk/admin/js/imgpro-cdn-admin.js

    r3411500 r3419619  
    363363                    // Revert toggle
    364364                    $toggle.prop('checked', !isEnabled);
    365                     showNotice('error', response.data.message || imgproCdnAdmin.i18n.settingsError);
     365                    // Account exists with email - show recovery modal
     366                    if (response.data.show_recovery) {
     367                        showRecoveryVerificationModal(response.data.email_hint);
     368                    } else {
     369                        showNotice('error', response.data.message || imgproCdnAdmin.i18n.settingsError);
     370                    }
    366371                }
    367372            },
  • bandwidth-saver/trunk/imgpro-cdn.php

    r3411500 r3419619  
    44 * Plugin URI: https://github.com/img-pro/bandwidth-saver
    55 * Description: Instant image CDN. 100 GB/month free, no DNS changes, no external accounts.
    6  * Version: 0.2.3
     6 * Version: 0.2.4
    77 * Author: ImgPro
    88 * Author URI: https://img.pro
     
    4747// Define plugin constants
    4848if (!defined('IMGPRO_CDN_VERSION')) {
    49     define('IMGPRO_CDN_VERSION', '0.2.3');
     49    define('IMGPRO_CDN_VERSION', '0.2.4');
    5050}
    5151if (!defined('IMGPRO_CDN_PLUGIN_DIR')) {
  • bandwidth-saver/trunk/includes/class-imgpro-cdn-admin-ajax.php

    r3410342 r3419619  
    134134
    135135    /**
     136     * Auto-register a cloud account when toggling on for the first time
     137     *
     138     * This enables frictionless activation without requiring email upfront.
     139     * Email is collected later when user upgrades via Stripe.
     140     *
     141     * @since 0.2.3
     142     * @return true|WP_Error True on success, WP_Error on failure
     143     */
     144    private function auto_register_cloud_account() {
     145        $site_url = get_site_url();
     146
     147        // Register without email (frictionless free activation)
     148        $result = $this->api->create_site(null, $site_url, false);
     149
     150        if (is_wp_error($result)) {
     151            $error_code = $result->get_error_code();
     152
     153            // Handle existing account with email - needs recovery
     154            if ('conflict' === $error_code) {
     155                // Clear any stale API key from singleton before calling public endpoint
     156                $this->api->set_api_key(null);
     157
     158                // Automatically request recovery code
     159                $recovery_result = $this->api->request_recovery($site_url);
     160
     161                if (!is_wp_error($recovery_result)) {
     162                    // Check if this is a no-email account (no recovery needed)
     163                    if (!empty($recovery_result['no_recovery_needed'])) {
     164                        // This shouldn't happen since we just tried to register
     165                        // But handle it gracefully - try again
     166                        return new WP_Error('registration_failed', __('Registration failed. Please try again.', 'bandwidth-saver'));
     167                    }
     168
     169                    // Recovery email sent
     170                    return new WP_Error('account_exists', __('We found an existing account for this site. Please check your email for a verification code.', 'bandwidth-saver'), [
     171                        'show_recovery' => true,
     172                        'email_hint' => $recovery_result['email_hint'] ?? null,
     173                    ]);
     174                }
     175
     176                return new WP_Error('recovery_failed', __('An account exists but recovery failed. Please try again.', 'bandwidth-saver'));
     177            }
     178
     179            // Other API errors
     180            return $result;
     181        }
     182
     183        // Success - save site data to settings
     184        $this->save_site_data_to_settings($result);
     185
     186        return true;
     187    }
     188
     189    /**
     190     * Save site data from API response to plugin settings
     191     *
     192     * @since 0.2.3
     193     * @param array $site Site data from API
     194     * @return void
     195     */
     196    private function save_site_data_to_settings($site) {
     197        $data = [
     198            'setup_mode'           => ImgPro_CDN_Settings::MODE_CLOUD,
     199            'cloud_api_key'        => $site['api_key'] ?? '',
     200            'cloud_tier'           => $site['tier']['id'] ?? ImgPro_CDN_Settings::TIER_FREE,
     201            'onboarding_completed' => true,
     202        ];
     203
     204        // Only set email if provided
     205        if (!empty($site['email'])) {
     206            $data['cloud_email'] = $site['email'];
     207        }
     208
     209        // Extract source domains if available
     210        if (!empty($site['domains'])) {
     211            $domains = [];
     212            foreach ($site['domains'] as $domain_info) {
     213                if (!empty($domain_info['domain'])) {
     214                    $domains[] = $domain_info['domain'];
     215                }
     216            }
     217            if (!empty($domains)) {
     218                $data['source_urls'] = $domains;
     219            }
     220        }
     221
     222        $this->settings->update($data);
     223    }
     224
     225    /**
    136226     * AJAX handler for toggling CDN enabled state
    137227     *
     
    158248        $current_settings = $this->settings->get_all();
    159249
     250        $auto_registered = false;
     251
    160252        // Check if the mode is properly configured before allowing enable
    161253        if ($enabled && !ImgPro_CDN_Settings::is_mode_valid($mode, $current_settings)) {
    162             wp_send_json_error(['message' => __('Please complete setup first before enabling.', 'bandwidth-saver')]);
    163             return;
     254            // For cloud mode: auto-register if not yet set up
     255            if (ImgPro_CDN_Settings::MODE_CLOUD === $mode) {
     256                $registration_result = $this->auto_register_cloud_account();
     257                if (is_wp_error($registration_result)) {
     258                    $error_data = $registration_result->get_error_data();
     259
     260                    // Check if this needs recovery flow (account with email)
     261                    if (!empty($error_data['show_recovery'])) {
     262                        wp_send_json_error([
     263                            'message'       => $registration_result->get_error_message(),
     264                            'code'          => $registration_result->get_error_code(),
     265                            'show_recovery' => true,
     266                            'email_hint'    => $error_data['email_hint'] ?? null,
     267                        ]);
     268                        return;
     269                    }
     270
     271                    wp_send_json_error([
     272                        'message' => $registration_result->get_error_message(),
     273                        'code' => $registration_result->get_error_code(),
     274                    ]);
     275                    return;
     276                }
     277                // Registration succeeded - refresh settings and flag for page reload
     278                $this->settings->clear_cache();
     279                $current_settings = $this->settings->get_all();
     280                $auto_registered = true;
     281            } else {
     282                // Cloudflare mode still requires manual setup
     283                wp_send_json_error(['message' => __('Please complete setup first before enabling.', 'bandwidth-saver')]);
     284                return;
     285            }
    164286        }
    165287
     
    194316                : __('Image CDN disabled. Images now load from your server.', 'bandwidth-saver');
    195317
    196             wp_send_json_success(['message' => $message]);
     318            $response = ['message' => $message];
     319
     320            // If we just auto-registered, reload page to show full dashboard
     321            if ($auto_registered) {
     322                $response['redirect'] = admin_url('options-general.php?page=imgpro-cdn-settings&tab=cloud&activated=1');
     323            }
     324
     325            wp_send_json_success($response);
    197326        } else {
    198327            wp_send_json_error(['message' => __('Could not save settings. Please try again.', 'bandwidth-saver')]);
  • bandwidth-saver/trunk/includes/class-imgpro-cdn-admin.php

    r3411500 r3419619  
    574574
    575575        if (filter_input(INPUT_GET, 'activated', FILTER_VALIDATE_BOOLEAN)) {
     576            $tier = $this->settings->get('cloud_tier', ImgPro_CDN_Settings::TIER_FREE);
     577            $is_free = ImgPro_CDN_Settings::TIER_FREE === $tier;
    576578            ?>
    577579            <div class="imgpro-notice imgpro-notice-success">
    578580                <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="8" stroke="currentColor" stroke-width="2"/><path d="M6 10l3 3 5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
    579                 <p><strong><?php esc_html_e('Subscription activated. Your images now load from the global edge network.', 'bandwidth-saver'); ?></strong></p>
     581                <p><strong>
     582                    <?php if ($is_free): ?>
     583                        <?php esc_html_e('Account activated. Your images now load from the global edge network.', 'bandwidth-saver'); ?>
     584                    <?php else: ?>
     585                        <?php esc_html_e('Subscription activated. Your images now load from the global edge network.', 'bandwidth-saver'); ?>
     586                    <?php endif; ?>
     587                </strong></p>
    580588            </div>
    581589            <?php
     
    620628        $settings = $this->settings->get_all();
    621629
    622         // Check if should show onboarding
    623         if ($this->onboarding->should_show_onboarding()) {
    624             $this->render_onboarding_page();
    625             return;
    626         }
     630        // Onboarding wizard disabled - frictionless activation via toggle
     631        // Users now toggle ON directly, which auto-registers if needed
     632        // Keeping onboarding code for potential future use (e.g., guided tours)
    627633
    628634        // Handle mode switching (nonce verified immediately after isset check)
     
    11161122     */
    11171123    private function render_cloud_tab($settings) {
    1118         $is_configured = !empty($settings['cloud_api_key']);
    11191124        $tier = $settings['cloud_tier'] ?? ImgPro_CDN_Settings::TIER_NONE;
    1120         $has_subscription = in_array($tier, [ImgPro_CDN_Settings::TIER_FREE, ImgPro_CDN_Settings::TIER_LITE, ImgPro_CDN_Settings::TIER_PRO, ImgPro_CDN_Settings::TIER_BUSINESS, ImgPro_CDN_Settings::TIER_ACTIVE], true);
    1121         $pricing = $this->get_pricing();
     1125        $has_subscription = in_array($tier, [ImgPro_CDN_Settings::TIER_FREE, ImgPro_CDN_Settings::TIER_LITE, ImgPro_CDN_Settings::TIER_PRO, ImgPro_CDN_Settings::TIER_BUSINESS, ImgPro_CDN_Settings::TIER_ACTIVE, ImgPro_CDN_Settings::TIER_PAST_DUE], true);
    11221126        ?>
    11231127        <div class="imgpro-tab-panel" role="tabpanel">
    11241128            <?php if (!$has_subscription): ?>
    1125                 <?php $this->render_cloud_signup($pricing); ?>
     1129                <?php // New install - show toggle card (will auto-register on first enable) ?>
     1130                <?php $this->render_toggle_card($settings, ImgPro_CDN_Settings::MODE_CLOUD); ?>
     1131                <p class="imgpro-safety-note">
     1132                    <?php esc_html_e('Your original images stay on your server. Turning the CDN off or deactivating the plugin will not break your site — image URLs simply return to normal.', 'bandwidth-saver'); ?>
     1133                </p>
    11261134            <?php else: ?>
    11271135                <?php $this->render_cloud_settings($settings); ?>
     
    13391347                </div>
    13401348                <div class="imgpro-account-card__footer">
    1341                     <span><?php echo esc_html($email); ?></span>
    1342                     <span class="imgpro-separator">·</span>
    13431349                    <span><?php esc_html_e('Free Plan — 100 GB/month included', 'bandwidth-saver'); ?></span>
     1350                    <?php if (!empty($email)): ?>
     1351                        <span class="imgpro-separator">·</span>
     1352                        <span><?php echo esc_html($email); ?></span>
     1353                    <?php endif; ?>
    13441354                </div>
    13451355            </div>
     
    13771387                </div>
    13781388                <div class="imgpro-account-card__footer">
    1379                     <span><?php echo esc_html($email); ?></span>
     1389                    <?php if (!empty($email)): ?>
     1390                        <span><?php echo esc_html($email); ?></span>
     1391                    <?php endif; ?>
    13801392                    <?php if (!$is_business): ?>
    1381                         <span class="imgpro-separator">·</span>
     1393                        <?php if (!empty($email)): ?>
     1394                            <span class="imgpro-separator">·</span>
     1395                        <?php endif; ?>
    13821396                        <button type="button" class="imgpro-btn-link" id="imgpro-manage-subscription">
    13831397                            <?php esc_html_e('Manage Subscription', 'bandwidth-saver'); ?>
  • bandwidth-saver/trunk/includes/class-imgpro-cdn-api.php

    r3410342 r3419619  
    277277     * Create new site account
    278278     *
    279      * @param string $email          User email.
    280      * @param string $site_url       WordPress site URL.
    281      * @param bool   $marketing_opt_in Marketing consent.
     279     * Email is optional for free accounts. If the site_url already exists:
     280     * - If existing site has NO email: returns existing site (reconnection)
     281     * - If existing site HAS email: returns conflict (requires recovery)
     282     *
     283     * @param string|null $email          User email (optional for free tier).
     284     * @param string      $site_url       WordPress site URL.
     285     * @param bool        $marketing_opt_in Marketing consent.
    282286     * @return array|WP_Error Site data array or error.
    283287     */
    284288    public function create_site($email, $site_url, $marketing_opt_in = false) {
    285         if (empty($email) || empty($site_url)) {
    286             return new WP_Error('missing_fields', __('Email and site URL are required', 'bandwidth-saver'));
     289        if (empty($site_url)) {
     290            return new WP_Error('missing_fields', __('Site URL is required', 'bandwidth-saver'));
    287291        }
    288292
     
    290294        $this->set_api_key(null);
    291295
    292         $response = $this->request('POST', '/api/sites', [
    293             'email'            => $email,
     296        $data = [
    294297            'site_url'         => $site_url,
    295298            'marketing_opt_in' => $marketing_opt_in,
    296         ]);
     299        ];
     300
     301        // Only include email if provided
     302        if (!empty($email)) {
     303            $data['email'] = $email;
     304        }
     305
     306        $response = $this->request('POST', '/api/sites', $data);
    297307
    298308        if (is_wp_error($response)) {
     
    301311
    302312        $site = $response['site'] ?? $response;
     313
     314        // Check if this was a reconnection (existing account without email)
     315        $reconnected = !empty($response['reconnected']);
     316        if ($reconnected) {
     317            $site['_reconnected'] = true;
     318        }
     319
    303320        $this->cache_site($site);
    304321
  • bandwidth-saver/trunk/readme.txt

    r3411500 r3419619  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 0.2.3
     7Stable tag: 0.2.4
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    1919Bandwidth Saver fixes this by serving your images from servers close to your visitors — automatically. A visitor in Tokyo loads images from Asia. A visitor in London loads from Europe. Everyone gets faster pages.
    2020
    21 **The best part?** You don't need to understand how it works. Just activate the plugin, enter your email, and toggle it on. Your images start loading faster immediately.
     21**The best part?** You don't need to understand how it works. Just activate the plugin and flip the switch. Your images start loading faster immediately.
    2222
    2323= What You Get =
     
    3535Behind the scenes, Bandwidth Saver uses a global CDN (Content Delivery Network) with 300+ edge locations. But you don't need to know what that means or how to set it up.
    3636
    37 1. You activate the plugin and enter your email
    38 2. The plugin automatically rewrites image URLs on your pages
    39 3. Visitors load images from the nearest edge server
    40 4. Your original images stay exactly where they are
    41 
    42 That's it. No DNS changes. No external accounts to manage. No settings to configure.
     371. Install the plugin from your WordPress dashboard
     382. Flip the switch to activate
     393. Images instantly load from 300+ global servers
     40
     41That's it. No DNS changes. No external accounts. No settings to configure. Your original images stay exactly where they are.
    4342
    4443= Why People Choose This Over Other Speed Plugins =
     
    83821. Install and activate the plugin
    84832. Go to **Settings → Bandwidth Saver**
    85 3. Enter your email
    86 4. Toggle the CDN on
    87 
    88 Done. Your images are now loading faster.
     843. Toggle the CDN on
     85
     86Done. Your images are now loading faster. No email required for the free tier.
    8987
    9088== Frequently Asked Questions ==
     
    9694= I'm not technical. Can I still use this? =
    9795
    98 Yes. That's exactly who this is for. You don't need to understand CDNs, DNS, or servers. Just activate, enter your email, and toggle it on.
     96Yes. That's exactly who this is for. You don't need to understand CDNs, DNS, or servers. Just activate and toggle it on.
    9997
    10098= How do I know it's working? =
     
    104102= Is there really a free plan? =
    105103
    106 Yes. 100 GB of bandwidth per month, free forever. No credit card required. No trial period. Most small to medium sites never need to upgrade.
     104Yes. 100 GB of bandwidth per month, free forever. No credit card required. No trial period. Most sites never need to upgrade.
    107105
    108106= What if I go over my bandwidth limit? =
     
    151149
    152150* Your site URL is used to configure CDN routing
    153 * Your email address is used for account creation
     151* Email is optional — only collected if you upgrade or request account recovery
    154152* Custom domain settings are sent if configured
    155153
     
    173171
    174172* Purpose: Account management, usage tracking
    175 * Data sent: Site URL, email, custom domain (if configured)
     173* Data sent: Site URL, email (if provided), custom domain (if configured)
    176174
    177175Self-hosted users connect only to their own Cloudflare account.
    178176
    179177== Changelog ==
     178
     179= 0.2.4 =
     180* New: Frictionless activation — no email required for free tier
     181* Improved: Toggle on directly from dashboard, account created automatically
     182* Improved: Cleaner first-run experience with fewer steps
     183* Fixed: Account card displays correctly when email is not set
    180184
    181185= 0.2.3 =
     
    237241== Upgrade Notice ==
    238242
     243= 0.2.4 =
     244Frictionless activation: Just flip the switch, no email required. Simpler than ever.
     245
    239246= 0.2.3 =
    240247Clearer messaging and improved onboarding experience. Recommended for all users.
Note: See TracChangeset for help on using the changeset viewer.