Index: t3lib/class.t3lib_befunc.php
===================================================================
--- t3lib/class.t3lib_befunc.php	(revision 3835)
+++ t3lib/class.t3lib_befunc.php	(working copy)
@@ -75,6 +75,7 @@
  *  919:     function getSpecConfParts($str, $defaultExtras)
  *  950:     function getSpecConfParametersFromArray($pArr)
  *  978:     function getFlexFormDS($conf,$row,$table,$fieldName='',$WSOL=TRUE)
+ *           function resolveShortcutToPageOrContent($shortcut)
  *
  *              SECTION: Caching related
  * 1105:     function storeHash($hash,$data,$ident)
@@ -1171,11 +1172,78 @@
 		return $dataStructArray;
 	}
 
+        /**
+         * Resolves shortcuts to pages or tt_content elements: an array ( pid=int, uid=int|false ) will be returned.
+         * A workspace overlay is performed for tt_content shortcuts, if applicable:
+         *  - for the pid to link to, it doesn't matter, if the uid is deleted or not visible even for WS reasons.
+         *  - for the uid (will be the section link), this is relevant: If the tt_content linked to is not visible for any reason, no id but false is returned.
+         *
+         * @param       string          row content of field 'shortcut'
+         * @return      array           Array with two elements: (1) int: pid of tt_content (2) int or false: uid of tt_content, if visible
+         * @see t3lib::resolveShortcutToPageOrContent
+         */
+	public static function resolveShortcutToPageOrContent($shortcut) {
+		$pid = false;
+		$uid = false;
 
+		$wsid = $GLOBALS['BE_USER']->workspace;
 
+		$shortcutParts = explode('_', $shortcut);
+		$shortcutUid = intval(array_pop($shortcutParts)); // chop off the uid, separated by '_'. Remark: '_' is likely to be part of the table name as well.
+		$shortcutTable = implode('_', $shortcutParts); // rebuild the table name
 
+		if ($shortcutTable == 'tt_content') { // is this shortcut an anchor to tt_content?
 
+			// first: get the tt_content record, disregarding any disabled fields:
+			// If the record turns out to be disabled (even deleted), we want at least return its pid.
+			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'tt_content', 'uid=' . $shortcutUid);
+			$shortcutContent = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+			$GLOBALS['TYPO3_DB']->sql_free_result($res);
+			if ($shortcutContent) { // WS overlay.
+				if ($shortcutContent['pid'] > 0) { // Save record from Live WS, if any.
+					$liveRecord = $shortcutContent;
+				} else {
+					$liveRecord = false;
+				}
+				t3lib_BEfunc::workspaceOL('tt_content', $shortcutContent, false, false); // get WS overlay. May unset $shortcutContent.
+				if (!is_array($shortcutContent) && is_array($liveRecord)) {
+					// WS overlay failed, but there is a live version => fallback to live WS
+					$pid = $liveRecord['pid'];
+					$uid = $liveRecord['uid'];
+				} elseif (is_array($shortcutContent)) {
 
+					// WS overlay was successful
+					$pid = $shortcutContent['pid'];
+					// uid is returned, if current ws id matches the one overlayed
+					if (    $wsid == $shortcutContent['t3ver_wsid'] ||
+						!strcmp($shortcutContent['t3ver_wsid'],'0')
+					) {
+						$uid = $shortcutContent['uid'];
+					} else {
+						$uid = false;
+					}
+				} else {
+					// no live record, no workspace record.
+					$pid = 0;
+					$uid = false;
+				}
+			} else {
+				// failsafe: the tt_content record didn't even exist.
+				$pid = 0;
+				$uid = false;
+			}
+			// now check, if the WS overlayed tt_content record itself and its parent page is accessible
+			if (    $uid && !is_array(t3lib_BEfunc::getRecordWSOL('tt_content',$uid)) ||
+				$uid && !is_array(t3lib_BEfunc::getRecordWSOL('pages',$pid))
+			) {
+				$uid = false;
+			}
+		} else { // shortcut to page - just return the pid
+			$pid = $shortcutUid;
+			$uid = false;
+		}
+		return array($pid, $uid);
+	}
 
 
 
@@ -1795,15 +1863,16 @@
 		if ($row['doktype']=='3') {
 			$parts[] = $LANG->sL($TCA['pages']['columns']['url']['label']).' '.$row['url'];
 		} elseif ($row['doktype']=='4') {
+			list($shortcutUid, $shortcutSection) = t3lib_BEfunc::resolveShortcutToPageOrContent($row['shortcut']);
 			if ($perms_clause) {
-				$label = t3lib_BEfunc::getRecordPath(intval($row['shortcut']), $perms_clause, 20);
+				$label = t3lib_BEfunc::getRecordPath(intval($shortcutUid), $perms_clause, 20);
 			} else {
-				$lRec = t3lib_BEfunc::getRecordWSOL('pages', intval($row['shortcut']), 'title');
+				$lRec = t3lib_BEfunc::getRecordWSOL('pages', intval($shortcutUid), 'title');
 				$label = $lRec['title'];
 			}
 			if ($row['shortcut_mode']>0) {
 				$label.=', '.$LANG->sL($TCA['pages']['columns']['shortcut_mode']['label']).' '.
-							$LANG->sL(t3lib_BEfunc::getLabelFromItemlist('pages', 'shortcut_mode', $row['shortcut_mode']));
+						$LANG->sL(t3lib_BEfunc::getLabelFromItemlist('pages', 'shortcut_mode', $row['shortcut_mode']));
 			}
 			$parts[] = $LANG->sL($TCA['pages']['columns']['shortcut']['label']).' '.$label;
 		} elseif ($row['doktype']=='7') {
Index: t3lib/class.t3lib_page.php
===================================================================
--- t3lib/class.t3lib_page.php	(revision 3835)
+++ t3lib/class.t3lib_page.php	(working copy)
@@ -56,6 +56,7 @@
  *  640:     function getPathFromRootline($rl,$len=20)
  *  661:     function getExtURL($pagerow,$disable=0)
  *  685:     function getMountPointInfo($pageId, $pageRec=FALSE, $prevMountPids=array(), $firstPageUid=0)
+ *           function resolveShortcutToPageOrContent($shortcut)
  *
  *              SECTION: Selecting records in general
  *  762:     function checkRecord($table,$uid,$checkPage=0)
@@ -454,15 +455,16 @@
 					} else unset($row);	// If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
 				}
 
-					// if shortcut, look up if the target exists and is currently visible
+				// if shortcut, look up if the target exists and is currently visible
 				if ($row['doktype'] == 4 && ($row['shortcut'] || $row['shortcut_mode']) && $checkShortcuts)	{
+					list($shortcutUid, $shortcutSection) = $this->resolveShortcutToPageOrContent($row['shortcut']);
 					if ($row['shortcut_mode'] == 0)	{
 						$searchField = 'uid';
-						$searchUid = intval($row['shortcut']);
+						$searchUid = $shortcutUid;
 					} else { // check subpages - first subpage or random subpage
 						$searchField = 'pid';
-							// If a shortcut mode is set and no valid page is given to select subpags from use the actual page.
-						$searchUid = intval($row['shortcut'])?intval($row['shortcut']):$row['uid'];
+						// If a shortcut mode is set and no valid page is given to select subpags from use the actual page.
+						$searchUid = ($shortcutUid > 0) ? $shortcutUid : $row['uid'];
 					}
 					$res2 = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', $searchField.'='.$searchUid.$this->where_hid_del.$this->where_groupAccess.' '.$addWhere, '', $sortField);
 					if (!$GLOBALS['TYPO3_DB']->sql_num_rows($res2))	{
@@ -777,10 +779,78 @@
 		return $result;
 	}
 
+	/**
+	 * Resolves shortcuts to pages or tt_content elements: an array ( pid=int, uid=int|false ) will be returned.
+	 * A workspace overlay is performed for tt_content shortcuts, if applicable:
+	 *  - for the pid to link to, it doesn't matter, if the uid is deleted or not visible even for WS reasons.
+	 *  - for the uid (will be the section link), this is relevant: If the tt_content linked to is not visible for any reason, no id but false is returned.
+	 *
+	 * @param	string		row content of field 'shortcut'
+	 * @return	array		Array with two elements: (1) int: pid of tt_content (2) int or false: uid of tt_content, if visible
+	 * @see tslib_menu::link(), tslib_fe::getPageAndRootline
+	 */
+	function resolveShortcutToPageOrContent($shortcut) {
+		$pid = false;
+		$uid = false;
 
+		$shortcutParts = explode('_', $shortcut);
+		$shortcutUid = intval(array_pop($shortcutParts)); // chop off the uid, separated by '_'. Remark: '_' is likely to be part of the table name as well.
+		$shortcutTable = implode('_', $shortcutParts); // rebuild the table name
 
+		if ($shortcutTable == 'tt_content') { // is this shortcut an anchor to tt_content?
 
+			// first: get the tt_content record, disregarding any disabled fields:
+			// If the record turns out to be disabled (even deleted), we want at least return its pid.
+			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'tt_content', 'uid=' . $shortcutUid);
+			$shortcutContent = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+			$GLOBALS['TYPO3_DB']->sql_free_result($res);
+			if ($shortcutContent) { // WS overlay.
+				if ($shortcutContent['pid'] > 0) { // Save record from Live WS, if any.
+					$liveRecord = $shortcutContent;
+				} else {
+	    				$liveRecord = false;
+				}
+				$this->versionOL('tt_content', $shortcutContent, false, false); // get WS overlay. May unset $shortcutContent.
+				if (!is_array($shortcutContent) && is_array($liveRecord)) {
+					// WS overlay failed, but there is a live version => fallback to live WS
+					$pid = $liveRecord['pid'];
+					$uid = $liveRecord['uid'];
+				} elseif (is_array($shortcutContent)) {
 
+					// WS overlay was successful
+					$pid = $shortcutContent['pid'];
+					// uid is returned, if current ws id matches the one overlayed
+					if (	$this->versioningWorkspaceId == $shortcutContent['t3ver_wsid'] ||
+						!strcmp($shortcutContent['t3ver_wsid'],'0')
+					) {
+						$uid = $shortcutContent['uid'];
+					} else {
+						$uid = false;
+					}
+				} else {
+					// failsafe: no live record, no workspace record.
+					// fall back to current page
+					$pid = $this->fixVersioningPid('tt_content',$shortcutContent);
+					$uid = false;
+				}
+			} else {
+				// failsafe: the tt_content record didn't even exist.
+				// fall back to current page
+				$pid = $GLOBALS['TSFE']->id;
+				$uid = false;
+			}
+			// now check, if the WS overlayed tt_content record itself and its parent page is accessible
+			if (	$uid && !is_array($this->checkRecord('tt_content',$uid)) ||
+				$uid && !is_array($this->checkRecord('pages',$pid))
+			) {
+				$uid = false;
+			}
+		} else { // shortcut to page - just return the pid
+			$pid = $shortcutUid;
+			$uid = false;
+		}
+		return array($pid, $uid);
+	}
 
 
 
@@ -1382,4 +1452,4 @@
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_page.php'])	{
 	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_page.php']);
 }
-?>
+?>
\ No newline at end of file
Index: typo3/sysext/cms/ext_tables.php
===================================================================
--- typo3/sysext/cms/ext_tables.php	(revision 3835)
+++ typo3/sysext/cms/ext_tables.php	(working copy)
@@ -314,7 +314,7 @@
 			'config' => array (
 				'type' => 'group',
 				'internal_type' => 'db',
-				'allowed' => 'pages',
+				'allowed' => 'pages,tt_content',
 				'size' => '3',
 				'maxitems' => '1',
 				'minitems' => '0',
Index: typo3/sysext/cms/ext_tables.sql
===================================================================
--- typo3/sysext/cms/ext_tables.sql	(revision 3835)
+++ typo3/sysext/cms/ext_tables.sql	(working copy)
@@ -385,7 +385,7 @@
   starttime int(11) unsigned DEFAULT '0' NOT NULL,
   endtime int(11) unsigned DEFAULT '0' NOT NULL,
   urltype tinyint(4) unsigned DEFAULT '0' NOT NULL,
-  shortcut int(10) unsigned DEFAULT '0' NOT NULL,
+  shortcut varchar(255) DEFAULT '0' NOT NULL,
   shortcut_mode int(10) unsigned DEFAULT '0' NOT NULL,
   no_cache int(10) unsigned DEFAULT '0' NOT NULL,
   fe_group varchar(100) DEFAULT '0' NOT NULL,
Index: typo3/sysext/cms/tslib/class.tslib_fe.php
===================================================================
--- typo3/sysext/cms/tslib/class.tslib_fe.php	(revision 3835)
+++ typo3/sysext/cms/tslib/class.tslib_fe.php	(working copy)
@@ -1040,7 +1040,8 @@
 			// Is the ID a link to another page??
 		if ($this->page['doktype']==4)	{
 			$this->MP = '';		// We need to clear MP if the page is a shortcut. Reason is if the short cut goes to another page, then we LEAVE the rootline which the MP expects.
-			$this->page = $this->getPageShortcut($this->page['shortcut'],$this->page['shortcut_mode'],$this->page['uid']);
+			list($shortcutUid,$sectionUid) = $this->sys_page->resolveShortcutToPageOrContent($this->page['shortcut']);
+			$this->page = $this->getPageShortcut($shortcutUid,$this->page['shortcut_mode'],$this->page['uid']);
 			$this->id = $this->page['uid'];
 		}
 
@@ -1133,9 +1134,11 @@
 
 			// Check if short cut page was a shortcut itself, if so look up recursively:
 		if ($page['doktype']==4)	{
+
 			if (!in_array($page['uid'],$pageLog) && $itera>0)	{
 				$pageLog[] = $page['uid'];
-				$page = $this->getPageShortcut($page['shortcut'],$page['shortcut_mode'],$page['uid'],$itera-1,$pageLog);
+				list($shortcutUid,$sectionUid) = $this->sys_page->resolveShortcutToPageOrContent($page['shortcut']);
+				$page = $this->getPageShortcut($shortcutUid,$page['shortcut_mode'],$page['uid'],$itera-1,$pageLog);
 			} else {
 				$pageLog[] = $page['uid'];
 				$message = 'Page shortcuts were looping in uids '.implode(',',$pageLog).'...!';
Index: typo3/sysext/cms/tslib/class.tslib_menu.php
===================================================================
--- typo3/sysext/cms/tslib/class.tslib_menu.php	(revision 3835)
+++ typo3/sysext/cms/tslib/class.tslib_menu.php	(working copy)
@@ -449,7 +449,6 @@
 							$res = $GLOBALS['TSFE']->cObj->exec_getQuery('pages',Array('pidInList'=>$id,'orderBy'=>$altSortField));
 							while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
 								$GLOBALS['TSFE']->sys_page->versionOL('pages',$row);
-
 								if (is_array($row))	{
 										// Keep mount point?
 									$mount_info = $this->sys_page->getMountPointInfo($row['uid'], $row);
@@ -1208,12 +1207,32 @@
 			// Setting main target:
 		$mainTarget = $altTarget ? $altTarget : $this->mconf['target'];
 
+
 			// Creating link:
 		if ($this->mconf['collapse'] && $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key)))	{
+		
+			// collapse active menu item, link to pid
 			$thePage = $this->sys_page->getPage($this->menuArr[$key]['pid']);
 			$LD = $this->menuTypoLink($thePage,$mainTarget,'','',$overrideArray, $this->mconf['addParams'].$MP_params.$this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
 		} else {
-			$LD = $this->menuTypoLink($this->menuArr[$key],$mainTarget,'','',$overrideArray, $this->mconf['addParams'].$MP_params.$this->I['val']['additionalParams'].$this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
+
+			// Handle shortcut menut item (may be an anchorlink to a tt_content element as well)
+			if ($this->menuArr[$key]['doktype'] == 4) {
+				$shortcutPage = $this->menuArr[$key];
+
+				if (strlen($shortcutPage['shortcut']) > 0 && $shortcutPage['shortcut'] != '0') {
+					list ($shortcutPid, $shortcutUid) = $this->sys_page->resolveShortcutToPageOrContent($shortcutPage['shortcut']);
+					$shortcutPage = $this->sys_page->getPage($shortcutPid);
+					// section link?
+					$shortcutPage['uid'].= ($shortcutUid) ? ('#'.$shortcutUid) : '';
+				} else {
+					// failsafe: shortcut page set, but no shortcut target chosen: take current page
+					$shortcutPage = $this->sys_page->getPage($GLOBALS['TSFE']->id);
+				}
+				$LD = $this->menuTypoLink($shortcutPage,$mainTarget,'','',$overrideArray, $this->mconf['addParams'].$MP_params.$this->I['val']['additionalParams'].$this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
+			} else {
+				$LD = $this->menuTypoLink($this->menuArr[$key],$mainTarget,'','',$overrideArray, $this->mconf['addParams'].$MP_params.$this->I['val']['additionalParams'].$this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
+			}
 		}
 
 			// Override URL if using "External URL" as doktype with a valid e-mail address:
@@ -2904,4 +2923,4 @@
 	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_menu.php']);
 }
 
-?>
+?>
\ No newline at end of file
Index: typo3/sysext/cms/tslib/class.tslib_content.php
===================================================================
--- typo3/sysext/cms/tslib/class.tslib_content.php	(revision 3835)
+++ typo3/sysext/cms/tslib/class.tslib_content.php	(working copy)
@@ -5312,7 +5312,8 @@
 								$page2 = $page;	// Save in case of broken destination or endless loop
 								$maxLoopCount = 20;	// Same as in RealURL, seems enough
 								while ($maxLoopCount && is_array($page) && $page['doktype'] == 4 && $page['shortcut_mode'] == 0) {
-									$page = $GLOBALS['TSFE']->sys_page->getPage($page['shortcut'], $disableGroupAccessCheck);
+									list($shortcutUid, $shortcutSection) = $this->resolveShortcutToPageOrContent($page['shortcut']);
+									$page = $GLOBALS['TSFE']->sys_page->getPage($shortcutUid, $disableGroupAccessCheck);
 									$maxLoopCount--;
 								}
 								if (count($page) == 0 || $maxLoopCount == 0) {
