5

I have a specific module that does a few things to tidy up the CMS. Let's call it silverstripe-cleanup.

One of the things this module does is move the MetaData fields to their own tab which I want to always be the final tab in the CMS.

So if my /httpdocs/silverstripe-cleanup/config/config.yml looks as shown below, how do I ensure this extension is applied after all others?

---
Name: silverstripe-cleanup
---

SiteTree:
  extensions:
    - MetaDataMovementExtension
3dgoo
  • 15,716
  • 6
  • 46
  • 58
Hailwood
  • 89,623
  • 107
  • 270
  • 423

3 Answers3

3

To make a module the last one to load we can add something like After: "*" to our module config.yml file:

---
Name: silverstripe-cleanup
After: "*"
---

SiteTree:
  extensions:
    - MetaDataMovementExtension

This should ensure this module is called after all others.

This still may not load after all fields and tabs are added to a page's CMS fields. This is because of the point at which updateCMSFields is called in a page's getCMSFields function.

Say this is our updateCMSFields function:

class MetaDataMovementExtension extends Extension {

    function updateCMSFields($fields) {
        if ($metadataFields = $fields->fieldByName('Root.Main.Metadata')) {
            $fields->removeFieldFromTab('Root.Main', 'Metadata');
            $fields->addFieldToTab('Root.Metadata', $metadataFields);
        }
    }
}

And this is one of our classes:

class HomePage extends Page {

    // ...

    public function getCMSFields()
    {
        $fields = parent::getCMSFields();

        $slidesField = GridField::create(
            'Slides',
            'Slide',
            $this->Slides(),
            GridFieldConfig_RecordEditor::create()
        );
        $fields->addFieldToTab('Root.Slides', $slidesField);

        $fields->addFieldToTab('Root.Column', TextField::create('ColumnTitle', 'Title'));

        return $fields;
    }

}

The updateCMSFields hook gets called in SiteTree::getCMSFields. Looking at our getCMSFields function above, the updateCMSFields function will be called at the top of our function at the point that we call parent::getCMSFields(). After that we then add extra fields. This means our extension will get called before we add extra fields. These extra fields will be placed after our moved metadata tab.

What we can do is wrap our additional fields in each of our getCMSFields with beforeUpdateCMSFields:

    public function getCMSFields()
    {
        $self =& $this;
        $this->beforeUpdateCMSFields(function ($fields) use ($self) {

            $slidesField = new GridField(
                'Slides',
                'Slide',
                $self->Slides(),
                GridFieldConfig_RecordEditor::create()
            );
            $fields->addFieldToTab('Root.Slides', $slidesField);

            $fields->addFieldToTab('Root.Column', TextField::create('ColumnTitle', 'Title'));
        });

        return parent::getCMSFields();
    }

This will ensure that our fields are added before updateCMSFields is called.

An important thing to note when using beforeUpdateCMSFields is that we need to use $self instead of $this inside our beforeUpdateCMSFields block.

3dgoo
  • 15,716
  • 6
  • 46
  • 58
0

Use the Before: and After: constructs from the config header section (the bits between the --- lines before the definitions).

cf. The default mysite one from silverstripe/installer for hints.

yrkrghdh
  • 71
  • 1
  • I've tried doing that although I always get confused with Before:/After: but I have another module that adds in another tab, so I tried doing both variants of (with appropriate indentation/new lines) `Before: - 'other-module'` and `After: - 'other-module'` to no effect. the only time I did manage to get anything out of it was when I replace `'other-module'` with `'*'` on one of them but that simply threw an error saying it had been asked to run both before and after something, which nothing else referenced this module directly so I'm confused. – Hailwood Feb 29 '16 at 21:40
0

In my case it worked just the opposite way, i.e. changing After for Before. I wanted to have an extension from 'mymodule' loaded after an extension from 'anothermodule' and firstly I had:

---
Name: mymodule           # (it is also in mymodule/)
After:
  - "anothermodule/*"    # (this is also in anothermodule/)
---
SiteConfig:
  extensions:
    - MyModuleSiteConfigExtension

However it did not work so I tried:

---
Name: mymodule
Before:
  - "anothermodule/*"
---
SiteConfig:
  extensions:
    - MyModuleSiteConfigExtension

After this change the loading order seemed proper for me (AnotherModuleSiteConfigExtension, MyModuleSiteConfigExtension), I do not know why it goes against all of my understanding.. So in your case you could try this maybe?

---
Name: silverstripe-cleanup
Before: "*"
---

SiteTree:
  extensions:
    - MetaDataMovementExtension
zemiacsik
  • 41
  • 1
  • 6