Initial shortcode implementation
This commit is contained in:
90
Plugin.php
Normal file
90
Plugin.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php namespace Sensory5\Shortcode;
|
||||
|
||||
use App;
|
||||
use Str;
|
||||
use Html;
|
||||
use Event;
|
||||
use System\Classes\PluginBase;
|
||||
use Illuminate\Foundation\AliasLoader;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
use Sensory5\Shortcode\Models\Settings;
|
||||
|
||||
/**
|
||||
* Shortcode Plugin Information File
|
||||
*/
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns information about this plugin.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function pluginDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Shortcode',
|
||||
'description' => 'Shortcode integration for OctoberCMS.',
|
||||
'author' => 'Sensory 5',
|
||||
'icon' => 'icon-code'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register service provider, Twig extensions, and alias facade.
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
// Service provider
|
||||
App::register('\Sensory5\Shortcode\Classes\ShortcodeServiceProvider');
|
||||
|
||||
// Register alias
|
||||
$alias = AliasLoader::getInstance();
|
||||
$alias->alias('Shortcode', '\Sensory5\Shortcode\Classes\ShortcodeFacade');
|
||||
|
||||
// Enable shortcodes on all pages if requested
|
||||
if (Settings::get('enable_on_render', false))
|
||||
{
|
||||
Event::listen('cms.page.render', function($controller, $content) {
|
||||
|
||||
return \Shortcode::parse($content);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register twig filters
|
||||
*/
|
||||
public function registerMarkupTags()
|
||||
{
|
||||
|
||||
return [
|
||||
'filters' => [ 'shortcode' => ['\Shortcode', 'parse'] ],
|
||||
'functions' => ['shortcode' => ['\Shortcode', 'parse'] ]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register backend settings
|
||||
*/
|
||||
public function registerSettings()
|
||||
{
|
||||
|
||||
return [
|
||||
'settings' => [
|
||||
'label' => 'Shortcode Settings',
|
||||
'description' => 'Manage shortcode settings',
|
||||
'category' => 'Shortcodes',
|
||||
'icon' => 'icon-code',
|
||||
'class' => 'Sensory5\Shortcode\Models\Settings',
|
||||
'order' => 600,
|
||||
'keywords' => 'shortcode shortcodes'
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
}
|
62
README.md
62
README.md
@ -1,2 +1,62 @@
|
||||
# oc-shortcode-plugin
|
||||
# Shortcodes for October CMS
|
||||
|
||||
Adds the ability to use shortcodes within October CMS
|
||||
|
||||
### Add new shortcodes
|
||||
|
||||
Add the shortcode in the `boot` function of a plugin.
|
||||
|
||||
Then, use the provided facade to add new shortcodes in your own plugins:
|
||||
|
||||
\Shortcode::add('code', function(ShortcodeInterface $s) {
|
||||
$text = "<h2>Shortcode Name: {$s->getName()}</h2>";
|
||||
$text .= "<p>Shortcode Parameter: {$s->getParameter('param', 'Not Found')}</p>";
|
||||
$text .= "<p>Shortcode Content: {$s->getContent()}</p>";
|
||||
return $text;
|
||||
});
|
||||
|
||||
The above registration would enable the following shortcode to be used:
|
||||
|
||||
[code param="Parameter Value"] Inside Content [/code]
|
||||
|
||||
### Use the shortcode within a page or blog post:
|
||||
|
||||
The usual shortcode syntax is supported via the [Thunderer\Shortcode](https://github.com/thunderer/Shortcode) project.
|
||||
|
||||
[code]
|
||||
[code argument="value"]
|
||||
[code novalue argument=simple other="complex value"]
|
||||
[code]content[/code]
|
||||
[code argument="value"]content[/code]
|
||||
|
||||
### Enable shortcodes on all pages
|
||||
|
||||
To enable shortcodes on all page rendering, go to **Shortcode Settings** in the admin settings panel and check "Enable Shortcodes on all page rendering".
|
||||
|
||||
### Using filters and functions
|
||||
|
||||
If you don't want to enable shortcodes on all page rendering, you can use the built-in filter or function.
|
||||
|
||||
To use the `shortcode` filter within a blog post or page, add the `shortcode` filter before any `raw` filtering.
|
||||
|
||||
<div class="cp-post-content">{{ post.content_html|shortcode|raw }}</div>
|
||||
|
||||
To use the `shortcode` function within a layout and against the October CMS `page` tag, change the `page` tag from a token to a function:
|
||||
|
||||
{% page %}
|
||||
|
||||
Becomes:
|
||||
|
||||
{{ shortcode(page()) }}
|
||||
|
||||
-- or --
|
||||
|
||||
{{ page()|shortcode }}
|
||||
|
||||
### Strip Shortcodes
|
||||
|
||||
You can strip shortcodes from text using the `Shortcode::strip` function. For example, when using with the `Sensory5\BlogExtension` plugin, you can strip shortcodes from the summary using the following code:
|
||||
|
||||
Event::listen('sensory5.blog.summary', function($content) {
|
||||
return Str::limit(Html::strip(\Shortcode::strip($content)), 600);
|
||||
});
|
||||
|
153
classes/Shortcode.php
Normal file
153
classes/Shortcode.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php namespace Sensory5\Shortcode\Classes;
|
||||
|
||||
/**
|
||||
* Shortcodes
|
||||
*
|
||||
* Original idea from Pingpong Labs (https://github.com/pingpong-labs/shortcode)
|
||||
*
|
||||
* Changed to fit closer to the Thunderer\Shortcode syntax.
|
||||
*/
|
||||
|
||||
use Countable;
|
||||
use Thunder\Shortcode\HandlerContainer\HandlerContainer;
|
||||
use Thunder\Shortcode\Parser\RegexParser;
|
||||
use Thunder\Shortcode\Processor\Processor;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class Shortcode implements Countable
|
||||
{
|
||||
/** @var HandlerContainer */
|
||||
private $handlers;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->handlers = new HandlerContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names for all registered shortcodes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNames()
|
||||
{
|
||||
return $this->handlers->getNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new shortcode to the handler container.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $callback
|
||||
*/
|
||||
public function add($name, $callback)
|
||||
{
|
||||
$this->handlers->add($name, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified shortcode name from the handler.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if ($this->exists($name)) {
|
||||
$this->handlers->remove($name);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered shortcodes
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function destroyAll()
|
||||
{
|
||||
$this->handlers = new HandlerContainer();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip any shortcodes from the content.
|
||||
*
|
||||
* @param string $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function strip($content)
|
||||
{
|
||||
$handlers = new HandlerContainer();
|
||||
$handlers->setDefault(function(ShortcodeInterface $s) { return $s->getContent(); });
|
||||
$processor = new Processor(new RegexParser(), $handlers);
|
||||
|
||||
return $processor->process($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count from all shortcodes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->handlers->getNames());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true is the given name exist in shortcodes array.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($name)
|
||||
{
|
||||
return $this->handlers->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true is the given content contains the named shortcode.
|
||||
*
|
||||
* @param string $content
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function contains($content, $name)
|
||||
{
|
||||
$hasShortcode = false;
|
||||
|
||||
$handlers = new HandlerContainer();
|
||||
$handlers->setDefault(function(ShortcodeInterface $s) use($name, &$hasShortcode) {
|
||||
if($s->getName() === $name) {
|
||||
$hasShortcode = true;
|
||||
}
|
||||
});
|
||||
$processor = new Processor(new RegexParser(), $handlers);
|
||||
$processor->process($content);
|
||||
|
||||
return $hasShortcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse content and replace parts of it using registered handlers
|
||||
*
|
||||
* @param $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parse($content)
|
||||
{
|
||||
$processor = new Processor(new RegexParser(), $this->handlers);
|
||||
|
||||
return $processor->process($content);
|
||||
}
|
||||
}
|
||||
|
17
classes/ShortcodeFacade.php
Normal file
17
classes/ShortcodeFacade.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php namespace Sensory5\Shortcode\Classes;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class ShortcodeFacade extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'shortcode';
|
||||
}
|
||||
}
|
||||
|
35
classes/ShortcodeServiceProvider.php
Normal file
35
classes/ShortcodeServiceProvider.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php namespace Sensory5\Shortcode\Classes;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class ShortcodeServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if loading of the provider is deferred.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $defer = false;
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app['shortcode'] = $this->app->share(function ($app) {
|
||||
return new Shortcode();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provides()
|
||||
{
|
||||
return array('shortcode');
|
||||
}
|
||||
|
||||
}
|
||||
|
26
composer.json
Normal file
26
composer.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "sensory5/oc-shortcode-plugin",
|
||||
"description": "Adds the ability to use shortcodes within October CMS",
|
||||
"type": "october-plugin",
|
||||
"extra": {
|
||||
"installer-name": "shortcode"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Patrick Ward",
|
||||
"email": "patrick@sensory5.com"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"composer/installers": "~1.0",
|
||||
"thunderer/shortcode": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sensory5\\Shortcode\\": ""
|
||||
}
|
||||
}
|
||||
}
|
169
composer.lock
generated
Normal file
169
composer.lock
generated
Normal file
@ -0,0 +1,169 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "1af5d57fe99292fd0a02e59af2fe9fd5",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/installers",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/installers.git",
|
||||
"reference": "e420b539e8d7b38b7c6f3f99dccc0386bd3dfe41"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/installers/zipball/e420b539e8d7b38b7c6f3f99dccc0386bd3dfe41",
|
||||
"reference": "e420b539e8d7b38b7c6f3f99dccc0386bd3dfe41",
|
||||
"shasum": ""
|
||||
},
|
||||
"replace": {
|
||||
"roundcube/plugin-installer": "*",
|
||||
"shama/baton": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "1.0.*@dev",
|
||||
"phpunit/phpunit": "4.1.*"
|
||||
},
|
||||
"type": "composer-installer",
|
||||
"extra": {
|
||||
"class": "Composer\\Installers\\Installer",
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Composer\\Installers\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kyle Robinson Young",
|
||||
"email": "kyle@dontkry.com",
|
||||
"homepage": "https://github.com/shama"
|
||||
}
|
||||
],
|
||||
"description": "A multi-framework Composer library installer",
|
||||
"homepage": "http://composer.github.com/installers/",
|
||||
"keywords": [
|
||||
"Craft",
|
||||
"Dolibarr",
|
||||
"Hurad",
|
||||
"MODX Evo",
|
||||
"OXID",
|
||||
"SMF",
|
||||
"Thelia",
|
||||
"WolfCMS",
|
||||
"agl",
|
||||
"aimeos",
|
||||
"annotatecms",
|
||||
"bitrix",
|
||||
"cakephp",
|
||||
"chef",
|
||||
"codeigniter",
|
||||
"concrete5",
|
||||
"croogo",
|
||||
"dokuwiki",
|
||||
"drupal",
|
||||
"elgg",
|
||||
"fuelphp",
|
||||
"grav",
|
||||
"installer",
|
||||
"joomla",
|
||||
"kohana",
|
||||
"laravel",
|
||||
"lithium",
|
||||
"magento",
|
||||
"mako",
|
||||
"mediawiki",
|
||||
"modulework",
|
||||
"moodle",
|
||||
"phpbb",
|
||||
"piwik",
|
||||
"ppi",
|
||||
"puppet",
|
||||
"roundcube",
|
||||
"shopware",
|
||||
"silverstripe",
|
||||
"symfony",
|
||||
"typo3",
|
||||
"wordpress",
|
||||
"zend",
|
||||
"zikula"
|
||||
],
|
||||
"time": "2015-06-13 15:30:38"
|
||||
},
|
||||
{
|
||||
"name": "thunderer/shortcode",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thunderer/Shortcode.git",
|
||||
"reference": "8a57fc61058e616279e758d0437fb5c525fdf837"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thunderer/Shortcode/zipball/8a57fc61058e616279e758d0437fb5c525fdf837",
|
||||
"reference": "8a57fc61058e616279e758d0437fb5c525fdf837",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "if you want to use XML serializer",
|
||||
"ext-json": "if you want to use JSON serializer",
|
||||
"symfony/yaml": "if you want to use YAML serializer"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Thunder\\Shortcode\\": "src/",
|
||||
"Thunder\\Shortcode\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tomasz Kowalczyk",
|
||||
"email": "tomasz@kowalczyk.cc"
|
||||
}
|
||||
],
|
||||
"description": "Advanced shortcode (BBCode) parser and engine for PHP",
|
||||
"keywords": [
|
||||
"bbcode",
|
||||
"engine",
|
||||
"library",
|
||||
"parser",
|
||||
"shortcode"
|
||||
],
|
||||
"time": "2015-10-19 19:17:59"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"thunderer/shortcode": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"platform-dev": []
|
||||
}
|
17
models/Settings.php
Normal file
17
models/Settings.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php namespace Sensory5\Shortcode\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Settings extends Model
|
||||
{
|
||||
|
||||
public $implement = ['System.Behaviors.SettingsModel'];
|
||||
|
||||
// Unique code
|
||||
public $settingsCode = 'sensory5_shortcode_settings';
|
||||
|
||||
// Reference to field configuration
|
||||
public $settingsFields = 'fields.yaml';
|
||||
|
||||
|
||||
}
|
10
models/settings/fields.yaml
Normal file
10
models/settings/fields.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
# ===================================
|
||||
# Form Field Definitions
|
||||
# ===================================
|
||||
|
||||
fields:
|
||||
enable_on_render:
|
||||
label: Enable Shortcodes on all page rendering
|
||||
comment: Checking this enables shortcodes for all page rendering and does not require the use of twig filters or functions.
|
||||
type: checkbox
|
||||
default: 0
|
91
tests/ShortcodeTest.php
Normal file
91
tests/ShortcodeTest.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php namespace Sensory5\Shortcode;
|
||||
|
||||
use Sensory5\Shortcode\Classes\Shortcode;
|
||||
use Thunder\Shortcode\HandlerContainer\HandlerContainer;
|
||||
use Thunder\Shortcode\Parser\RegexParser;
|
||||
use Thunder\Shortcode\Processor\Processor;
|
||||
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
||||
|
||||
class ShortcodeTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideTexts
|
||||
*/
|
||||
public function testParse($text, $expect)
|
||||
{
|
||||
$this->assertSame($expect, $this->getShortcode()->parse($text));
|
||||
}
|
||||
|
||||
public function provideTexts()
|
||||
{
|
||||
return [
|
||||
['[name]', 'name'],
|
||||
['[content]', ''],
|
||||
['[content]thunder[/content]', 'thunder'],
|
||||
['[content][name][/content]', 'name'],
|
||||
['[nc][name][/nc]', 'nc: name'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testCount()
|
||||
{
|
||||
$this->assertSame(3, $this->getShortcode()->count());
|
||||
}
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
$this->assertSame(['name', 'content', 'nc'], $this->getShortcode()->all());
|
||||
}
|
||||
|
||||
public function testUnregister()
|
||||
{
|
||||
$this->assertSame('[name]', $this->getShortcode()->unregister('name')->parse('[name]'));
|
||||
}
|
||||
|
||||
public function testDestroy()
|
||||
{
|
||||
$this->assertSame('[name]', $this->getShortcode()->destroy()->parse('[name]'));
|
||||
}
|
||||
|
||||
public function testStrip()
|
||||
{
|
||||
$this->assertSame('', $this->getShortcode()->strip('[name]'));
|
||||
$this->assertSame('x y', $this->getShortcode()->strip('x [name]y'));
|
||||
$this->assertSame('x a a y', $this->getShortcode()->strip('x [name] a [content /] a [/name] y'));
|
||||
}
|
||||
|
||||
public function testExists()
|
||||
{
|
||||
$shortcode = $this->getShortcode();
|
||||
|
||||
$this->assertTrue($shortcode->exists('name'));
|
||||
$this->assertTrue($shortcode->exists('content'));
|
||||
$this->assertTrue($shortcode->exists('nc'));
|
||||
$this->assertFalse($shortcode->exists('invalid'));
|
||||
}
|
||||
|
||||
public function testContains()
|
||||
{
|
||||
$shortcode = $this->getShortcode();
|
||||
|
||||
$this->assertTrue($shortcode->contains('[name]', 'name'));
|
||||
$this->assertFalse($shortcode->contains('[x]', 'name'));
|
||||
}
|
||||
|
||||
private function getShortcode()
|
||||
{
|
||||
$shortcode = new Shortcode();
|
||||
|
||||
$shortcode->register('name', function(ShortcodeInterface $s) {
|
||||
return $s->getName();
|
||||
});
|
||||
$shortcode->register('content', function(ShortcodeInterface $s) {
|
||||
return $s->getContent();
|
||||
});
|
||||
$shortcode->register('nc', function(ShortcodeInterface $s) {
|
||||
return $s->getName().': '.$s->getContent();
|
||||
});
|
||||
|
||||
return $shortcode;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user