├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── .styleci.yml
├── composer.json
├── config
└── shortcodes.php
├── contributing.md
├── license.md
├── phpunit.xml
├── readme.md
├── src
├── Commands
│ └── MakeShortcodeCommand.php
├── Debugbar
│ └── ShortcodesCollector.php
├── Facades
│ └── Shortcodes.php
├── LaravelShortcodesServiceProvider.php
├── Manager.php
├── Renderer.php
├── Shortcode.php
├── ShortcodeContract.php
├── Shortcodes
│ └── BShortcode.php
├── View
│ ├── Factory.php
│ └── View.php
└── helpers.php
├── stubs
└── shortcode.stub
├── tests
├── Resources
│ ├── BShortcode.php
│ ├── CastsShortcode.php
│ ├── ExceptionShortcode.php
│ ├── ExceptionViewShortcode.php
│ ├── HrShortcode.php
│ └── ValidationShortcode.php
├── TestCase.php
├── Unit
│ ├── BladeTest.php
│ ├── HelpersTest.php
│ ├── ManagerTest.php
│ ├── ShortcodeTest.php
│ └── ViewTest.php
└── views
│ ├── bold.blade.php
│ ├── directive-block.blade.php
│ ├── directive-inline.blade.php
│ ├── exception.blade.php
│ └── shortcode-exception.blade.php
└── views
└── b.blade.php
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on: [push]
3 | jobs:
4 | run-tests:
5 | runs-on: ubuntu-latest
6 | name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
7 | strategy:
8 | fail-fast: true
9 | matrix:
10 | php: [ 7.4, 8.0, 8.1 ]
11 | laravel: [ 6.*, 8.*, 9.* ]
12 | exclude:
13 | - php: 8.0
14 | laravel: 6.*
15 | - php: 8.1
16 | laravel: 6.*
17 | - php: 7.4
18 | laravel: 9.*
19 | include:
20 | - aravel: 6.*
21 | testbench: 4.*
22 | phpunit: 8.*
23 | - laravel: 8.*
24 | testbench: 6.*
25 | phpunit: 9.*
26 | - laravel: 9.*
27 | testbench: 7.*
28 | phpunit: 9.*
29 | steps:
30 | - name: Check out repository code
31 | uses: actions/checkout@v2
32 | - name: Setup PHP
33 | uses: shivammathur/setup-php@v2
34 | with:
35 | php-version: ${{ matrix.php }}
36 | - name: Install dependencies
37 | run: |
38 | composer require "illuminate/support:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "phpunit/phpunit:${{ matrix.phpunit }}" --no-interaction --no-update
39 | composer update --prefer-stable --prefer-dist --no-interaction --no-suggest
40 | - name: Cache dependencies
41 | uses: actions/cache@v1
42 | with:
43 | path: ~/.composer/cache/files
44 | key: dependencies-${{ matrix.dependency-version }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
45 | - name: Execute tests
46 | run: vendor/bin/phpunit
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | /vendor
3 | npm-debug.log
4 | yarn-error.log
5 | composer.lock
6 | .phpunit.result.cache
7 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: laravel
2 |
3 | finder:
4 | not-name:
5 | - "Renderer.php"
6 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vedmant/laravel-shortcodes",
3 | "description": "Wordress like shortcodes for Laravel",
4 | "license": "MIT",
5 | "authors": [
6 | {
7 | "name": "Vedmant",
8 | "email": "vedmant@gmail.com",
9 | "homepage": "https://vedmant.com/laravel-shortcodes"
10 | }
11 | ],
12 | "homepage": "https://github.com/vedmant/laravel-shortcodes",
13 | "keywords": ["Laravel", "Shortcodes"],
14 | "require": {
15 | "php": ">=7.0.0",
16 | "illuminate/contracts": ">=5.5.0",
17 | "illuminate/view": ">=5.5.0",
18 | "illuminate/support": ">=5.5.0"
19 | },
20 | "require-dev": {
21 | "phpunit/phpunit": "9.*",
22 | "mockery/mockery": "^1.2",
23 | "orchestra/testbench": "^4",
24 | "sempro/phpunit-pretty-print": "^1.0"
25 | },
26 | "autoload": {
27 | "files": [
28 | "src/helpers.php"
29 | ],
30 | "psr-4": {
31 | "Vedmant\\LaravelShortcodes\\": "src/"
32 | }
33 | },
34 | "autoload-dev": {
35 | "psr-4": {
36 | "Vedmant\\LaravelShortcodes\\Tests\\": "tests"
37 | }
38 | },
39 | "extra": {
40 | "laravel": {
41 | "providers": [
42 | "Vedmant\\LaravelShortcodes\\LaravelShortcodesServiceProvider"
43 | ],
44 | "aliases": {
45 | "FeedReader": "Vedmant\\LaravelShortcodes\\Facades\\FeedReader"
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/config/shortcodes.php:
--------------------------------------------------------------------------------
1 | true,
16 |
17 | /*
18 | |--------------------------------------------------------------------------
19 | | Automatically render views
20 | |--------------------------------------------------------------------------
21 | |
22 | | If it should automatically render shortcodes in views.
23 | |
24 | */
25 |
26 | 'render_views' => true,
27 |
28 | /*
29 | |--------------------------------------------------------------------------
30 | | Laravel Debugbar integration
31 | |--------------------------------------------------------------------------
32 | |
33 | | If it should integrate in the Laravel Debug Bar.
34 | |
35 | */
36 |
37 | 'debugbar' => true,
38 |
39 | ];
40 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are welcome and will be fully credited.
4 |
5 | Contributions are accepted via Pull Requests on [Github](https://github.com/vedmant/laravelshortcodes).
6 |
7 | ## Pull Requests
8 |
9 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests.
10 |
11 | - **Document any change in behaviour** - Make sure the `readme.md` and any other relevant documentation are kept up-to-date.
12 |
13 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
14 |
15 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
16 |
17 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
18 |
19 |
20 | **Happy coding**!
21 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2019 Vedmat, Inc. http://vedmant.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | ./tests/Unit
15 |
16 |
17 |
18 |
19 | src/
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Laravel Shortcodes
2 |
3 | [![Latest Version on Packagist][ico-version]][link-packagist]
4 | [![Software License][ico-license]](license.md)
5 | [![Total Downloads][ico-downloads]][link-downloads]
6 | 
7 | [](https://styleci.io/repos/182276041)
8 |
9 | Wordpress based Shortcodes for [Laravel Framework](https://github.com/laravel/laravel) with shared variables, debugbar integration,
10 | flexible configurations and other useful features.
11 |
12 | Build powerful and simple layouts using shortcodes in the content or views like this:
13 |
14 | ```php
15 | [b]Bold text[/b]
16 |
17 | [row]
18 | [col md=8]
19 | [posts_list types="post,gallery" show_tags="yes"]
20 | [/col]
21 | [col md=4]
22 | [poll id="1"]
23 | [user_info username="test_user" website="mywebsite.com" active="yes"]
24 | [last_free_post title="Free Posts"]
25 | [/col]
26 | [/row]
27 | ```
28 |
29 | ## Installation
30 |
31 | Via Composer
32 |
33 | ``` bash
34 | $ composer require vedmant/laravel-shortcodes
35 | ```
36 |
37 | ## Configuraton
38 |
39 | Publish configuration.
40 | ```bash
41 | php artisan vendor:publish --tag=shortcodes
42 | ```
43 |
44 | It will publish configuration file `shortcodes.php`, edit it as needed.
45 |
46 |
47 | ## Usage
48 |
49 |
50 | ### Shortcode class
51 |
52 | Shortcode class should extend abstract \Vedmant\LaravelShortcodes\Shortcode class.
53 |
54 | This packages adds the `make:shortcode` artisan command:
55 | ```bash
56 | php artisan make:shortcode PostsListShortcode
57 | ```
58 | Which generates a shortcode class in the `app/Shortcodes` folder by default.
59 |
60 |
61 | ### Register shortcodes
62 |
63 | You can use `AppServiceProvider::boot` method to register all needed shortcodes.
64 |
65 | Using shortcode class:
66 | ```php
67 | Shortcodes::add('b', BShortcode::class);
68 | ```
69 |
70 | Using shortcode classes in array, preferable for lots of shortcodes:
71 | ```php
72 | Shortcodes::add([
73 | 'a' => AShortcode::class,
74 | 'b' => BShortcode::class,
75 | ]);
76 | ```
77 |
78 | Using closure:
79 | ```php
80 | Shortcodes::add('test', function ($atts, $content, $tag, $manager) {
81 | return new HtmlString('some test shortcode');
82 | });
83 | ```
84 |
85 | ### Render shortcodes
86 |
87 | #### Views auto-render
88 |
89 | By default this package extends the `View` class to parse all shortcodes during views rendering.
90 | This feature can be disabled in the config file: `'render_views' => false`.
91 | For better performance with lots of views it's advised to disable views auto-render.
92 |
93 | #### Enable / disable rendering per view
94 |
95 | Also to enable / disable rendering shortcodes for a specific view you can use:
96 |
97 | ```php
98 | view('some-view')->withShortcodes();
99 | // Or
100 | view('some-view')->withoutShortcodes();
101 | ```
102 |
103 | #### Render shortcodes with the facade
104 |
105 | ```blade
106 | {{ Shortcodes::render('[b]bold[/b]') }}
107 | ```
108 |
109 | #### Render shortcodes with blade directive
110 |
111 | ```blade
112 | @shortcodes
113 | [b class="block"]Content[/b]
114 | @endshortcodes
115 |
116 | Or
117 |
118 | @shortcodes('[b]bold[/b]')
119 | ```
120 |
121 | #### Render shortcodes with `shortcodes()` helper
122 |
123 | ```blade
124 |
125 | {{ shortcodes('[b]bold[/b]') }}
126 |
127 | ```
128 |
129 | ### Shared attributes
130 |
131 | Occasionally, you may need to share a piece of data with all shortcodes that are rendered by your application.
132 | You may do so using the shortode facade's `share` method.
133 | Typically, you should place calls to share in the controller, or within a service provider's boot method.
134 | ```php
135 | Shortcodes::share('post', $post);
136 | ```
137 |
138 | Then you can get shared attributes in the shortcode class:
139 |
140 | ```php
141 | $post = $this->shared('post');
142 | $allShared = $this->shared();
143 | ```
144 |
145 | ### Attribute casting
146 |
147 | The $casts property on your shortcode class provides a convenient method of converting attributes to
148 | common data types. The $casts property should be an array where the key is the name of the attribute
149 | being cast and the value is the type you wish to cast the column to. The supported cast types are:
150 | `int`, `integer`, `real`, `float`, `double`, `boolean`, `array` (comma separated values) and `date`.
151 |
152 | ```php
153 | class YourShortcode extends Shortcode
154 | {
155 | /**
156 | * The attributes that should be cast to native types.
157 | *
158 | * @var array
159 | */
160 | protected $casts = [
161 | 'show_ids' => 'array',
162 | ];
163 | }
164 | ```
165 |
166 | Now the `show_ids` attribute will always be cast to an array when you access it.
167 | (array attributes are casted from comma separated string, eg. "1,2,3").
168 |
169 |
170 | ### Attribute validation
171 |
172 | There is a simple way to validate attributes.
173 | Error messages will be rendered on the shortcode place.
174 | For convenients it will return attributes.
175 |
176 | ```php
177 | class YourShortcode extends Shortcode
178 | {
179 | /**
180 | * Render shortcode
181 | *
182 | * @param string $content
183 | * @return string
184 | */
185 | public function render($content)
186 | {
187 | $atts = $this->validate([
188 | 'post_id' => 'required|numeric|exists:posts,id',
189 | ]);
190 |
191 | //
192 | }
193 | }
194 | ```
195 |
196 | ### Option to not throw exceptions from shortcodes
197 |
198 | There is a useful option to aviod server (500) error for whole page when one of shortocode has thrown an exception.
199 |
200 | To enable it set `'throw_exceptions' => false,` in the `shortcodes.php` config file.
201 |
202 | This will render exception details in the place of a shortcode and will not crash whole page request with 500 error.
203 | It will still log exception to a log file and report to [Sentry](https://sentry.io/) if it's integrated.
204 |
205 |
206 | ### Generate data for documentation
207 |
208 | There can be hundreds of registered shortcodes and having a way to show documentation for all
209 | shortcodes is quite a good feature. There is simple method that will collect descriptions and attributes data
210 | from all registered shortcodes:
211 | ```php
212 | $data = Shortcodes::registeredData();
213 | ```
214 | It returns Collection object with generated data that can be used to generate any help information.
215 |
216 |
217 | ### Integration with Laravel Debugbar
218 |
219 | This packages supports [Laravel Debugbar](https://github.com/barryvdh/laravel-debugbar)
220 | and adds a tab with detailed info about rendered shortcodes.
221 | Integration can be disabled in the config file with option: `'debugbar' => false,`.
222 |
223 |
224 | ## Testing
225 |
226 | ``` bash
227 | $ vendor/bin/phpunit
228 | ```
229 |
230 |
231 | ## TODO
232 |
233 | 1. Add custom widget for debugbar integration
234 | 1. Create performance profile tests, optimize performance
235 |
236 | ## Contributing
237 |
238 | Please see [contributing.md](contributing.md) for details and a todolist.
239 |
240 | ## Security
241 |
242 | If you discover any security related issues, please email vedmant@gmail.com instead of using the issue tracker.
243 |
244 | ## Credits
245 |
246 | - [All Contributors][link-contributors]
247 |
248 | ## License
249 |
250 | MIT. Please see the [license file](license.md) for more information.
251 |
252 | [ico-version]: https://img.shields.io/packagist/v/vedmant/laravel-shortcodes.svg?style=flat-square
253 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
254 | [ico-downloads]: https://img.shields.io/packagist/dt/vedmant/laravel-shortcodes.svg?style=flat-square
255 | [ico-travis]: https://img.shields.io/travis/vedmant/laravel-shortcodes/master.svg?style=flat-square
256 |
257 | [link-packagist]: https://packagist.org/packages/vedmant/laravel-shortcodes
258 | [link-downloads]: https://packagist.org/packages/vedmant/laravel-shortcodes
259 | [link-styleci]: https://github.styleci.io/repos/182276041
260 | [link-author]: https://github.com/vedmant
261 | [link-contributors]: ../../contributors
262 |
--------------------------------------------------------------------------------
/src/Commands/MakeShortcodeCommand.php:
--------------------------------------------------------------------------------
1 | shortcodes[] = $data;
30 | }
31 |
32 | /**
33 | * Returns the list of shortcodes being profiled.
34 | *
35 | * @return array
36 | */
37 | public function getShortcodes(): array
38 | {
39 | return $this->shortcodes;
40 | }
41 |
42 | /**
43 | * Called by the DebugBar when data needs to be collected.
44 | *
45 | * @return array Collected data
46 | */
47 | public function collect()
48 | {
49 | $shortcodes = new Collection($this->shortcodes);
50 |
51 | $shortcodesData = $shortcodes->mapWithKeys(function ($data) {
52 | $time = $this->getDataFormatter()->formatDuration($data['time']);
53 |
54 | return [
55 | "[{$data['tag']}] - {$time}" => $this->getVarDumper()->renderVar($data['shortcode']->atts()),
56 | ];
57 | });
58 |
59 | return [
60 | 'count' => count($this->shortcodes),
61 | 'shortcodes' => $shortcodesData->prepend(
62 | $this->getDataFormatter()->formatDuration($shortcodes->sum('time')),
63 | 'Total time'
64 | ),
65 | ];
66 | }
67 |
68 | /**
69 | * @return string
70 | */
71 | public function getName()
72 | {
73 | return 'shortcodes';
74 | }
75 |
76 | /**
77 | * @return array
78 | */
79 | public function getWidgets()
80 | {
81 | return [
82 | 'shortcodes' => [
83 | 'icon' => 'tags',
84 | 'widget' => 'PhpDebugBar.Widgets.HtmlVariableListWidget',
85 | 'map' => 'shortcodes.shortcodes',
86 | 'default' => '[]',
87 | ],
88 | 'shortcodes:badge' => [
89 | 'map' => 'shortcodes.count',
90 | 'default' => 'null',
91 | ],
92 | ];
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/Facades/Shortcodes.php:
--------------------------------------------------------------------------------
1 | loadViewsFrom(__DIR__.'/../views', 'shortcodes');
21 |
22 | // Publishing is only necessary when using the CLI.
23 | if ($this->app->runningInConsole()) {
24 | $this->bootForConsole();
25 | }
26 |
27 | if ($this->app['config']->get('shortcodes.debugbar') && $this->app->bound('debugbar')) {
28 | $this->app['debugbar']->addCollector(new ShortcodesCollector());
29 | }
30 |
31 | Blade::directive('shortcodes', function ($expression) {
32 | if ($expression === '') {
33 | return '';
34 | } else {
35 | return "render($expression); ?>";
36 | }
37 | });
38 |
39 | Blade::directive('endshortcodes', function () {
40 | return "render(ob_get_clean()); ?>";
41 | });
42 | }
43 |
44 | /**
45 | * Console-specific booting.
46 | *
47 | * @return void
48 | */
49 | protected function bootForConsole()
50 | {
51 | // Publishing the configuration file.
52 | $this->publishes([
53 | __DIR__.'/../config/shortcodes.php' => config_path('shortcodes.php'),
54 | ], 'shortcodes');
55 |
56 | // Registering package commands.
57 | $this->commands([
58 | MakeShortcodeCommand::class,
59 | ]);
60 | }
61 |
62 | /**
63 | * Register any package services.
64 | *
65 | * @return void
66 | */
67 | public function register()
68 | {
69 | $this->mergeConfigFrom(__DIR__.'/../config/shortcodes.php', 'shortcodes');
70 |
71 | // Register the service the package provides.
72 | $this->app->singleton('shortcodes', function ($app) {
73 | return new Manager($app, $app->make('config')->get('shortcodes'));
74 | });
75 |
76 | $this->registerView();
77 | }
78 |
79 | /**
80 | * Register the view environment.
81 | *
82 | * @return void
83 | */
84 | public function registerView()
85 | {
86 | $this->app->singleton('view', function ($app) {
87 | // Next we need to grab the engine resolver instance that will be used by the
88 | // environment. The resolver will be used by an environment to get each of
89 | // the various engine implementations such as plain PHP or Blade engine.
90 | $resolver = $app['view.engine.resolver'];
91 |
92 | $finder = $app['view.finder'];
93 |
94 | $factory = new Factory($resolver, $finder, $app['events']);
95 |
96 | // We will also set the container instance on this view environment since the
97 | // view composers may be classes registered in the container, which allows
98 | // for great testable, flexible composers for the application developer.
99 | $factory->setContainer($app);
100 |
101 | $factory->share('app', $app);
102 |
103 | return $factory;
104 | });
105 | }
106 |
107 | /**
108 | * Get the services provided by the provider.
109 | *
110 | * @return array
111 | */
112 | public function provides()
113 | {
114 | return ['shortcodes', 'view'];
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/Manager.php:
--------------------------------------------------------------------------------
1 | app = $app;
44 | $this->config = $config;
45 | $this->renderer = new Renderer($app, $this);
46 | }
47 |
48 | /**
49 | * Share attribute.
50 | *
51 | * @param string $key
52 | * @param mixed $value
53 | * @return Manager
54 | */
55 | public function share($key, $value)
56 | {
57 | $this->shared[$key] = $value;
58 |
59 | return $this;
60 | }
61 |
62 | /**
63 | * Set / get shared variable.
64 | *
65 | * @param string $key
66 | * @param null $default
67 | * @return mixed
68 | */
69 | public function shared($key = null, $default = null)
70 | {
71 | if ($key === null) {
72 | return $this->shared;
73 | }
74 |
75 | return Arr::get($this->shared, $key, $default);
76 | }
77 |
78 | /**
79 | * Register a shortcode.
80 | *
81 | * @param string|array $name
82 | * @param string|callable $callable
83 | * @return Manager
84 | */
85 | public function add($name, $callable = null)
86 | {
87 | if (is_array($name)) {
88 | $this->renderer->shortcodes = array_merge($this->renderer->shortcodes, $name);
89 | } else {
90 | $this->renderer->shortcodes[$name] = $callable;
91 | }
92 |
93 | return $this;
94 | }
95 |
96 | /**
97 | * Unregister a shortcode.
98 | *
99 | * @param string $name
100 | * @return Manager
101 | */
102 | public function remove($name)
103 | {
104 | unset($this->renderer->shortcodes[$name]);
105 |
106 | return $this;
107 | }
108 |
109 | /**
110 | * Get all registered shortcodes.
111 | *
112 | * @return array
113 | */
114 | public function registered(): array
115 | {
116 | return $this->renderer->shortcodes;
117 | }
118 |
119 | /**
120 | * Get list of rendered shortcodes.
121 | *
122 | * @return array
123 | */
124 | public function rendered(): array
125 | {
126 | return $this->renderer->rendered;
127 | }
128 |
129 | /**
130 | * Render shortcodes in the content.
131 | *
132 | * @param string $content
133 | * @return HtmlString
134 | */
135 | public function render($content)
136 | {
137 | return new HtmlString($this->renderer->apply($content));
138 | }
139 |
140 | /**
141 | * Generate all registered shortcodes info.
142 | *
143 | * @return Collection
144 | */
145 | public function registeredData(): Collection
146 | {
147 | return (new Collection($this->renderer->shortcodes))->mapWithKeys(function ($class, $name) {
148 | if (! is_string($class) || ! class_exists($class)) {
149 | return [];
150 | }
151 | /** @var Shortcode $shortcode */
152 | $shortcode = new $class($this->app, $this, [], $name);
153 |
154 | return [$name => [
155 | 'class' => $class,
156 | 'name' => $name,
157 | 'description' => $shortcode->description,
158 | 'attributes' => $shortcode->attributes(),
159 | ]];
160 | });
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/Renderer.php:
--------------------------------------------------------------------------------
1 | app = $app;
46 | $this->manager = $manager;
47 | }
48 |
49 | /**
50 | * Apply shortcodes to content.
51 | *
52 | * @param string $content
53 | * @return string
54 | */
55 | public function apply($content)
56 | {
57 | return $this->doShortcode($content);
58 | }
59 |
60 | /**
61 | * Search content for shortcodes and filter shortcodes through their hooks.
62 | *
63 | * If there are no shortcode tags defined, then the content will be returned
64 | * without any filtering. This might cause issues when plugins are disabled but
65 | * the shortcode will still show up in the post or content.
66 | *
67 | * @param string $content Content to search for shortcodes.
68 | * @return string Content with shortcodes filtered out.
69 | */
70 | private function doShortcode($content)
71 | {
72 | if (false === strpos($content, '[')) {
73 | return $content;
74 | }
75 |
76 | if (empty($this->shortcodes) || ! is_array($this->shortcodes)) {
77 | return $content;
78 | }
79 |
80 | // Find all registered tag names in $content.
81 | preg_match_all('@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches);
82 | $tagnames = array_intersect(array_keys($this->shortcodes), $matches[1]);
83 |
84 | if (empty($tagnames)) {
85 | return $content;
86 | }
87 |
88 | $pattern = $this->getShortcodeRegex($tagnames);
89 | $content = preg_replace_callback("/$pattern/", [$this, 'doShortcodeTag'], $content);
90 |
91 | // Always restore square braces so we don't break things like