Plugin Directory

Changeset 3468187


Ignore:
Timestamp:
02/24/2026 03:38:59 AM (5 weeks ago)
Author:
fernandopimenta
Message:

Update trunk to version 2.0.1

Location:
pap-afiliados-pro/trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • pap-afiliados-pro/trunk/assets/css/papafpro-template-builder.css

    r3466192 r3468187  
    361361   ========================================================================== */
    362362
     363/* ==========================================================================
     364   PRESET EDITING CONTEXT BAR
     365   ========================================================================== */
     366
     367.papafpro-preset-editing-bar {
     368    background: #fff3cd;
     369    border: 1px solid #ffc107;
     370    border-radius: 4px;
     371    padding: 10px 16px;
     372    margin-bottom: 16px;
     373    display: flex;
     374    align-items: center;
     375    justify-content: space-between;
     376    gap: 12px;
     377}
     378
     379.papafpro-preset-editing-label {
     380    font-size: 14px;
     381    color: #664d03;
     382}
     383
     384.papafpro-back-to-global {
     385    white-space: nowrap;
     386}
     387
    363388/* Tablet: empilhar verticalmente */
    364389@media (max-width: 1024px) {
  • pap-afiliados-pro/trunk/assets/js/papafpro-linker-tracker.js

    r3466192 r3468187  
    2828        };
    2929
    30         var url = papafpro_linker.rest_url + 'track-click';
     30        var url = papafpro_linker.rest_url + 'track-click?_wpnonce=' + encodeURIComponent( papafpro_linker.rest_nonce );
    3131
    3232        // Primary: sendBeacon with JSON blob (non-blocking).
  • pap-afiliados-pro/trunk/assets/js/papafpro-template-builder.js

    r3466192 r3468187  
    1616    }
    1717
    18     var ajaxUrl = papafproTemplateBuilder.ajax_url;
    19     var nonce   = papafproTemplateBuilder.nonce;
     18    var ajaxUrl           = papafproTemplateBuilder.ajax_url;
     19    var nonce             = papafproTemplateBuilder.nonce;
     20    var currentPresetId   = null;
     21    var currentPresetName = null;
    2022
    2123    /**
     
    5961
    6062    /**
     63     * Atualizar UI da barra de contexto (preset vs global).
     64     *
     65     * Mostra/esconde a barra e ajusta o texto do botão de salvar.
     66     */
     67    function updatePresetEditingUI() {
     68        var $bar     = $( '#papafpro-preset-editing-bar' );
     69        var $nameEl  = $( '#papafpro-preset-editing-name' );
     70        var $saveBtn = $( '#papafpro-save-settings' );
     71        var i18n     = papafproTemplateBuilder.i18n || {};
     72
     73        if ( currentPresetId ) {
     74            $bar.show();
     75            if ( $nameEl.length ) {
     76                $nameEl[0].textContent = currentPresetName || '';
     77            }
     78            $saveBtn.text(
     79                i18n.save_preset_label
     80                    ? i18n.save_preset_label.replace( '%s', currentPresetName )
     81                    : 'Save Preset'
     82            );
     83        } else {
     84            $bar.hide();
     85            $nameEl.empty();
     86            $saveBtn.text( i18n.save_settings_label || 'Save Settings' );
     87        }
     88    }
     89
     90    /**
    6191     * Coletar todos os campos do formulário.
    6292     *
     
    70100            var name  = $( this ).attr( 'name' );
    71101            var value = $( this ).val();
    72             if ( name && value ) {
     102            if ( name ) {
    73103                data[ name ] = value;
    74104            }
     
    187217        e.preventDefault();
    188218
    189         var $btn   = $( this );
    190         $btn.prop( 'disabled', true );
    191 
    192         var data = {
    193             action:   'papafpro_save_settings',
    194             nonce:    nonce,
    195             settings: collectFormData()
    196         };
    197 
    198         $.post( ajaxUrl, data, function( response ) {
    199             if ( response.success ) {
    200                 showNotice( response.data.message || 'Configurações salvas!', 'success' );
    201             } else {
    202                 showNotice( response.data.message || 'Erro ao salvar.', 'error' );
    203             }
    204         }).fail( function() {
    205             showNotice( 'Erro de conexão.', 'error' );
    206         }).always( function() {
    207             $btn.prop( 'disabled', false );
    208         });
     219        var $btn     = $( this );
     220        $btn.prop( 'disabled', true );
     221
     222        var formData = collectFormData();
     223
     224        if ( currentPresetId ) {
     225            // Save to preset.
     226            $.post( ajaxUrl, {
     227                action:    'papafpro_update_preset',
     228                nonce:     nonce,
     229                preset_id: currentPresetId,
     230                settings:  formData
     231            }, function( response ) {
     232                if ( response.success ) {
     233                    showNotice( response.data.message, 'success' );
     234                } else {
     235                    showNotice(
     236                        ( response.data && response.data.message ) || 'Error saving preset.',
     237                        'error'
     238                    );
     239                }
     240            }).fail( function() {
     241                showNotice( 'Erro de conexão.', 'error' );
     242            }).always( function() {
     243                $btn.prop( 'disabled', false );
     244            });
     245        } else {
     246            // Save global settings.
     247            $.post( ajaxUrl, {
     248                action:   'papafpro_save_settings',
     249                nonce:    nonce,
     250                settings: formData
     251            }, function( response ) {
     252                if ( response.success ) {
     253                    showNotice( response.data.message, 'success' );
     254                } else {
     255                    showNotice(
     256                        ( response.data && response.data.message ) || 'Error saving settings.',
     257                        'error'
     258                    );
     259                }
     260            }).fail( function() {
     261                showNotice( 'Erro de conexão.', 'error' );
     262            }).always( function() {
     263                $btn.prop( 'disabled', false );
     264            });
     265        }
    209266    });
    210267
     
    285342            if ( response.success && response.data.settings ) {
    286343                applySettings( response.data.settings );
     344                currentPresetId   = id;
     345                currentPresetName = response.data.preset_name || '';
     346                updatePresetEditingUI();
    287347                showNotice( response.data.message || 'Preset carregado!', 'success' );
    288348            } else {
     
    291351        }).fail( function() {
    292352            showNotice( 'Erro de conexão.', 'error' );
     353        }).always( function() {
     354            $btn.prop( 'disabled', false );
     355        });
     356    });
     357
     358    // =========================================================================
     359    // 6b. BACK TO GLOBAL
     360    // =========================================================================
     361
     362    $( document ).on( 'click', '#papafpro-back-to-global', function( e ) {
     363        e.preventDefault();
     364
     365        var $btn = $( this );
     366        $btn.prop( 'disabled', true );
     367
     368        $.post( ajaxUrl, {
     369            action:    'papafpro_load_preset',
     370            nonce:     nonce,
     371            preset_id: 0
     372        }, function( response ) {
     373            if ( response.success && response.data.settings ) {
     374                applySettings( response.data.settings );
     375                currentPresetId   = null;
     376                currentPresetName = null;
     377                updatePresetEditingUI();
     378                var i18n = papafproTemplateBuilder.i18n || {};
     379                showNotice(
     380                    i18n.global_restored || 'Global settings restored.',
     381                    'success'
     382                );
     383            }
    293384        }).always( function() {
    294385            $btn.prop( 'disabled', false );
  • pap-afiliados-pro/trunk/includes/api/class-papafpro-linker-api.php

    r3466192 r3468187  
    5555
    5656        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
     57        add_filter( 'rest_authentication_errors', array( $this, 'bypass_cookie_auth_for_tracking' ), 999 );
    5758    }
    5859
     
    9394    public function check_edit_permission() {
    9495        return current_user_can( 'edit_posts' );
     96    }
     97
     98    /**
     99     * Bypass cookie authentication errors for the track-click endpoint.
     100     *
     101     * WordPress REST cookie authentication (rest_cookie_check_errors)
     102     * rejects requests that carry auth cookies without a valid nonce,
     103     * returning WP_Error 'rest_cookie_invalid_nonce' (HTTP 403).
     104     * This blocks navigator.sendBeacon() for logged-in users because
     105     * sendBeacon cannot send custom headers (X-WP-Nonce) and cookies
     106     * are sent automatically by the browser.
     107     *
     108     * This filter nullifies that specific error ONLY for the public
     109     * track-click route, which uses permission_callback __return_true
     110     * and relies on transient rate-limiting for anti-spam protection.
     111     *
     112     * @since  2.0.27
     113     * @param  WP_Error|null|true $errors Authentication result.
     114     * @return WP_Error|null|true Unchanged or null for track-click route.
     115     */
     116    public function bypass_cookie_auth_for_tracking( $errors ) {
     117        // Only act when there is a cookie-nonce error.
     118        if ( ! is_wp_error( $errors ) || 'rest_cookie_invalid_nonce' !== $errors->get_error_code() ) {
     119            return $errors;
     120        }
     121
     122        // Only bypass for our specific tracking route.
     123        $rest_route = $GLOBALS['wp']->query_vars['rest_route'] ?? '';
     124        if ( '/papafpro/v1/track-click' !== $rest_route ) {
     125            return $errors;
     126        }
     127
     128        // Nullify the error — let permission_callback decide access.
     129        return null;
    95130    }
    96131
  • pap-afiliados-pro/trunk/includes/blocks/class-papafpro-linker-block.php

    r3466192 r3468187  
    5151            'papafpro/linker',
    5252            array(
    53                 'api_version'     => 2,
     53                'api_version'     => 3,
    5454                'editor_script'   => 'papafpro-linker-block-editor',
    5555                'render_callback' => array( $this, 'render_linker_block' ),
     
    164164        $this->maybe_enqueue_tracker();
    165165
    166         // Block wrapper attributes for theme layout alignment (api_version 2).
     166        // Block wrapper attributes for theme layout alignment (api_version 3).
    167167        $wrapper_attributes = get_block_wrapper_attributes(
    168168            array(
     
    183183
    184184    /**
     185     * Ensure the linker tracker script is registered and localized.
     186     *
     187     * Normally PAPAFPRO_Shortcodes::register_assets() handles registration
     188     * on the wp_enqueue_scripts hook. This method is a defensive fallback
     189     * so that Block and Format Type enqueue paths are self-sufficient and
     190     * do not silently fail if the primary registration did not run.
     191     *
     192     * @since  2.0.29
     193     * @access private
     194     */
     195    private function ensure_tracker_registered() {
     196        if ( wp_script_is( 'papafpro-linker-tracker', 'registered' ) ) {
     197            return;
     198        }
     199
     200        wp_register_script(
     201            'papafpro-linker-tracker',
     202            PAPAFPRO_PLUGIN_URL . 'assets/js/papafpro-linker-tracker.js',
     203            array(),
     204            PAPAFPRO_VERSION,
     205            true
     206        );
     207
     208        wp_localize_script(
     209            'papafpro-linker-tracker',
     210            'papafpro_linker',
     211            array(
     212                'rest_url'   => esc_url_raw( rest_url( 'papafpro/v1/' ) ),
     213                'rest_nonce' => wp_create_nonce( 'wp_rest' ),
     214            )
     215        );
     216    }
     217
     218    /**
    185219     * Enqueue the linker tracker script on the frontend.
    186220     *
    187      * Localization is handled by PAPAFPRO_Shortcodes::register_assets()
    188      * at registration time — this method only enqueues.
     221     * Ensures registration before enqueuing so this path works
     222     * independently of PAPAFPRO_Shortcodes::register_assets().
    189223     *
    190224     * @since  2.0.0
     
    192226     */
    193227    private function maybe_enqueue_tracker() {
     228        $this->ensure_tracker_registered();
    194229        wp_enqueue_script( 'papafpro-linker-tracker' );
    195230    }
     
    208243     */
    209244    public function maybe_enqueue_linker_from_content( $content ) {
    210         if ( wp_script_is( 'papafpro-linker-tracker', 'registered' )
    211             && false !== strpos( $content, 'papafpro-linker' )
    212         ) {
     245        if ( false !== strpos( $content, 'papafpro-linker' ) ) {
     246            $this->ensure_tracker_registered();
    213247            wp_enqueue_script( 'papafpro-linker-tracker' );
    214248        }
  • pap-afiliados-pro/trunk/includes/class-papafpro-help-page.php

    r3466192 r3468187  
    185185                    ),
    186186                    array(
    187                         'name'        => 'preset',
     187                        'name'        => 'preset_id',
    188188                        'type'        => 'preset',
    189189                        'required'    => false,
     
    211211                    ),
    212212                    array(
    213                         'name'        => 'preset',
     213                        'name'        => 'preset_id',
    214214                        'type'        => 'preset',
    215215                        'required'    => false,
     
    243243                    ),
    244244                    array(
    245                         'name'        => 'preset',
     245                        'name'        => 'preset_id',
    246246                        'type'        => 'preset',
    247247                        'required'    => false,
     
    269269                    ),
    270270                    array(
    271                         'name'        => 'preset',
     271                        'name'        => 'preset_id',
    272272                        'type'        => 'preset',
    273273                        'required'    => false,
  • pap-afiliados-pro/trunk/includes/class-papafpro-template-builder.php

    r3466192 r3468187  
    333333        if ( $existing && $overwrite ) {
    334334            // UPDATE existente.
    335             wp_cache_get( 'papafpro_preset_' . $existing->id, 'papafpro' );
    336335            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
    337336            $wpdb->update(
     
    355354
    356355        // INSERT novo.
    357         wp_cache_get( 'papafpro_presets_list', 'papafpro' );
    358356        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
    359357        $wpdb->insert(
     
    386384
    387385    /**
     386     * AJAX: Update existing preset settings by ID.
     387     *
     388     * Updates the settings JSON of a preset without changing its name.
     389     * Used when the admin edits a loaded preset and clicks "Save".
     390     *
     391     * @since 2.0.1
     392     */
     393    public function ajax_update_preset() {
     394        check_ajax_referer( 'papafpro_template_builder', 'nonce' );
     395
     396        if ( ! current_user_can( 'manage_options' ) ) {
     397            wp_send_json_error(
     398                array(
     399                    'message' => __( 'Insufficient permissions.', 'pap-afiliados-pro' ),
     400                )
     401            );
     402        }
     403
     404        $preset_id = isset( $_POST['preset_id'] ) ? absint( $_POST['preset_id'] ) : 0;
     405
     406        if ( $preset_id < 1 ) {
     407            wp_send_json_error(
     408                array(
     409                    'message' => __( 'Invalid preset ID.', 'pap-afiliados-pro' ),
     410                )
     411            );
     412        }
     413
     414        global $wpdb;
     415        $table_name = $wpdb->prefix . 'papafpro_presets';
     416
     417        // Verify preset exists.
     418        $cache_key = 'papafpro_preset_' . $preset_id;
     419        $existing  = wp_cache_get( $cache_key, 'papafpro' );
     420        if ( false === $existing ) {
     421            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
     422            $existing = $wpdb->get_row(
     423                $wpdb->prepare(
     424                    'SELECT id, name, settings FROM %i WHERE id = %d',
     425                    $table_name,
     426                    $preset_id
     427                )
     428            );
     429            if ( null !== $existing ) {
     430                wp_cache_set( $cache_key, $existing, 'papafpro' );
     431            }
     432        }
     433
     434        if ( ! $existing ) {
     435            wp_send_json_error(
     436                array(
     437                    'message' => __( 'Preset not found.', 'pap-afiliados-pro' ),
     438                )
     439            );
     440        }
     441
     442        // Sanitize settings.
     443        $raw_settings = isset( $_POST['settings'] ) && is_array( $_POST['settings'] )
     444            ? map_deep( wp_unslash( $_POST['settings'] ), 'sanitize_text_field' )
     445            : array();
     446
     447        $sanitized = $this->sanitize_partial_settings( $raw_settings );
     448
     449        // Update preset in database.
     450        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
     451        $result = $wpdb->update(
     452            $table_name,
     453            array( 'settings' => wp_json_encode( $sanitized ) ),
     454            array( 'id' => $preset_id ),
     455            array( '%s' ),
     456            array( '%d' )
     457        );
     458
     459        // Invalidate cache.
     460        wp_cache_delete( 'papafpro_preset_' . $preset_id, 'papafpro' );
     461
     462        if ( false === $result ) {
     463            wp_send_json_error(
     464                array(
     465                    'message' => __( 'Failed to update preset.', 'pap-afiliados-pro' ),
     466                )
     467            );
     468        }
     469
     470        wp_send_json_success(
     471            array(
     472                'message'   => sprintf(
     473                    /* translators: %s: preset name */
     474                    __( 'Preset "%s" updated successfully.', 'pap-afiliados-pro' ),
     475                    esc_html( $existing->name )
     476                ),
     477                'preset_id' => $preset_id,
     478            )
     479        );
     480    }
     481
     482    /**
    388483     * AJAX: Carregar preset.
    389484     *
     
    405500        $preset_id = isset( $_POST['preset_id'] ) ? absint( $_POST['preset_id'] ) : 0;
    406501
    407         if ( $preset_id < 1 ) {
    408             wp_send_json_error(
    409                 array(
    410                     'message' => __( 'Invalid preset ID.', 'pap-afiliados-pro' ),
     502        // preset_id=0 returns global settings.
     503        if ( 0 === $preset_id ) {
     504            $settings = get_option( 'papafpro_settings', array() );
     505            wp_send_json_success(
     506                array(
     507                    'preset_id'   => 0,
     508                    'name'        => '',
     509                    'preset_name' => '',
     510                    'settings'    => $settings,
     511                    'message'     => __( 'Global settings loaded.', 'pap-afiliados-pro' ),
    411512                )
    412513            );
     
    446547        wp_send_json_success(
    447548            array(
    448                 'preset_id' => absint( $preset->id ),
    449                 'name'      => $preset->name,
    450                 'settings'  => $settings,
     549                'preset_id'   => absint( $preset->id ),
     550                'name'        => $preset->name,
     551                'preset_name' => esc_html( $preset->name ),
     552                'settings'    => $settings,
    451553            )
    452554        );
     
    482584        $table = $wpdb->prefix . 'papafpro_presets';
    483585
    484         wp_cache_get( 'papafpro_preset_' . $preset_id, 'papafpro' );
    485586        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
    486587        $deleted = $wpdb->delete(
     
    726827
    727828        foreach ( $ids as $id ) {
    728             wp_cache_get( 'papafpro_preset_' . $id, 'papafpro' );
    729829            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
    730830            $result = $wpdb->delete(
     
    815915            $new_name = $this->generate_unique_preset_name( $original->name, $table );
    816916
    817             wp_cache_get( 'papafpro_presets_list', 'papafpro' );
    818917            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table, no WP API available.
    819918            $wpdb->insert(
     
    9601059                    'ajax_url' => admin_url( 'admin-ajax.php' ),
    9611060                    'nonce'    => wp_create_nonce( 'papafpro_template_builder' ),
     1061                    'i18n'     => array(
     1062                        /* translators: %s: preset name */
     1063                        'save_preset_label'   => __( 'Save Preset: %s', 'pap-afiliados-pro' ),
     1064                        'save_settings_label' => __( 'Save Settings', 'pap-afiliados-pro' ),
     1065                        'global_restored'     => __( 'Global settings restored.', 'pap-afiliados-pro' ),
     1066                    ),
    9621067                )
    9631068            );
  • pap-afiliados-pro/trunk/includes/class-papafpro-template-render.php

    r3466192 r3468187  
    3636     */
    3737    public function render_card( $product_id, $settings = array() ) {
     38        $merged_settings = $this->get_merged_settings( $settings );
     39        return $this->build_single_card( $product_id, $merged_settings );
     40    }
     41
     42    /**
     43     * Build HTML for a single product card.
     44     *
     45     * Internal method that receives already-merged settings.
     46     * MUST NOT call get_merged_settings() or get_option() directly.
     47     *
     48     * @since  2.0.1
     49     * @access private
     50     * @param  int   $product_id      Product post ID.
     51     * @param  array $merged_settings Settings array already merged with defaults.
     52     * @return string Card HTML or empty string.
     53     */
     54    private function build_single_card( $product_id, $merged_settings ) {
    3855        $product_id = absint( $product_id );
    3956
     
    5673        }
    5774
    58         $product_data    = $this->get_product_data( $product_id );
    59         $merged_settings = $this->get_merged_settings( $settings );
     75        $product_data = $this->get_product_data( $product_id );
    6076
    6177        return $this->build_card_html( $product_data, $merged_settings );
     
    8399
    84100        foreach ( $product_ids as $product_id ) {
    85             $cards_html .= $this->render_card( absint( $product_id ), $merged_settings );
     101            $cards_html .= $this->build_single_card( absint( $product_id ), $merged_settings );
    86102        }
    87103
  • pap-afiliados-pro/trunk/languages/pap-afiliados-pro-pt_BR.po

    r3466192 r3468187  
    77"Report-Msgid-Bugs-To: https://pap-afiliados-pro.com.br\n"
    88"POT-Creation-Date: 2026-02-18T00:00:00+00:00\n"
    9 "PO-Revision-Date: 2026-02-18 00:00+0000\n"
     9"PO-Revision-Date: 2026-02-23 00:00+0000\n"
    1010"Last-Translator: Fernando Pimenta\n"
    1111"Language-Team: Brazilian Portuguese\n"
     
    540540msgstr "%d preset(s) duplicado(s) com sucesso."
    541541
     542#. translators: %s: preset name
     543#: includes/class-papafpro-template-builderphp:469
     544msgid "Preset \"%s\" updated successfully."
     545msgstr "Preset \"%s\" atualizado com sucesso."
     546
     547#: includes/class-papafpro-template-builderphp:460
     548msgid "Failed to update preset."
     549msgstr "Falha ao atualizar preset."
     550
     551#: includes/class-papafpro-template-builderphp:416
     552msgid "Global settings loaded."
     553msgstr "Configurações globais carregadas."
     554
     555#. translators: %s: preset name
     556#: includes/class-papafpro-template-builderphp:964
     557msgid "Save Preset: %s"
     558msgstr "Salvar Preset: %s"
     559
     560#: includes/class-papafpro-template-builderphp:966
     561msgid "Global settings restored."
     562msgstr "Configurações globais restauradas."
     563
     564#. translators: %s: preset name placeholder, replaced dynamically by JavaScript
     565#: views/papafpro-template-builderphp:389
     566msgid "Editing preset: %s"
     567msgstr "Editando preset: %s"
     568
     569#: views/papafpro-template-builderphp:395
     570msgid "Back to Global Settings"
     571msgstr "Voltar para Configurações Globais"
     572
    542573#: includes/class-papafpro-template-builderphp:871
    543574#: views/papafpro-help-pagephp:57
  • pap-afiliados-pro/trunk/languages/pap-afiliados-pro.pot

    r3466192 r3468187  
    55"Project-Id-Version: PAP Afiliados Pro 2.0.0\n"
    66"Report-Msgid-Bugs-To: https://pap-afiliados-pro.com.br\n"
    7 "POT-Creation-Date: 2026-02-18T00:00:00+00:00\n"
     7"POT-Creation-Date: 2026-02-23T00:00:00+00:00\n"
    88"MIME-Version: 1.0\n"
    99"Content-Type: text/plain; charset=UTF-8\n"
     
    536536msgstr ""
    537537
     538#. translators: %s: preset name
     539#: includes/class-papafpro-template-builderphp:469
     540msgid "Preset \"%s\" updated successfully."
     541msgstr ""
     542
     543#: includes/class-papafpro-template-builderphp:460
     544msgid "Failed to update preset."
     545msgstr ""
     546
     547#: includes/class-papafpro-template-builderphp:416
     548msgid "Global settings loaded."
     549msgstr ""
     550
     551#. translators: %s: preset name
     552#: includes/class-papafpro-template-builderphp:964
     553msgid "Save Preset: %s"
     554msgstr ""
     555
     556#: includes/class-papafpro-template-builderphp:966
     557msgid "Global settings restored."
     558msgstr ""
     559
     560#. translators: %s: preset name placeholder, replaced dynamically by JavaScript
     561#: views/papafpro-template-builderphp:389
     562msgid "Editing preset: %s"
     563msgstr ""
     564
     565#: views/papafpro-template-builderphp:395
     566msgid "Back to Global Settings"
     567msgstr ""
     568
    538569#: includes/class-papafpro-template-builderphp:871
    539570#: views/papafpro-help-pagephp:57
  • pap-afiliados-pro/trunk/pap-afiliados-pro.php

    r3466192 r3468187  
    44 * Plugin URI:        https://pap-afiliados-pro.com.br
    55 * Description:       Professional affiliate link management for Brazilian marketplaces (Amazon, Mercado Livre, Shopee, AliExpress, and others).
    6  * Version:           2.0.0
     6 * Version:           2.0.1
    77 * Requires at least: 6.2
    88 * Requires PHP:      7.4
     
    2424 * Constantes do plugin.
    2525 */
    26 define( 'PAPAFPRO_VERSION', '2.0.0' );
     26define( 'PAPAFPRO_VERSION', '2.0.1' );
    2727define( 'PAPAFPRO_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    2828define( 'PAPAFPRO_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
     
    108108    $loader->add_action( 'wp_ajax_papafpro_save_preset', $template_builder, 'ajax_save_preset' );
    109109    $loader->add_action( 'wp_ajax_papafpro_load_preset', $template_builder, 'ajax_load_preset' );
     110    $loader->add_action( 'wp_ajax_papafpro_update_preset', $template_builder, 'ajax_update_preset' );
    110111    $loader->add_action( 'wp_ajax_papafpro_delete_preset', $template_builder, 'ajax_delete_preset' );
    111112    $loader->add_action( 'wp_ajax_papafpro_update_preview', $template_builder, 'ajax_update_preview' );
  • pap-afiliados-pro/trunk/readme.txt

    r3466192 r3468187  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 2.0.0
     7Stable tag: 2.0.1
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    4848* Custom badges per marketplace
    4949* Adjustable colors, borders and spacing
    50 * Custom CSS with sanitization
    5150* Saved presets for reuse
    5251
     
    113112= Can I customize the card appearance? =
    114113
    115 Absolutely! The Template Builder lets you adjust 19 CSS variables, colors, borders, spacing, button styles and custom CSS. You can save presets to reuse across different pages.
     114Absolutely! The Template Builder lets you adjust 19 CSS variables, colors, borders, spacing and button styles. You can save presets to reuse across different pages.
    116115
    117116= What happens when I uninstall the plugin? =
     
    131130
    132131== Changelog ==
     132
     133= 2.0.1 =
     134* Fixed: Preset system now correctly applies individual visual configurations per shortcode
     135* Fixed: Shortcode generator produces correct preset_id parameter
     136* Fixed: Click tracking for PAP Link and PAP Linker block works reliably for all users including logged-in administrators
     137* Improved: Block API updated to version 3 for WordPress 7.0 compatibility
     138* Improved: Template Builder displays visual indicator when editing a preset
    133139
    134140= 2.0.0 =
     
    158164== Upgrade Notice ==
    159165
     166= 2.0.1 =
     167Bug fixes for preset system, shortcode generator, and click tracking. Block API updated for WordPress 7.0 compatibility.
     168
    160169= 2.0.0 =
    161170Complete rewrite! Version 2.0 is not compatible with 1.0.2. Please back up before upgrading.
  • pap-afiliados-pro/trunk/views/papafpro-template-builder.php

    r3466192 r3468187  
    381381            </div>
    382382
     383            <!-- Preset Editing Context Bar -->
     384            <div id="papafpro-preset-editing-bar" class="papafpro-preset-editing-bar" style="display:none;">
     385                <span class="papafpro-preset-editing-label">
     386                    <?php
     387                    printf(
     388                        /* translators: %s: preset name placeholder, replaced dynamically by JavaScript */
     389                        esc_html__( 'Editing preset: %s', 'pap-afiliados-pro' ),
     390                        '<strong id="papafpro-preset-editing-name"></strong>'
     391                    );
     392                    ?>
     393                </span>
     394                <button type="button" id="papafpro-back-to-global" class="button papafpro-back-to-global">
     395                    <?php esc_html_e( 'Back to Global Settings', 'pap-afiliados-pro' ); ?>
     396                </button>
     397            </div>
     398
    383399            <!-- Botões de Ação -->
    384400            <div class="papafpro-builder-actions">
Note: See TracChangeset for help on using the changeset viewer.