From 1e32544a44ca558cba3c21aa32e52ae484b80317 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:38:25 +0200 Subject: [PATCH 01/10] main.py: Add include_code function easier to use than include_file --- main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.py b/main.py index 168977021f..b930e921dd 100644 --- a/main.py +++ b/main.py @@ -52,6 +52,10 @@ def include_file(filename, start_line=0, end_line=None, glue='', remove_indent=F return glue.join(line_range) + @env.macro + def include_code(filename, start_line=1, end_line=None, indent_level=0, remove_indent=False): + return include_file(filename, start_line-1, end_line, ' ' * indent_level, remove_indent).rstrip() + @env.macro def cards(pages, columns=1, style="cards", force_version=False): current_page = env.variables.page From 3f920d133a95eb690f2721190fceb76b05ba5027 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:46:10 +0200 Subject: [PATCH 02/10] include_file VS include_code --- .../recent_activity/recent_activity.md | 24 ++++++ .../rest_api/rest_api_usage/rest_requests.md | 6 ++ docs/search/search_api.md | 81 +++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/docs/administration/recent_activity/recent_activity.md b/docs/administration/recent_activity/recent_activity.md index 0f531270f7..3b3c4544c0 100644 --- a/docs/administration/recent_activity/recent_activity.md +++ b/docs/administration/recent_activity/recent_activity.md @@ -85,6 +85,9 @@ It uses the default `admin` user that has a [permission](#permission-and-securit ```php hl_lines="34-38" [[= include_file('code_samples/recent_activity/src/Command/MonitorRecentContentCreationCommand.php') =]] ``` +```php hl_lines="34-38" +[[= include_code('code_samples/recent_activity/src/Command/MonitorRecentContentCreationCommand.php') =]] +``` ```console % php bin/console app:monitor-content-creation @@ -145,6 +148,9 @@ This event has the information needed by a log entry (see details after the exam ```php [[= include_file('code_samples/recent_activity/src/EventSubscriber/MyFeatureEventSubscriber.php') =]] ``` +```php +[[= include_code('code_samples/recent_activity/src/EventSubscriber/MyFeatureEventSubscriber.php') =]] +``` `ActivityLogService::build()` function returns an `Ibexa\Contracts\ActivityLog\Values\CreateActivityLogStruct` which can then be passed to `ActivityLogService::save`. @@ -192,6 +198,9 @@ In the following example, several actions are logged into one context group, eve ``` php [[= include_file('code_samples/recent_activity/src/Command/ActivityLogContextTestCommand.php', 46, 66, remove_indent=True) =]] ``` +``` php +[[= include_code('code_samples/recent_activity/src/Command/ActivityLogContextTestCommand.php', 47, 66, remove_indent=True) =]] +``` Context groups can't be nested. If a new context is prepared when a context is already grouping log entries, this new context is ignored. @@ -229,12 +238,18 @@ It can be used during development as a fallback for classes that aren't mapped y ``` twig [[= include_file('code_samples/recent_activity/templates/themes/admin/activity_log/ui/default.html.twig') =]] ``` +``` twig +[[= include_code('code_samples/recent_activity/templates/themes/admin/activity_log/ui/default.html.twig') =]] +``` Here is an example of a `ClassNameMapperInterface` associating the class `App\MyFeature\MyFeature` with the identifier `my_feature`: ``` php [[= include_file('code_samples/recent_activity/src/ActivityLog/ClassNameMapper/MyFeatureNameMapper.php') =]] ``` +``` php +[[= include_code('code_samples/recent_activity/src/ActivityLog/ClassNameMapper/MyFeatureNameMapper.php') =]] +``` This mapper also provides a translation for the class name in the **Filters** menu. This translation can be extracted with `php bin/console jms:translation:extract en --domain=ibexa_activity_log --dir=src --output-dir=translations`. @@ -244,12 +259,18 @@ To be taken into account, this mapper must be registered as a service: ``` yaml [[= include_file('code_samples/recent_activity/config/append_to_services.yaml') =]] ``` +``` yaml +[[= include_code('code_samples/recent_activity/config/append_to_services.yaml') =]] +``` Here is an example of a `PostActivityListLoadEvent` subscriber which loads the related object when it's an `App\MyFeature\MyFeature`, and attaches it to the log entry: ``` php [[= include_file('code_samples/recent_activity/src/EventSubscriber/MyFeaturePostActivityListLoadEventSubscriber.php') =]] ``` +``` php +[[= include_code('code_samples/recent_activity/src/EventSubscriber/MyFeaturePostActivityListLoadEventSubscriber.php') =]] +``` The following template is made to display the object of `App\MyFeature\MyFeature` (now identified as `my_feature`) when the action is `simulate`, so, it's named in `templates/themes/admin/activity_log/ui/my_feature/simulate.html.twig`. @@ -258,6 +279,9 @@ Thanks to the previous subscriber, the related object is available at display ti ``` twig [[= include_file('code_samples/recent_activity/templates/themes/admin/activity_log/ui/my_feature/simulate.html.twig') =]] ``` +``` twig +[[= include_code('code_samples/recent_activity/templates/themes/admin/activity_log/ui/my_feature/simulate.html.twig') =]] +``` ## REST API diff --git a/docs/api/rest_api/rest_api_usage/rest_requests.md b/docs/api/rest_api/rest_api_usage/rest_requests.md index 81c3038f1a..ea2e52b6cc 100644 --- a/docs/api/rest_api/rest_api_usage/rest_requests.md +++ b/docs/api/rest_api/rest_api_usage/rest_requests.md @@ -171,12 +171,18 @@ This script: ``` php [[= include_file('code_samples/api/rest_api/create_image.xml.php', 0, None, ' ') =]] ``` + ``` php + [[= include_code('code_samples/api/rest_api/create_image.xml.php', 1, None, 1) =]] + ``` === "JSON" ``` php [[= include_file('code_samples/api/rest_api/create_image.json.php', 0, None, ' ') =]] ``` + ``` php + [[= include_code('code_samples/api/rest_api/create_image.json.php', indent_level=1) =]] + ``` ### Search (`/views`) diff --git a/docs/search/search_api.md b/docs/search/search_api.md index dd0f39a8aa..e5a345da0e 100644 --- a/docs/search/search_api.md +++ b/docs/search/search_api.md @@ -34,6 +34,15 @@ The following command takes the content type identifier as an argument and lists [[= include_file('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 32, 48) =]] [[= include_file('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 48, 49) =]] ``` +``` php hl_lines="14 16" +// ... +[[= include_code('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 5, 7) =]] +// ... +[[= include_code('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 18, 19) =]] + // ... +[[= include_code('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 33, 48) =]] +[[= include_code('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 49, 49) =]] +``` [`SearchService::findContentInfo`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-SearchService.html#method_findContentInfo) (line 16) retrieves [`ContentInfo`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Persistence-Content-ContentInfo.html) objects of the found content items. @@ -124,6 +133,14 @@ For example, the following command lists all content items under the specified p // ... [[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 19, 21) =]][[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 33, 53) =]] ``` +``` php hl_lines="15-18" +// ... +[[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 5, 9) =]] + +// ... +[[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 20, 21) =]] +[[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 34, 53) =]] +``` The same Filter can be applied to find locations instead of content items, for example: @@ -133,6 +150,14 @@ The same Filter can be applied to find locations instead of content items, for e [[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 19, 21) =]]// ... [[= include_file('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 33, 53) =]] ``` +``` php hl_lines="20" +// ... +[[= include_code('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 5, 9) =]] + +[[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 20, 21) =]] +// ... +[[= include_code('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 34, 53) =]] +``` !!! caution @@ -186,6 +211,12 @@ For example, in the code below, `locationId` is provided to list all children of [[= include_file('code_samples/api/public_php_api/src/Controller/CustomController.php', 4, 12) =]] // ... [[= include_file('code_samples/api/public_php_api/src/Controller/CustomController.php', 16, 32) =]] ``` +``` php hl_lines="22-24" +// ... +[[= include_code('code_samples/api/public_php_api/src/Controller/CustomController.php', 5, 12) =]] + // ... +[[= include_code('code_samples/api/public_php_api/src/Controller/CustomController.php', 17, 32) =]] +``` The rendering of results is then relegated to [templates](templates.md) (lines 22-24). @@ -196,6 +227,12 @@ When using Repository filtering, provide the results of `ContentService::find()` [[= include_file('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 4, 12) =]] // ... [[= include_file('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 16, 31) =]] ``` +``` php hl_lines="19" +// ... +[[= include_code('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 5, 12) =]] + // ... +[[= include_code('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 17, 31) =]] +``` ### Paginate search results @@ -206,12 +243,21 @@ To paginate search or filtering results, it's recommended to use the [Pagerfanta [[= include_file('code_samples/api/public_php_api/src/Controller/PaginationController.php', 8, 15) =]] // ... [[= include_file('code_samples/api/public_php_api/src/Controller/PaginationController.php', 19, 39) =]] ``` +``` php +// ... +[[= include_code('code_samples/api/public_php_api/src/Controller/PaginationController.php', 9, 15) =]] + // ... +[[= include_code('code_samples/api/public_php_api/src/Controller/PaginationController.php', 20, 39) =]] +``` Pagination can then be rendered for example using the following template: ``` html+twig [[= include_file('code_samples/api/public_php_api/templates/themes/standard/full/custom_pagination.html.twig') =]] ``` +``` html+twig +[[= include_code('code_samples/api/public_php_api/templates/themes/standard/full/custom_pagination.html.twig') =]] +``` For more information and examples, see [PagerFanta documentation](https://www.babdev.com/open-source/packages/pagerfanta/docs/2.x/usage). @@ -244,6 +290,12 @@ You can do it using logical operators: `LogicalAnd`, `LogicalOr`, and `LogicalNo [[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 44, 49) =]][[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 53, 54) =]] [[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 60, 65) =]] +``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 45, 49) =]] +[[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 54, 54) =]] + +[[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 61, 65) =]] ``` This example takes three parameters from a command — `$text`, `$contentTypeId`, and `$locationId`. @@ -259,6 +311,9 @@ that doesn't belong to the provided Section: ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 46, 54) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 47, 54) =]] +``` ### Combine independent Criteria @@ -292,6 +347,9 @@ For example, to order search results by their publication date, from oldest to n ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 55, 59) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 56, 59) =]] +``` !!! tip @@ -310,6 +368,9 @@ To do this, you use of the query's `$aggregations` property: ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 30, 35) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 31, 35) =]] +``` The name of the aggregation must be unique in the given query. @@ -318,12 +379,18 @@ Access the results by using the `get()` method of the aggregation: ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 39, 40) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 40, 40) =]] +``` Aggregation results contain the name of the result and the count of found items: ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 42, 45) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 43, 45) =]] +``` With field aggregations you can group search results according to the value of a specific field. In this case the aggregation takes the content type identifier and the field identifier as parameters. @@ -333,6 +400,9 @@ The following example creates an aggregation named `selection` that groups resul ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 35, 36) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 36, 36) =]] +``` With term aggregation you can define additional limits to the results. The following example limits the number of terms returned to 5 and only considers terms that have 10 or more results: @@ -340,6 +410,9 @@ The following example limits the number of terms returned to 5 and only consider ``` php [[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 30, 33) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 31, 33) =]] +``` To use a range aggregation, you must provide a `ranges` array containing a set of `Range` objects that define the borders of the specific range sets. @@ -396,6 +469,9 @@ This example shows a minimal embedding query executed directly through the searc ``` php hl_lines="38-39 41-47 49" [[= include_file('code_samples/api/public_php_api/src/Command/FindByTaxonomyEmbeddingCommand.php') =]] ``` +``` php hl_lines="38-39 41-47 49" +[[= include_code('code_samples/api/public_php_api/src/Command/FindByTaxonomyEmbeddingCommand.php') =]] +``` For more information, see [Embeddings reference](embeddings_reference.md). @@ -414,6 +490,11 @@ For a list of supported Criteria and Sort Clauses, see [Search in trash referenc [[= include_file('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 4, 6) =]]//... [[= include_file('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 35, 42) =]] ``` +``` php +[[= include_code('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 5, 6) =]] +//... +[[= include_code('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 36, 42) =]] +``` !!! caution From fee654d97b07177e13ed0cb3ff527bafd9fa3ac3 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:52:55 +0200 Subject: [PATCH 03/10] Remove include_file from converted example --- .../recent_activity/recent_activity.md | 24 ------- .../rest_api/rest_api_usage/rest_requests.md | 6 -- docs/search/search_api.md | 70 ------------------- 3 files changed, 100 deletions(-) diff --git a/docs/administration/recent_activity/recent_activity.md b/docs/administration/recent_activity/recent_activity.md index 3b3c4544c0..aec993b4de 100644 --- a/docs/administration/recent_activity/recent_activity.md +++ b/docs/administration/recent_activity/recent_activity.md @@ -82,9 +82,6 @@ See [Activity Log Search Criteria reference](activity_log_criteria.md) and [Acti In the following example, log groups that contain at least one creation of a Content item are displayed in terminal, with a maximum of 10 groups within the last hour. It uses the default `admin` user that has a [permission](#permission-and-security) to list everyone's entries. -```php hl_lines="34-38" -[[= include_file('code_samples/recent_activity/src/Command/MonitorRecentContentCreationCommand.php') =]] -``` ```php hl_lines="34-38" [[= include_code('code_samples/recent_activity/src/Command/MonitorRecentContentCreationCommand.php') =]] ``` @@ -145,9 +142,6 @@ First, inject `Ibexa\Contracts\ActivityLog\ActivityLogServiceInterface` into you In the following example, an event subscriber is subscribing to an event dispatched by a custom feature. This event has the information needed by a log entry (see details after the example). -```php -[[= include_file('code_samples/recent_activity/src/EventSubscriber/MyFeatureEventSubscriber.php') =]] -``` ```php [[= include_code('code_samples/recent_activity/src/EventSubscriber/MyFeatureEventSubscriber.php') =]] ``` @@ -195,9 +189,6 @@ In the following example, several actions are logged into one context group, eve - `simulate` - `complete` -``` php -[[= include_file('code_samples/recent_activity/src/Command/ActivityLogContextTestCommand.php', 46, 66, remove_indent=True) =]] -``` ``` php [[= include_code('code_samples/recent_activity/src/Command/ActivityLogContextTestCommand.php', 47, 66, remove_indent=True) =]] ``` @@ -235,18 +226,12 @@ Your template can extend `@ibexadesign/activity_log/ui/default.html.twig`, and o First, follow an example of a default template overriding the one from the bundle. It can be used during development as a fallback for classes that aren't mapped yet. -``` twig -[[= include_file('code_samples/recent_activity/templates/themes/admin/activity_log/ui/default.html.twig') =]] -``` ``` twig [[= include_code('code_samples/recent_activity/templates/themes/admin/activity_log/ui/default.html.twig') =]] ``` Here is an example of a `ClassNameMapperInterface` associating the class `App\MyFeature\MyFeature` with the identifier `my_feature`: -``` php -[[= include_file('code_samples/recent_activity/src/ActivityLog/ClassNameMapper/MyFeatureNameMapper.php') =]] -``` ``` php [[= include_code('code_samples/recent_activity/src/ActivityLog/ClassNameMapper/MyFeatureNameMapper.php') =]] ``` @@ -256,18 +241,12 @@ This translation can be extracted with `php bin/console jms:translation:extract To be taken into account, this mapper must be registered as a service: -``` yaml -[[= include_file('code_samples/recent_activity/config/append_to_services.yaml') =]] -``` ``` yaml [[= include_code('code_samples/recent_activity/config/append_to_services.yaml') =]] ``` Here is an example of a `PostActivityListLoadEvent` subscriber which loads the related object when it's an `App\MyFeature\MyFeature`, and attaches it to the log entry: -``` php -[[= include_file('code_samples/recent_activity/src/EventSubscriber/MyFeaturePostActivityListLoadEventSubscriber.php') =]] -``` ``` php [[= include_code('code_samples/recent_activity/src/EventSubscriber/MyFeaturePostActivityListLoadEventSubscriber.php') =]] ``` @@ -276,9 +255,6 @@ The following template is made to display the object of `App\MyFeature\MyFeature so, it's named in `templates/themes/admin/activity_log/ui/my_feature/simulate.html.twig`. Thanks to the previous subscriber, the related object is available at display time: -``` twig -[[= include_file('code_samples/recent_activity/templates/themes/admin/activity_log/ui/my_feature/simulate.html.twig') =]] -``` ``` twig [[= include_code('code_samples/recent_activity/templates/themes/admin/activity_log/ui/my_feature/simulate.html.twig') =]] ``` diff --git a/docs/api/rest_api/rest_api_usage/rest_requests.md b/docs/api/rest_api/rest_api_usage/rest_requests.md index ea2e52b6cc..0fe823b589 100644 --- a/docs/api/rest_api/rest_api_usage/rest_requests.md +++ b/docs/api/rest_api/rest_api_usage/rest_requests.md @@ -168,18 +168,12 @@ This script: === "XML" - ``` php - [[= include_file('code_samples/api/rest_api/create_image.xml.php', 0, None, ' ') =]] - ``` ``` php [[= include_code('code_samples/api/rest_api/create_image.xml.php', 1, None, 1) =]] ``` === "JSON" - ``` php - [[= include_file('code_samples/api/rest_api/create_image.json.php', 0, None, ' ') =]] - ``` ``` php [[= include_code('code_samples/api/rest_api/create_image.json.php', indent_level=1) =]] ``` diff --git a/docs/search/search_api.md b/docs/search/search_api.md index e5a345da0e..262a01214b 100644 --- a/docs/search/search_api.md +++ b/docs/search/search_api.md @@ -27,13 +27,6 @@ For example, to search for all content of a selected content type, use one Crite The following command takes the content type identifier as an argument and lists all results: -``` php hl_lines="14 16" -// ... -[[= include_file('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 4, 7) =]]// ... -[[= include_file('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 17, 19) =]] // ... -[[= include_file('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 32, 48) =]] -[[= include_file('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 48, 49) =]] -``` ``` php hl_lines="14 16" // ... [[= include_code('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 5, 7) =]] @@ -127,12 +120,6 @@ It doesn't use the `SearchService` and isn't based on indexed data. For example, the following command lists all content items under the specified parent location and sorts them by name in descending order: -``` php hl_lines="15-18" -// ... -[[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 4, 9) =]] -// ... -[[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 19, 21) =]][[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 33, 53) =]] -``` ``` php hl_lines="15-18" // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 5, 9) =]] @@ -144,12 +131,6 @@ For example, the following command lists all content items under the specified p The same Filter can be applied to find locations instead of content items, for example: -``` php hl_lines="20" -// ... -[[= include_file('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 4, 9) =]] -[[= include_file('code_samples/api/public_php_api/src/Command/FilterCommand.php', 19, 21) =]]// ... -[[= include_file('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 33, 53) =]] -``` ``` php hl_lines="20" // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 5, 9) =]] @@ -206,11 +187,6 @@ $filter You can use the `SearchService` or repository filtering in a controller, as long as you provide the required parameters. For example, in the code below, `locationId` is provided to list all children of a location by using the `SearchService`. -``` php hl_lines="22-24" -// ... -[[= include_file('code_samples/api/public_php_api/src/Controller/CustomController.php', 4, 12) =]] // ... -[[= include_file('code_samples/api/public_php_api/src/Controller/CustomController.php', 16, 32) =]] -``` ``` php hl_lines="22-24" // ... [[= include_code('code_samples/api/public_php_api/src/Controller/CustomController.php', 5, 12) =]] @@ -222,11 +198,6 @@ The rendering of results is then relegated to [templates](templates.md) (lines 2 When using Repository filtering, provide the results of `ContentService::find()` as parameters to the view: -``` php hl_lines="19" -// ... -[[= include_file('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 4, 12) =]] // ... -[[= include_file('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 16, 31) =]] -``` ``` php hl_lines="19" // ... [[= include_code('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 5, 12) =]] @@ -238,11 +209,6 @@ When using Repository filtering, provide the results of `ContentService::find()` To paginate search or filtering results, it's recommended to use the [Pagerfanta library](https://github.com/BabDev/Pagerfanta) and [[[= product_name =]]'s adapters for it.](https://github.com/ibexa/core/blob/main/src/lib/Pagination/Pagerfanta/Pagerfanta.php) -``` php -// ... -[[= include_file('code_samples/api/public_php_api/src/Controller/PaginationController.php', 8, 15) =]] // ... -[[= include_file('code_samples/api/public_php_api/src/Controller/PaginationController.php', 19, 39) =]] -``` ``` php // ... [[= include_code('code_samples/api/public_php_api/src/Controller/PaginationController.php', 9, 15) =]] @@ -252,9 +218,6 @@ To paginate search or filtering results, it's recommended to use the [Pagerfanta Pagination can then be rendered for example using the following template: -``` html+twig -[[= include_file('code_samples/api/public_php_api/templates/themes/standard/full/custom_pagination.html.twig') =]] -``` ``` html+twig [[= include_code('code_samples/api/public_php_api/templates/themes/standard/full/custom_pagination.html.twig') =]] ``` @@ -286,11 +249,6 @@ For more information and examples, see [PagerFanta documentation](https://www.ba For more complex searches, you need to combine multiple Criteria. You can do it using logical operators: `LogicalAnd`, `LogicalOr`, and `LogicalNot`. -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 44, 49) =]][[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 53, 54) =]] -[[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 60, 65) =]] - -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 45, 49) =]] [[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 54, 54) =]] @@ -308,9 +266,6 @@ You can also nest different operators to construct more complex queries. The example below uses the `LogicalNot` operator to search for all content containing a given phrase that doesn't belong to the provided Section: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 46, 54) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 47, 54) =]] ``` @@ -344,9 +299,6 @@ To sort the results of a query, use one of more [Sort Clauses](sort_clause_refer For example, to order search results by their publication date, from oldest to newest, and then alphabetically by content name, add the following Sort Clauses to the query: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 55, 59) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindComplexCommand.php', 56, 59) =]] ``` @@ -365,9 +317,6 @@ With aggregations you can find the count of search results or other result infor To do this, you use of the query's `$aggregations` property: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 30, 35) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 31, 35) =]] ``` @@ -376,18 +325,12 @@ The name of the aggregation must be unique in the given query. Access the results by using the `get()` method of the aggregation: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 39, 40) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 40, 40) =]] ``` Aggregation results contain the name of the result and the count of found items: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 42, 45) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 43, 45) =]] ``` @@ -397,9 +340,6 @@ In this case the aggregation takes the content type identifier and the field ide The following example creates an aggregation named `selection` that groups results according to the value of the `topic` field in the `article` content type: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 35, 36) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 36, 36) =]] ``` @@ -407,9 +347,6 @@ The following example creates an aggregation named `selection` that groups resul With term aggregation you can define additional limits to the results. The following example limits the number of terms returned to 5 and only considers terms that have 10 or more results: -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 30, 33) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindWithAggregationCommand.php', 31, 33) =]] ``` @@ -466,9 +403,6 @@ You build an `EmbeddingQuery` instance by using a builder and pass it to the sea This example shows a minimal embedding query executed directly through the search service: -``` php hl_lines="38-39 41-47 49" -[[= include_file('code_samples/api/public_php_api/src/Command/FindByTaxonomyEmbeddingCommand.php') =]] -``` ``` php hl_lines="38-39 41-47 49" [[= include_code('code_samples/api/public_php_api/src/Command/FindByTaxonomyEmbeddingCommand.php') =]] ``` @@ -486,10 +420,6 @@ For a list of supported Criteria and Sort Clauses, see [Search in trash referenc Searching through the trashed content items operates directly on the database, therefore you cannot use external search engines, such as Solr or Elasticsearch, and it's impossible to reindex the data. -``` php -[[= include_file('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 4, 6) =]]//... -[[= include_file('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 35, 42) =]] -``` ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 5, 6) =]] //... From 3fa8a8a3c69737c00a31565049a2f6b8950e0563 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:07:21 +0200 Subject: [PATCH 04/10] image_twig_functions.md: include_code --- docs/templating/twig_function_reference/image_twig_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templating/twig_function_reference/image_twig_functions.md b/docs/templating/twig_function_reference/image_twig_functions.md index 32bb7e9c49..f7eb49c639 100644 --- a/docs/templating/twig_function_reference/image_twig_functions.md +++ b/docs/templating/twig_function_reference/image_twig_functions.md @@ -13,7 +13,7 @@ page_type: reference To render images, use the [`ibexa_render_field()`](field_twig_functions.md#ibexa_render_field) Twig function with the variation name passed as an argument, for example: ``` html+twig -[[= include_file('docs/templating/twig_function_reference/field_twig_functions.md', 40, 48) =]] +[[= include_code('docs/templating/twig_function_reference/field_twig_functions.md', 42, 48) =]] ``` ## Image information From 8d54540003f13595ee254c44f7a33c1f235e4330 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 16:03:26 +0200 Subject: [PATCH 05/10] code_samples_usage.php: Update for include_code --- tools/code_samples/code_samples_usage.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tools/code_samples/code_samples_usage.php b/tools/code_samples/code_samples_usage.php index 2d7716d4a0..a90b365fc2 100644 --- a/tools/code_samples/code_samples_usage.php +++ b/tools/code_samples/code_samples_usage.php @@ -35,7 +35,7 @@ function displayBlocks(array $docFileBlocks, ?string $docFilePath = null, $lineO try { $blockContents = getBlockContents($block); foreach ($blockContents['contents'] as $contentLineNumber => $contentLine) { - $prefixedBlockContentLines[] = str_pad($contentLineNumber, 3, 0, STR_PAD_LEFT) . (in_array($contentLineNumber, $blockContents['highlights']) ? '❇️' : '⫶') . $contentLine; + $prefixedBlockContentLines[] = str_pad($contentLineNumber, 3, '0', STR_PAD_LEFT) . (in_array($contentLineNumber, $blockContents['highlights']) ? '❇️' : '⫶') . $contentLine; } echo implode(PHP_EOL, $prefixedBlockContentLines) . PHP_EOL . PHP_EOL; } catch (Exception $exception) { @@ -55,9 +55,9 @@ function displayBlocks(array $docFileBlocks, ?string $docFilePath = null, $lineO */ function getIncludingFileList(?string $codeSampleFilePath = null): array { - $pattern = null === $codeSampleFilePath ? '= include_file' : $codeSampleFilePath; + $pattern = null === $codeSampleFilePath ? '= (include_file|include_code)' : $codeSampleFilePath; $pattern = escapeshellarg($pattern); - $command = "grep $pattern -Rl docs | sort"; + $command = "grep -E $pattern -Rl docs | sort"; exec($command, $rawIncludingFileList, $commandResultCode); if (0 === $commandResultCode) { return $rawIncludingFileList; @@ -73,7 +73,7 @@ function getIncludingFileList(?string $codeSampleFilePath = null): array */ function getInclusionBlocks(string $docFilePath, ?string $codeSampleFilePath = null): array { - $pattern = null === $codeSampleFilePath ? '= include_file' : $codeSampleFilePath; + $pattern = null === $codeSampleFilePath ? '@= (include_file|include_code)@' : "@$codeSampleFilePath@"; $docFileLines = file($docFilePath, FILE_IGNORE_NEW_LINES); if (!$docFileLines) { @@ -87,7 +87,7 @@ function getInclusionBlocks(string $docFilePath, ?string $codeSampleFilePath = n if ($includingFileLineIndex <= $blockEndingLineIndex + 1) { continue; } - if (str_contains($includingFileLine, $pattern)) { + if (preg_match($pattern, $includingFileLine)) { for ($blockStartingLineIndex = $includingFileLineIndex - 1; 0 <= $blockStartingLineIndex; $blockStartingLineIndex--) { $previousLine = $docFileLines[$blockStartingLineIndex]; if (str_contains($previousLine, '```')) { @@ -147,8 +147,8 @@ function getBlockContents(array $block): array $blockHighlightedLines[] = (int)$rawHighlightedLine; } } - } elseif (str_contains($blockSourceLine, '[[= include_file')) { - preg_match_all("@\[\[= include_file\('(?[^']+)'(, (?[0-9]+)(, (?([0-9]+|None))(, '(?[^']+)')?)?)?\) =\]\]@", $blockSourceLine, $matches); + } elseif (str_contains($blockSourceLine, '[[= include_file') || str_contains($blockSourceLine, '[[= include_code')) { + preg_match_all("@\[\[= (?include_file|include_code)\('(?[^']+)'(, (?[0-9]+)(, (?([0-9]+|None))(, '(?[^']+)')?)?)?\) =\]\]@", $blockSourceLine, $matches); $solvedLine = $blockSourceLine; if (empty($matches['file'])) { throw new RuntimeException("The following line doesn't include file correctly: $blockSourceLine"); @@ -167,9 +167,15 @@ function getBlockContents(array $block): array if ('' === $matches['start'][$matchIndex]) { $sample = $includedFilesLines[$includedFilePath]; } else { + if ('include_code' === $matches['function'][$matchIndex]) { + $matches['start'][$matchIndex] = (int)$matches['start'][$matchIndex] -1; + } $sample = array_slice($includedFilesLines[$includedFilePath], (int)$matches['start'][$matchIndex], (int)$matches['end'][$matchIndex] - (int)$matches['start'][$matchIndex]); } - $solvedLine = str_replace($matchString, implode(PHP_EOL . $matches['glue'][$matchIndex], $sample) . PHP_EOL, $solvedLine); + if ('include_code' === $matches['function'][$matchIndex] && !empty($matches['glue'][$matchIndex])) { + $matches['glue'][$matchIndex] = str_repeat(' ', $matches['glue'][$matchIndex]); + } + $solvedLine = str_replace($matchString, implode(PHP_EOL . $matches['glue'][$matchIndex], $sample) . ('include_code' === $matches['function'][$matchIndex] ? '' : PHP_EOL), $solvedLine); } $rawBlockCodeLines = array_merge($rawBlockCodeLines, explode(PHP_EOL, $solvedLine)); } elseif (str_contains($blockSourceLine, '--8<--')) { From 934ddc415e5586c1472121ed1efe7cbc9a6e29b9 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 16:12:50 +0200 Subject: [PATCH 06/10] search_api.md: Rearrange ellipsis for code_samples_usage.php test --- docs/search/search_api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/search/search_api.md b/docs/search/search_api.md index 262a01214b..f41061d603 100644 --- a/docs/search/search_api.md +++ b/docs/search/search_api.md @@ -124,8 +124,8 @@ For example, the following command lists all content items under the specified p // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 5, 9) =]] -// ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 20, 21) =]] + // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 34, 53) =]] ``` @@ -136,7 +136,7 @@ The same Filter can be applied to find locations instead of content items, for e [[= include_code('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 5, 9) =]] [[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 20, 21) =]] -// ... + // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 34, 53) =]] ``` @@ -423,7 +423,7 @@ For a list of supported Criteria and Sort Clauses, see [Search in trash referenc ``` php [[= include_code('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 5, 6) =]] //... -[[= include_code('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 36, 42) =]] +[[= include_code('code_samples/api/public_php_api/src/Command/FindInTrashCommand.php', 36, 42, remove_indent=True) =]] ``` !!! caution From 980e3a6cd2fe595bb5a4df5c1b2447c106cab883 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 16:59:42 +0200 Subject: [PATCH 07/10] code_samples_usage.php: handle named parameters --- tools/code_samples/code_samples_usage.php | 25 +++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tools/code_samples/code_samples_usage.php b/tools/code_samples/code_samples_usage.php index a90b365fc2..f7e31417a9 100644 --- a/tools/code_samples/code_samples_usage.php +++ b/tools/code_samples/code_samples_usage.php @@ -148,7 +148,7 @@ function getBlockContents(array $block): array } } } elseif (str_contains($blockSourceLine, '[[= include_file') || str_contains($blockSourceLine, '[[= include_code')) { - preg_match_all("@\[\[= (?include_file|include_code)\('(?[^']+)'(, (?[0-9]+)(, (?([0-9]+|None))(, '(?[^']+)')?)?)?\) =\]\]@", $blockSourceLine, $matches); + preg_match_all("@\[\[= (?include_file|include_code)\('(?[^']+)'(, (?[^,\)]+)(, (?([^,\)]+))(, (?[^,\)]+)(, (?[^,\)]+))?)?)?)?\) =\]\]@", $blockSourceLine, $matches); $solvedLine = $blockSourceLine; if (empty($matches['file'])) { throw new RuntimeException("The following line doesn't include file correctly: $blockSourceLine"); @@ -161,6 +161,23 @@ function getBlockContents(array $block): array throw new RuntimeException("The following included file can't be opened: $includedFilePath"); } } + + // Named argument mapping + foreach(['start', 'end', 'indent_level', 'remove_indent'] as $key) { + if (str_starts_with($matches[$key][$matchIndex], 'glue=')) { + $matches['indent_level'][$matchIndex] = str_replace('glue=', '', $matches[$key][$matchIndex]); + $matches[$key][$matchIndex] = ''; + } + elseif (str_starts_with($matches[$key][$matchIndex], 'indent_level=')) { + $matches['indent_level'][$matchIndex] = str_replace('indent_level=', '', $matches[$key][$matchIndex]); + $matches[$key][$matchIndex] = ''; + } + elseif (str_starts_with($matches[$key][$matchIndex], 'remove_indent=')) { + $matches['remove_indent'][$matchIndex] = str_replace('remove_indent=', '', $matches[$key][$matchIndex]); + $matches[$key][$matchIndex] = ''; + } + } + if ('None' === $matches['end'][$matchIndex]) { $matches['end'][$matchIndex] = count($includedFilesLines[$includedFilePath]); } @@ -172,10 +189,10 @@ function getBlockContents(array $block): array } $sample = array_slice($includedFilesLines[$includedFilePath], (int)$matches['start'][$matchIndex], (int)$matches['end'][$matchIndex] - (int)$matches['start'][$matchIndex]); } - if ('include_code' === $matches['function'][$matchIndex] && !empty($matches['glue'][$matchIndex])) { - $matches['glue'][$matchIndex] = str_repeat(' ', $matches['glue'][$matchIndex]); + if ('include_code' === $matches['function'][$matchIndex] && !empty($matches['indent_level'][$matchIndex])) { + $matches['indent_level'][$matchIndex] = str_repeat(' ', $matches['indent_level'][$matchIndex]); } - $solvedLine = str_replace($matchString, implode(PHP_EOL . $matches['glue'][$matchIndex], $sample) . ('include_code' === $matches['function'][$matchIndex] ? '' : PHP_EOL), $solvedLine); + $solvedLine = str_replace($matchString, implode(PHP_EOL . $matches['indent_level'][$matchIndex], $sample) . ('include_code' === $matches['function'][$matchIndex] ? '' : PHP_EOL), $solvedLine); } $rawBlockCodeLines = array_merge($rawBlockCodeLines, explode(PHP_EOL, $solvedLine)); } elseif (str_contains($blockSourceLine, '--8<--')) { From e16019ad2989a2460e40d43cc44eb9d7d129484c Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 17:48:20 +0200 Subject: [PATCH 08/10] code_samples_usage.php: handle remove_indent --- tools/code_samples/code_samples_usage.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/code_samples/code_samples_usage.php b/tools/code_samples/code_samples_usage.php index f7e31417a9..10d8601a83 100644 --- a/tools/code_samples/code_samples_usage.php +++ b/tools/code_samples/code_samples_usage.php @@ -192,6 +192,19 @@ function getBlockContents(array $block): array if ('include_code' === $matches['function'][$matchIndex] && !empty($matches['indent_level'][$matchIndex])) { $matches['indent_level'][$matchIndex] = str_repeat(' ', $matches['indent_level'][$matchIndex]); } + if ('True' === $matches['remove_indent'][$matchIndex]) { + $removable = null; + foreach ($sample as $line) { + if ('' !== $line) { + $removable = min($removable ?? strlen($line), strlen($line) - strlen(ltrim($line))); + } + } + if ($removable) { + foreach ($sample as $n => $line) { + $sample[$n] = substr($line, $removable); + } + } + } $solvedLine = str_replace($matchString, implode(PHP_EOL . $matches['indent_level'][$matchIndex], $sample) . ('include_code' === $matches['function'][$matchIndex] ? '' : PHP_EOL), $solvedLine); } $rawBlockCodeLines = array_merge($rawBlockCodeLines, explode(PHP_EOL, $solvedLine)); From bdad3cd269c2afda8d24808a252cff01c6a344e5 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:38:28 +0200 Subject: [PATCH 09/10] code_samples_usage.php: remove quotes around `glue` value --- tools/code_samples/code_samples_usage.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/code_samples/code_samples_usage.php b/tools/code_samples/code_samples_usage.php index 10d8601a83..c0813f00f0 100644 --- a/tools/code_samples/code_samples_usage.php +++ b/tools/code_samples/code_samples_usage.php @@ -189,8 +189,12 @@ function getBlockContents(array $block): array } $sample = array_slice($includedFilesLines[$includedFilePath], (int)$matches['start'][$matchIndex], (int)$matches['end'][$matchIndex] - (int)$matches['start'][$matchIndex]); } - if ('include_code' === $matches['function'][$matchIndex] && !empty($matches['indent_level'][$matchIndex])) { - $matches['indent_level'][$matchIndex] = str_repeat(' ', $matches['indent_level'][$matchIndex]); + if (!empty($matches['indent_level'][$matchIndex])) { + if ('include_code' === $matches['function'][$matchIndex]) { + $matches['indent_level'][$matchIndex] = str_repeat(' ', $matches['indent_level'][$matchIndex]); + } elseif ('include_file' === $matches['function'][$matchIndex]) { + $matches['indent_level'][$matchIndex] = trim($matches['indent_level'][$matchIndex], '"\''); + } } if ('True' === $matches['remove_indent'][$matchIndex]) { $removable = null; From a9391ca40c63773f1ab448c9811a58e25f116b4d Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Wed, 29 Apr 2026 10:40:00 +0200 Subject: [PATCH 10/10] main.py: Docstrings --- main.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index b930e921dd..3c38638782 100644 --- a/main.py +++ b/main.py @@ -32,6 +32,7 @@ def define_env(env): @env.macro def include_file(filename, start_line=0, end_line=None, glue='', remove_indent=False): """ + DEPRECATED: Use include_code instead. Include a file, optionally indicating start_line and end_line (start counting from 0) optionally set a glue string to lead every string except the first one (can be used for indent) @@ -53,8 +54,16 @@ def include_file(filename, start_line=0, end_line=None, glue='', remove_indent=F return glue.join(line_range) @env.macro - def include_code(filename, start_line=1, end_line=None, indent_level=0, remove_indent=False): - return include_file(filename, start_line-1, end_line, ' ' * indent_level, remove_indent).rstrip() + def include_code(file_path, start_line=1, end_line=None, indent_level=0, remove_indent=False): + """ + Include a file + file_path (string): The path to the file from project root + start_line (int): The line number to start including from (start counting from 1) - default is 1 (include first line) + end_line (int or None): The line number to end including to. If None, include until the end of the file - default is None (include end of file) + indent_level (int): The number of indent (4 spaces) to add to the beginning of each line - default is 0 (no indent added). + remove_indent (bool): Whether to remove absolute indent, the maximum of leading whitespaces without breaking relative indent - default is False (no indent removed) + """ + return include_file(file_path, start_line-1, end_line, ' ' * indent_level, remove_indent).rstrip() @env.macro def cards(pages, columns=1, style="cards", force_version=False):