Back to Shortcodes Engine Support

gabor19990
gabor19990

Hello,

let's say i have a custom component:

\MyVendor\MyPlugin\Components\Demo

Whcih i can embed in my pages to render Demo items. I want a shrotcode like this:

[demo id="1"][/demo]

which renders the Demo item with its own partial, like if it was called on a page where the Demo component is embedded. How can i acieve this please? So how can i access/initialize components from the shortcode engine?

Linkonoid
Linkonoid

Hi,

Do you want to write a shortcode component? See my SCPAdSense code for example. Just pass the variable from your component:

public function onRender() {
        $this->page['id'] = 1;
}

and then use it in the shortcode:

public function init()
    {
        $this->manager->getHandlers()->add('demo', function(ProcessedShortcode $sc) {

            //.....................

            $output = Twig::parse(File::get(__DIR__.'/../../../myvendor/myplugin/components/demo/default.htm'), array(
                'id' => $id,
            ));
            return $output;
        });
    }

Everything is very simple: a variable is defined in the component code, and then in the shortcode the component output is rendered using Twig::parse()

Pay attention to the path to your component for File::get()

Last updated

gabor19990
gabor19990

Thanks, thats is useful but i mean this: imagine there is a site with Rainlab.Blog plugin, and users want to have a shortcode to dispaly a blogpost on anywhere, like in a static page. How can i create a

[blog id="1"][/blog]

shortcode, which renders the Rainlab.Blog item with its "Post" component, using my custom template defined for it in my theme (instead of the default: https://github.com/rainlab/blog-plugin/blob/master/components/post/default.htm )

I went along this way with my similar Demo component, not sure it's the good/best way:

1, in my shortcode code section ($id is the paramater name):


return \H3kft\Ia\Helpers\ShortcodeHelper::demo($id);

2, in the H3kft\Ia\Helpers\ShortcodeHelper helper class (simplified):


public static function demo($id) {
  $item = \H3kft\Ia\Models\Demo::where('id', $id)->published()->first();
  if ($item === null) return;

  $controller = new \Cms\Classes\Controller();
  $controller->setComponentContext(new \H3kft\Ia\Components\Demo);
  return $controller->renderPartial('ia/demo/item.htm', ['item'=>$item], false);
}

So in general i want to use an existing component to render a partial and return that from the shortcode engine.

Actually for the above to work i had to patch

https://github.com/octobercms/october/blob/master/modules/cms/classes/Controller.php

az line 1070 wit the following:


// CmsException::mask($this->page, 300);
CmsException::mask($partial, 300);

will investigate that later if i misunderstod something here, or it's a bug in OCMS core.

Last updated

Linkonoid
Linkonoid

If we are talking about rendering from a finished component, then your path is right. The difficulty lies in the fact that some methods in the blog component are private, i.e. they should not be used from code without redefinition. I did not redefine the classes, just changed the code for the blog component a bit. Here is the work code, it can still be improved, but, alas, there is no time for this (it was added to the v1.0.4 engine and published, use:[blog id=1][/blog], demo link for StaticPage: https://shortcodes.test.linkonoid.com/test-shortcode-plugin.html):

<?php namespace Linkonoid\ShortcodesEngine\Classes;

use Thunder\Shortcode\Shortcode\ShortcodeInterface;
use RainLab\Blog\Components\Post as BlogPostComponent;
use RainLab\Blog\Models\Post as BlogPost;
use Cms\Classes\Controller;

class BlogShortcode extends Shortcode
{

    public $postId;

    public function __construct($manager)
    {
        parent::__construct();
        $this->manager = $manager;
    }

    public function init()
    {
        $this->manager->getHandlers()->add('blog', function(ShortcodeInterface $sc) {

           $this->postId = $sc->getParameter('id');

            BlogPostComponent::extend(function ($component) {

                $component->addDynamicMethod('onRenderNew', function () use($component) {
                    $component->categoryPage = $component->property('categoryPage');

                    $post = new BlogPost;
                    $post = $post->isClassExtendedWith('RainLab.Translate.Behaviors.TranslatableModel')
                        ? $post->transWhere('id', $this->postId)
                        : $post->where('id', $this->postId);

                    try {
                        $component->post = $post->firstOrFail();
                    } catch (ModelNotFoundException $ex) {
                    }

                    $controller = new Controller;
                    $controller->setComponentContext($component);
/*
                    if (!$component->checkEditor()) {
                        $post = $post->isPublished();
                    }

*/

                    if ($component->post && $component->post->categories->count()) {
                        $blogPostsComponent = null;//$component->getComponent('blogPosts', $component->categoryPage);

                        $component->post->categories->each(function ($category) use ($component,$controller,$blogPostsComponent) {
                            $category->setUrl($component->categoryPage, $controller, [
                                //'slug' => $component->urlProperty(null, 'categoryFilter')
                            ]);
                        });
                    }

                    return $controller->renderPartial('@default.htm');
                });
            });

            $blogPostComponent = new BlogPostComponent;
            return $blogPostComponent->onRenderNew();
        });
    }
}

Last updated

1-4 of 4