# Hooks for add-ons - Sheetline 1.x documentation

> The PHP filters and actions around post types, listing and saving, and the JavaScript API for adding buttons and behaviour to the grid.

Beyond columns, Sheetline has hooks for code that adds Bulk Editors, changes how posts are listed and saved, or adds to the Bulk Editor screen. Sheetline Pro is built entirely on them.

## More post types

`sheetline_post_types` lists the post types that get a Bulk Editor (posts and pages by default). Each one gets its own screen under its menu, with a column for each of its taxonomies:

```php
add_filter( 'sheetline_post_types', function ( $types ) {
	$types[] = 'book';
	return $types;
} );
```

Only types with an admin screen (`show_ui`) count; attachments never do. Sheetline Pro adds the custom post types chosen in its settings this way.

## Checking a post before it's saved

`sheetline_check` runs once a post's changes are recorded and before it's saved. Return errors by column key; any error stops that post being saved, and the message appears on the cell.

```php
// Posts in "News" need a title of 70 characters or fewer.
add_filter( 'sheetline_check', function ( $errors, $draft, $changed ) {
	if ( in_array( 'title', $changed, true )
		&& has_category( 'news', $draft->post )
		&& mb_strlen( (string) $draft->get( 'post_title' ) ) > 70 ) {
		$errors['title'] = 'News titles are 70 characters at most.';
	}
	return $errors;
}, 10, 3 );
```

## After a save

`sheetline_save_result` filters what a save sends back to the grid. Its second argument lists every cell that changed as `[ post ID, column key, old value, new value ]`, and the third is the post type, which makes it a good place to log changes:

```php
add_filter( 'sheetline_save_result', function ( $result, $changed, $post_type ) {
	foreach ( $changed as list( $id, $key, $old, $new ) ) {
		error_log( sprintf( 'Bulk Editor: %s %d %s %s → %s', $post_type, $id, $key, wp_json_encode( $old ), wp_json_encode( $new ) ) );
	}
	return $result;
}, 10, 3 );
```

## Request parameters and queries

- `sheetline_list_args` gets the arguments for a page of posts and the REST request, so you can read your own (sanitized) query parameters.
- `sheetline_query_args` gets the `WP_Query` arguments built from them (and the grid's arguments, and the post type), to change the query.

## The Bulk Editor screen

- `sheetline_editor_load` fires when a Bulk Editor loads, with the screen and the post type. Enqueue your script there, with `sheetline` as a dependency:

  ```php
  add_action( 'sheetline_editor_load', function ( $screen, $post_type ) {
  	add_action( 'admin_enqueue_scripts', function () {
  		wp_enqueue_script( 'my-grid', plugins_url( 'my-grid.js', __FILE__ ), array( 'sheetline', 'wp-hooks' ), '1.0', true );
  	} );
  }, 10, 2 );
  ```

- `sheetline_page_actions` prints next to the screen's title, with the post type; use `page-title-action` buttons there.
- `sheetline_loaded` fires once Sheetline has loaded (on `plugins_loaded`). Hook an add-on's setup to it; `SHEETLINE_VERSION` is defined from then on.

## The grid's JavaScript

The grid sets `window.sheetline` and starts once the page is ready, after every script in the footer has run, so your script can add its `wp.hooks` first. Give your hooks your own namespace.

| Hook | Gets | Use it to |
|---|---|---|
| `sheetline.init` (action) | the API | run once before the first load |
| `sheetline.query` (filter) | query parameters, state | add parameters to the posts request (read them with `sheetline_list_args`) |
| `sheetline.filters` (filter) | elements, state | add controls after the Filter button |
| `sheetline.bulkActions` (filter) | elements, state | add buttons to the left of the filters |
| `sheetline.selectable` (filter) | `false` | return `true` to show a checkbox column; selected post IDs are in `state.selected` |
| `sheetline.rowClass` (filter) | class names, row | add classes to a row |
| `sheetline.rowActions` (filter) | elements, row | add links under a post's title |
| `sheetline.savedNotice` (filter) | HTML parts, result | add to the notice after a save (escape text with `sheetline.escape()`) |
| `sheetline.loaded` (action) | state | react after a page of posts loads |

```js
// A button that shows how many posts are on the page.
wp.hooks.addFilter( 'sheetline.bulkActions', 'my-grid', ( nodes, state ) => nodes.concat(
	window.sheetline.el( 'button', {
		type: 'button',
		class: 'button',
		text: 'Count',
		onclick: () => window.sheetline.notice( 'info', window.sheetline.escape( state.rows.length + ' posts on this page' ) ),
	} )
) );
```

`window.sheetline` also has `api( path, options )` for Sheetline's REST routes, `setValue( row, key, value )` to make an unsaved change, `query()` for the current search and filters, `rowById()`, `render()`, `load()`, `go( changes )` (change filters or page and reload, after asking about unsaved changes), `pickImages()` for the media library, and more; the plugin's README lists them all.

## REST API

`sheetline/v1/posts` lists (GET, with `post_type` and the grid's parameters) and saves (POST, `post_type` and `changes` as `[ { id, key, value } ]`) for users who can edit posts of that type. Sheetline Pro adds its routes to the same namespace.

Source: https://extendiment.com/plugins/sheetline/docs/1.x/hooks-for-add-ons
