Plugin Directory

Changeset 3492952


Ignore:
Timestamp:
03/27/2026 07:41:43 PM (2 days ago)
Author:
efficiencynext
Message:

Feature: Added support for Basic Authentication and API Key Authentication

Location:
efficiencynext-data-connector/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • efficiencynext-data-connector/trunk/efficiencynext-data-connector.php

    r3474007 r3492952  
    703703        }
    704704
    705         $data = $this->fetch_json( $uri );
     705        $data = $this->fetch_json( $uri, $source );
    706706        if ( null === $data ) {
    707707            $data = array();
     
    838838     * Fetch JSON from URL using WordPress HTTP API.
    839839     *
    840      * @param string $url URL to fetch.
     840     * @param string $url    URL to fetch.
     841     * @param array  $source Optional source config for authentication.
     842     * @param string $error  Optional reference populated with a human-readable error on failure.
    841843     * @return array|null JSON data or null on failure.
    842844     */
    843     private function fetch_json( string $url ): ?array {
     845    private function fetch_json( string $url, array $source = array(), string &$error = '' ): ?array {
     846        $headers = array(
     847            'Accept'     => 'application/json',
     848            'User-Agent' => 'EfficiencyNext-Data-Connector/' . self::VERSION . ' WordPress/' . get_bloginfo( 'version' ),
     849        );
     850
     851        $auth_type = $source['auth_type'] ?? 'none';
     852
     853        if ( 'basic' === $auth_type ) {
     854            $username = $source['auth_username'] ?? '';
     855            $password = $source['auth_password'] ?? '';
     856            if ( '' !== $username || '' !== $password ) {
     857                // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
     858                $headers['Authorization'] = 'Basic ' . base64_encode( $username . ':' . $password );
     859            }
     860        } elseif ( 'apikey' === $auth_type ) {
     861            $key_name      = $source['auth_key_name'] ?? '';
     862            $key_value     = $source['auth_key_value'] ?? '';
     863            $key_placement = $source['auth_key_placement'] ?? 'header';
     864
     865            // Last-resort guard: the sentinel should never reach the HTTP layer.
     866            if ( '__UNCHANGED__' === $key_value ) {
     867                $key_value = '';
     868            }
     869
     870            if ( '' !== $key_name && '' !== $key_value ) {
     871                if ( 'header' === $key_placement ) {
     872                    $headers[ $key_name ] = $key_value;
     873                } elseif ( 'query' === $key_placement ) {
     874                    $separator = str_contains( $url, '?' ) ? '&' : '?';
     875                    $url      .= $separator . rawurlencode( $key_name ) . '=' . rawurlencode( $key_value );
     876                }
     877            }
     878        }
     879
    844880        $response = wp_remote_get(
    845881            $url,
     
    847883                'timeout'     => 15,
    848884                'redirection' => 3,
    849                 'headers'     => array(
    850                     'Accept'     => 'application/json',
    851                     'User-Agent' => 'EfficiencyNext-Data-Connector/' . self::VERSION . ' WordPress/' . get_bloginfo( 'version' ),
    852                 ),
     885                'headers'     => $headers,
    853886            )
    854887        );
    855888
    856889        if ( is_wp_error( $response ) ) {
    857             $this->log_error( 'Fetch error: ' . $response->get_error_message() );
     890            $error = $response->get_error_message();
     891            $this->log_error( 'Fetch error: ' . $error );
    858892            return null;
    859893        }
     
    861895        $code = wp_remote_retrieve_response_code( $response );
    862896        if ( $code < 200 || $code >= 300 ) {
     897            $error = 'HTTP ' . $code;
    863898            $this->log_error( 'HTTP error: ' . $code );
    864899            return null;
     
    867902        $body = wp_remote_retrieve_body( $response );
    868903        if ( empty( $body ) ) {
     904            $error = 'Empty response body';
    869905            return null;
    870906        }
     
    872908        $data = json_decode( $body, true );
    873909        if ( JSON_ERROR_NONE !== json_last_error() ) {
     910            $error = 'JSON parse error: ' . json_last_error_msg();
    874911            $this->log_error( 'JSON error: ' . json_last_error_msg() );
    875912            return null;
     
    9681005                    'requestFailed'    => __( 'Request failed.', 'efficiencynext-data-connector' ),
    9691006                    'insertTooltip'    => __( 'Click to insert into template', 'efficiencynext-data-connector' ),
     1007                    'authNone'         => __( 'No Authentication', 'efficiencynext-data-connector' ),
     1008                    'authBasic'        => __( 'Basic Auth', 'efficiencynext-data-connector' ),
     1009                    'authApiKey'       => __( 'API Key', 'efficiencynext-data-connector' ),
     1010                    'authPlacementHeader' => __( 'Header', 'efficiencynext-data-connector' ),
     1011                    'authPlacementQuery'  => __( 'Query Parameter', 'efficiencynext-data-connector' ),
     1012                    'passwordStored'   => __( '(stored — leave blank to keep unchanged)', 'efficiencynext-data-connector' ),
    9701013                ),
    9711014            )
     
    9981041        $api_url     = $this->sanitize_api_url( wp_unslash( $_POST['api_url'] ?? '' ) );
    9991042        $template    = $this->sanitize_template( wp_unslash( $_POST['template'] ?? '' ) );
    1000         $inline = ( sanitize_text_field( wp_unslash( $_POST['inline'] ?? '0' ) ) ) === '1';
     1043        $inline      = ( sanitize_text_field( wp_unslash( $_POST['inline'] ?? '0' ) ) ) === '1';
     1044
     1045        // Auth fields.
     1046        $allowed_auth_types = array( 'none', 'basic', 'apikey' );
     1047        $auth_type          = sanitize_text_field( wp_unslash( $_POST['auth_type'] ?? 'none' ) );
     1048        if ( ! in_array( $auth_type, $allowed_auth_types, true ) ) {
     1049            $auth_type = 'none';
     1050        }
     1051        $auth_username      = sanitize_text_field( wp_unslash( $_POST['auth_username'] ?? '' ) );
     1052        $auth_key_name      = sanitize_text_field( wp_unslash( $_POST['auth_key_name'] ?? '' ) );
     1053        $auth_key_placement = sanitize_text_field( wp_unslash( $_POST['auth_key_placement'] ?? 'header' ) );
     1054        if ( ! in_array( $auth_key_placement, array( 'header', 'query' ), true ) ) {
     1055            $auth_key_placement = 'header';
     1056        }
     1057
     1058        // For password/API key value: if the submitted value is the mask sentinel, preserve the existing stored value.
     1059        $mask_sentinel  = '__UNCHANGED__';
     1060        $auth_password  = wp_unslash( $_POST['auth_password'] ?? '' );
     1061        $auth_key_value = wp_unslash( $_POST['auth_key_value'] ?? '' );
     1062
     1063        // If editing and the field comes back as the mask sentinel, keep whatever was stored before.
     1064        if ( ! empty( $id ) ) {
     1065            foreach ( $sources as $existing ) {
     1066                if ( ( $existing['id'] ?? '' ) === $id ) {
     1067                    if ( $mask_sentinel === $auth_password ) {
     1068                        $auth_password = $existing['auth_password'] ?? '';
     1069                    }
     1070                    if ( $mask_sentinel === $auth_key_value ) {
     1071                        $auth_key_value = $existing['auth_key_value'] ?? '';
     1072                    }
     1073                    break;
     1074                }
     1075            }
     1076        }
     1077
     1078        // If the sentinel was not resolved (e.g. brand-new source with an empty secret field),
     1079        // treat it as an intentionally empty value — never persist the sentinel literal.
     1080        if ( $mask_sentinel === $auth_password ) {
     1081            $auth_password = '';
     1082        }
     1083        if ( $mask_sentinel === $auth_key_value ) {
     1084            $auth_key_value = '';
     1085        }
     1086
     1087        // Sanitize — these are stored as-is (plain text in wp_options, protected by WP access controls).
     1088        $auth_password  = sanitize_text_field( $auth_password );
     1089        $auth_key_value = sanitize_text_field( $auth_key_value );
    10011090
    10021091        // Validate required fields.
     
    10211110
    10221111        $source_data = array(
    1023             'id'          => ! empty( $id ) ? $id : wp_generate_uuid4(),
    1024             'name'        => $name,
    1025             'placeholder' => $placeholder,
    1026             'api_url'     => $api_url,
    1027             'template'    => $template,
    1028             'inline'      => $inline,
     1112            'id'                 => ! empty( $id ) ? $id : wp_generate_uuid4(),
     1113            'name'               => $name,
     1114            'placeholder'        => $placeholder,
     1115            'api_url'            => $api_url,
     1116            'template'           => $template,
     1117            'inline'             => $inline,
     1118            'auth_type'          => $auth_type,
     1119            'auth_username'      => $auth_username,
     1120            'auth_password'      => $auth_password,
     1121            'auth_key_name'      => $auth_key_name,
     1122            'auth_key_value'     => $auth_key_value,
     1123            'auth_key_placement' => $auth_key_placement,
    10291124        );
    10301125
     
    10891184        }
    10901185
    1091         wp_send_json_success( array( 'sources' => $this->get_sources() ) );
     1186        // Return sources with secrets masked — the JS layer uses the __UNCHANGED__ sentinel
     1187        // to preserve the stored value when the user saves without re-entering credentials.
     1188        $sources = $this->get_sources();
     1189        $masked  = array_map( function ( $s ) {
     1190            if ( ! empty( $s['auth_password'] ) ) {
     1191                $s['auth_password'] = '__UNCHANGED__';
     1192            }
     1193            if ( ! empty( $s['auth_key_value'] ) ) {
     1194                $s['auth_key_value'] = '__UNCHANGED__';
     1195            }
     1196            return $s;
     1197        }, $sources );
     1198
     1199        wp_send_json_success( array( 'sources' => $masked ) );
    10921200    }
    10931201
     
    11091217        }
    11101218
     1219        // Build a temporary source config for auth.
     1220        $allowed_auth_types = array( 'none', 'basic', 'apikey' );
     1221        $auth_type          = sanitize_text_field( wp_unslash( $_POST['auth_type'] ?? 'none' ) );
     1222        if ( ! in_array( $auth_type, $allowed_auth_types, true ) ) {
     1223            $auth_type = 'none';
     1224        }
     1225        $preview_source = array(
     1226            'auth_type'          => $auth_type,
     1227            'auth_username'      => sanitize_text_field( wp_unslash( $_POST['auth_username'] ?? '' ) ),
     1228            'auth_password'      => sanitize_text_field( wp_unslash( $_POST['auth_password'] ?? '' ) ),
     1229            'auth_key_name'      => sanitize_text_field( wp_unslash( $_POST['auth_key_name'] ?? '' ) ),
     1230            'auth_key_value'     => sanitize_text_field( wp_unslash( $_POST['auth_key_value'] ?? '' ) ),
     1231            'auth_key_placement' => sanitize_text_field( wp_unslash( $_POST['auth_key_placement'] ?? 'header' ) ),
     1232        );
     1233
     1234        // If credentials come in as the mask sentinel, load them from the saved source.
     1235        $source_id = sanitize_text_field( wp_unslash( $_POST['source_id'] ?? '' ) );
     1236        if ( ! empty( $source_id ) ) {
     1237            $sources = $this->get_sources();
     1238            foreach ( $sources as $existing ) {
     1239                if ( ( $existing['id'] ?? '' ) === $source_id ) {
     1240                    if ( '__UNCHANGED__' === $preview_source['auth_password'] ) {
     1241                        $preview_source['auth_password'] = $existing['auth_password'] ?? '';
     1242                    }
     1243                    if ( '__UNCHANGED__' === $preview_source['auth_key_value'] ) {
     1244                        $preview_source['auth_key_value'] = $existing['auth_key_value'] ?? '';
     1245                    }
     1246                    break;
     1247                }
     1248            }
     1249        }
     1250
    11111251        // Remove mustache tags for preview.
    11121252        $url = preg_replace( '/\{\{[\w.]+\}\}/', '', $url );
    11131253        $url = esc_url_raw( $url );
    11141254
    1115         $data = $this->fetch_json( $url );
     1255        $fetch_error = '';
     1256        $data = $this->fetch_json( $url, $preview_source, $fetch_error );
    11161257        if ( null === $data ) {
    1117             wp_send_json_error( array( 'message' => __( 'Could not fetch data from the API. Check the URL and try again.', 'efficiencynext-data-connector' ) ) );
     1258            $message = __( 'Could not fetch data from the API.', 'efficiencynext-data-connector' );
     1259            if ( ! empty( $fetch_error ) ) {
     1260                $message .= ' ' . sprintf(
     1261                    /* translators: %s: error detail such as "HTTP 401" */
     1262                    __( 'Server responded: %s', 'efficiencynext-data-connector' ),
     1263                    $fetch_error
     1264                );
     1265                // Give targeted hints for common HTTP auth errors.
     1266                if ( str_starts_with( $fetch_error, 'HTTP 401' ) || str_starts_with( $fetch_error, 'HTTP 403' ) ) {
     1267                    $message .= ' — ' . __( 'check your credentials.', 'efficiencynext-data-connector' );
     1268                } elseif ( str_starts_with( $fetch_error, 'HTTP 404' ) ) {
     1269                    $message .= ' — ' . __( 'check the API URL.', 'efficiencynext-data-connector' );
     1270                }
     1271            }
     1272            wp_send_json_error( array( 'message' => $message ) );
    11181273        }
    11191274
     
    15061661        margin-top: 10px;
    15071662    }
     1663    .auth-field-row {
     1664        flex-direction: column;
     1665    }
     1666}
     1667
     1668/* Auth section */
     1669.auth-fields {
     1670    margin-top: 10px;
     1671    padding: 12px 14px;
     1672    background: #f6f7f7;
     1673    border: 1px solid #dcdcde;
     1674    border-radius: 4px;
     1675}
     1676.auth-field-row {
     1677    display: flex;
     1678    gap: 12px;
     1679    margin-bottom: 10px;
     1680}
     1681.auth-field-row:last-child {
     1682    margin-bottom: 0;
     1683}
     1684.auth-field-col {
     1685    flex: 1;
     1686    min-width: 0;
     1687}
     1688.auth-field-col-full {
     1689    flex: 1 1 100%;
     1690}
     1691.auth-field-col label {
     1692    display: block;
     1693    font-weight: 600;
     1694    font-size: 12px;
     1695    margin-bottom: 4px;
     1696    color: #1d2327;
     1697}
     1698.auth-field-col input,
     1699.auth-field-col select {
     1700    width: 100%;
     1701}
     1702.auth-stored-note {
     1703    display: block;
     1704    font-size: 11px;
     1705    color: #646970;
     1706    margin-top: 3px;
     1707    font-style: italic;
     1708}
     1709.source-meta .auth-badge {
     1710    display: inline-block;
     1711    font-size: 10px;
     1712    font-weight: 600;
     1713    padding: 1px 6px;
     1714    border-radius: 10px;
     1715    text-transform: uppercase;
     1716    letter-spacing: 0.03em;
     1717}
     1718.source-meta .auth-badge.auth-none {
     1719    background: #f0f0f1;
     1720    color: #646970;
     1721}
     1722.source-meta .auth-badge.auth-basic {
     1723    background: #e7f0f5;
     1724    color: #2271b1;
     1725}
     1726.source-meta .auth-badge.auth-apikey {
     1727    background: #fef3e7;
     1728    color: #9a6700;
    15081729}
    15091730        <?php
     
    15711792            });
    15721793
     1794            // Auth type toggle.
     1795            $('#db-source-auth-type').on('change', function() {
     1796                DB.toggleAuthFields($(this).val());
     1797                DB.saveDraft();
     1798            });
     1799
    15731800            // Auto-save draft on every field change.
    15741801            $('#db-source-name, #db-source-placeholder, #db-source-url, #db-source-template').on('input change', function() {
     
    15781805                DB.saveDraft();
    15791806            });
     1807            $('#db-auth-username, #db-auth-password, #db-auth-key-name, #db-auth-key-value').on('input', function() {
     1808                DB.saveDraft();
     1809            });
     1810            $('#db-auth-key-placement').on('change', function() {
     1811                DB.saveDraft();
     1812            });
    15801813        },
    15811814
     
    15871820
    15881821            this.draft = {
    1589                 source_id:   $('#db-source-id').val(),
    1590                 name:        $('#db-source-name').val(),
    1591                 placeholder: $('#db-source-placeholder').val(),
    1592                 api_url:     $('#db-source-url').val(),
    1593                 template:    $('#db-source-template').val(),
    1594                 inline:      $('#db-source-inline').is(':checked'),
    1595                 timestamp:   Date.now()
     1822                source_id:        $('#db-source-id').val(),
     1823                name:             $('#db-source-name').val(),
     1824                placeholder:      $('#db-source-placeholder').val(),
     1825                api_url:          $('#db-source-url').val(),
     1826                template:         $('#db-source-template').val(),
     1827                inline:           $('#db-source-inline').is(':checked'),
     1828                auth_type:        $('#db-source-auth-type').val(),
     1829                auth_username:    $('#db-auth-username').val(),
     1830                auth_key_name:    $('#db-auth-key-name').val(),
     1831                auth_key_placement: $('#db-auth-key-placement').val(),
     1832                // Never persist secret values in sessionStorage.
     1833                timestamp:        Date.now()
    15961834            };
    15971835
     
    16271865            $('#db-source-template').val(this.draft.template || '');
    16281866            $('#db-source-inline').prop('checked', !!this.draft.inline);
     1867            var authType = this.draft.auth_type || 'none';
     1868            $('#db-source-auth-type').val(authType);
     1869            $('#db-auth-username').val(this.draft.auth_username || '');
     1870            $('#db-auth-password').val('');
     1871            $('#db-auth-password-note').hide();
     1872            $('#db-auth-key-name').val(this.draft.auth_key_name || '');
     1873            $('#db-auth-key-placement').val(this.draft.auth_key_placement || 'header');
     1874            $('#db-auth-key-value').val('');
     1875            $('#db-auth-key-value-note').hide();
     1876            this.toggleAuthFields(authType);
    16291877        },
    16301878
     
    16581906            this.sources.forEach(function(source) {
    16591907                var shortcode = '[effcncynxtdc source="' + DB.escHtml(source.name) + '"]';
     1908                var authType  = source.auth_type || 'none';
     1909                var authLabels = { none: 'No Auth', basic: 'Basic', apikey: 'API Key' };
     1910                var authLabel  = authLabels[authType] || 'No Auth';
    16601911                var $item = $(
    16611912                    '<div class="effcncynxtdc-source-item" data-id="' + DB.escHtml(source.id) + '">' +
     
    16661917                                '<span>' + effcncynxtdcAdmin.i18n.labelShortcode + ' <code>' + DB.escHtml(shortcode) + '</code></span>' +
    16671918                                '<span>' + effcncynxtdcAdmin.i18n.labelInline + ' ' + (source.inline ? effcncynxtdcAdmin.i18n.yes : effcncynxtdcAdmin.i18n.no) + '</span>' +
     1919                                '<span><span class="auth-badge auth-' + DB.escHtml(authType) + '">' + DB.escHtml(authLabel) + '</span></span>' +
    16681920                            '</div>' +
    16691921                        '</div>' +
     
    16941946                $('#db-source-template').val(source.template);
    16951947                $('#db-source-inline').prop('checked', source.inline);
     1948                // Auth fields.
     1949                var authType = source.auth_type || 'none';
     1950                $('#db-source-auth-type').val(authType);
     1951                $('#db-auth-username').val(source.auth_username || '');
     1952                $('#db-auth-password').val('');
     1953                $('#db-auth-password-note').toggle(source.auth_password === '__UNCHANGED__');
     1954                $('#db-auth-key-name').val(source.auth_key_name || '');
     1955                $('#db-auth-key-placement').val(source.auth_key_placement || 'header');
     1956                $('#db-auth-key-value').val('');
     1957                $('#db-auth-key-value-note').toggle(source.auth_key_value === '__UNCHANGED__');
     1958                this.toggleAuthFields(authType);
    16961959                this.clearDraft();
    16971960            } else if (this.hasDraft() && !this.draft.source_id) {
     
    17231986            $('#db-source-template').val('');
    17241987            $('#db-source-inline').prop('checked', false);
     1988            $('#db-source-auth-type').val('none');
     1989            $('#db-auth-username').val('');
     1990            $('#db-auth-password').val('');
     1991            $('#db-auth-password-note').hide();
     1992            $('#db-auth-key-name').val('');
     1993            $('#db-auth-key-value').val('');
     1994            $('#db-auth-key-value-note').hide();
     1995            $('#db-auth-key-placement').val('header');
     1996            this.toggleAuthFields('none');
     1997        },
     1998
     1999        toggleAuthFields: function(type) {
     2000            $('.auth-fields').hide();
     2001            if (type === 'basic')  { $('#db-auth-basic').show(); }
     2002            if (type === 'apikey') { $('#db-auth-apikey').show(); }
    17252003        },
    17262004
     
    17332011        saveSource: function() {
    17342012            var data = {
    1735                 action: 'effcncynxtdc_save_source',
    1736                 nonce: effcncynxtdcAdmin.nonce,
    1737                 source_id: $('#db-source-id').val(),
    1738                 name: $('#db-source-name').val(),
    1739                 placeholder: $('#db-source-placeholder').val(),
    1740                 api_url: $('#db-source-url').val(),
    1741                 template: $('#db-source-template').val(),
    1742                 inline: $('#db-source-inline').is(':checked') ? '1' : '0'
     2013                action:             'effcncynxtdc_save_source',
     2014                nonce:              effcncynxtdcAdmin.nonce,
     2015                source_id:          $('#db-source-id').val(),
     2016                name:               $('#db-source-name').val(),
     2017                placeholder:        $('#db-source-placeholder').val(),
     2018                api_url:            $('#db-source-url').val(),
     2019                template:           $('#db-source-template').val(),
     2020                inline:             $('#db-source-inline').is(':checked') ? '1' : '0',
     2021                auth_type:          $('#db-source-auth-type').val(),
     2022                auth_username:      $('#db-auth-username').val(),
     2023                auth_password:      $('#db-auth-password').val() || '__UNCHANGED__',
     2024                auth_key_name:      $('#db-auth-key-name').val(),
     2025                auth_key_value:     $('#db-auth-key-value').val() || '__UNCHANGED__',
     2026                auth_key_placement: $('#db-auth-key-placement').val()
    17432027            };
    17442028
     
    17982082
    17992083            $.post(effcncynxtdcAdmin.ajaxUrl, {
    1800                 action: 'effcncynxtdc_preview_api',
    1801                 nonce: effcncynxtdcAdmin.nonce,
    1802                 api_url: url
     2084                action:             'effcncynxtdc_preview_api',
     2085                nonce:              effcncynxtdcAdmin.nonce,
     2086                api_url:            url,
     2087                source_id:          $('#db-source-id').val(),
     2088                auth_type:          $('#db-source-auth-type').val(),
     2089                auth_username:      $('#db-auth-username').val(),
     2090                auth_password:      $('#db-auth-password').val() || '__UNCHANGED__',
     2091                auth_key_name:      $('#db-auth-key-name').val(),
     2092                auth_key_value:     $('#db-auth-key-value').val() || '__UNCHANGED__',
     2093                auth_key_placement: $('#db-auth-key-placement').val()
    18032094            }, function(resp) {
    18042095                $btn.prop('disabled', false).text(effcncynxtdcAdmin.i18n.previewApi);
     
    19622253                            </div>
    19632254                            <p class="description"><?php esc_html_e( 'HTML template with Mustache-style tags. Only safe HTML tags are allowed (no script/iframe/form). Click "Preview API" above to see available fields.', 'efficiencynext-data-connector' ); ?></p>
     2255                        </div>
     2256
     2257                        <div class="form-row">
     2258                            <label for="db-source-auth-type"><?php esc_html_e( 'Authentication', 'efficiencynext-data-connector' ); ?></label>
     2259                            <select id="db-source-auth-type" class="regular-text">
     2260                                <option value="none"><?php esc_html_e( 'No Authentication', 'efficiencynext-data-connector' ); ?></option>
     2261                                <option value="basic"><?php esc_html_e( 'Basic Auth', 'efficiencynext-data-connector' ); ?></option>
     2262                                <option value="apikey"><?php esc_html_e( 'API Key', 'efficiencynext-data-connector' ); ?></option>
     2263                            </select>
     2264
     2265                            <!-- Basic Auth fields -->
     2266                            <div id="db-auth-basic" class="auth-fields auth-fields-basic" style="display:none;">
     2267                                <div class="auth-field-row">
     2268                                    <div class="auth-field-col">
     2269                                        <label for="db-auth-username"><?php esc_html_e( 'Username', 'efficiencynext-data-connector' ); ?></label>
     2270                                        <input type="text" id="db-auth-username" class="regular-text" autocomplete="off">
     2271                                    </div>
     2272                                    <div class="auth-field-col">
     2273                                        <label for="db-auth-password"><?php esc_html_e( 'Password', 'efficiencynext-data-connector' ); ?></label>
     2274                                        <input type="password" id="db-auth-password" class="regular-text" autocomplete="new-password">
     2275                                        <span class="auth-stored-note" id="db-auth-password-note" style="display:none;"><?php esc_html_e( '(stored — leave blank to keep unchanged)', 'efficiencynext-data-connector' ); ?></span>
     2276                                    </div>
     2277                                </div>
     2278                            </div>
     2279
     2280                            <!-- API Key fields -->
     2281                            <div id="db-auth-apikey" class="auth-fields auth-fields-apikey" style="display:none;">
     2282                                <div class="auth-field-row">
     2283                                    <div class="auth-field-col">
     2284                                        <label for="db-auth-key-name"><?php esc_html_e( 'Key Name', 'efficiencynext-data-connector' ); ?></label>
     2285                                        <input type="text" id="db-auth-key-name" class="regular-text" placeholder="X-API-Key" autocomplete="off">
     2286                                        <p class="description"><?php esc_html_e( 'Header name or query parameter name.', 'efficiencynext-data-connector' ); ?></p>
     2287                                    </div>
     2288                                    <div class="auth-field-col">
     2289                                        <label for="db-auth-key-placement"><?php esc_html_e( 'Send As', 'efficiencynext-data-connector' ); ?></label>
     2290                                        <select id="db-auth-key-placement">
     2291                                            <option value="header"><?php esc_html_e( 'Header', 'efficiencynext-data-connector' ); ?></option>
     2292                                            <option value="query"><?php esc_html_e( 'Query Parameter', 'efficiencynext-data-connector' ); ?></option>
     2293                                        </select>
     2294                                    </div>
     2295                                </div>
     2296                                <div class="auth-field-row">
     2297                                    <div class="auth-field-col auth-field-col-full">
     2298                                        <label for="db-auth-key-value"><?php esc_html_e( 'Key Value', 'efficiencynext-data-connector' ); ?></label>
     2299                                        <input type="password" id="db-auth-key-value" class="regular-text" autocomplete="new-password">
     2300                                        <span class="auth-stored-note" id="db-auth-key-value-note" style="display:none;"><?php esc_html_e( '(stored — leave blank to keep unchanged)', 'efficiencynext-data-connector' ); ?></span>
     2301                                    </div>
     2302                                </div>
     2303                            </div>
    19642304                        </div>
    19652305
  • efficiencynext-data-connector/trunk/readme.txt

    r3474007 r3492952  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 1.0.0
     7Stable tag: 1.0.1
    88License: GPL-2.0-or-later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    108108* Full internationalization (i18n) with load_plugin_textdomain and translatable JavaScript strings
    109109* Automatic migration from pre-release storage format
     110
     111= 1.0.1 =
     112* Added support for Basic Authentication and API Key Authentication
Note: See TracChangeset for help on using the changeset viewer.