Why are my typolinks t3: not replaced if I fetch them with CONTENT? - typo3

I have Typoscript like this:
lib.rccProcessTexts = CONTENT
lib.rccProcessTexts {
table = tt_content
select {
pidInList = {$rcc.ids.pidRccProcessTexts}
}
renderObj = COA
renderObj {
10 = TEXT
# The field tt_content.bodytext holds the content text.
10.stdWrap.field = bodytext
10.stdWrap.wrap = <div data-phase-id="{field:colPos}">|</div>
10.insertData = 1
}
wrap = <div class="hidden" data-process-texts>|</div>
}
So this Typoscript fetches content from tt_content. Any typolinks (t3://...) are not replaced by real links (like https://www.example.com/go/to/page).
How can I make TYPO3 create real links?

You have 2 possibilities.
is documented here: https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/ContentObjects/Text/Index.html
It is to add this parseFunc to the TEXT object:
10.stdWrap.parseFunc < lib.parseFunc_RTE
This will cause the text to be parsed as usual.
So finally:
...
...
renderObj = COA
renderObj {
10 = TEXT
# The field tt_content.bodytext holds the content text.
10.stdWrap.field = bodytext
10.stdWrap.wrap = <div data-phase-id="{field:colPos}">|</div>
10.insertData = 1
10.stdWrap.parseFunc < lib.parseFunc_RTE
}
...
The second is to write a userfunc with PHP.
10.stdWrap.parseFunc.userFunc = My\Way\To\MyClass.php->doSomething()
Then just add Class.php with doSomething() to the Classes/UserFunc folder. The class is like so:
<?php
namespace My\Way\To;
class MyClass
{
/**
* #var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
public $cObj;
/**
*
* #param string When custom methods are used for data processing (like in stdWrap functions), the $content variable will hold the value to be processed. When methods are meant to just return some generated content (like in USER and USER_INT objects), this variable is empty.
* #param array TypoScript properties passed to this method.
* #return string The input string reversed. If the TypoScript property "uppercase" was set, it will also be in uppercase. May also be linked.
*/
public function doSomething(string $content, array $conf): string
{
// Have fun
}
}

Related

Pass a variable to a content object containing a tx_news plugin

This is very similar to my question Counter for mask elements in a TYPO3 column
I need to pass a variable (in my case, the value of cObj:parentRecordNumber which is the counter for the current item in it's column) to the template.
In the main page template:
<f:cObject typoscriptObjectPath="lib.content.pageteasers" />
In typoscript:
lib.content {
pageteasers < styles.content.get
pageteasers {
select {
where = colPos=2
max = 8
}
// this passes the variable elementCounter to the fluid template of the rendered mask content element:
renderObj.mask_teaser {
variables {
elementCounter = TEXT
elementCounter.value = {cObj:parentRecordNumber}
elementCounter.insertData = 1
}
}
// this should pass the same value to a rendered tx_news plugin:
variables {
elementCounter = TEXT
elementCounter.value = {cObj:parentRecordNumber}
elementCounter.insertData = 1
}
// it doesn't. what about these trial & error:
renderObj.list < .variables
renderObj.plugin.tx_news < .variables
renderObj.list.20.news_pi1 < .variables
renderObj.news_pi1 < .variables
// none of these seem to work either
}
}
And then in the rendered CE template (News/List.html)
<f:debug title="" inline="1">{_all}</f:debug>
I don't manage to see the above variable in here. What is the correct way to pass the variable from TS to the news fluid template?
PS Another try was using the Good Old Register
pageteasers < styles.content.get
pageteasers {
select {
where = colPos=2
max = 8
}
append = LOAD_REGISTER
append {
elementCounter = TEXT
elementCounter.value = {cObj:parentRecordNumber}
elementCounter.insertData = 1
}
}
And in the template:
{v:variable.register.get(name: 'elementCounter')}
but that is NULL
Your try via register could work. But you have to care, where you are doing what...
Registers
LOAD_REGISTER is of type string/stdWrap and not a cObject per definition. If you wanna use content based on a cObject, you can declare this via the stdWrap-property (as shown in the examples):
1 = LOAD_REGISTER
1.param.cObject = TEXT
1.param.cObject.stdWrap.data = GP:the_id
So, in your case it should like:
elementCounter.cObject = TEXT
elementCounter.cObject.data = cObj:parentRecordNumber
Appending at the right place
You are trying to use append directly as a property of pageteasers (which is a copy of styles.content.get which is of type CONTENT.
CONTENT does not have an append-property. In addition, you would put the register in front of the entire content, not the individual content elements.
=> It's needed as part of the renderObj, so it's rendered per CE.
The renderObj of CONTENT is of type CASE, which also has no stdWrap-properties directly. But it has a property stdWrap with stdWrap-properties...
Conclusion
So, you can end up with this snippet:
lib.content {
pageteasers {
renderObj {
stdWrap {
append = LOAD_REGISTER
append {
elementCounter.cObject = TEXT
elementCounter.cObject.data = cObj:parentRecordNumber
}
}
}
}
}

TYPO3: Render a plugin via Typoscript or ViewHelper and change settings

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.

Get FlexForm configuration in TypoScript

I need to get the page.headerData in typoscript from pi_flexform.How can implement my requirement?
page = PAGE
page {
headerData {
10 = TEXT
10.value =<script>/**********************/</script>
}
}
I am not so sure about what you really need. I am guessing you want to access a FlexForm configuration inside your TypoScript?
Since the version 8.4 this is possible by using plain TypoScript
lib.flexformContent = CONTENT
lib.flexformContent {
table = tt_content
select {
pidInList = this
}
renderObj = COA
renderObj {
10 = TEXT
10 {
data = flexform: pi_flexform:settings.categories
}
}
}
The key flexform is followed by the field which holds the flexform data and the name of the property whose content should be retrieved.
Before 8.4 you need to use a userFunc and retrieve the value by using PHP
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
$flexFormKey = str_replace('.', '|', $keyParts[1]);
$settings = $flexFormService->convertFlexFormContentToArray($flexFormContent);

Combining TypoScript and Fluid: Iterations?

I'm combining a TypoScript CONTENT Object with a fluid template.
In the page template:
<f:cObject typoscriptObjectPath="lib.myItem" />
In TS:
lib.myItem = CONTENT
lib.myItem {
table = tt_content
select.where = colPos = 0
select.languageField = sys_language_uid
renderObj = FLUIDTEMPLATE
renderObj {
file = {$customContentTemplatePath}/Myfile.html
layoutRootPath = {$customContentLayoutPath}
partialRootPath = {$customContentPartialPath}
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
10.references.fieldName = image
}
}
}
In Myfile.html:
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
<div class="small-12 medium-6 large-4 columns">
<f:for each="{files}" as="file">
<v:media.image src="{file}" srcset="1200,900,600" srcsetDefault="600" alt="{file.alternative}" treatIdAsReference="1"/>
</f:for>
<div class="fp-ql-txt">
{data.header} >
</div>
</div>
But now I realized that because the template is applied by the renderObj for each content element, I don't have access to fluid's for-each information about iteration. So, I can't do this:
<f:for each="{data}" as="item" iteration="itemIterator">
{itemIterator.cycle}
</f:for>
to find out in which of the rendered items we are ... because each element is rendered individually by renderObj.
How can I get the iteration information about the renderObj's products? Only in TS with the old and terrifying counters as in http://typo3-beispiel.net/index.php?id=9 ?
You could make your own IteratorDataProcessor:
<?php
namespace Vendor\MyExt\DataProcessing;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;
use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException;
/**
* This data processor will keep track of how often he was called and whether it is an
* even or odd number.
*/
class IteratorProcessor implements DataProcessorInterface, SingletonInterface
{
/**
* #var int
*/
protected $count = 0;
/**
* Process data for multiple CEs and keep track of index
*
* #param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element
* #param array $contentObjectConfiguration The configuration of Content Object
* #param array $processorConfiguration The configuration of this processor
* #param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
* #return array the processed data as key/value store
* #throws ContentRenderingException
*/
public function process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData)
{
$iterator = [];
$iterator['index'] = $this->count;
$iterator['isFirst'] = $this->count === 0;
$this->count++;
$iterator['cycle'] = $this->count;
$iterator['isEven'] = $this->count % 2 === 0;
$iterator['isOdd'] = !$iterator['isEven'];
$processedData['iterator'] = $iterator;
return $processedData;
}
}
In Typoscript you pass your data through that processor:
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
10 {
references.fieldName = image
}
20 = Vendor\MyExt\DataProcessing\IteratorProcessor
}
In fluid you can access the stuff you set in your DataProcessor with e.g. {iterator.isFirst}.
You should check out the DatabaseQueryProcessor shipped with the TYPO3 Core.
https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/Fluidtemplate/Index.html#dataprocessing
Please note that data processing only work inside the FLUIDTEMPLATE cObject.
You also find a working example inside the documentation.

TypoScript / Typo3: How to build sub-content of a page using header_link value?

How can I build a sub-content (nested content) of a page using typoscript with reference to the parent's header_link field?
Desired output is something like:
<h1>Title of parent</h1>
<p class="prt">Body of parent</p>
<h3>Title of Child</h3>
<p class="cld">Contents of child</p>
Sample of my Typoscript:
temp.myParentVal = CONTENT
temp.myParentVal {
table = tt_content
select {
begin = 1
orderBy = sorting
where = (colPos = 1)
}
renderObj = COA
renderObj {
10 = TEXT
10 {
required = 1
wrap = <h1> | </h1>
stdWrap.field = header
}
20 = TEXT
20 {
required = 1
wrap = <p class="prt"> | </p>
stdWrap.field = bodytext
}
# #
# WHAT SHOULD I DO HERE TO SHOW THE CHILD CONTENT OF THIS PAGE #
# (REFERENCED BY header_link FIELD IN THE PARENT'S ROW), #
# WHICH HAS THE FORMAT OF <child_pid#child_uid>, EG.'11#28' #
# #
stdWrap.wrap = <div> | </div>
}
I would like to make use of parent's header_link field value to generate the content for the child. (I'm using TYPO3 v. 6.2.14)
You can use a nested CONTENT element and split the header_link via Regex like this:
30 = CONTENT
30 {
table = tt_content
select {
uidInList {
field = header_link
stdWrap.replacement.10 {
search = /^.+#/
replace =
useRegExp = 1
}
}
pidInList {
field = header_link
stdWrap.replacement.10 {
search = /#.+$/
replace =
useRegExp = 1
}
}
}
renderObj = COA
renderObj {
10 = TEXT
10.value {
required = 1
wrap = <h3> | </h3>
field = header
}
20 = TEXT
20.value {
required = 1
wrap = <p class="cld"> | </p>
field = bodytext
}
}
}
Also, I wanted to suggest that you use the field property directly on the TEXT elements (which works). But I looked it up in the docs:
stdWrap properties are available on the very rootlevel of the object. This is non-standard! You should use these stdWrap properties consistently to those of the other cObjects by accessing them through the property "stdWrap".
https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/Text/Index.html
As value is a stdWrap object, you could use it as I did above.