I have TYPO3 11.
I created a Page Title Provider
<?php
declare(strict_types=1);
namespace Myvendor\modellobando\Seo;
use TYPO3\CMS\Core\PageTitle\AbstractPageTitleProvider;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class BandoTitleProvider extends AbstractPageTitleProvider
{
private const DEFAULT_PROPERTIES = 'title';
private const DEFAULT_GLUE = '" "';
public function setTitle(string $title): void
{
$this->title = "ecco ".$title;
}
}
I defined it in template.setup
config.pageTitleProviders {
record {
provider = Goproject\modellobando\Seo\BandoTitleProvider
}
}
It works with meta tag title but the data of the page is not changed, I have to set the tag h1 in html in my layout, how can I do that?
updated question:
As I wrote in comment I tried a query to get info about my model but I don't know how avoid SQL injection using query string parameter (GET) like uid=12
page.10 {
dataProcessing {
1001 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
1001 {
table=mytable
pidInList = 16
markers.uid.field = uid
as = datainfobando
where = (uid = ???)
}
}
}
Using a h1 tag means you are in the body of the HTML document. That content does not have an automated content.
But you can insert it in your page template. If you want it set everywhere you can use the page layout template. You only have to provide the information to your FLUID page template, which can be done easily in typoscript.
Avoiding SQL-injection within a select can be done with using markers and securing them.
Eg. reducing them to integer values.
1001 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
1001 {
table=mytable
pidInList = 16
where = {#uid} = ###recordId###
as = datainfobando
markers {
recordId.data = GP:myId
recordId.intval = 1
}
}
Related
I have a sysfolder with records which get displayed in the frontend via a custom content element.
Now I have the problem that the frontend is not updated when a new record is added or an existing record is changed.
To clear the cache I'm using a hook in ext_localconf.php:
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']['foobar'] =
\Vendor\Name\Hooks\DataHandler::class . '->clearCachePostProc';
The hook looks like this:
<?php
namespace Vendor\Name\Hooks;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class DataHandler implements SingletonInterface
{
public function clearCachePostProc(array $params): void
{
if (isset($params['table']) && $params['table'] === 'tx_foo_domain_model_bar') {
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
$cacheManager->flushCachesByTag('1642782027');
}
}
}
And the content element is implemented with FLUIDTEMPLATE and a dataprocessor:
tt_content {
foo_bar =< lib.contentElement
foo_bar {
templateName = myTemplate
stdWrap.cache {
key = tx_foo_domain_model_bar
tags = 1642782027
lifetime = default
}
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
10 {
table = tx_foo_domain_model_bar
pidInList = {$foo.storage_pid}
as = foobar
}
}
}
}
Everything seems to work but when I hit Cmd+R/Ctrl+R and reload the page or visit it again via the navigation, the page is not updated with the latest content.
I implemented the following solution.
Within the Typoscript Setup add a addPageCacheTag to your custom content element:
tt_content {
foo_bar =< lib.contentElement
foo_bar {
templateName = FooBar
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
10 {
table = tx_foo_domain_model_bar
pidInList = {$foo.storage_pid}
as = foobar
}
}
stdWrap.addPageCacheTags = foo_bar
}
}
Add the clearCacheCmd to the Page TSConfig from the storage page like:
TCEMAIN.clearCacheCmd = cacheTag:foo_bar
For testing, add this to your Fluid-Template and be sure to test with a separate browser (without BE login):
<div style="color: red;"><f:format.date format="d.m.Y - H:i:s">now</f:format.date></div>
Kudos to https://daniel-siepmann.de/posts/2019/typo3-content-caching.html
You could use the EXT:Fluid Page Cache
https://extensions.typo3.org/extension/fluid_page_cache
This EXT does all the things you need automatically.
I would like to load a plugin dynamically according to some data. First I tried to do it with Typoscript, but after some research I figured out, that it is not possible to change the settings of the plugin (see old forum entry).
I need to change settings.simplepoll.uid according to the passed data:
This is the Typoscript I tried:
lib.loadSimplepoll = USER
lib.loadSimplepoll {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = Simplepoll
pluginName = Polllisting
vendorName = Pixelink
switchableControllerActions {
SimplePoll {
1 = list
}
}
settings < plugin.tx_simplepoll.settings
settings {
simplepoll {
uid.current = 1
}
}
}
The call in the template looks like that:
<f:cObject typoscriptObjectPath="lib.loadSimplepoll">{newsItem.simplepoll}</f:cObject>
After figuring out, that changing the settings is not possible, I tried a viewhelper:
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class LoadSimplepollViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
* #param int $uid Uid of poll
* #return string
*/
public function render($uid) {
$cObj = GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$configurationManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManager');
$simplepollTs = $configurationManager->getConfiguration(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'simplepoll',
'Polllisting'
);
$ttContentConfig = array(
'tables' => 'tt_content',
'source' => 1030,
'dontCheckPid' => 1
);
// returning this works perfectly!
// but I need to change the "settings.simplepoll.uid"
$data = $cObj->RECORDS($ttContentConfig);
$cObj->start($data, 'tx_simplepoll_domain_model_simplepoll');
$renderObjName = '<tt_content.list.20.simplepoll_polllisting';
$renderObjConf = $GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']['simplepoll_polllisting.'];
$renderObjConf['persistence']['storagePid'] = 394; // This does not work!
$renderObjConf['settings'] = $simplepollTs;
$renderObjConf['settings']['simplepoll']['uid'] = $uid;
return $cObj->cObjGetSingle($renderObjName, $renderObjConf);
}
}
The viehelper is called like this:
{vh:LoadSimplepoll(uid: '{newsItem.simplepoll}')}
Now I am able to change the uid of the poll with this line:
$renderObjConf['settings']['simplepoll']['uid'] = $uid;
My problem is now, that it loads the poll, but not the answers. I tracked this down to the fact, that the plugin somehow does not know the Record Storage Page anymore. The line $renderObjConf['persistence']['storagePid'] = 394; does not help.
How can I tell the plugin the Storage Pid?
Or is there another/better way to load a plugin with changing data?
Why shouldn't it be possible to modify settings.simplepoll.uid in typoscript?
because the extension simplepoll does not handle any stdWrap functionality to its typoscript settings.
Have a look into the code:
this special setting is used here:
$simplePoll = $this->simplePollRepository->findByUid($this->settings['simplepoll']['uid']);
no stdWrap, just plain usage.
compare it to ext:news:
before any settings is used it is processed. A dedicated join of typoscript settings with the settings in the plugin. And if necessary there is a stdWrap possible: here
$this->originalSettings = $originalSettings;
// Use stdWrap for given defined settings
if (isset($originalSettings['useStdWrap']) && !empty($originalSettings['useStdWrap'])) {
$typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
$typoScriptArray = $typoScriptService->convertPlainArrayToTypoScriptArray($originalSettings);
$stdWrapProperties = GeneralUtility::trimExplode(',', $originalSettings['useStdWrap'], true);
foreach ($stdWrapProperties as $key) {
if (is_array($typoScriptArray[$key . '.'])) {
$originalSettings[$key] = $this->configurationManager->getContentObject()->stdWrap(
$typoScriptArray[$key],
$typoScriptArray[$key . '.']
);
}
}
}
As you can see:
extbase does not support you with typoscript stdWrap functionality.
You (and every extension author) need to do it by hand. But that was so even before extbase.
In this way: as you can not configure your value you only can trick TYPO3 (and the plugin):
if you have a small number of uids you can have one variant for each uid
lib.loadSimplepoll123 < lib.loadSimplepoll
lib.loadSimplepoll123.settings.simplepoll.uid = 123
lib.loadSimplepoll234 < lib.loadSimplepoll
lib.loadSimplepoll234.settings.simplepoll.uid = 234
lib.loadSimplepoll345 < lib.loadSimplepoll
lib.loadSimplepoll345.settings.simplepoll.uid = 345
lib.loadSimplepoll456 < lib.loadSimplepoll
lib.loadSimplepoll456.settings.simplepoll.uid = 456
and call it like
<f:cObject typoscriptObjectPath="lib.loadSimplepoll{newsItem.simplepoll}" />
or you build a pull request implementing the stdWrap functionality and send it to the extension author.
Why shouldn't it be possible to modify settings.simplepoll.uid in typoscript?
you just need the correct construction to modify it.
For a single value you can use current, but use it properly. It is a stdWrap function which needs to be evaluated.
If there is no stdWrap evaluation by default it might work with a cObject of type TEXT
settings.simplepoll.uid.cObject = TEXT
settings.simplepoll.uid.cObject.current = 1
or to indicate a stdWrap you need to use stdWrap literally:
settings.simplepoll.uid.stdWrap.current = 1
another variant of data transfer are named parameters. Just build an associative array as data parameter and access the values individual:
fluid:
<f:cObject typoscriptObjectPath="lib.arraytest" data="{a:'abc',b:'xyz'}" >
inside text
</f:cObject>
and the typoscript:
lib.arraytest = COA
lib.arraytest {
10 = TEXT
10.field = a
10.wrap = /|/
20 = TEXT
20.field = b
20.wrap = \|\
}
which results in an output of /abc/\xyz\. Be aware: the inner text of the f:cobject tag will be lost as the data parameter has priority about inner children.
In the meantime I got the Viewhelpter to work:
Viewhelper:
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class LoadSimplepollViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
* #return void
*/
public function initializeArguments()
{
parent::initializeArguments();
$this->registerArgument('simplepollUid', 'int', 'Uid of simplepoll', false);
}
/**
* #return string
*/
public function render()
{
$configurationManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManager');
$simplepollTs = $configurationManager->getConfiguration(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'simplepoll',
'Polllisting');
$cObj = GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$renderObjName = '<tt_content.list.20.simplepoll_polllisting';
$renderObjConf = $GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']['simplepoll_polllisting.'];
$renderObjConf['settings'] = $simplepollTs;
$renderObjConf['settings']['simplepoll']['uid'] = (int)$this->arguments['simplepollUid'];
return $cObj->cObjGetSingle($renderObjName, $renderObjConf);
}
}
Call the viewhelper in the template (don't forget to register the namespace):
{vh:LoadSimplepoll(simplepollUid: '{newsItem.ipgSimplepoll}')}
That's it.
I'm trying to extend the fluid_styled_content element "Menu". Within my partial (e.g. typo3conf/ext/my_theme/Resources/Private/Templates/Content/Partials/Menu/Type-1.html I need to access the page properties of the page where the menu CE resides. How can I archive this? {data} contains only the data of the content element.
In {data.pid} you have the uid of the page.
You can use a viewhelper to get the complete pages record (in ext:vhs there is a viewhelper to get any kind of records).
or you can use <f:cObject> and some typoscript to access single values.
Use \TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor.
I cannot check the code right now but you could take this as a starting point:
tt_content.menu.dataProcessing {
30 = \TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
30 {
table = pages
where.dataWrap = uid = {TSFE:id}
as = page
}
}
Afterwards you can access the current page‘s properties via {page.0.property}.
There‘s just one query for each menu content object with this approach while most view helper solutions tend to increase the number of database queries issued.
#undko: The DatabaseQueryProcessor was the perfect hint. But your snippet had two problems I had to fix:
- the TypoScript code needs pidInList to work
- in the Fluid Template there was data missing: pageproperties.0.data.myproperty
Here is my final code that works fine for me:
tt_content.menu.dataProcessing {
30 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
30 {
table = pages
where.dataWrap = uid = {TSFE:id}
pidInList = 1
as = pageproperties
}
}
In the Fluid template I use {pageproperties.0.data.tx_mytheme_fieldname}.
I don't know why exactly but I can't access page properties with the proposed solution. I'm using Typo3 10.4.9.
I found an alternative solution :
tt_content.menu dataProcessing {
30 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
30 {
table = pages
pidInList = 0
recursive = 99
uidInList = this
as = pageproperties
}
}
Maybe this will help someone else.
More brutal approach; to access the page properties everywhere, for example in a custom content element. Create in the sitepackage Classes/ViewHelper/GetPagePropertiesViewHelper.php :
<?php namespace Xxx\Sitepackage\ViewHelpers;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class GetPagePropertiesViewHelper extends \TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper
{
public function initializeArguments()
{
$this->registerArgument('pid', 'int', 'The page uid to get the pageproperties from', true, 1);
$this->registerArgument('property', 'string', 'A specific page property to be returned', false, null);
}
public function render()
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connectionPool->getQueryBuilderForTable('pages');
$pageProperties = [];
$statement = $queryBuilder
->select('*')
->from('pages')
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($this->arguments['pid'], \PDO::PARAM_INT))
)
->execute();
while ($row = $statement->fetch()) {
$pageProperties[] = $row;
}
if ($property) {
return $pageProperties[0][$property];
}
return $pageProperties[0];
}
}
Usage in a template or partial:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:c="http://typo3.org/ns/Xxx/Sitepackage/ViewHelpers"
data-namespace-typo3-fluid="true">
<c:getPageProperties pid="{data.pid}" property="description"/>
<f:debug><c:getPageProperties pid="{data.pid}"/></f:debug>
I'm trying to change the browser page title when in single view of my extbase extension. All my attempts failed:
/**
* action show
*
* #param \Vendor\Abc\Domain\Model\Abc $record
* #return void
*/
public function showAction(\Vendor\Abc\Domain\Model\Abc $record) {
$this->view->assign('record', $record);
//$GLOBALS['TSFE']->page['title'] = $record->getAbc();
//$GLOBALS['TSFE']->indexedDocTitle = $record->getAbc();
//$GLOBALS['TSFE']->page['title'] = $record;
//$GLOBALS['TSFE']->indexedDocTitle = $record;
//$GLOBALS['TSFE']->additionalHeaderData['CustomUserIntTitle']
//= '<title>' . $this->getAbc($record) . '</title>';
//$myNewTitle = 'Title';
//$title = '<title>' . $myNewTitle . '</title>';
//$this->response->addAdditionalHeaderData($title);
//$GLOBALS['TSFE']->content = preg_replace('#<title>.*<\/title>#', '<title>' . $record->getTitle() . '</title>', $GLOBALS['TSFE']->content);
//$this->response->addAdditionalHeaderData('<title>Mein eigener Title</title>');
}
I registred the action as non-cacheable (not sure if I really have to though)
If TYPO3 >= 9 LTS follow:
https://stackoverflow.com/a/63745294/4533462
For TYPO3 <= 8 LTS you can do it like this
The solution of Jan is a regular way of changing the depending on GET Params or Page ID.
As you tried to change the title inside the controller is depending on how the page title is set in the Typoscript. However, changing the title inside the controller is possible using the PageRenderer:
$this->objectManager->get(\TYPO3\CMS\Core\Page\PageRenderer::class)->setTitle('My title');
// For the search
$GLOBALS['TSFE']->indexedDocTitle = 'My title';
If it is not working with PageRenderer, you must have a special configuration for your page title in Typoscript or other extensions override the title.
In TYPO3 9-10 new logic. The last answer doesn't work for me so I used this
https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/PageTitleApi/Index.html
First. Create your own Title provider. path 'ext/Classes/PageTitle/MyRecordTitleProvider.php'
<?php
namespace Vendor\Ext\PageTitle;
use TYPO3\CMS\Core\PageTitle\AbstractPageTitleProvider;
class MyRecordTitleProvider extends AbstractPageTitleProvider
{
/**
* #param string $title
*/
public function setTitle(string $title)
{
$this->title = $title;
}
}
Second. In your TypoScript Setup pageTitleProviders. The main idea that classes override each other and you can set up the order (priority). Like that
config.pageTitleProviders.myext {
provider = Vendor\Ext\PageTitle\MyRecordTitleProvider
before = altPageTitle,record,seo
}
}
Expl. First, check the normal page title and all normal setup like
config{
pageTitleFirst = 1
pageTitleSeparator = |
pageTitleSeparator.noTrimWrap = | | |
}
Will make all page titles like that "Page title | Website title"
'Website title' will be taken from Sites -> websiteTitle
Then In priority our next Provider, Will override the normal page title. Like "Ext title | Website title"
Last in our settings seo_title override.
Now all ready for our title setup in ExtBase controller. We need just add in showAction
$GLOBALS['TSFE']->indexedDocTitle = $title;
$titleProvider = GeneralUtility::makeInstance(MyRecordTitleProvider::class);
$titleProvider->setTitle($title);
Try with TS (sample is from Georg Ringers excellent ext:news):
[globalVar = TSFE:id = NEWS-DETAIL-PAGE-ID]
config.noPageTitle = 2
temp.newsTitle = RECORDS
temp.newsTitle {
dontCheckPid = 1
tables = tx_news_domain_model_news
source.data = GP:tx_news_pi1|news
source.intval = 1
conf.tx_news_domain_model_news = TEXT
conf.tx_news_domain_model_news {
field = title
htmlSpecialChars = 1
}
wrap = <title>|</title>
}
page.headerData.1 >
page.headerData.1 < temp.newsTitle
[global]
you just need to make some changes accordingly to your extension
Is it possible to set a page's templavoila template with typoscript?
I have solved it with:
includeLibs.lang = fileadmin/user_tvtest.php
page.1 = USER_INT
page.1.userFunc = user_tvtest->main
page.10 = USER_INT
page.10.userFunc = tx_templavoila_pi1->main_page
page.10.disableExplosivePreview = 1
and in fileadmin/user_tvtest.php:
class user_tvtest
{
function main($content, $conf)
{
if (is_mobile())
{
$GLOBALS['TSFE']->page['tx_templavoila_to'] = 7;
//$GLOBALS['TSFE']->page['tx_templavoila_ds'] = 7;
}
}
}
http://daschmi.de/templavoila-template-domainbezogen-umschalten-gleicher-seitenbaum/
Look how the page is configured by TemplaVoila:
page = PAGE
page.typeNum = 0
page.10 = USER
page.10.userFunc = tx_templavoila_pi1->main_page
page.shortcutIcon = {$faviconPath}
They call the main_page function of class tx_templavoila_pi1 via page.userFunc:
/**
* Main function for rendering of Page Templates of TemplaVoila
*
* #param string Standard content input. Ignore.
* #param array TypoScript array for the plugin.
* #return string HTML content for the Page Template elements.
*/
function main_page($content,$conf) {
$this->initVars($conf);
// Current page record which we MIGHT manipulate a little:
$pageRecord = $GLOBALS['TSFE']->page;
// Find DS and Template in root line IF there is no Data Structure set for the current page:
if (!$pageRecord['tx_templavoila_ds']) {
foreach($GLOBALS['TSFE']->tmpl->rootLine as $pRec) {
if ($pageRecord['uid'] != $pRec['uid']) {
if ($pRec['tx_templavoila_next_ds']) { // If there is a next-level DS:
$pageRecord['tx_templavoila_ds'] = $pRec['tx_templavoila_next_ds'];
$pageRecord['tx_templavoila_to'] = $pRec['tx_templavoila_next_to'];
} elseif ($pRec['tx_templavoila_ds']) { // Otherwise try the NORMAL DS:
$pageRecord['tx_templavoila_ds'] = $pRec['tx_templavoila_ds'];
$pageRecord['tx_templavoila_to'] = $pRec['tx_templavoila_to'];
}
} else break;
}
}
// "Show content from this page instead" support. Note: using current DS/TO!
if ($pageRecord['content_from_pid']) {
$ds = $pageRecord['tx_templavoila_ds'];
$to = $pageRecord['tx_templavoila_to'];
$pageRecord = $GLOBALS['TSFE']->sys_page->getPage($pageRecord['content_from_pid']);
$pageRecord['tx_templavoila_ds'] = $ds;
$pageRecord['tx_templavoila_to'] = $to;
}
return $this->renderElement($pageRecord, 'pages');
}
This function checks the current page or search trough the rootline (TSFE) for the configured page template. The script does not check any TypoScript settings at all so I suppose thats not supported by TemplaVoila right now.
It should not be too hard extending this class with a custom function that will check some TypoScript settings.