PHPackages                             unclecheese/betterbuttons - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. unclecheese/betterbuttons

ActiveSilverstripe-module[Utility &amp; Helpers](/categories/utility)

unclecheese/betterbuttons
=========================

Adds new form actions and buttons to GridField detail form for usability enhancements.

1.3.15(8y ago)85544.9k↓14.2%86[24 issues](https://github.com/unclecheese/silverstripe-gridfield-betterbuttons/issues)[10 PRs](https://github.com/unclecheese/silverstripe-gridfield-betterbuttons/pulls)19GNUPHP

Since Jul 23Pushed 3y ago14 watchersCompare

[ Source](https://github.com/unclecheese/silverstripe-gridfield-betterbuttons)[ Packagist](https://packagist.org/packages/unclecheese/betterbuttons)[ RSS](/packages/unclecheese-betterbuttons/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (1)Versions (49)Used By (19)

Much of this module is getting merged into core
===============================================

[](#much-of-this-module-is-getting-merged-into-core)

[silverstripe/silverstripe-admin#436](https://github.com/silverstripe/silverstripe-admin/issues/436)

But I want to use it now!
-------------------------

[](#but-i-want-to-use-it-now)

If you're looking to use it in SS4 ahead of the merge, you can use [this branch](https://github.com/unclecheese/silverstripe-gridfield-betterbuttons/tree/feature/ss4-upgrade).

[![Build Status](https://camo.githubusercontent.com/fda3aacac2a8ca1620beca64bf8d909693d39e417790a46f6842fbc4ce2164a2/68747470733a2f2f7472617669732d63692e6f72672f756e636c656368656573652f73696c7665727374726970652d677269646669656c642d626574746572627574746f6e732e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/unclecheese/silverstripe-gridfield-betterbuttons)

[![Screenshot](https://camo.githubusercontent.com/2361f4ba90c7f6ad99ff1cff21777728ec04e9737353922619670064ae91c472/687474703a2f2f692e6375626575706c6f61642e636f6d2f4a38765751662e706e67)](https://camo.githubusercontent.com/2361f4ba90c7f6ad99ff1cff21777728ec04e9737353922619670064ae91c472/687474703a2f2f692e6375626575706c6f61642e636f6d2f4a38765751662e706e67)

#### Modifies the detail form of GridFields to use more user-friendly actions, including:

[](#modifies-the-detail-form-of-gridfields-to-use-more-user-friendly-actions-including)

- **Save and add another**: Create a record, and go right to adding another one, without having to click the back button, and then add again.
- **Save and close**: Save the record and go back to list view
- **User-friendly delete**: Extracted from the tray of constructive actions and moved away so is less likely to be clicked accidentally. Includes inline confirmation of action instead of browser alert box.
- [![Screenshot](https://camo.githubusercontent.com/6796e75fd356c4724c34473a5eaa4de9896610fb9840c7c20e03ad674cffba74/687474703a2f2f692e6375626575706c6f61642e636f6d2f5465714756752e706e67)](https://camo.githubusercontent.com/6796e75fd356c4724c34473a5eaa4de9896610fb9840c7c20e03ad674cffba74/687474703a2f2f692e6375626575706c6f61642e636f6d2f5465714756752e706e67)
- **Cancel**: Same as the back button, but in a more convenient location
- **Previous/Next record**: Navigate to the previous or next record in the list without returning to list view
- **Frontend Links**: If your DataObject has a Link() method, get links to the draft site and published site to view the record in context in a single click
- [![Screenshot](https://camo.githubusercontent.com/d5968242b31d15f5062ba5505d3026542fce3226abef369a47f19ef4f0bb1f12/687474703a2f2f692e6375626575706c6f61642e636f6d2f3759495976392e706e67)](https://camo.githubusercontent.com/d5968242b31d15f5062ba5505d3026542fce3226abef369a47f19ef4f0bb1f12/687474703a2f2f692e6375626575706c6f61642e636f6d2f3759495976392e706e67)
- **Versioning**: Save, Save &amp; Publish, Rollback, Unpublish
- [![Screenshot](https://camo.githubusercontent.com/e2bce1c3334c56f60ab51bfd2c309e0983bc79c2fe1ec7561b22bc9b4ce38309/687474703a2f2f692e6375626575706c6f61642e636f6d2f584a6e734d712e706e67)](https://camo.githubusercontent.com/e2bce1c3334c56f60ab51bfd2c309e0983bc79c2fe1ec7561b22bc9b4ce38309/687474703a2f2f692e6375626575706c6f61642e636f6d2f584a6e734d712e706e67)
- **Configurable UI**: Add buttons to the top (utilities) or bottom (actions).
- **Disambiguated tabs**: In model admin, the top tabs toggle between the models. On the detail view, they toggle between the groups of fields, creating a confusing user exierience. Better Buttons groups the fields as they are in CMSMain, using a tabset within the main editing area.
- [![Screenshot](https://camo.githubusercontent.com/b5a9727aa2a81bea9e382ad08e6ffed88b4333c224328722e3b8e15621836fcb/687474703a2f2f692e6375626575706c6f61642e636f6d2f6f464d4762582e706e67)](https://camo.githubusercontent.com/b5a9727aa2a81bea9e382ad08e6ffed88b4333c224328722e3b8e15621836fcb/687474703a2f2f692e6375626575706c6f61642e636f6d2f6f464d4762582e706e67)
- Add your own custom actions!

#### Create custom actions the detail view

[](#create-custom-actions-the-detail-view)

[![Screenshot](https://camo.githubusercontent.com/a7c345eda46533e154e8768d0b49b12bfc993873695abb35a610b0b928d84e5b/687474703a2f2f692e6375626575706c6f61642e636f6d2f51514c386f442e706e67)](https://camo.githubusercontent.com/a7c345eda46533e154e8768d0b49b12bfc993873695abb35a610b0b928d84e5b/687474703a2f2f692e6375626575706c6f61642e636f6d2f51514c386f442e706e67)

Requirements
------------

[](#requirements)

SilverStripe 4.0 or higher

Installation
------------

[](#installation)

```
composer require unclecheese/betterbuttons 2.x-dev

```

Customising the button collections
----------------------------------

[](#customising-the-button-collections)

Preferences for which buttons should appear where will vary from user to user. BetterButtons comes with a default set of button collections for the "create" and "edit" views in a GridField detail form, but these can be easily overridden in a config.yml file.

The default configuration:

```
BetterButtonsUtils:
  edit:
    BetterButtonPrevNextAction: true
    BetterButton_New: true
  versioned_edit:
    BetterButtonPrevNextAction: true
    BetterButton_New: true

BetterButtonsActions:
  create:
    BetterButton_Save: true
    BetterButton_SaveAndClose: true

  edit:
    BetterButton_Save: true
    BetterButton_SaveAndClose: true
    BetterButton_Delete: true
    BetterButtonFrontendLinksAction: true

  versioned_create:
    BetterButton_SaveDraft: true
    BetterButton_Publish: true
  versioned_edit:
    BetterButton_SaveDraft: true
    BetterButton_Publish: true
    Group_Versioning: true
    BetterButton_Delete: true
    BetterButtonFrontendLinksAction: true

BetterButtonsGroups:
  SaveAnd:
    label: Save and...
    buttons:
      BetterButton_SaveAndAdd: true
      BetterButton_SaveAndClose: true
      BetterButton_SaveAndNext: true
      BetterButton_SaveAndPrev: true
  Versioning:
    label: Versioning...
    buttons:
      BetterButton_Rollback: true
      BetterButton_Unpublish: true

```

Each button type is assigned a symbol in the YAML definition. It can be placed anywhere any number of times. Further, it can be placed in a named group, provided that group has been defined in the BetterButtonsGroups node. A button group is a single button with a label that exposes a series of options on click.

Because of the idiosyncracies of the Config layer merging arrays, the buttons must be defined as on or off (true or false). To remove a button from the default configuration, you must explicitly set it to false in your project configuration. Here is an example custom configuration.

```
BetterButtonsActions:
  edit:
    BetterButton_Save: false
    Group_SaveAnd: false
    Group_MyGroup: true
BetterButtonsGroups:
  MyGroup:
    label: This is a group
    buttons:
      BetterButton_Save: true
      BetterButton_SaveAndNext: true

```

When creating groups, be sure not to duplicate any buttons that are outside the group, as form fields with the same name cannot appear twice in a form.

Creating a custom action
------------------------

[](#creating-a-custom-action)

In the example below, we'll create a custom action in the GridField detail form that updates a DataObject to be "approved" or "denied."

We can add the action in one of two places:

- **Actions** at the bottom of the form (e.g. save, cancel)
- **Utils** at the top right of the form (e.g. new record, prev/next)

First, we'll overload the model's `getBetterButtonsActions` or `getBetterButtonsUtils` method, depending on where we want the button to appear in the UI.

```
    public function getBetterButtonsActions() {
        $fields = parent::getBetterButtonsActions();
        if($this->IsApproved) {
            $fields->push(BetterButtonCustomAction::create('deny', 'Deny'));
        }
        else {
            $fields->push(BetterButtonCustomAction::create('approve', 'Approve'));
        }
        return $fields;
    }
```

The `BetterButtonCustomAction` object takes parameters for the method name ("deny" or "approve") to invoke on the model, as well as a label for the button.

Now let's add the methods to the DataObject.

```
    public function approve() {
        $this->IsApproved = true;
        $this->write();
    }

    public function deny() {
        $this->IsApproved = false;
        $this->write();
    }
```

Lastly, for security reasons, we need to whitelist these methods as callable by the GridField form. This works a lot like `$allowed_actions` in controllers.

```
    private static $better_buttons_actions = array (
        'approve',
        'deny'
    );
```

Now we have a new button in the UI!

[![Screenshot](https://camo.githubusercontent.com/863bf40a258bc3b08887ba8df27970bfea884d2fb1e69dc6e8002065fa7a99d1/687474703a2f2f692e6375626575706c6f61642e636f6d2f686f5536366f2e706e67)](https://camo.githubusercontent.com/863bf40a258bc3b08887ba8df27970bfea884d2fb1e69dc6e8002065fa7a99d1/687474703a2f2f692e6375626575706c6f61642e636f6d2f686f5536366f2e706e67)

### Customising the user experience

[](#customising-the-user-experience)

Let's ensure that the form refreshes after clicking "approve" or "deny".

```
  $fields->push(
    BetterButtonCustomAction::create('deny', 'Deny')
      ->setRedirectType(BetterButtonCustomAction::REFRESH)
  );
```

The redirect type can use the constants:

```
BetterButtonCustomAction::REFRESH
BetterButtonCustomAction::GOBACK
```

To refresh the form, or go back to list view, respectively.

Additionally, we can add a success message that will render on completion of the action by returning a message in our method.

```
    public function deny() {
        $this->IsApproved = false;
        $this->write();

        return 'Denied for publication';
    }
```

### Defining arbitrary links

[](#defining-arbitrary-links)

Sometimes, you might not want to sent a request to the controller at all. For that, there's the much simpler `BetterButtonLink` class.

```
    $fields->push(
        new BetterButtonLink(
          'View on Meetup.com',
           $this->MeetUpLink
        )
    );
```

[![Screenshot](https://camo.githubusercontent.com/d4d34063aa987f1cfde9ca1b3565f3746e350e297c7c4f7bc508702e1d18e833/687474703a2f2f692e6375626575706c6f61642e636f6d2f596262684c372e706e67)](https://camo.githubusercontent.com/d4d34063aa987f1cfde9ca1b3565f3746e350e297c7c4f7bc508702e1d18e833/687474703a2f2f692e6375626575706c6f61642e636f6d2f596262684c372e706e67)

### Creating nested forms

[](#creating-nested-forms)

You may have an action that needs to prompt for user input, for example "Send this customer message" on an Order record. For complex actions like these, you can use `BetterButtonNestedForm`.

```
	public function getBetterButtonsActions() {
		$f = parent::getBetterButtonsActions();
		$f->push(BetterButtonNestedForm::create('sendmessage','Send this customer a message', FieldList::create(
			TextareaField::create('Content')
		)));

		return $f;
	}
```

In this case, your action handler receives `$data` and `$form`, just like a controller would.

```
    public function sendmessage ($data, $form) {
    	$message = Message::create(array (
    		'OrderID' => $this->ID,
    		'Content' => $data['Content']
    	));

    	$message->write();
    	$form->sessionMessage('Message sent','good');
    }
```

### Disabling Better Buttons

[](#disabling-better-buttons)

Sometimes you might find it necessary to disable better buttons on certain classes. You can do this by changing the static `better_buttons_enabled` to be false via YML configuration.

```
MyBetterButtonLessClass
  better_buttons_enabled: false
```

###  Health Score

48

—

FairBetter than 95% of packages

Maintenance14

Infrequent updates — may be unmaintained

Popularity53

Moderate usage in the ecosystem

Community41

Growing community involvement

Maturity76

Established project with proven stability

 Bus Factor6

6 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~64 days

Recently: every ~395 days

Total

43

Last Release

1834d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/654636?v=4)[Aaron Carlino](/maintainers/unclecheese)[@unclecheese](https://github.com/unclecheese)

---

Top Contributors

[![robbieaverill](https://avatars.githubusercontent.com/u/5170590?v=4)](https://github.com/robbieaverill "robbieaverill (10 commits)")[![dhensby](https://avatars.githubusercontent.com/u/563596?v=4)](https://github.com/dhensby "dhensby (6 commits)")[![irkeepin](https://avatars.githubusercontent.com/u/5104208?v=4)](https://github.com/irkeepin "irkeepin (6 commits)")[![ShrikeFIN](https://avatars.githubusercontent.com/u/1734521?v=4)](https://github.com/ShrikeFIN "ShrikeFIN (6 commits)")[![Taitava](https://avatars.githubusercontent.com/u/13002142?v=4)](https://github.com/Taitava "Taitava (3 commits)")[![stevie-mayhew](https://avatars.githubusercontent.com/u/1953220?v=4)](https://github.com/stevie-mayhew "stevie-mayhew (3 commits)")[![unclecheese](https://avatars.githubusercontent.com/u/654636?v=4)](https://github.com/unclecheese "unclecheese (2 commits)")[![martinduparc](https://avatars.githubusercontent.com/u/839534?v=4)](https://github.com/martinduparc "martinduparc (2 commits)")[![chillu](https://avatars.githubusercontent.com/u/111025?v=4)](https://github.com/chillu "chillu (2 commits)")[![hdpero](https://avatars.githubusercontent.com/u/13778690?v=4)](https://github.com/hdpero "hdpero (2 commits)")[![reflektera](https://avatars.githubusercontent.com/u/2722559?v=4)](https://github.com/reflektera "reflektera (2 commits)")[![pathum](https://avatars.githubusercontent.com/u/2272185?v=4)](https://github.com/pathum "pathum (2 commits)")[![adamjudd](https://avatars.githubusercontent.com/u/287335?v=4)](https://github.com/adamjudd "adamjudd (2 commits)")[![ntd](https://avatars.githubusercontent.com/u/160618?v=4)](https://github.com/ntd "ntd (1 commits)")[![sunnysideup](https://avatars.githubusercontent.com/u/167154?v=4)](https://github.com/sunnysideup "sunnysideup (1 commits)")[![tony13tv](https://avatars.githubusercontent.com/u/4117485?v=4)](https://github.com/tony13tv "tony13tv (1 commits)")[![tylerkidd](https://avatars.githubusercontent.com/u/1338983?v=4)](https://github.com/tylerkidd "tylerkidd (1 commits)")[![MattyBalaam](https://avatars.githubusercontent.com/u/1246923?v=4)](https://github.com/MattyBalaam "MattyBalaam (1 commits)")[![andrewhoule](https://avatars.githubusercontent.com/u/658446?v=4)](https://github.com/andrewhoule "andrewhoule (1 commits)")[![cameronbourgeois](https://avatars.githubusercontent.com/u/1127276?v=4)](https://github.com/cameronbourgeois "cameronbourgeois (1 commits)")

---

Tags

silverstripebuttonsgridfield

### Embed Badge

![Health badge](/badges/unclecheese-betterbuttons/health.svg)

```
[![Health](https://phpackages.com/badges/unclecheese-betterbuttons/health.svg)](https://phpackages.com/packages/unclecheese-betterbuttons)
```

###  Alternatives

[symbiote/silverstripe-gridfieldextensions

A collection of useful grid field components

971.8M235](/packages/symbiote-silverstripe-gridfieldextensions)[undefinedoffset/sortablegridfield

Adds drag and drop functionality to Silverstripe's GridField

941.2M50](/packages/undefinedoffset-sortablegridfield)[briceburg/silverstripe-pickerfield

GridField based management of has\_one , has\_many , and many\_many relationship selection

2541.2k1](/packages/briceburg-silverstripe-pickerfield)[webbuilders-group/silverstripe-frontendgridfield

Wraps gridfield adding support for using it on the front-end.

2029.8k1](/packages/webbuilders-group-silverstripe-frontendgridfield)[milkyway-multimedia/ss-gridfield-utils

A collection of GridField components that you can use with any GridField, including Editable Rows and amy more

207.3k2](/packages/milkyway-multimedia-ss-gridfield-utils)[markguinn/silverstripe-gridfieldmultiselect

Gridfield extensions to add checkboxes for each row to easily delete or perform actions on multiple rows.

115.9k](/packages/markguinn-silverstripe-gridfieldmultiselect)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
