Developer
Architecture
Ai3 FAQ follows the Ai3 Suite capability pattern provided by wegewerk/ai3_core :
- A Capability class registers the feature under a unique key.
- An Endpoint class implements the ZAK-AI API call.
- A FormEngine element renders the backend widget.
- A backend AJAX controller handles the generation request.
- Bootstrap Package integration provides accordion functionality.
PHP API
ArticlefaqCapability
-
class
ArticlefaqCapability -
- Fully qualified name
-
\Wegewerk\Ai3Faq\ Domain\ Capabilities\ Articlefaq Capability
Extends
Wegewerk\. Registered viaAi3Core\ Domain\ Capabilities\ Capability Configuration/with the following wiring:Services. yaml $key:articlefaq$title:Article FAQ$endpoint:ZakAi Faq - Tagged as
ai3.capability
ZakAiFaq
-
class
ZakAiFaq -
- Fully qualified name
-
\Wegewerk\Ai3Faq\ Api\ Zak Ai Faq
Extends
Wegewerk\(implementingAi3Core\ Api\ Abstract Zak Ai Endpoint Zak). WrapsAi Endpoint Interface Zakto call the ZAK-AIAi Client faqREST endpoint.generate(array $options = [])-
Sends page content to the ZAK-AI API and returns the generated FAQ data as a JSON string containing question-answer pairs.
- param array $options
-
Associative array of options: ``text`` (string, required): The page content text to analyze for FAQ generation.
language(string, optional): Target language for the FAQ (e.g. 'de'). ``min`` (int|null, optional): Minimum number of questions to generate.max(int|null, optional): Maximum number of questions to generate. ``keyword`` (string|null, optional): Focus keyword.previous(mixed, optional): Previous context or suggestions. - returntype
-
string
The response contains a JSON string with an array of objects with
questionandanswerproperties.
ArticlefaqController
-
class
ArticlefaqController -
- Fully qualified name
-
\Wegewerk\Ai3Faq\ Controller\ Ajax\ Articlefaq Controller
Backend AJAX controller (
#), extends[As Controller] Wegewerk\.Ai3Core\ Controller\ Ajax\ Abstract Ajax Controller getFaq(ServerRequestInterface $request)-
Handles the AJAX FAQ generation request.
- Reads
page_andid languagefrom the POST body. - Fetches all page content via
Pages.Repository:: get Page Content () - Calls
Articlefaqendpoint to generate the FAQ.Capability - Parses the JSON response to extract question-answer pairs.
- Returns a JSON response with
faq,Data source, andtype: 'faq'on success, or an error JSON on failure.
- returntype
-
ResponseInterface
- Reads
FormEngine integration
The custom FormEngine node ai3Faq is registered in
TCA configuration:
$GLOBALS['TCA']['tt_content']['columns']['tx_ai3_faq_generator'] = [
'exclude' => true,
'label' => 'LLL:EXT:ai3_faq/Resources/Private/Language/locallang.xlf:tx_ai3.faq.generator',
'config' => [
'type' => 'user',
'renderType' => 'ai3FaqGeneratorElement',
],
];
-
class
Ai3FaqGeneratorElement -
- Fully qualified name
-
\Wegewerk\Ai3Faq\ Form Engine\ Ai3Faq Generator Element
Extends
TYPO3\. Renders aCMS\ Backend\ Form\ Element\ Abstract Form Element <div data-withai3="ai3- faq- container"> data-andpage- id data-attributes. The Lit-HTMLrecord- uid Faqmounts into the innerApp <div data-.ai3="ai3- faq- app">
TCA Configuration
Content element registration
The ai3_ content type is registered in Configuration/:
ExtensionManagementUtility::addTcaSelectItem('tt_content',
'CType',
[
'label' => 'LLL:EXT:ai3_faq/Resources/Private/Language/locallang.xlf:tx_ai3.faq.label_ctype',
'value' => 'ai3_faq',
'icon' => 'ai3-faq-icon',
'description' => 'LLL:EXT:ai3_faq/Resources/Private/Language/locallang.xlf:tx_ai3.faq.label_description',
'group' => 'AI3',
],
'textmedia',
'after',
);
Bootstrap Package integration
The FAQ element inherits accordion functionality from Bootstrap Package:
$GLOBALS['TCA']['tt_content']['types']['ai3_faq'] = $GLOBALS['TCA']['tt_content']['types']['accordion'];
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
'*',
'FILE:EXT:bootstrap_package/Configuration/FlexForms/Accordion.xml',
'ai3_faq'
);
AJAX route
The backend AJAX route is registered in
Configuration/:
| Route name | Path | Handler |
|---|---|---|
ai3_ | /ai3/ | Articlefaq |
Request (POST, JSON body):
{
"page_id": 42,
"language": "de"
}
Response (success):
{
"success": true,
"faqData": [
{
"question": "What is this page about?",
"answer": "This page describes..."
},
{
"question": "How do I use this feature?",
"answer": "To use this feature, you need to..."
}
],
"source": "Page content extracted from...",
"type": "faq"
}
Response (error):
{
"success": false,
"error": "Error message describing what went wrong"
}
JavaScript modules
JavaScript modules are registered via Configuration/
under the @wegewerk/ import map prefix.
- ``@wegewerk/Ai3Faq/ai3api.js`` --
Ai3Apiclass withgeneratethat POSTs to the AJAX route via TYPO3'sFaq (page Id, record Uid, language) Ajax.Request - ``@wegewerk/Ai3Faq/faq.js`` -- Lit-HTML
Faqthat renders the backend widget, handles button clicks, callsApp Ai3Api, displays FAQ preview, and manages the accordion data.
FaqApp Class
.. js:class:: FaqAppThe main JavaScript class that handles the FAQ generation interface.
.. js:method:: generateFaq()Initiates FAQ generation by calling the backend AJAX endpoint. Shows loading state and handles success/error responses.
.. js:method:: previewFaq(generatedFAQ)Displays the generated FAQ in a preview table with questions and answers.
.. js:method:: useFaq()Saves the generated FAQ data to the content element fields and triggers
form submission via Form.
Updates the hidden AI3 core fields with the generated FAQ data:
tx_- Set to 'faq'ai3_ type tx_- Contains the original page contentai3_ source tx_- Contains the JSON-encoded FAQ dataai3_ raw
Services Configuration
The extension's services are configured in Configuration/:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Wegewerk\Ai3Faq\:
resource: '../Classes/*'
Wegewerk\Ai3Faq\Domain\Capabilities\ArticlefaqCapability:
arguments:
$key: 'articlefaq'
$title: 'Article FAQ'
$endpoint: '@Wegewerk\Ai3Faq\Api\ZakAiFaq'
tags:
- { name: 'ai3.capability' }
Event listener
-
class
AfterFormEnginePageInitializedEventListener -
- Fully qualified name
-
\Wegewerk\Ai3Faq\ Event Listener\ After Form Engine Page Initialized Event Listener
Listens to
After(Form Engine Page Initialized Event #). Adds the extension's[As Event Listener] locallang.as an inline language label file to thexlf Page, making all translation keys available to JavaScript.Renderer
Schema.org Integration
The extension automatically generates schema.org markup for FAQ pages when using the brotkrueml/schema extension. This provides structured data for search engines and enables rich snippets.
The schema markup uses the FAQPage type and includes:
- Main entity as
FAQPage - Individual
Questionentities for each FAQ item - Proper
acceptedmarkup for each answerAnswer
Customization and Extension
Adding Language Support
To add support for additional languages, modify the get
method in faq.:
getLanguageOptions() {
return [
{
value: 'de',
label: 'Deutsch'
},
{
value: 'en',
label: 'English'
},
{
value: 'fr',
label: 'Français'
}
];
}
Custom FAQ Processing
To customize FAQ processing, extend the Zak class:
class CustomZakAiFaq extends ZakAiFaq
{
public function generate(array $options = []): string
{
$result = parent::generate($options);
// Custom processing of FAQ data
$faqData = json_decode($result, true);
$processedData = $this->customProcessing($faqData);
return json_encode($processedData);
}
private function customProcessing(array $faqData): array
{
// Your custom logic here
return $faqData;
}
}
Template Customization
Override the Bootstrap Package accordion template to customize FAQ output:
<!-- EXT:your_sitepackage/Resources/Private/Templates/ContentElements/Accordion.html -->
<div class="accordion faq-accordion" id="accordion_{data.uid}">
<f:for each="{accordionItems}" as="item" iteration="iteration">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button faq-question" type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse_{data.uid}_{iteration.cycle}">
{item.question}
</button>
</h2>
<div id="collapse_{data.uid}_{iteration.cycle}"
class="accordion-collapse collapse">
<div class="accordion-body faq-answer">
<f:format.html>{item.answer}</f:format.html>
</div>
</div>
</div>
</f:for>
</div>