Merged existing shortcode docs with new topics docs from 3.0

This commit is contained in:
Ingo Schommer 2013-05-17 14:01:42 +02:00
parent 4c7c40e8b9
commit 306d3b0c7e
2 changed files with 144 additions and 212 deletions

View File

@ -1,32 +1,143 @@
# Shortcodes
# Shortcodes: Flexible Content Embedding
The Shortcode API is a way to replace simple bbcode-like tags within HTML. It is inspired by and very similar to
the [Wordpress implementation](http://codex.wordpress.org/Shortcode_API) of shortcodes.
## Overview
A guide to syntax
The `[api:ShortcodeParser]` API is simple parser that allows you to map specifically
formatted content to a callback to transform them into something else.
You might know this concept from forum software which don't allow you to insert
direct HTML, instead resorting to a custom syntax.
Unclosed - [shortcode]
Explicitly closed - [shortcode/]
With parameters, mixed quoting - [shortcode parameter=value parameter2='value2' parameter3="value3"]
Old style parameter separation - [shortcode,parameter=value,parameter2='value2',parameter3="value3"]
With contained content & closing tag - [shortcode]Enclosed Content[/shortcode]
Escaped (will output [just] [text] in response) - [[just] [[text]]
In the CMS, authors often want to insert content elements which go beyond
standard formatting, at an arbitrary position in their WYSIWYG editor.
Shortcodes are a semi-technical solution for this. A good example would
be embedding a 3D file viewer or a Google Map at a certain location.
Shortcode parsing is already hooked into HTMLText and HTMLVarchar fields when rendered into a template
Here's some syntax variations:
## Attribute and element scope
[my_shortcode]
[my_shortcode /]
[my_shortcode,myparameter="value"]
[my_shortcode,myparameter="value"]Enclosed Content[/my_shortcode]
## Usage
In its most basic form, you can invoke the `[api:ShortcodeParser]` directly:
:::php
ShortcodeParser::get_active()->parse($myvalue);
In addition, shortcodes are automatically parsed on any database field which is declared
as `[api:HTMLValue]` or `[api:HTMLText]`, when rendered into a template.
This means you can use shortcodes on common fields like `SiteTree.Content`,
and any other `[api:DataObject::$db]` definitions of these types.
In order to allow shortcodes in your own template placeholders,
ensure they're casted correctly:
:::php
class MyObject extends DataObject {
static $db = array('Content' => 'HTMLText');
static $casting = array('ContentHighlighted' => 'HTMLText');
public function ContentHighlighted($term) {
return str_replace($term, "<em>$term</em>", $this->Content);
}
}
There is currently no way to allow shortcodes directly in template markup
(as opposed to return values of template placeholders).
## Defining Custom Shortcodes
All you need to do to define a shortcode is to register a callback with the parser that will be called whenever a
shortcode is encountered. This callback will return a string to replace the shortcode with.
If the shortcode is used for template placeholders of type `HTMLText` or `HTMLVarchar`,
the returned value should be valid HTML
To register a shortcode you call:
ShortcodeParser::get('default')->register('my_shortcode', <callback>);
These parameters are passed to the callback:
- Any parameters attached to the shortcode as an associative array (keys are lower-case).
- Any content enclosed within the shortcode (if it is an enclosing shortcode). Note that any content within this
will not have been parsed, and can optionally be fed back into the parser.
- The ShortcodeParser instance used to parse the content.
- The shortcode tag name that was matched within the parsed content.
## Example: Google Maps Iframe by Address
To demonstrate how easy it is to build custom shortcodes, we'll build one to display
a Google Map based on a provided address. Format:
[googlemap,width=500,height=300]97-99 Courtenay Place, Wellington, New Zealand[/googlemap]
So we've got the address as "content" of our new `googlemap` shortcode tags,
plus some `width` and `height` arguments. We'll add defaults to those in our shortcode parser so they're optional.
:::php
ShortcodeParser::get('default')->register('googlemap', function($arguments, $address, $parser, $shortcode) {
$iframeUrl = sprintf(
'http://maps.google.com/maps?q=%s&amp;hnear=%s&amp;ie=UTF8&hq=&amp;t=m&amp;z=14&amp;output=embed',
urlencode($address),
urlencode($address)
);
$width = (isset($args['width']) && $args['width']) ? $args['width'] : 400;
$height = (isset($args['height']) && $args['height']) ? $args['height'] : 300;
return sprintf(
'<iframe width="%d" height="%d" src="%s" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>',
$width,
$height,
$iframeUrl
);
});
The hard bits are taken care of (parsing out the shortcodes), everything we need to do is a bit of string replacement.
CMS users still need to remember the specific syntax, but these shortcodes can form the basis
for more advanced editing interfaces (with visual placeholders). See the built-in `[embed]` shortcode as an example
for coupling shortcodes with a form to create and edit placeholders.
## Built-in Shortcodes
SilverStripe comes with several shortcode parsers already.
### Links
Internal page links keep references to their database IDs rather than
the URL, in order to make these links resilient against moving the target page to a different
location in the page tree. This is done through the `[sitetree_link]` shortcode, which
takes an `id` parameter. Example: `<a href="[sitetree_link,id=99]">`
Links to internal `File` database records work exactly the same, but with the `[file_link]` shortcode.
### Media (Photo, Video and Rich Content)
Many media formats can be embedded into websites through the `<object>`
tag, but some require plugins like Flash or special markup and attributes.
OEmbed is a standard to discover these formats based on a simple URL,
for example a Youtube link pasted into the "Insert Media" form of the CMS.
Since TinyMCE can't represent all these varations, we're showing a placeholder
instead, and storing the URL with a custom `[embed]` shortcode.
Example: `.[embed width=480 height=270 class=left thumbnail=http://i1.ytimg.com/vi/lmWeD-vZAMY/hqdefault.jpg?r=8767]http://www.youtube.com/watch?v=lmWeD-vZAMY[/embed]`
## Syntax
* Unclosed - `[shortcode]`
* Explicitly closed - `[shortcode/]`
* With parameters, mixed quoting - `[shortcode parameter=value parameter2='value2' parameter3="value3"]`
* Old style parameter separation - `[shortcode,parameter=value,parameter2='value2',parameter3="value3"]`
* With contained content & closing tag - `[shortcode]Enclosed Content[/shortcode]`
* Escaped (will output `[just] [text]` in response) - `[[just] [[text]]`
### Attribute and element scope
HTML with unprocessed shortcodes in it is still valid HTML. As a result, shortcodes can be in two places in HTML:
- In an attribute value, like so:
<a title="[title]">link</a>
- In an element's text, like so:
<p>
Some text [shortcode] more text
</p>
- In an attribute value, like so: `<a title="[title]">link</a>`
- In an element's text, like so: `<p>Some text [shortcode] more text</p>`
The first is called "element scope" use, the second "attribute scope"
@ -37,11 +148,8 @@ change the name of a tag. These usages are forbidden:
<a [titleattribute]>link</a>
Also note:
- you may need to escape text inside attributes `>` becomes `&gt;` etc
- you can include HTML tags inside a shortcode tag, but you need to be careful of nesting to ensure you don't
You may need to escape text inside attributes `>` becomes `&gt;`,
You can include HTML tags inside a shortcode tag, but you need to be careful of nesting to ensure you don't
break the output
Good:
@ -61,12 +169,12 @@ Bad:
[/shortcode]
</p>
## Location
### Location
Element scoped shortcodes have a special ability to move the location they are inserted at to comply with
HTML lexical rules. Take for example this basic paragraph tag:
<p><a href="#">Head [figure src="assets/a.jpg" caption="caption"] Tail</a></p>
<p><a href="#">Head [figure,src="assets/a.jpg",caption="caption"] Tail</a></p>
When converted naively would become
@ -83,43 +191,11 @@ When the location attribute is "leftAlone" or "center" then the DOM is split aro
<p><a href="#">Head </a></p><figure><img src="assets/a.jpg" /><figcaption>caption</figcaption></figure><p><a href="#"> Tail</a></p>
## Defining Custom Shortcodes
All you need to do to define a shortcode is to register a callback with the parser that will be called whenever a
shortcode is encountered. This callback will return a string to replace the shortcode with.
:::php
public static function my_shortcode_handler($attributes, $enclosedContent, $parser, $tagName) {
// This simple callback simply converts the shortcode to a span.
return "<span class=\"$tagName\">$enclosedContent</span>";
}
The parameters passed to the callback are, in order:
* Any parameters attached to the shortcode as an associative array (keys are lower-case).
* Any content enclosed within the shortcode (if it is an enclosing shortcode). Note that any content within this will
not have been parsed, and can optionally be fed back into the parser.
* The ShortcodeParser instance used to parse the content.
* The shortcode tag name that was matched within the parsed content.
For the shortcode to work, you need to register it with the `ShortcodeParser`. Assuming you've placed the
callback function in the `Page` class, you would need to make the following call from `_config.php`:
:::php
ShortcodeParser::get('default')->register(
'shortcode_tag_name',
array('Page', 'my_shortcode_handler')
);
An example result of installing such a shortcode would be that the string `[shortcode_tag_name]Testing
testing[/shortcode_tag_name]` in the page *Content* would be replaced with the `<span class="shortcode_tag_name">Testing
testing</span>`.
### Parameter values
Here is a summary of the callback parameter values based on some example shortcodes.
#### Short
Short
[my_shortcodes]
@ -128,7 +204,7 @@ Here is a summary of the callback parameter values based on some example shortco
$parser => ShortcodeParser instance
$tagName => 'my_shortcode'
#### Short with attributes
Short with attributes
[my_shortcode,attribute="foo",other="bar"]
@ -137,7 +213,7 @@ Here is a summary of the callback parameter values based on some example shortco
$parser => ShortcodeParser instance
$tagName => 'my_shortcode'
#### Long with attributes
Long with attributes
[my_shortcode,attribute="foo"]content[/my_shortcode]
@ -146,11 +222,6 @@ Here is a summary of the callback parameter values based on some example shortco
$parser => ShortcodeParser instance
$tagName => 'my_shortcode'
## Inbuilt Shortcodes
All internal links inserted via the CMS into a content field are in the form `<a href="[sitetree_link,id=n]">`. At
runtime this is replaced by a plain link to the page with the ID in question.
## Limitations
Since the shortcode parser is based on a simple regular expression it cannot properly handle nested shortcodes. For
@ -161,3 +232,7 @@ example the below code will not work as expected:
[/shortcode]
The parser will raise an error if it can not find a matching opening tag for any particular closing tag
## Related
* [Wordpress implementation](http://codex.wordpress.org/Shortcode_API)

View File

@ -1,143 +0,0 @@
# Shortcodes: Flexible Content Embedding
## Overview
The `[api:ShortcodeParser]` API is simple parser that allows you to map specifically
formatted content to a callback to transform them into something else.
You might know this concept from forum software which don't allow you to insert
direct HTML, instead resorting to a custom syntax.
In the CMS, authors often want to insert content elements which go beyond
standard formatting, at an arbitrary position in their WYSIWYG editor.
Shortcodes are a semi-technical solution for this. A good example would
be embedding a 3D file viewer or a Google Map at a certain location.
Here's some syntax variations:
[myshortcode]
[myshortcode /]
[myshortcode,myparameter="value"]
[myshortcode,myparameter="value"]Enclosed Content[/myshortcode]
## Usage
In its most basic form, you can invoke the `[api:ShortcodeParser]` directly:
:::php
ShortcodeParser::get_active()->parse($myvalue);
In addition, shortcodes are automatically parsed on any database field which is declared
as `[api:HTMLValue]` or `[api:HTMLText]`, when rendered into a template.
This means you can use shortcodes on common fields like `SiteTree.Content`,
and any other `[api:DataObject::$db]` definitions of these types.
In order to allow shortcodes in your own template placeholders,
ensure they're casted correctly:
:::php
class MyObject extends DataObject {
static $db = array('Content' => 'HTMLText');
static $casting = array('ContentHighlighted' => 'HTMLText');
public function ContentHighlighted($term) {
return str_replace($term, "<em>$term</em>", $this->Content);
}
}
There is currently no way to allow shortcodes directly in template markup
(as opposed to return values of template placeholders).
## Defining Custom Shortcodes
All you need to do to define a shortcode is to register a callback with the parser that will be called whenever a
shortcode is encountered. This callback will return a string to replace the shortcode with.
If the shortcode is used for template placeholders of type `HTMLText` or `HTMLVarchar`,
the returned value should be valid HTML
To register a shortcode you call:
ShortcodeParser::get('default')->register('myshortcode', <callback>);
These parameters are passed to the callback:
- Any parameters attached to the shortcode as an associative array (keys are lower-case).
- Any content enclosed within the shortcode (if it is an enclosing shortcode). Note that any content within this
will not have been parsed, and can optionally be fed back into the parser.
- The ShortcodeParser instance used to parse the content.
- The shortcode tag name that was matched within the parsed content.
## Example: Google Maps Iframe by Address
To demonstrate how easy it is to build custom shortcodes, we'll build one to display
a Google Map based on a provided address. Format:
[googlemap,width=500,height=300]97-99 Courtenay Place, Wellington, New Zealand[/googlemap]
So we've got the address as "content" of our new `googlemap` shortcode tags,
plus some `width` and `height` arguments. We'll add defaults to those in our shortcode parser so they're optional.
:::php
ShortcodeParser::get('default')->register('googlemap', function($arguments, $address, $parser, $shortcode) {
$iframeUrl = sprintf(
'http://maps.google.com/maps?q=%s&amp;hnear=%s&amp;ie=UTF8&hq=&amp;t=m&amp;z=14&amp;output=embed',
urlencode($address),
urlencode($address)
);
$width = (isset($args['width']) && $args['width']) ? $args['width'] : 400;
$height = (isset($args['height']) && $args['height']) ? $args['height'] : 300;
return sprintf(
'<iframe width="%d" height="%d" src="%s" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>',
$width,
$height,
$iframeUrl
);
});
The hard bits are taken care of (parsing out the shortcodes), everything we need to do is a bit of string replacement.
CMS users still need to remember the specific syntax, but these shortcodes can form the basis
for more advanced editing interfaces (with visual placeholders). See the built-in `[embed]` shortcode as an example
for coupling shortcodes with a form to create and edit placeholders.
## Built-in Shortcodes
SilverStripe comes with several shortcode parsers already.
### Links
Internal page links keep references to their database IDs rather than
the URL, in order to make these links resilient against moving the target page to a different
location in the page tree. This is done through the `[sitetree_link]` shortcode, which
takes an `id` parameter. Example: `<a href="[sitetree_link,id=99]">`
Links to internal `File` database records work exactly the same, but with the `[file_link]` shortcode.
### Media (Photo, Video and Rich Content)
Many media formats can be embedded into websites through the `<object>`
tag, but some require plugins like Flash or special markup and attributes.
OEmbed is a standard to discover these formats based on a simple URL,
for example a Youtube link pasted into the "Insert Media" form of the CMS.
Since TinyMCE can't represent all these varations, we're showing a placeholder
instead, and storing the URL with a custom `[embed]` shortcode.
Example: `.[embed width=480 height=270 class=left thumbnail=http://i1.ytimg.com/vi/lmWeD-vZAMY/hqdefault.jpg?r=8767]http://www.youtube.com/watch?v=lmWeD-vZAMY[/embed]`
## Limitations
Since the shortcode parser is based on a simple regular expression it cannot properly handle nested shortcodes. For
example the below code will not work as expected:
[shortcode]
[shortcode][/shortcode]
[/shortcode]
The parser will recognise this as:
[shortcode]
[shortcode]
[/shortcode]
## Related
* [Wordpress implementation](http://codex.wordpress.org/Shortcode_API)