diff --git a/_config.php b/_config.php
index 18967d846..6b0f5553f 100644
--- a/_config.php
+++ b/_config.php
@@ -36,6 +36,11 @@ Director::addRules(1, array(
'$URLSegment//$Action/$ID/$OtherID' => 'ModelAsController',
));
+/**
+ * Register the default internal shortcodes.
+ */
+ShortcodeParser::get('default')->register('sitetree_link', array('SiteTree', 'link_shortcode_handler'));
+
/**
* PHP 5.2 has a namespace conflict with our datetime class,
* for legacy support, we use this overload method.
diff --git a/core/model/SiteTree.php b/core/model/SiteTree.php
index 1c560b212..70450a6f0 100755
--- a/core/model/SiteTree.php
+++ b/core/model/SiteTree.php
@@ -263,6 +263,29 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $classes;
}
+ /**
+ * Replace a "[sitetree_link id=n]" shortcode with a link to the page with the corresponding ID.
+ *
+ * @return string
+ */
+ public static function link_shortcode_handler($arguments, $content = null, $parser = null) {
+ if(!isset($arguments['id']) || !is_numeric($arguments['id'])) return;
+
+ if (
+ !($page = DataObject::get_by_id('SiteTree', $arguments['id'])) // Get the current page by ID.
+ && !($page = Versioned::get_latest_version('SiteTree', $arguments['id'])) // Attempt link to old version.
+ && !($page = DataObject::get_one('ErrorPage', '"ErrorCode" = \'404\'')) // Link to 404 page directly.
+ ) {
+ return; // There were no suitable matches at all.
+ }
+
+ if($content) {
+ return sprintf('%s', $page->Link(), $parser->parse($content));
+ } else {
+ return $page->Link();
+ }
+ }
+
/**
* Return the link for this {@link SiteTree} object, with the {@link Director::baseURL()} included.
*
diff --git a/tests/SiteTreeTest.php b/tests/SiteTreeTest.php
index e7cfbf47f..2209790fa 100644
--- a/tests/SiteTreeTest.php
+++ b/tests/SiteTreeTest.php
@@ -380,7 +380,42 @@ class SiteTreeTest extends SapphireTest {
$this->assertEquals($memberID, $publishedVersion['PublisherID']);
}
-
+
+ public function testLinkShortcodeHandler() {
+ $aboutPage = $this->objFromFixture('Page', 'about');
+ $errorPage = $this->objFromFixture('ErrorPage', '404');
+
+ $parser = new ShortcodeParser();
+ $parser->register('sitetree_link', array('SiteTree', 'link_shortcode_handler'));
+
+ $aboutShortcode = sprintf('[sitetree_link id=%d]', $aboutPage->ID);
+ $aboutEnclosed = sprintf('[sitetree_link id=%d]Example Content[/sitetree_link]', $aboutPage->ID);
+
+ $aboutShortcodeExpected = $aboutPage->Link();
+ $aboutEnclosedExpected = sprintf('Example Content', $aboutPage->Link());
+
+ $this->assertEquals($aboutShortcodeExpected, $parser->parse($aboutShortcode), 'Test that simple linking works.');
+ $this->assertEquals($aboutEnclosedExpected, $parser->parse($aboutEnclosed), 'Test enclosed content is linked.');
+
+ $aboutPage->delete();
+
+ $this->assertEquals($aboutShortcodeExpected, $parser->parse($aboutShortcode), 'Test that deleted pages still link.');
+ $this->assertEquals($aboutEnclosedExpected, $parser->parse($aboutEnclosed));
+
+ $aboutShortcode = '[sitetree_link id="-1"]';
+ $aboutEnclosed = '[sitetree_link id="-1"]Example Content[/sitetree_link]';
+
+ $aboutShortcodeExpected = $errorPage->Link();
+ $aboutEnclosedExpected = sprintf('Example Content', $errorPage->Link());
+
+ $this->assertEquals($aboutShortcodeExpected, $parser->parse($aboutShortcode), 'Test link to 404 page if no suitable matches.');
+ $this->assertEquals($aboutEnclosedExpected, $parser->parse($aboutEnclosed));
+
+ $this->assertEquals('', $parser->parse('[sitetree_link]'), 'Test that invalid ID attributes are not parsed.');
+ $this->assertEquals('', $parser->parse('[sitetree_link id="text"]'));
+ $this->assertEquals('', $parser->parse('[sitetree_link]Example Content[/sitetree_link]'));
+ }
+
}
// We make these extend page since that's what all page types are expected to do
@@ -388,4 +423,4 @@ class SiteTreeTest_PageNode extends Page implements TestOnly { }
class SiteTreeTest_PageNode_Controller extends Page_Controller implements TestOnly {
}
-?>
\ No newline at end of file
+?>