1

I have a template with a slideshow in it. Each slide consists of:

  • Image
  • Caption
  • A paragraph of text
  • Button

For the first 3 items, I have set up the following in my template:

{repeater name="slideshow" prompt="Add another slide" tab="Slideshow"}
  {variable name="image" label="Image" type="mediafinder" mode="image"}{/variable}
  {variable name="caption" type="text" label="Caption"}Caption{/variable}
  {variable name="body" type="textarea" label="Body"}Body{/variable}
{/repeater}

However, I'm a little stuck about what field type to use for the button, which needs to link to a static page within the site.

I don't want to use a text box where the user can enter a URL as it will be too difficult for the user to understand. I'd rather have a dropdown menu that works in the same way as the static menu plugin (ie: select "Static Page" from "type" and then get a list of static pages in a 2nd dropdown menu) but it doesn't see obvious how to do this.

Joseph
  • 2,737
  • 1
  • 30
  • 56

3 Answers3

3

Yes you can add drop-down there with list of static pages.

to show list of pages in drop-down you need to extend pages and add dynamic method to it so when repeater add drop down it will get its values/options from that method.

You need to add code to boot method inside any of your plugin, it will extend pages class which can further handle ajax request.

    \RainLab\Pages\Classes\Page::extend(function($model) {
        $model->addDynamicMethod('getPageOptions', function() {
            $theme = \Cms\Classes\Theme::getEditTheme();
            $pageList = new \RainLab\Pages\Classes\PageList($theme);
            $pages = [];
            foreach ($pageList->listPages() as $name => $pageObject) {
                $pages[$pageObject->url] = $pageObject->title . ' (' . $pageObject->url . ')';
            }
            return $pages;
        });
    });

and inside your repeater you can add dropdown

    {repeater name="slideshow" prompt="Add another slide" tab="Slideshow"}
      {variable name="image" label="Image" type="mediafinder" mode="image"}{/variable}
      {variable name="caption" type="text" label="Caption"}Caption{/variable}
      {variable name="body" type="textarea" label="Body"}Body{/variable}
      {variable name="page" type="dropdown" label="Page"}{/variable}
    {/repeater}

so you can see we added dynamic method getPageOptions it consist of three part 1: get 2nd: fieldname 3rd: Options

So our method name will be get + Page + Options => getPageOptions

within that page we are returning array as value => Label pair you can customize there as per your need.

so when drop-down created it will search this method and use its return value as option.

if you find any further difficulties please comment.

Update

ok so now we can finally add conditional drop-downs its not ajax updatable so far but yes we can hide and show it based on condition.

you can add this mark-up in layout.

    {repeater name="slideshow" prompt="Add another slide" tab="Slideshow"}
      {variable name="type" type="dropdown" label="Link Type"}{/variable}
      {variable name="cms-page" type="dropdown" label="Cms Page" trigger="action:show|field:type|condition:value[cms-page]" }{/variable}
      {variable name="static-page" type="dropdown" label="Static Page" trigger="action:show|field:type|condition:value[static-page]"}{/variable}
      {variable name="blog-post" type="dropdown" label="Post" trigger="action:show|field:type|condition:value[blog-post]"}{/variable}
    {/repeater}

then inside plugin you need to add some additional methods.

your boot method of plugin.php look like this

public function boot()
{

    $pluginSelf = $this;
    \RainLab\Pages\Classes\Page::extend(function($model) {
            $model->addDynamicMethod('getTypeOptions', function() {

            return [
                '' => 'Select Type',
                'cms-page' => 'CMS page',
                'static-page' => 'Static Page',
                'blog-post' => 'Blog post'
            ];

        });
    });

    \RainLab\Pages\Classes\Page::extend(function($model) use ($pluginSelf) {
        $model->addDynamicMethod('getStaticPageOptions', function() use ($pluginSelf) {
            $result =  $pluginSelf::getTypeInfo('static-page');
            return $result['references'];
        });
    });

    \RainLab\Pages\Classes\Page::extend(function($model) use ($pluginSelf) {
        $model->addDynamicMethod('getCmsPageOptions', function() use ($pluginSelf) {
            $result =  $pluginSelf::getTypeInfo('cms-page');
            return $result['references'];
        });
    });

    \RainLab\Pages\Classes\Page::extend(function($model) use ($pluginSelf) {
        $model->addDynamicMethod('getBlogPostOptions', function() use ($pluginSelf) {
            $result = $pluginSelf::getTypeInfo('blog-post'); 
            return $result['references'];
        });
    });

}

and one additional method you need to add inside plugin.php

public static function getTypeInfo($type)
{
    $result = [];
    $apiResult = \Event::fire('pages.menuitem.getTypeInfo', [$type]);

    if (is_array($apiResult)) {
        foreach ($apiResult as $typeInfo) {
            if (!is_array($typeInfo)) {
                continue;
            }

            foreach ($typeInfo as $name => $value) {
                if ($name == 'cmsPages') {
                    $cmsPages = [];

                    foreach ($value as $page) {
                        $baseName = $page->getBaseFileName();
                        $pos = strrpos($baseName, '/');

                        $dir = $pos !== false ? substr($baseName, 0, $pos).' / ' : null;
                        $cmsPages[$baseName] = strlen($page->title)
                            ? $dir.$page->title
                            : $baseName;
                    }

                    $value = $cmsPages;
                }

                $result[$name] = $value;
            }
        }
    }

    return $result;
}

as a result you can see in first drop down we can have options 'cms-page' , 'static-page' and 'Blog post', based on that we can show other drop downs.

and during showing or using results first you need to check value of type field based on that fields value you can further choose which dropdown's value you need to use for example type=cms-page then you need to look for cms-page field.

notice : not sure used - (dash) in variables so if value is not in out put you can convert variables in cmsPage camel case if needed not sure about this stuff

one additional changes you need to add this change as its require to change core file , I also created pull request for it so they also include that change in next release mean while we need to do it manually. its required for this to work
please refer this PR request : https://github.com/octobercms/library/pull/292/files

Hardik Satasiya
  • 9,547
  • 3
  • 22
  • 40
  • Thank you so much for your super-detailed answer and also the explanation about why the method name is important. I have marked your answer correct as it does what I asked for, but I'd also like to know if there's a way to implement the "type/reference" style of the Static Menu Plugin whereby a user could select, URL, Header, CMS Page, Blog Post or Static Page and then have a 2nd dropdown populated with a list relevant to the selection in the first dropdown? – Joseph Dec 11 '17 at 14:10
  • To clarify, I understand how to extend the pages class to retrieve options for blog posts but I'm not sure how to recreate the dynamic dual dropdown functionality that the Static Menu component offers. – Joseph Dec 11 '17 at 14:17
  • hey yes I need to check it out, may be its possible , let me do that stuff and i will let you know, its like dependent dropdown right ? – Hardik Satasiya Dec 11 '17 at 14:26
  • hey added some solution for your drop downs may be it will work for you, just check it out :) – Hardik Satasiya Dec 11 '17 at 18:09
  • Thank you, it seems like you understand what I want to do perfectly. I am getting an error when I try to implement this, though: `Undefined variable: references on line 169 of /path/to/project/modules/cms/classes/Page.php` on build 430. – Joseph Dec 14 '17 at 11:37
  • it may possible you don't have any cms pages , try to add at least one cms page then test it – Hardik Satasiya Dec 14 '17 at 13:09
  • @HardikSatasiya what about if you want to apply this without repeater? – Panagiotis Koursaris Jan 12 '18 at 19:42
  • yes you can just remove repeater and it should work i didn't test but it should work. – Hardik Satasiya Jan 12 '18 at 20:35
  • I'got an error without repeater: "get_class() expects parameter 1 to be object, array given". That's why I said. Thank you for your time – Panagiotis Koursaris Jan 13 '18 at 08:26
  • hmmm, i need more details can you please add question and add more details in it so, it will be helpful form me to solve issue, thanks – Hardik Satasiya Jan 13 '18 at 10:05
  • @HardikSatasiya ok take a look at my question: https://stackoverflow.com/questions/48243527/static-page-plugin-list-with-all-pages-url-as-a-custom-page-field – Panagiotis Koursaris Jan 13 '18 at 19:29
  • Hi guys, I have problem when adding $pageList->getPageTree(true). The child pages is not display. Here is my code: https://pastebin.com/aWJHDPEZ – claudchan Nov 07 '18 at 08:32
  • may be you also need to use `$pageList->getPageSubTree($page)` with that. – Hardik Satasiya Nov 19 '18 at 09:48
  • Hi, I unsure how to put in the code $pageList->getPageSubTree($page), I tried and not getting it right. So, I use "getPageSubTree" after $pageList->getPageTree(true) or have to code in other way? – claudchan Nov 26 '18 at 02:48
  • hmm, maybe I need to check your code .... open new question with code ? – Hardik Satasiya Nov 26 '18 at 06:24
  • Ok, i had opened new question: https://stackoverflow.com/questions/53477068/how-to-get-static-page-dropdown-in-octobercms-with-get-page-tree – claudchan Nov 26 '18 at 08:21
0

You could use the staticpagepicker widget if you don't need to link to CMS pages. https://github.com/rainlab/pages-plugin#backend-forms

If you need to select from a list of static pages in your own backend forms, you can use the staticpagepicker widget:

fields:
    field_name:
        label: Static Page
        type: staticpagepicker

The field's assigned value will be the static page's file name, which can be used to link to the page as described above.

In your layout file:

{variable name="button_page" label="Button URL" type="staticpagepicker"}{/variable}

<a href="{{ button_page | staticPage }}">Button</a>

Because CMS Pages aren't listed in this widget, you could always setup an alternative field to offer more flexibility to the user.

{variable name="button_url" label="Button (URL)" type="text" span="left" comment="Leave empty if using Button (Page) instead" placeholder="http://"}{/variable}
{variable name="button_page" label="Button (Page)" type="staticpagepicker" span="right" comment="Used if Button (URL) is left empty"}{/variable}

<a href="{{ button_url ? button_url : (button_page | staticPage) }}">Button</a>
  • Thank you for this! This has been very useful in my project. Is there any way to filter out specific pages, so that only the children of a specific page appear in the staticpagepicker? – chocolata Jan 13 '19 at 16:44
  • There's no filter feature unfortunately, you'll have to extend the staticpagepicker form widget in order to filter the results. – Jeremy M Jan 14 '19 at 21:34
  • Thanks Jeremy, I've created a custom solution that I'm in the process of refining. If you're interested, you might share your views here: https://github.com/rainlab/pages-plugin/issues/376 – chocolata Jan 15 '19 at 10:38
0

I have the same Problem like Panagiotis Koursaris. I used the template variables without a repeater. I fixed the problem by specifying the options and adding an alias in Plugin boot method. e.g.:

{variable name="type" type="dropdown" options="StaticPage | getTypeOptions" label="Link Type" tab="Text Image Header (dark)"}{/variable}

\Illuminate\Foundation\AliasLoader::getInstance()->alias('StaticPage','RainLab\\Pages\\Classes\\Page');

But the trigger don't work, all dropdowns were displayed. Any idea to fix it?

The next problem is, that all cms pages are displayed as follows:

projects [projects]

I change the code in the second loop as follows:

if ($type == 'cms-page') {
            $cmsPages = [];

            if (!is_array($value)) {
              continue;
            }

            foreach ($value as $url => $pageArray) {
              $page = \Cms\Classes\Page::find($url);
              if ($page) {
                $baseName = $page->getBaseFileName();
                $pos = strrpos($baseName, '/');

                $dir = $pos !== false ? substr($baseName, 0, $pos) . ' / ' : null;
                $cmsPages[$baseName] = strlen($page->title) ? $dir . $page->title : $baseName;
              }
            }

            $value = $cmsPages;
          }
Hacko
  • 1
  • 2
  • If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. – Matt Ke Jun 04 '20 at 14:36