concrete5 – Custom Toolbar Button

with concrete5 you usually put your add-on code in a package and don’t touch the core. This concept allows you to update the CMS core without overriding anything you’ve built on your own. In order to interact with the CMS you can use several functions helping you to integrate your add-on into the CMS interface.

In this short article we’re going to look at a simple example which will place a button next to the edit button and shows a dialog with a quote. Nothing fancy, just an example aimed at developers who want to use this feature in their add-ons.

This is how your button is going to look like:

But let’s start at the beginning, every package needs a controller to handle the installation process and in this case the integration of the button as well. The following code box shows the complete package controller you have to create at /packages/remo_toolbar_button/controller.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
 
class RemoToolbarButtonPackage extends Package {
 
   protected $pkgHandle = 'remo_toolbar_button';
   protected $appVersionRequired = '5.5.1';
   protected $pkgVersion = '1.0.0';
 
   public function getPackageDescription() {
      return t("Toolbar Button Example.");
   }
 
   public function getPackageName() {
      return t("Toolbar Button");
   }
 
   public function on_start() {
      if(version_compare(APP_VERSION,'5.4.1.1', '>')){
         $ihm = Loader::helper('concrete/interface/menu');
         $uh = Loader::helper('concrete/urls');
 
         $ihm->addPageHeaderMenuItem('help', t('Help'), 'left', array(
            'dialog-title'    => t('Help'),
            'href'            => $uh->getToolsUrl('help', 'remo_toolbar_button'),
            'dialog-on-open'  => "$(\'#ccm-page-edit-nav-help\').removeClass(\'ccm-nav-loading\')",
            'dialog-modal'    => "false",
            'dialog-width'    => '200',
            'dialog-height'   => "160",
            'class'           => 'dialog-launch'
         ), 'remo_toolbar_button');         
      }   
   }  
}

The function on_start is called in every installed package when a page is rendered. It allows us to inject code into the running process. There’s a helper method addPageHeaderMenuItem, first parameter is our id, second the text, followed by an array of attributes to create the link tag as well as the package name as the last parameter. Having a reference to the package is important because our button needs a few more files located in the package.

Let’s create those files! Within your package /package/remo_toolbar_button/, create a new directory structure called “elements/header_menu/help”. The last directory has to match the first parameter of addPageHeaderMenuItem. Within that directory, create a file called view.css and put this content in it:

1
2
3
#ccm-page-edit-nav-help {
   color: red ! important;
}

It’s pretty basic, just to show you where you have to put your CSS code to style your button. Next, create another file in the same directory called view.js with this content:

1
2
3
$(function() {
	$("#ccm-page-edit-nav-help").dialog();
});

The ID used in this little jQuery code is generated by addPageHeaderMenuItem in combination with the first parameter we’ve specified. We use this to launch our dialog.
Next, we have to create another controller, this time the button controller. Still in the same directory, create a file called controller.php and put the following content in it:

1
2
3
4
5
6
7
8
9
<?php 
defined('C5_EXECUTE') or die("Access Denied.");
class HelpConcreteInterfaceMenuItemController extends ConcreteInterfaceMenuItemController {
   public function displayItem() {
      // button is always enabled
      return true;
   }
}
?>

We always return true since our button has to be active all the time. Be careful with the name of the class, it must follow the concrete5 rule. Our ID is “help” which we start with a capital letter and put it as a prefix before “ConcreteInterfaceMenuItemController”. If our ID was help_me, the class name would have to be HelpMeConcreteInterfaceMenuItemController, after every underscode, we have to start with a capital letter (camel case).

There’s just one more file we have to create. The dialog we want to display needs some content. We’ve used this url

$uh->getToolsUrl('help', 'remo_toolbar_button')

when we’ve added our button. This file has to be located at /packages/remo_toolbar_button/tools/ and is named help.php. The content could look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
$ih = Loader::helper('concrete/interface');
 
$quotes = array(
   array('The best way out is always through.', 'Robert Frost'),
   array('Whatever you do will be insignificant, but it is very important that you do it.', 'Mahatma Gandhi'),
   array('Failure is the condiment that gives success its flavor.', 'Truman Capote'),
   array('Experience is what you get when you don\'t get what you want.', 'Dan Stanford'),
   array('The best way to cheer yourself up is to try to cheer somebody else up.', 'Mark Twain')
);
 
$quote = $quotes[array_rand($quotes)];
 
echo "<b>{$quote[0]}</b><br/> - {$quote[1]}";
 
echo '<div class="dialog-buttons"><a href="javascript:void(0)" class="btn primary ccm-button-right" onclick="jQuery.fn.dialog.closeTop();">' . t('Close') . '</a></div>';
?>

Nothing but a simple PHP code to display a random quote as well as a button using the concrete5 style to close the dialog.

If everything works, you’ll see a dialog like this:

After you created all the file, you’ll have to hover the dashboard button and click on “Install” where you’ll see our new add-on available for installation.

If you had any problem with the code, click here to download the complete add-on.




23 Comments

Thanks Mike! Have you tried to use “background-image: url(..)” in view.css? It should be enough if you replace the “color: red” in my tutorial.

Awesome! Thanks, Remo! I was looking for this exact kind of thing a few months back… I needed to add a button into the toolbar to link to a “hidden” page of training videos. Looks like this would do the trick… just change the ‘href’ in the on_start function to point have the “http://path-to-videos” URL!

Thanks!

Hi Remo

First of all a big thank you for this guide. I wanted to create a button that would link to the Customize Theme window and have sort of got there but just the body content shows without the navigation or ccm-theme-style-attribute to change any colors.

I am using

‘href’ => REL_DIR_FILES_TOOLS_REQUIRED . ‘/themes/preview_internal?themeID=4&previewCID=1’,

But I am not sure if preview_internal? is the correct one to use. Please can you advise

Thanks

Hi Rob, I don’t really understand what you’re trying to achieve, but when you want to see the current page with a different page theme, you have to change the value of previewCID as well. It’s the internal page ID. You can find this id if you look at the code of a page and search for CCM_CID. The link you’ve posted will always show the home page.

Hi Remo,

I think what I am trying to achieve is a button that will open the Customize window for my current theme and get the same results as dashboard>themes>customize.

When I open in the usual route I check the source on the customize window and see /index.php/tools/required/themes/preview_internal?themeID=4&previewCID=1. I thought that if I put this in the Href as I gave before it should show the same results.

It does open the window but does not show the Div class ccm-pane-options at the top, which is where the options are to change the background styles etc. It does however show the main page which is what should be shown. So I am not sure if this is the correct href to use to open an equivalent of the Cusomize page or if indeed c5 uses this preview_internal.php to create the page.

Sorry but still trying to find my way around c5.

Okay, the problem is that when you’ve viewed the source, you had the mouse cursor in an iframe. This is why you just got the content and not the pane around it..
If you want to see the complete page, you’ll have to use /index.php/dashboard/pages/themes/customize/1/ Please note the last parameter which is the theme id. You can do this with $c->getCollectionThemeID()

This is really great, but I have one question:

How would you get this to work with a static link to a page? I’d like to make a package that simply links to the composer edit page if a page was created / enabled for composer. I don’t need to do a dialog at all.

Any thoughts on how to do this?

Hey Jeremy! Yes, this is also possible.
Basically in my example, I’m catching the click on the button with the little JavaScript. First option would be to replace it with something like this:

1
2
3
4
5
6
7
8
$(function() {
 
    $("#ccm-page-edit-nav-help").click(function(event) {
        event.preventDefault();
        window.location.href = "http://composer.oi.ai"
    });    
 
});

However, you could also use an old fashioned link, don’t run any JavaScript code and simple use the standard href attribute. The package controller method on_start would then look like this:

1
2
3
4
5
6
7
8
9
10
11
12
   public function on_start() {
      if(version_compare(APP_VERSION,'5.4.1.1', '>')){
         $ihm = Loader::helper('concrete/interface/menu');
         $uh = Loader::helper('concrete/urls');
 
         $ihm->addPageHeaderMenuItem('help', t('Help'), 'left', array(
            'dialog-title'    => t('Help'),
            'href'            => 'http://www.google.com',
            'target'          => '_blank'
         ), 'remo_toolbar_button');         
      }   
   }

By the way, I also think that the composer needs a few tiny things. It’s already a great feature but I never liked that I had to navigate through the sitemap to edit an existing page using the composer. My approach to improve this was a bit different but I think both ideas can work great. Check out this add-on: https://github.com/Remo/concrete5-composer-list

Hey Remo,

1. Loved your new book, took my C5 abilities to a new level

2. Thank you for this tutorial, I think a lot of developers forget that clients have trouble understanding actions that take more then 1 or 2 levels of interaction to get to. Tutorials like this help us solve real problems for them.

Hey Remo,

I am having a devil of a time with this

Okay, the problem is that when you’ve viewed the source, you had the mouse cursor in an iframe. This is why you just got the content and not the pane around it..
If you want to see the complete page, you’ll have to use /index.php/dashboard/pages/themes/customize/1/ Please note the last parameter which is the theme id. You can do this with $c->getCollectionThemeID()

Would it be possible for me to see an example?

I am also trying to open theme customization in that window.

-Sam

When I have installed multiple packages on the same toolbar the 2-4 package can no longer bring up the dialog box, is there a way around this?

Sam, I haven’t found time to create an example about the customize theme issue yet but I think I know why only one package works. There’s an ID in the code (ccm-page-edit-nav-help). This has to be unique across the whole page and thus every package as well. Have you or can you try to replace that ID in package 2-4 with something different?

Thanks Remo, it did work!

Side benefit, I am new to php, and have always had trouble understanding how OOP and php work, after spending 8 hours investigating the ID issue I now have a full grasp of the MVC and OOP concept, Thanks again 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *