Schlagwort-Archive: TYPO3

TYPO3 Inhaltsverzeichnis (Section Index) mit Gridelements

Das Inhaltsverzeichnis (Content Element: Menu Section Index) funktioniert ohne Eingreifen leider nicht mit der Extension Gridelements. Hierfür bitte folgenden ViewHelper benutzen:


<?php
namespace [DEINNAMESPACE];

/**
 * @author 2020 Paulina Seroczynska <ps [ät] sitegefuehl [punkt] de>
 * The original Menu\SectionViewHelper from fluid_styled_content was used and modified
 */

/*
 *
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;

/**
 * A view helper which returns content elements with 'Show in Section Menus' enabled
 *
 * By default only content in colPos=0 will be found. This can be overruled by using "column"
 *
 * If you set property "type" to 'all', then the 'Show in Section Menus' checkbox is not considered
 * and all content elements are selected.
 *
 * If the property "type" is 'header' then only content elements with a visible header layout
 * (and a non-empty 'header' field!) are selected.
 * In other words, if the header layout of an element is set to 'Hidden' then the element will not be in the results.
 *
 * = Example =
 *
 * <code title="Content elements in page with uid = 1 and 'Show in Section Menu's' enabled">
 * <ce:menu.section pageUid="1" as="contentElements">
 *   <f:for each="{contentElements}" as="contentElement">
 *     {contentElement.header}
 *   </f:for>
 * </ce:menu.section>
 * </code>
 *
 * <output>
 * Content element 1 in page with uid = 1 and "Show in section menu's" enabled
 * Content element 2 in page with uid = 1 and "Show in section menu's" enabled
 * Content element 3 in page with uid = 1 and "Show in section menu's" enabled
 * </output>
 */
class SectionViewHelper extends AbstractViewHelper
{
    use \TYPO3\CMS\FluidStyledContent\ViewHelpers\Menu\MenuViewHelperTrait;

    /**
     * Initialize ViewHelper arguments
     *
     * @return void
     */
    public function initializeArguments()
    {
        $this->registerArgument('as', 'string', 'Name of the template variable that will contain selected pages', true);
        $this->registerArgument('column', 'integer', 'Column number (colPos) from which to select content', false, null);
        $this->registerArgument('pageUid', 'integer', 'UID of page containing section-objects; defaults to current page', false, null);
        $this->registerArgument('type', 'string', 'Search method when selecting indices from page', false, '');
    }

    /**
     * Render the view helper
     *
     * @return string
     */
    public function render()
    {
        $as = (string)$this->arguments['as'];
        $pageUid = (int)$this->arguments['pageUid'];
        $type = (string)$this->arguments['type'];

        if (empty($pageUid)) {
            $pageUid = $this->getTypoScriptFrontendController()->id;
        }

        if (!empty($type) &amp;amp;&amp;amp; !in_array($type, array('all', 'header'), true)) {
            return '';
        }

        return $this->renderChildrenWithVariables(array(
            $as => $this->findBySection($pageUid, $type, $this->arguments['column'])
        ));
    }

    /**
     * Find content with 'Show in Section Menus' enabled in a page
     *
     * By default only content in colPos=0 will be found. This can be overruled by using $column
     *
     * If you set property type to "all", then the 'Show in Section Menus' checkbox is not considered
     * and all content elements are selected.
     *
     * If the property $type is 'header' then only content elements with a visible header layout
     * (and a non-empty 'header' field!) is selected.
     * In other words, if the header layout of an element is set to 'Hidden' then the page will not appear in the menu.
     *
     * @param int $pageUid The page uid
     * @param string $type Search method
     * @param int $column Restrict content by the column number
     * @return array
     */
    protected function findBySection($pageUid, $type = '', $column = null)
    {
        $constraints = array(
        );
        if ($column !== null) {
            $constraints[] = 'tt_content.colPos = ' . (int)$column;
        }

        switch ($type) {
            case 'all':
                break;
            case 'header':
                $constraints[] = 'tt_content.sectionIndex = 1';
                $constraints[] = 'tt_content.header <> \'\'';
                $constraints[] = 'tt_content.header_layout <> 100';
                break;
            default:
                $constraints[] = 'tt_content.sectionIndex = 1';
                $constraints[] = 'tt_content.header <> \'\'';
        }
        //$constraints[] = 't2.uid IS NULL OR (t2.deleted = 0 AND t2.hidden = 0)';

        $whereStatement = implode(' AND ', $constraints);

        $contentElements = $this->getTypoScriptFrontendController()->cObj->getRecords('tt_content', [
            'selectFields' => 'tt_content.header, tt_content.sorting as original, ((IFNULL(t2.sorting, tt_content.sorting) * 10000) + tt_content.sorting)  as sorting',
            'leftjoin' => 'tt_content t2 on t2.uid = tt_content.tx_gridelements_container ',
            'where' => $whereStatement,
            'orderBy' => 'sorting asc',
            'languageField = sys_language_uid',
            'pidInList' => (int)$pageUid
        ]);

        return $contentElements;
    }
}

Ausgabe eines Bildes (FAL) aus einer bestimmten Seite aus tt_content (ctype image oder textpic)

Mein Ziel war es von Fluid heraus die uid einer Seite an TypoScript zu übergeben



<f:cObject typoscriptObjectPath="lib.caseStudyImage" data="{casestudy}" />


Jedes Object casestudy hatte eine UID, die die uid einer Seite war. Es wurden über eine foreach Schleife mehrere Case Studys ausgegeben. Bei der Ausgabe dieser Case Studys sollte dann aus dem Inhalt der jeweiligen Seite das erste Bild ausgegeben werden.

Leider hat kein einziger Code, den ich im Netz gefunden habe korrekt mit FAL funktioniert. Daher hier meine Lösung


lib.caseStudyImage = CONTENT
lib.caseStudyImage {
	table = tt_content
	select {
		languageField = sys_language_uid
		orderBy = sorting
		max = 1
		where = (CType = "image" OR CType = "textpic") AND colPos = 0 
		pidInList.field = uid
	}
	renderObj = FILES
	renderObj {
		begin = 0
		maxItems = 1
		references {
			table = tt_content
			uid.data = uid
			fieldName = image
		}
		renderObj = IMAGE
		renderObj {
			file.import.data = file:current:uid
			file.treatIdAsReference = 1
			file.width = 335c
			file.height = 220c
			altText.data = file:current:title
		}
	}
}

Anzahl Kommentare in der tt_news SINGLE Ansicht (Ext: comments in TYPO3)

Endergebnis: Anzahl Kommentare in der SINGLE Ansicht
Ihr benutzt tt_news und die comments Extensions? Komischerweise ist die Ausgabe der Anzahl der Kommentare nur in der LIST, LATEST und SEARCH Ansicht möglich. Was müsst ihr machen, um die Anzahl der Kommentare auch in der SINGLE Ansicht anzeigen zu lassen? Leider in die Extension eingreifen!

Dort wird die Art des tt_news Views über Strings abgefragt. In der Funktion extraItemMarkerProcessor (ca ab Zeile 64) in der Datei class.tx_comments_ttnews.php unter typo3conf/ext/comments/.

In dieser Funktion werden die Marker mit Inhalt befüllt.
Vorher wird über Switch abgefragt in welchem tt_news View ihr euch befindet.

Hier muss SINGLE hinzugefügt werden. Also muss euer Code so aussehen:


	function extraItemMarkerProcessor($markerArray, $row, $lConf, &amp;amp;amp;$pObj) {
		/* @var $pObj tx_ttnews */
		switch ($pObj->theCode) {
			case 'LATEST':
			case 'LIST':
			case 'SEARCH':
			case 'SINGLE':
				// Add marker for number of comments
				$commentCount = $this->getNumberOfComments($row['uid'], $pObj);
				$templateName = $commentCount ? '###TTNEWS_COMMENT_COUNT_SUB###' : '###TTNEWS_COMMENT_NONE_SUB###';
				if (($template = $this->getTemplate($templateName, $lConf, $pObj))) {
					$lang = t3lib_div::makeInstance('language');
					/* @var $lang language */
					$lang->init($GLOBALS['TSFE']->lang);
					$markerArray['###TX_COMMENTS_COUNT###'] = $pObj->cObj->substituteMarkerArray(
						$template, array(
							'###COMMENTS_COUNT_NUMBER###' => $commentCount,
							'###COMMENTS_COUNT###' => sprintf($lang->sL('LLL:EXT:comments/locallang_hooks.xml:comments_number'), $commentCount),
							'###COMMENTS_COUNT_NONE###' => $lang->sL('LLL:EXT:comments/locallang_hooks.xml:comments_number_none'),
							'###UID###' => $row['uid'],
							'###COMMENTS_LINK###' => $this->getItemLink($markerArray['###LINK_ITEM###'], $row['uid'], $pObj),
						)
					);
					unset($lang);	// Free memory explicitely!
				}
				break;
		}
		return $markerArray;
	}

Natürlich muss auch der Marker ###TX_COMMENTS_COUNT### in euer tt_news SINGLE Template eingefügt werden.

TYPO3: mm_forum Antworten Button ueber den Posts

mm_forum ist sehr mächtig und somit kann eine kleine Änderung schonmal ganz anstrengend werden.. Leider habe ich bisher keine bessere Methode gefunden,  um den Antworten Button von unter den Posts nach oben zu verschieben. Im Template „list_post.html“ ist der Reply Button im Marker ###POSTBOTTOM### versteckt. Der Marker wird aber nur befüllt, wenn er sich auch zwischen dem subpart <!-- ###LIST_POSTS_END### begin --> und <!-- ###LIST_POSTS_END### end --> befindet. Würde man ###POSTBOTTOM###  nun zwischen <!-- ###LIST_POSTS_BEGIN### begin --> und <!-- ###LIST_POSTS_BEGIN### end --> einfügen, würde der Marker nicht ersetzt werden. Lösung hierfür:

In der Datei class.tx_mmforum_postfunctions.php unter ext/mm_forum/pi1 sollte man (je nach Version) ab ca. Zeile 222, also nach // Output topic name den Code für die $this->createButton('reply', $linkParams) Funktion einfügen. Der sieht folgendermaßen aus:


if ((!$topicData['read_flag'] && !$topicData['closed_flag']) || $this->getIsMod($topicData['forum_id']) || $this->getIsAdmin()) {
			if ($this->getMayWrite_topic($topicId)) {
				$linkParams[$this->prefixId] = array(
					'action' => 'new_post',
					'tid'    => $topicId
				);
				if ($this->useRealUrl()) {
					$linkParams[$this->prefixId]['fid'] = $topicData['forum_id'];
				}
				$marker['###POSTBOTTOM###'] = $this->createButton('reply', $linkParams);
			} else {
				$marker['###POSTBOTTOM###'] = '';
			}
		} else {
			$marker['###POSTBOTTOM###'] = $this->pi_getLL('topic.adminsOnly');
		}

Vernuenftige Druckversion (printlink) mit TYPO3 4.6, tt_news und realURL mit typeNum 98

Ich konnte es kaum glauben, dass ich so lange an der Lösung eines manuellen (ohne Extension, sondern nur mit TypoScript) printlinks saß. Teilweise waren die Lösungen veraltet (z.B. GPvar anstatt GP) oder nahmen keine Rücksicht auf die Get Variablen von tt_news. Außerdem war es mir wichtig, dass ich nicht direkt über JavaScript ein window.print aufrufe und dann „nur“ noch die print.css genommen wird. Ich wollte ein komplett neues Template, somit eine Druck-Vorschaufunktion für den User und erst dann das automatische OS Druck-Fenster. Das TypoScript kann natürlich nach belieben angepasst werden.

Hiermit erstelle ich den Printlink und später kopiere ich ihn einen Marker.


temp.print-link = COA
temp.print-link {
	10 = TEXT
	10.value = Seite drucken
	stdWrap.wrap = |
	stdWrap.typolinkno_cache = 1
	stdWrap.typolink.target = print
	stdWrap.typolink.ATagParams = target = _top
	stdWrap.typolink.parameter.cObject = COA
	stdWrap.typolink.parameter.cObject {
 
        5 = TEXT
        5.data = page:uid
        5.wrap = index.php?id=|
        5.required = 1
 
        10 = TEXT
        10.value = &amp;amp;amp;no_cache=1
 
        20 = TEXT
        20.data = GP:L
        20.wrap = &amp;amp;amp;L=|
        20.required = 1
 
        30 = TEXT
        30.data = GP:tx_ttnews | backPid
        30.wrap = &amp;amp;amp;tx_ttnews[backPid]=|
        30.required = 1
 
        40 = TEXT
        40.data = GP:tx_ttnews | tt_news
        40.wrap = &amp;amp;amp;tx_ttnews[tt_news]=|
        40.required = 1
 
        50 = TEXT
        50.data = GP:cHash
        50.wrap = &amp;amp;amp;cHash=|
        50.required = 1
 
        60 = TEXT
        60.value = &amp;amp;amp;type=98
    }
}

Und hiermit definiere ich das Drucktemplate


print = PAGE
print {
  typeNum = 98
  bodyTag = <body onload="javascript:window.print()">   
  ##disable typo3 index
  config.index_enable = 0
 
  ##disable google index
  headerData.123 = TEXT
  headerData.123.value = <meta name="robots" content="noindex, nofollow" />
 
  includeCSS.fileDefault = fileadmin/templates/css/print.css
  10 = TEMPLATE
  10 {
      template = FILE
      template.file = fileadmin/templates/print.tmpl
      workOnSubpart = DOCUMENT_BODY
 
      marks { 
        CONTENT < styles.content.get
      }      
   }
}

.htaccess Weiterleitung von *.html Datei-Endungen auf das Verzeichnis (TYPO3)

Stellt man nachträglich die TYPO3 RealURL Konfiguration mit folgendem Befehl 'defaultToHTMLsuffixOnPrev' => false um und erhält dadurch Seiten ohne eine *.html Endung, erscheint für bestehende Links mit der Endung ein Server Error. Das Entfernen der *.html Endung soll aus SEO Sicht vorteilhaft sein. Daher sollte man auf jeden Fall auch eine Weiterleitung einrichten. Diese Weiterleitung leitet dann allgemeingültig alle *.html Dateien zu dem Verzeichnis um. Dies tut man am besten über die htaccess Datei mit folgendem Befehl:


RedirectMatch (.*)\.html$ $1/

Aus http://domain.de/datei.html wird http://domain.de/datei/

Am besten wäre es noch, wenn man alle URLs von http://domain.de/datei auf http://domain.de/datei/ leiten würde, somit jedesmal den endenen Slash (trailing slash) hinzufügen würde. Somit vermeidet man Duplicate Content. Leider hat bei mir u.g. Code nicht funktioniert. Vielleicht weiß jemand Rat?


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)([^/])$ http://domain.de/$1$2/ [R=301,L]

TYPO3 404 Handling, feuser (geschuetzter Bereich) und die Mehrsprachigkeit

Vielleicht haben es einige von euch bemerkt: Hat man einen geschützten Bereich in TYPO3 (4.5.5) mit feuser und srfeuserregister laufen, außerdem eine Mehrsprachigkeit (in meinem Fall deutsch als default und englisch als id=1) und das 404 Handling an, dann kommt es zu Problemen. Anstatt die Login Maske von feuser aufzurufen, nachdem ein Link zum geschützen Bereich aufgerufen wurde, erscheint eine 404 Seite. Dieses Problem habe ich folgendermaßen mit einer kleinen Funktion behoben:


<?php
define(LOGIN_URL, "http://www.domain.de/login.html");
define(LOGIN_URL_EN, "http://www.domain.de/en/login.html");
define(NOTFOUND_URL, "http://www.domain.de/404.html");
define(NOTFOUND_URL_EN, "http://www.domain.de/en/404.html");
  
class user_pageNotFound {
  function pageNotFound($param, $ref) {
    if ($param["pageAccessFailureReasons"]["fe_group"] != array(""=>0)) {
      header("HTTP/1.0 403 Forbidden");
	  if ($_GET['L'] == 1){
      	$url = LOGIN_URL_EN."?redirect_url=" . $param["currentUrl"]; 
       } else {
			$url = LOGIN_URL."?redirect_url=" . $param["currentUrl"];
	  }
    } elseif ((substr($param['currentUrl'], 1, 2)) == "en") {
      	$url = NOTFOUND_URL_EN;   
    } else {
		$url = NOTFOUND_URL;  
	}
     
    session_start();
    $strCookie = 'PHPSESSID=' . $_COOKIE['PHPSESSID'] . '; path=/';
    session_write_close();
   
    $c = curl_init();
    curl_setopt($c, CURLOPT_URL, $url);
    curl_setopt($c, CURLOPT_COOKIE, $strCookie);
    $contents = curl_exec($c);
    curl_close($c);
 
    if ($contents) return $contents;
        else return FALSE;
  }
}
?>

Hierbei wird vor dem 404 Handling auch noch die RealURL abgefragt und je nach Sprache (in meinem Fall „en“) eine andere 404 Seite ausgegeben. Bitte ersetzt oder erweitert diesen Bereich nach euren Anforderungen. Außerdem müssen von euch natürlich auch die vier Konstanten (LOGIN_URL, NOTFOUND_URL..) geändert werden.

Zuvor muss in dem Install Tool oder in der localconf.php folgender Eintrag geändert werden: [FE][pageNotFound_handling] = USER_FUNCTION:fileadmin/scripts/pageNotFoundHandling.php:user_pageNotFound->pageNotFound und natürlich der oben genannte Code in das jeweilige Verzeichnis unter fileadmin in die Datei pageNotFoundHandling.php eingefügt werden.

Facebook Like Button und Twitter Share Button ueber TypoScript in TYPO3 einfuegen

Da die Nachfrage über die komplette Einbindung von Facebook und Twitter kam, hier nochmal der Code für die Einbindung der Buttons über das TypoScript Template.

Das ganze basiert auf den Anforderung, dass die Buttons auf allen Seiten eingeblendet werden sollen. Ich habe außerdem über eine kleine Extension das Abschalten der Buttons für jede Seite in den Seiteneigenschaften erstellt.

Den Code kann man mit Sicherheit auch für den Google+ Button erweitern.

temp.bookmarks = COA
temp.bookmarks {
		5 = TEXT
		5.value = <br/>
		5.if.isFalse.field = tx_nobookmarks_nobookmarks
		10 = COA
	   	10 {
	     	10 = TEXT
			10.value (
			<div style="float:left">
 			<a href="http://twitter.com/share" data-count="horizontal" data-lang="de">Tweet</a>
 			<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
 			</div>
			)
			10.if.isFalse.field = tx_nobookmarks_nobookmarks
	   	   }
  	   	20 = COA
	   	20 {
	     	10 = TEXT
			10.typolink.parameter.data = TSFE:id
			10.typolink.returnLast = url
			10.dataWrap = {TSFE:baseUrl}|
			10.rawUrlEncode = 1

		wrap (
                        <iframe src="http://www.facebook.com/plugins/like.php?href=|&layout=standard&show_faces=true&width=450&action=like&colorscheme=light&height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px; margin:-2px 0 0 15px;background-color:transparent;" allowTransparency="true"></iframe>
		)

	   }
		20.if.isFalse.field = tx_nobookmarks_nobookmarks

	}

Die Extension ermöglicht, dass ausschalten der Buttons über die Seiteneigenschaften.

So sieht es dann im Backend ausSie kann hier runtergeladen werden: TYPO3 Extension für die Facebook und Twitter Buttos (deaktiviert obigen Code)

Facebook Thumbnail Bild in TYPO3 + Description fuer den Like Button

Für WordPress gibt es ja mittlerweile ein Plugin, welches das Thumbnail-Bild für Facebooks Like Button festlegt. Früher hat Facebook das erste Bild im Quelltext als Thumbnail gewählt, heutzutage nimmt Facebook einfach irgendeins; manchmal sogar gar keins!

Ich habe also mal in TYPO3 etwas geTYPOscriptet 😉

Da nie Descriptions gepflegt wurden bei dem Kunden, sollte auch hier die Beschreibung bei den Like Button automatisch generiert werden.

Das Facebook Thumbnail-Bild im like Button, lasse ich über das Content-Element textpic (Text mit Bild) erstellen. Man kann das sicherlich noch erweitern auf CEs mit nur Bild. Außerdem muss das Bild über den Reiter media hochgeladen worden sein. Gibt es das CE nicht oder kein Bild unter media, dann wird auch einfach keins genommen. Der Like Button funtktioniert dann natürlich weiterhin.

Facebook Thumbnail festlegen

temp.metabild = COA
temp.metabild {
         10=CONTENT
         10.table= tt_content
         10.select {
           orderBy = sorting
           where = CType="textpic"
           selectFields = image
           max=1
           begin=0
           languageField = sys_language_uid
         }
         10.renderObj=COA
         10.renderObj {
         10 = TEXT
		 10 {
			field = image
			stdWrap.dataWrap = <link rel="image_src" href="/uploads/pics/|">
		}
	}
}
page.headerData.35 < temp.metabild

Für die Beschreibung neben dem Like Button, nutze ich den Meta-Tag Description. Hier werden aus dem ersten CE die ersten 300 Zeichen genommen und in den Meta-Tag geschrieben.

Facebook Like Button Beschreibung aus dem ersten Content-Element oder automatische Generierung der description aus den ersten Zeilen

temp.meta = COA
temp.meta {
         10=CONTENT
         10.table= tt_content
         10.select {
           selectFields = bodytext
           orderBy = sorting
           languageField = sys_language_uid
           where=colPos=0
           max=1
           begin=0
         }
         10.renderObj=COA
  	 10.renderObj{
    		10=TEXT
    		10{
      			field=bodytext
      			stripHtml=1
      			crop = 300 | ... | 1
    		}

  	}
}

page.headerData.76 < temp.meta
page.headerData.76.wrap = <meta name="description" content="|">

Ich habe außerdem noch die Extension tweet_and_like genutzt. Hier wird jeweils der Twitter-Share Button und der Facebook-Like Button in der LIST Ansicht unter jedem News Artikel eingefügt. Das tolle an der Extension: Der Facebook Like zeigt direkt auf die SINGLE Ansicht. Doch auch hier war es in meinem Fall nötig, die description zu generieren und das Thumbnail festzulegen. Das habe ich so getan:

tt_news Facebook Like Thumbnail

[globalVar = TSFE:id = 167]
temp.newsImage = COA
temp.newsImage {
        wrap=<link rel="image_src" href="/uploads/pics/|">
        5=RECORDS
        5 {
                source = {GPvar:tx_ttnews|tt_news}
                source.insertData = 1
                tables = tt_news
                conf.tt_news >
                conf.tt_news = TEXT
                conf.tt_news.field = image
        }
}
page.headerData.35 < temp.newsImage
[end]

Die ID 167 muss dann natürlich gegen die eigene ID der SINGLE Ansicht ausgetauscht werden.

tt_news Facebook Like Beschreibung setzen oder automatisch Generierung der description aus den ersten Zeilen

[globalVar = TSFE:id = 167]
temp.newsDesc = COA
temp.newsDesc {
        wrap=<meta name="description" content="|">
        5=RECORDS
        5 {
                source = {GPvar:tx_ttnews|tt_news}
                source.insertData = 1
                tables = tt_news
                conf.tt_news >
                conf.tt_news = TEXT
                conf.tt_news.field = bodytext
                conf.tt_news.stripHtml = 1
                conf.tt_news.crop = 300 | ... | 1
        }
}
page.headerData.76 < temp.newsDesc
[end]

TYPO3: Verschiedene Formatierungen der Ueberschriften je nach Spalte

Möchte man je nach Spalte in TYPO3 die Formatierung der Überschriften (header) von Content Elementen ändern, so hilft einem der TypoScript Code weiter:

temp.stdheader < lib.stdheader
lib.stdheader >
lib.stdheader = CASE
lib.stdheader  {
   key.field=colPos
   1 < temp.stdheader
   2 < temp.stdheader
   default < temp.stdheader
}
lib.stdheader.default.10.1.fontTag = <h2>|</h2>
lib.stdheader.1.10.1.fontTag = <h2>|</h2>
lib.stdheader.2.10.1.fontTag = <span class="rightLinksHeading">|</span>