Browse Source

Initial shortcode implementation

master
Patrick Ward 9 years ago
parent
commit
68bb5b0e24
  1. 90
      Plugin.php
  2. 62
      README.md
  3. 153
      classes/Shortcode.php
  4. 17
      classes/ShortcodeFacade.php
  5. 35
      classes/ShortcodeServiceProvider.php
  6. 26
      composer.json
  7. 169
      composer.lock
  8. 17
      models/Settings.php
  9. 10
      models/settings/fields.yaml
  10. 91
      tests/ShortcodeTest.php

90
Plugin.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'
]
];
}
}

62
README.md

@ -1,2 +1,62 @@
# oc-shortcode-plugin
# Shortcodes for October CMS
Adds the ability to use shortcodes within 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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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;
}
}
Loading…
Cancel
Save