0

I am trying to encode URI parameters for an ajax call in Wordpress without using JQuery. I think I achieved this, but I really don't know if it is a usefull function or it is just useless because already exists in a native JS function that I don't know.

Are there better solutions?

I also don't like the if (!recur) res = res.slice(0, -1); at the end, but I didn't found better solutions to delete the very last "&".

Here is what I wrote (also made a Pen https://codepen.io/globdug/pen/mdarxRo )

const action = "action_name";
const nonce = "nonce_value";
const data = [
    [1, 2, "abc", 3, false, "ciao"],
    "ciao",
    123,
    5213515,
    {
        name: "Tanto va la gatta al lardo",
        slug: "tanto-va-la-gatta-al-lardo"
    },
    {
        key: "ciao",
        test: ["a", "b", "ciao"]
    },
    {
        name: "Tre tigri contro tre tigri",
        slug: "tre-tigri-contro-tre-tigri"
    }
];

function arrayToEncodedString(
    obj, // Array of data to be processed
    varName = "data", // Name of variable that will be processed by the PHP function. It will receive an array
    encode = true, // Just for testing, if true keys and values will be encoded with encodeURIComponent
    prevKey = "", // Blank only during the first call
    recur = false // A flag to check if it is the last "&" at the end of the string.
) {
    let res = "";

    for (const key in obj) {
        const value = obj[key];

        let currentKey =
            prevKey === "" ? varName + "[" + key + "]" : prevKey + "[" + key + "]";

        /**
         * If current value is an object,
         * I will call the function again to iterate it.
         */
        if (typeof value === "object") {
            /*
             * This time I call the function with recur = true
             * to avoid deletion of the last "&"
             */
            res += arrayToEncodedString(value, varName, encode, currentKey, true);
        } else {
            /**
             * I add this check just for debugging and readability
             */
            if (encode) {
                res += `${encodeURIComponent(currentKey)}=${encodeURIComponent(value)}&`;
            } else {
                res += `${currentKey}=${value}&`;
            }
        }
    }

    /**
     * Remove last "&". Only if "recur" is true
     * to avoid deletion of the last "&" of data processed recursively
     */
    if (!recur) res = res.slice(0, -1);

    return res;
}

function prepareForAjax(data, action, nonce, encode = true, varName) {
    return `action=${action}&nonce=${nonce}&${arrayToEncodedString(
        data,
        varName,
        encode,
        undefined,
        undefined
    )}`;
}

/**
 * Thanks ChatGPT
 */
function highlightURLParameters(paramString) {
    // Regex per individuare chiavi e valori
    const regex = /([^&=]+)=([^&]+)/g;

    // Sostituisci la stringa con HTML formattato
    const formattedString = paramString.replace(
        regex,
        function (match, key, value) {
            return (
                '<span class="key">' +
                key +
                '</span>=<span class="value">' +
                value +
                "</span>"
            );
        }
    );

    return formattedString;
}

document.getElementById("resRaw").innerHTML = highlightURLParameters(
    prepareForAjax(data, action, nonce, false)
);

document.getElementById("res").innerHTML = highlightURLParameters(
    prepareForAjax(data, action, nonce)
);
.wrapper {
  font-family: monospace;
}

pre {
  background-color: #232323;
  border: 2px solid #000;
  padding: 10px;
  color: white;
  white-space: pre-wrap;
}

.key,
.value {
  font-weight: bold;
  margin: 0 5px;
}

.key {
  color: cyan;
}

.value {
  color: orange;
}
<div class="wrapper">
  <b>Data to send:</b><br>
  <pre id="resRaw"></pre>
  <b>String encoded:</b><br>
  <pre id="res"></pre>
</div>

0

1 Answer 1

0

Yes there is a built-in function URL.searchParams.

No need to encode.

const url = new URL("https://example.com/page.php");
const parms = {"action":"action_name","nonce":"nonce_value"};
Object.entries(parms).forEach(([key, value]) => url.searchParams.set(key,value))
console.log(url.toString())

In your case with the nested array, I would use JSON.stringify and pass the complete object instead of data[0][1] etc

Send JSON data from Javascript to PHP?

In your case:

Client:

const action = "action_name";
const nonce = "nonce_value";
const data = [
  // ... Your data
];

const payload = {
  action,
  nonce,
  data // No need to stringify data here; it will be part of the entire JSON payload
};

fetch('your-php-file.php', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload) // Stringify the entire payload
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

Server:

// Get the payload from frontend
$rawData = file_get_contents("php://input");

// Decode the JSON payload
$decodedData = json_decode($rawData, true);

$action = $decodedData['action'];
$nonce = $decodedData['nonce'];
$data = $decodedData['data']; // Data is already an array or object, as it was part of the JSON payload

// Here you have $action, $nonce, and $data to be used in the program

PS: To not remove the last thing in something, create an array and join on the thing. For example (but don't, use the above suggestions)

const keyValues = []; 
keyValues.push("action=action_name"); // loop here of course
keyValues.push("nonce=nonce_value"); 
const url = `${serverUrl}?${keyValues.join("&")}`
Sign up to request clarification or add additional context in comments.

6 Comments

I have tried with JSON.stringify this is an example. ` const d = [ { test1: "ciao", test2: "buongiorno", } ]; xhr.send(action=${action}&nonce=${nonce}&data=${JSON.stringify(d)}); ` And this is what the PHP page got: ` Array ( [action] => wc_manager_attributes_save [nonce] => 4e989c404d [data] => [{\"test1\":\"ciao\",\"test2\":\"buongiorno\"}] ) `
But without using encodeURIComponent, if the input text contains something like this: ``` const d = [ { test1: "ciao&test3=nooo", test2: "buongiorno", } ]; xhr.send(action=${action}&nonce=${nonce}&data=${JSON.stringify(d)}); ``` This is what PHP page will get: ``` Array ( [action] => wc_manager_attributes_save [nonce] => 4e989c404d [data] => [{\"test1\":\"ciao [test3] => nooo\",\"test2\":\"buongiorno\"}] ) ```
And also the json_encode that return the PHP function is a mess: ``` {"action":"wc_manager_attributes_save","nonce":"4e989c404d","data":"[{\\\\\\"test1\\\\\\":\\\\\\"ciao","test3":"nooo\\\\\\",\\\\\\"test2\\\\\\":\\\\\\"buongiorno\\\\\\"}]"} ```
OK, sorry for this disaster in commenting, is it understandable? 😅
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.