Search widgets adds double language parameter to URL after first search

GvandenAkker
Contributor

I'm not a developer but still hoping to fix this little bug on our bilangual site. Our search functions well the first time it's used, but after the search, the URL field is prepopulated with a querystring that contains two language parameters. As a result, any subsequent search yields zero results. Does anyknow know where this insertion of parameters is 'controlled'?


See: https://www.woodwing.com/search

0 Upvotes
13 Replies 13
MuhammadAmjad
Participant
 

Hi @GvandenAkker 

You're right that the duplicate language parameter is coming from JavaScript. When the WoodWing search module processes the URL, it's appending the language parameter without checking if it already exists.

To fix this, modify the JavaScript that handles the search parameter updates. Add a check to remove any existing language parameters before appending the new one:

let url = new URL(window.location);
url.searchParams.delete('lang');
url.searchParams.append('lang', currentLang);

Have you tried inspecting the WoodWing module's JavaScript to see where the duplication occurs?


Did my answer help? Please click "Mark as solution" — it helps others and means a lot to me!

I use my real experience, community knowledge, and expert tools (including AI when needed) to give the most accurate and human responses.


amjad_khatri.jpg

Muhammad Amjad

Senior Consultant • HubSpot + Web Automation Expert

Need HubSpot Help? Send Me a DM


free-linkedin-icon-130-thumbConnect with me On LinkedIn 

Specialties:

  • HubSpot CRM Setup & Automation
  • Custom Workflows & Email Marketing
  • API Integrations & Webhooks
  • WordPress + Laravel Development


Available for consulting, troubleshooting & custom HubSpot solutions.

0 Upvotes
GvandenAkker
Contributor

hi @MuhammadAmjad, thanks for your explanation. Would you mind taking a look at the javascript I copied in this post and tell me where to insert this check? I'm not a developer and I'm therefore not sure if this check can be inserted as is, and where exactly. Thank you very much!

0 Upvotes
MuhammadAmjad
Participant

 

MuhammadAmjad_0-1763539520227.png


Under Setting > Advanced ( Click on Advanced  )

MuhammadAmjad_1-1763539593079.png 


You will see an option Additonal code snippets, paste the javascript here and save.

<script>

let url = new URL(window.location);
url.searchParams.delete('lang');
url.searchParams.append('lang', currentLang);

</script>




 

0 Upvotes
GvandenAkker
Contributor

sorry, but that doesn't work. After the first search the page is not reloaded or anything, so the parameters in the URL are also not updated or removed.

0 Upvotes
MuhammadAmjad
Participant

Solution: 1

<script>
document.body.onload = () => {
let url = new URL(window.location);
url.searchParams.delete('lang');
url.searchParams.append('lang', currentLang);
};
</script>

Solutuon 2:

<script>
setTimeout( function(){
let url = new URL(window.location);
url.searchParams.delete('lang');
url.searchParams.append('lang', currentLang);
}, 1500)

</script>


0 Upvotes
Jaycee_Lewis
Thought Leader

Thanks for the additional details @GvandenAkker. Hey @felixmacaspac do you have any additional feedback? — Jaycee





loop


Loop Marketing is a new four-stage approach that combines AI efficiency and human authenticity to drive growth.

Learn More




0 Upvotes
BérangèreL
Community Manager
Community Manager

Hi @GvandenAkker and thanks for getting back to us!

Based on your code, the issue is likely in how you're building pagination URLs. When constructing the pageNumberParams in your JavaScript, you're using new URLSearchParams(params.toString()) which preserves all existing URL parameters, including any language parameters.
 

This may be because:


- Your pagination links are built by cloning the current URL parameters

- If a language parameter already exists in the URL, it gets preserved

- When the link is clicked, the language parameter may be added again

Could you please try the following: Before setting the offset parameter, ensure you're not duplicating language parameters. In your pagination function around line 200-250, modify how you create the pagination URLs:
 

let pageNumberParams = new URLSearchParams(params.toString());
pageNumberParams.set('offset', (i * updatedLimit));
// Remove any duplicate language parameters if they exist
pageNumberParams.delete('lang'); // or whatever your language param is called

Alternatively, check if HubSpot's automatic language URL rewriting is interfering. You can disable this for specific elements by adding the class hs-skip-lang-url-rewrite to your pagination links.
 

I hope this helps!

Have a great day!
Bérangère

This post was created with the assistance of AI tools.





loop


Loop Marketing is a new four-stage approach that combines AI efficiency and human authenticity to drive growth.

Learn More




0 Upvotes
GvandenAkker
Contributor
Thanks for the suggested additional code. However, the result is still identical: 2 language parameters.
Where would I have to add the class exactly? Is that also in the same piece of code share previously? Which line? Can you perhaps provide the sample code?

Again, I’m not a programmer 😉

Thanks a lot in advance!
0 Upvotes
BérangèreL
Community Manager
Community Manager

Hi @GvandenAkker and thanks for getting back to us! No worries at all, I’m not a programmer either, so you’re in good company! 😉

The hs get-started command is a streamlined CLI command that helps you quickly initialize and deploy a boilerplate project on HubSpot's developer platform.

It guides you through creating a project, configuring an app, uploading it to your account, and setting up local development.
 

According to the quickstart guide, after running hs get-started, you'll be prompted to select a project type (like App), name your project, set a local directory, and upload it to HubSpot.

The command handles dependency installation and initial deployment automatically.

Here are some resources that might help you:

- Quickstart
- Create a new app using the CLI
- HubSpot CLI commands (v7.10.0)

Now, let's consult our Top Experts: Hi @Anton, @SteveHTM and @sylvain_tirreau do you have suggestions to help @GvandenAkker, please?

Thanks so much and have a fantastic day!
Bérangère

This post was created with the assistance of AI tools.





loop


Loop Marketing is a new four-stage approach that combines AI efficiency and human authenticity to drive growth.

Learn More




0 Upvotes
GvandenAkker
Contributor

Thanks all for your suggestions. I thought it might help if I paste the code here?

 

Search result Module

 

{{ require_css(get_asset_url("/woodwing/web/modules/search/style/search-results.css"), { async: true} ) }}
{{ require_js(get_asset_url("/woodwing/web/modules/search/scripts/search-results.js"), { position: "footer" } ) }}

<!-- {% from '/woodwing/web/macros/web-components.html' import add_component %}
{{ add_component('@websites/chip', '/woodwing/web/vendor/components-library/chip/index.esm.js') }}
{{ add_component('@websites/ww-button', '/woodwing/web/vendor/components-library/ww-button/index.esm.js') }}
{{ add_component('@websites/ww-icon', '/woodwing/web/vendor/components-library/ww-icon/index.esm.js') }} -->

{% set module_classes = module.module_settings.top_padding %}
{% set module_classes = module.module_settings.bottom_padding ~ ' ' ~ module_classes %}

<section class="m-search-results smaller-search-results{{ module_classes }}">
<div class="container">
<div class="row row--justify-center">
<div class="col-12 col-sm-8 col-md-6">
<div class="hs-search-results" data-portal-id="{{ hub_id }}"
data-no-results-message='{{ module.no_results_text|escape|safe }}'
data-translations="{{ module.translations|tojson|escape|safe }}"
data-results-text="{{ module.translations.total_results_text|escape|safe }}">
<template class="hs-search-results__template">
<li>
<a class="hs-search-results__url" href="">
<wcl-chip slot="category" background-color="#F2F4F7">
<p slot="text" class="hs-search-results__type"></p>
</wcl-chip>
<h5 class="hs-search-results__title">Content Title</h5>
<p class="text_size-md text_color-gray-100 hs-search-results__description">Description</p>
<wcl-ww-button variant="tertiary" spacing="none" icon-position="right">
<span class="text_size-md hs-search-results__discover-more">View this page</span>
<wcl-ww-icon slot="icon" icon="arrow-right" color="#008697" size="20"></wcl-ww-icon>
<wcl-ww-icon slot="icon-hover" icon="arrow-right" color="#008697" size="20"></wcl-ww-icon>
</wcl-ww-button>
</a>
</li>
</template>

<ul id="hsresults" class="hs-search-results__listing"></ul>

<div class="hs-search-results__pagination" data-search-path="{{ content.absolute_url }}">
<ul class="hs-search-results__pages"></ul>
</div>
</div>
</div>
</div>

</div>
</section>

 

Search result .js code

 

let results = (function () {
    const searchResults = function () {
        let hsResultsPage = function (_resultsClass) {
            let params = new URLSearchParams(window.location.search.slice(1));

            function buildResultsPage(_instance) {
                let resultTemplate = _instance.querySelector('.hs-search-results__template'),
                    resultsSection = _instance.querySelector('.hs-search-results__listing'),
                    searchPath = _instance.querySelector('.hs-search-results__pagination').getAttribute('data-search-path'),
                    pagesContainer = _instance.querySelector('.hs-search-results__pages'),
                    paginationWrapper = _instance.querySelector('.hs-search-results__pagination'),
                    translations = _instance.dataset.translations ? JSON.parse(_instance.dataset.translations) : {};

                function getTerm() {
                    return params.get('term') || "";
                }
                function getOffset() {
                    return parseInt(params.get('offset')) || 0;
                }
                function getLimit() {
                    return parseInt(params.get('limit'));
                }
                function addResult(type, title, url, description) {
                    let newResult = document.importNode(resultTemplate.content, true);
                    let truncatedDescription = description;
                    let truncatedCharacterCount = 250;
                    if (description.length >= truncatedCharacterCount) {
                        truncatedDescription = description.substring(0, truncatedCharacterCount) + ' ...';
                    }
                    let button_text = translations.page_read_more;
                    let tag = translations.page_tag
                    if (type === "BLOG_POST" || type === "LISTING_PAGE" ) {
                        button_text = translations.blog_read_more;
                        tag = translations.blog_tag
                    }
  
                    newResult.querySelector('.hs-search-results__title').innerHTML = title;
                    newResult.querySelector('.hs-search-results__url').href = url;
                    newResult.querySelector('.hs-search-results__description').innerHTML = truncatedDescription;
                    newResult.querySelector('.hs-search-results__type').innerHTML = tag;
                    newResult.querySelector('.hs-search-results__discover-more').innerHTML = button_text;
                    resultsSection.appendChild(newResult);
                }
                function showResultCount(data) {
                    let resultsText = _instance.dataset.resultsText;
                    let text = `${data.total} ${resultsText}`;
                    let resultsCountElement = document.createElement('p');

                    resultsCountElement.classList.add('no-margin');
                    resultsCountElement.setAttribute('aria-label', text);
                    resultsCountElement.setAttribute('tabindex', 0);
                    resultsCountElement.innerText = text;

                    _instance.insertBefore(resultsCountElement, resultsSection);
                }
                function fillResults(results) {
                    results.results.forEach(function (result, i) {
                        addResult(result.type, result.title, result.url, result.description);
                    });
                }
                // function emptyPagination() {
                //     prevLink.innerHTML = "";
                //     nextLink.innerHTML = "";
                // }
                function emptyResults(searchedTerm) {
                    let message = _instance.dataset.noResultsMessage.replace('[...]', searchedTerm)
                    resultsSection.innerHTML = message;
                }
                function setSearchBarDefault(searchedTerm) {
                    let searchBars = document.querySelectorAll('.hs-search-field__input');
                    Array.prototype.forEach.call(searchBars, function (el) {
                        el.value = decodeURIComponent(searchedTerm);
                    });
                }
                function httpRequest(term, offset) {
                    let SEARCH_URL = "/_hcms/search?",
                        requestUrl = SEARCH_URL + params,
                        request = new XMLHttpRequest();

                        console.log(requestUrl);

                    request.open('GET', requestUrl, true);
                    request.onload = function () {
                        if (request.status >= 200 && request.status < 400) {
                            console.log(requestUrl);
                            
                            let data = JSON.parse(request.responseText);
                            setSearchBarDefault(data.searchTerm);
                            if (data.total > 0) {
                                showResultCount(data);
                                fillResults(data);
                                paginate(data);
                            }
                            else {
                                emptyResults(data.searchTerm);
                                // emptyPagination();
                            }
                        }
                        else {
                            console.error('Server reached, error retrieving results.');
                        }
                    };
                    request.onerror = function () {
                        console.error('Could not reach the server.');
                    };
                    request.send();
                }
                function addPagination(totalItems, currentPage, pageSize, maxPages) {
                    // calculate total pages
                    let totalPages = Math.ceil(totalItems / pageSize);

                    // ensure current page isn't out of range
                    if (currentPage < 1) {
                        currentPage = 1;
                    } else if (currentPage > totalPages) {
                        currentPage = totalPages;
                    }

                    let startPage, endPage;
                    if (totalPages <= maxPages) {
                        // total pages less than max so show all pages
                        startPage = 1;
                        endPage = totalPages;
                    } else {
                        // total pages more than max so calculate start and end pages
                        let maxPagesBeforeCurrentPage = Math.floor(maxPages / 2);
                        let maxPagesAfterCurrentPage = Math.ceil(maxPages / 2) - 1;
                        if (currentPage <= maxPagesBeforeCurrentPage) {
                            // current page near the start
                            startPage = 1;
                            endPage = maxPages;
                        } else if (currentPage + maxPagesAfterCurrentPage >= totalPages) {
                            // current page near the end
                            startPage = totalPages - maxPages + 1;
                            endPage = totalPages;
                        } else {
                            // current page somewhere in the middle
                            startPage = currentPage - maxPagesBeforeCurrentPage;
                            endPage = currentPage + maxPagesAfterCurrentPage;
                        }
                    }

                    // calculate start and end item indexes
                    let startIndex = (currentPage - 1) * pageSize;
                    let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

                    // create an array of pages to ng-repeat in the pager control
                    let pages = Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);

                    // return object with all pager properties required by the view
                    return {
                        totalItems: totalItems,
                        currentPage: currentPage,
                        pageSize: pageSize,
                        totalPages: totalPages,
                        startPage: startPage,
                        endPage: endPage,
                        startIndex: startIndex,
                        endIndex: endIndex,
                        pages: pages
                    };
                }

                function paginate(results) {
                    let updatedLimit = getLimit() || results.limit;

                    let pagesCount = Math.ceil(results.total / updatedLimit);

                    if (pagesCount > 1) {
                        paginationWrapper.classList.add('pagination');
                    }

                    function hasPreviousPage() {
                        return results.page > 0;
                    }

                    function hasNextPage() {
                        return results.offset < (results.total - updatedLimit);
                    }

                    if (pagesContainer && pagesCount > 1) {
                        // Prev page button
                        if (hasPreviousPage()) {
                            let prevParams = new URLSearchParams(params.toString());
                            prevParams.set('offset', (results.page * updatedLimit) - parseInt(updatedLimit));
                            
                            let pageNumberWrapper = document.createElement('li');
                            let pageNumber = document.createElement('a');
                            pageNumber.href = searchPath + "?" + prevParams;
                            pageNumber.classList.add('arrow');
                            pageNumber.innerHTML = '<img src="https://26222027.fs1.hubspotusercontent-eu1.net/hubfs/26222027/woodwing-theme-assets/icons/button%20icons/black/arrow-left.svg" alt="←" loading="lazy" width="20" height="20">';
                            pageNumberWrapper.appendChild(pageNumber);
                            pagesContainer.appendChild(pageNumberWrapper);
                        }
                        
                        let pagination = addPagination(results.total, results.page + 1, updatedLimit, 4);

                        for (let i = pagination.startPage - 1; i < pagination.endPage; i++) {
                            let pageNumberParams = new URLSearchParams(params.toString());
                            pageNumberParams.set('offset', (i * updatedLimit));
                            let pageNumberWrapper = document.createElement('li');

                            if (pagination.currentPage === (i + 1)) {
                                pageNumberWrapper.classList.add('active');
                            }

                            let pageNumber = document.createElement('a');
                            pageNumber.innerHTML = i + 1;
                            pageNumber.href = searchPath + "?" + pageNumberParams;
                            pageNumberWrapper.appendChild(pageNumber);
                            pagesContainer.appendChild(pageNumberWrapper);
                        }

                        // Next page button
                        if (hasNextPage()) {
                            let nextParams = new URLSearchParams(params.toString());
                            nextParams.set('offset', (results.page * updatedLimit) + parseInt(updatedLimit));

                            let pageNumberWrapper = document.createElement('li');
                            let pageNumber = document.createElement('a');
                            pageNumber.href = searchPath + "?" + nextParams;
                            pageNumber.classList.add('arrow');
                            pageNumber.innerHTML = '<img src="https://26222027.fs1.hubspotusercontent-eu1.net/hubfs/26222027/woodwing-theme-assets/icons/button%20icons/black/arrow-right.svg" alt="→" loading="lazy" width="20" height="20">';
                            pageNumberWrapper.appendChild(pageNumber);
                            pagesContainer.appendChild(pageNumberWrapper);
                        }
                    }
                }
                let getResults = (function () {
                    if (getTerm()) {
                        httpRequest(getTerm(), getOffset());
                    }
                    else {
                        // emptyPagination();
                    }
                })();
            }
            (function () {
                let searchResults = document.querySelectorAll(_resultsClass);
                Array.prototype.forEach.call(searchResults, function (el) {
                    buildResultsPage(el);
                });
            })();
        }

        if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
            let resultsPages = hsResultsPage('.hs-search-results');
        }
        else {
            document.addEventListener('DOMContentLoaded', function () {
                let resultsPages = hsResultsPage('.hs-search-results');
            });
        }
    };

    return searchResults;

})();
new results();

 

0 Upvotes
Sapna1
Participant

The double lang parameter is most likely coming from the front-end, not WoodWing’s internal search engine.

You probably have a language-switcher or code that always appends lang=, even when the URL already has one.

The WoodWing server-side “Locale” config may be set correctly, but because of the duplicated parameter, the search request fails or is interpreted incorrectly.

0 Upvotes
Jaycee_Lewis
Thought Leader

Hey @GvandenAkker 👋 Thanks for your post. @felixmacaspac is correct; without more details or access, it is challenging to give a definite answer to your question. — Jaycee





loop


Loop Marketing is a new four-stage approach that combines AI efficiency and human authenticity to drive growth.

Learn More




0 Upvotes
felixmacaspac
Contributor

Hi @GvandenAkker it's hard to assume what would be the problem in this scenario, it would be best if you can contact a developer that can verify the HubL and the JavaScript of the module. The insertion might be coming from the HubL implementation or the JavaScript implementation.

0 Upvotes