Patrick Ward
9 years ago
10 changed files with 669 additions and 1 deletions
-
90Plugin.php
-
62README.md
-
153classes/Shortcode.php
-
17classes/ShortcodeFacade.php
-
35classes/ShortcodeServiceProvider.php
-
26composer.json
-
169composer.lock
-
17models/Settings.php
-
10models/settings/fields.yaml
-
91tests/ShortcodeTest.php
@ -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' |
|||
] |
|||
]; |
|||
|
|||
} |
|||
|
|||
} |
@ -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); |
|||
}); |
@ -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); |
|||
} |
|||
} |
|||
|
@ -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'; |
|||
} |
|||
} |
|||
|
@ -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'); |
|||
} |
|||
|
|||
} |
|||
|
@ -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\\": "" |
|||
} |
|||
} |
|||
} |
@ -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": [] |
|||
} |
@ -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'; |
|||
|
|||
|
|||
} |
@ -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 |
@ -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; |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue