diff --git a/docs/helpers/esql.asciidoc b/docs/helpers/esql.asciidoc
new file mode 100644
index 000000000..7e1d0ee64
--- /dev/null
+++ b/docs/helpers/esql.asciidoc
@@ -0,0 +1,221 @@
+[[esql]]
+=== ES|QL in the PHP client
+++++
+ES|QL
+++++
+
+This page helps you understand and use {ref}/esql.html[ES|QL] in the
+PHP client.
+
+There are two ways to use ES|QL in the PHP client:
+
+* Use the Elasticsearch {es-docs}/esql-apis.html[ES|QL API] directly: This
+is the most flexible approach, but it's also the most complex because you must handle
+results in their raw form. You can choose the precise format of results,
+such as JSON, CSV, or text.
+* Use ES|QL `mapTo($class)` helper. This mapper takes care of parsing the raw
+response and converting into an array of objects. If you don't specify the class
+using the `$class` parameter, the mapper uses https://www.php.net/manual/en/class.stdclass.php[stdClass].
+
+[discrete]
+[[esql-how-to]]
+==== How to use the ES|QL API
+
+The {es-docs}/esql-query-api.html[ES|QL query API] allows you to specify how
+results should be returned. You can choose a
+{es-docs}/esql-rest.html#esql-rest-format[response format] such as CSV, text, or
+JSON, then fine-tune it with parameters like column separators
+and locale.
+
+The default response from Elasticsearch is a table in JSON, where `columns`
+is an array of descriptions and `values` is an array of rows containing the values.
+
+[[query-script]]
+Here's an example query and PHP script:
+
+```php
+$query = <<esql()->query([
+ 'body' => ['query' => $query]
+]);
+
+foreach ($result['values'] as $value) {
+ $i=0;
+ foreach ($result['columns'] as $col) {
+ printf("%s : %s\n", $col['name'], $value[$i++]);
+ }
+ print("---\n");
+}
+```
+
+Here's the JSON response from Elasticsearch:
+
+```json
+{
+ "columns": [
+ { "name": "author", "type": "text" },
+ { "name": "description", "type": "text" },
+ { "name": "publisher", "type": "keyword" },
+ { "name": "rating", "type": "double" },
+ { "name": "title", "type": "text" },
+ { "name": "year", "type": "integer" }
+ ],
+ "values": [
+ [
+ "Stephen King",
+ "The author ...",
+ "Turtleback",
+ 5.0,
+ "How writers write",
+ 2002
+ ],
+ [
+ "Stephen King",
+ "In Blockade Billy, a retired coach...",
+ "Simon and Schuster",
+ 5.0,
+ "Blockade",
+ 2010
+ ],
+ [
+ "Stephen King",
+ "A chilling collection of twenty horror stories.",
+ "Signet Book",
+ 4.55859375,
+ "Night Shift (Signet)",
+ 1979
+ ],
+ ...
+ ]
+}
+```
+
+Using this response, the PHP script (provided <>) produces the following output:
+
+```php
+author : Stephen King
+description : The author ...
+publisher : Turtleback
+rating : 5.0
+title : How writers write
+year : 2002
+---
+author : Stephen King
+description : In Blockade Billy, a retired coach...
+publisher : Simon and Schuster
+rating : 5.0
+title : Blockade
+year : 2010
+---
+author : Stephen King
+description : A chilling collection of twenty horror stories.
+publisher : Signet Book
+rating : 4.55859375
+title : Night Shift (Signet)
+year : 1979
+---
+```
+
+The following example gets ES|QL results as CSV and parses them:
+
+```php
+$result = $client->esql()->query([
+ 'format' => 'csv',
+ 'body' => ['query' => $query]
+]);
+
+var_dump($result->asArray());
+```
+
+The response looks something like this:
+
+```json
+array(12) {
+ [0]=>
+ array(6) {
+ [0]=>
+ string(6) "author"
+ [1]=>
+ string(11) "description"
+ [2]=>
+ string(9) "publisher"
+ [3]=>
+ string(6) "rating"
+ [4]=>
+ string(5) "title"
+ [5]=>
+ string(4) "year"
+ }
+ [1]=>
+ array(6) {
+ [0]=>
+ string(12) "Stephen King"
+ [1]=>
+ string(249) "The author ..."
+ [2]=>
+ string(18) "Turtleback"
+ [3]=>
+ string(3) "5.0"
+ [4]=>
+ string(8) "How writers write"
+ [5]=>
+ string(4) "2002"
+ }
+```
+In the response, the first row contains the column descriptions and the other rows contain
+the values, using a plain PHP array.
+
+
+[discrete]
+[[esql-custom-mapping]]
+==== Define your own mapping
+
+Although the `esql()->query()` API covers many use cases, your application
+might require a custom mapping.
+
+You can map the ES|QL result into an array of objects, using the `mapTo()`
+function. Here's an example:
+
+```php
+$result = $client->esql()->query([
+ 'body' => ['query' => $query]
+]);
+
+$books = $result->mapTo(); // Array of stdClass
+foreach ($books as $book) {
+ printf(
+ "%s, %s, %d, Rating: %.2f\n",
+ $book->author,
+ $book->title,
+ $book->year,
+ $book->rating
+ );
+}
+```
+
+You can also specify a class name for the mapping.
+All the values will be assigned to the properties of the class.
+
+Here's an example mapper that returns an array of `Book` objects:
+
+```php
+class Book
+{
+ public string $author;
+ public string $title;
+ public string $description;
+ public int $year;
+ public float $rating;
+}
+
+$result = $client->esql()->query([
+ 'body' => ['query' => $query]
+]);
+$books = $result->mapTo(Book::class); // Array of Book
+```
\ No newline at end of file
diff --git a/docs/helpers/index.asciidoc b/docs/helpers/index.asciidoc
new file mode 100644
index 000000000..53b06b77c
--- /dev/null
+++ b/docs/helpers/index.asciidoc
@@ -0,0 +1,10 @@
+[[client-helpers]]
+== Client helpers
+
+The PHP client comes with the following helpers:
+
+* <>
+* <>
+
+include::iterators.asciidoc[]
+include::esql.asciidoc[]
\ No newline at end of file
diff --git a/docs/helpers.asciidoc b/docs/helpers/iterators.asciidoc
similarity index 85%
rename from docs/helpers.asciidoc
rename to docs/helpers/iterators.asciidoc
index 3f308e7f9..1af6ee902 100644
--- a/docs/helpers.asciidoc
+++ b/docs/helpers/iterators.asciidoc
@@ -1,24 +1,16 @@
-[[client-helpers]]
-== Client helpers
-
-The client comes with helpers to give you a more comfortable experience with
-some APIs.
-
-
-[discrete]
[[iterators]]
=== Iterators
+The PHP client includes helpers for iterating through results by page or by hits.
-[discrete]
[[search-response-iterator]]
==== Search response iterator
-The `SearchResponseIterator` can be used to iterate page by page in a search
+Use the `SearchResponseIterator` to iterate page by page in a search
result using
https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html#paginate-search-results[pagination].
-An example as follows:
+Here's an example:
[source,php]
----
@@ -50,11 +42,11 @@ foreach($pages as $page) {
[[search-hit-iterator]]
==== Search hit iterator
-The `SearchHitIterator` can be used to iterate in a `SearchResponseIterator`
+Use the `SearchHitIterator` to iterate in a `SearchResponseIterator`
without worrying about
https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html#paginate-search-results[pagination].
-An example as follows:
+Here's an example:
[source,php]
----
@@ -81,4 +73,4 @@ foreach($hits as $hit) {
// e.g. prints the document id
echo $hit['_id'], PHP_EOL;
}
-----
\ No newline at end of file
+----
diff --git a/docs/index.asciidoc b/docs/index.asciidoc
index bc65a2baf..63dbe4551 100644
--- a/docs/index.asciidoc
+++ b/docs/index.asciidoc
@@ -6,6 +6,8 @@
include::{docs-root}/shared/versions/stack/{source_branch}.asciidoc[]
include::{asciidoc-dir}/../../shared/attributes.asciidoc[]
+:es-docs: https://www.elastic.co/guide/en/elasticsearch/reference/{branch}
+
include::overview.asciidoc[]
include::getting-started.asciidoc[]
@@ -20,7 +22,7 @@ include::configuration.asciidoc[]
include::operations.asciidoc[]
-include::helpers.asciidoc[]
+include::helpers/index.asciidoc[]
include::release-notes.asciidoc[]