Adding columns
Add your own fields to the Bulk Editor with the sheetline_columns filter: the column format, value types, validation, permissions and sorting.
Any post field can become a Bulk Editor column with the sheetline_columns filter. Put the code in a small custom plugin or your child theme's functions.php. Columns you add get everything the built-in ones have: keyboard editing, highlighted unsaved changes, errors on their cell, Screen Options, and with Sheetline Pro bulk changes, undo and CSV export and import.
A first column
// A "Subtitle" text column for posts, stored in post meta.
add_filter( 'sheetline_columns', function ( $columns, $post_type ) {
if ( 'post' !== $post_type ) {
return $columns;
}
$columns['subtitle'] = array(
'label' => 'Subtitle',
'group' => 'Extras',
'type' => 'text',
'get' => function ( WP_Post $post ) {
return (string) get_post_meta( $post->ID, 'subtitle', true );
},
'set' => function ( \Extendiment\Sheetline\Draft $draft, $value ) {
$draft->meta( 'subtitle', sanitize_text_field( $value ) );
},
'sort' => array( 'meta' => 'subtitle' ),
);
return $columns;
}, 10, 2 );
The key (subtitle) must be unique. The filter runs once per post type, with the post type as its second argument, so each Bulk Editor can have its own columns.
Setters record, they don't save
A column's set gets a Draft: the post's pending changes. Record the new value there and Sheetline writes everything once, after checking every cell of the post:
| Draft method | What it does when the post is saved |
|---|---|
$draft->field( 'post_title', $value ) |
Sets a wp_update_post() field (unslashed) |
$draft->meta( $key, $value ) |
Updates post meta ('' or null deletes the key) |
$draft->terms( $taxonomy, $ids ) |
Replaces the post's terms of a taxonomy |
$draft->before( fn( $id ) => … ) |
Runs before the post is updated |
$draft->after( fn( $id ) => … ) |
Runs after the post is updated |
$draft->post is the post as loaded, and $draft->get( 'post_status' ) a field as it will be saved. Never write to the database in set yourself: Sheetline Pro calls the same setters to preview bulk changes and imports without saving.
The column format
| Key | Required | What it is |
|---|---|---|
label |
yes | Shown in the header and in Screen Options |
type |
yes | How the value is shown and edited (see below) |
get |
yes | function ( WP_Post $post ) returning the value to edit |
set |
yes | function ( Draft $draft, $value ) recording a new value |
group |
no | Groups related columns (default "Other") |
options |
for select and terms |
value => label pairs, or a function returning them (called only when needed) |
applies |
no | function ( WP_Post $post ) returning false where the field doesn't exist (the cell shows a dash) |
can |
no | function ( WP_Post $post ) returning false where the current user may not change it (the cell is read-only). Sheetline already checks edit_post for every post |
hidden |
no | true to hide the column until switched on in Screen Options |
sort |
no | Makes it sortable: a WP_Query orderby value (e.g. 'title'), or array( 'meta' => 'my_key', 'num' => true ) |
bulk |
no | false keeps the column out of Sheetline Pro's bulk changes |
Types
| Type | Value | Edited with |
|---|---|---|
text |
string | a text box |
longtext |
HTML string | a larger text box over the cell |
number |
number as a string | a text box |
date |
Y-m-d string, '' for none |
a date picker |
datetime |
Y-m-d H:i string |
a date and time picker |
select |
one of the options keys |
a dropdown |
bool |
'yes' or 'no' |
a Yes/No dropdown |
terms |
array of term IDs | a checkbox list of the options |
image |
attachment ID as a string, '' for none |
the media library |
images |
array of attachment IDs | the media library, several in order |
readonly |
string | shown, not editable |
Values arrive in set as the grid sends them: strings, or arrays of IDs for terms and images. Sanitize them as you would any input.
Refusing a value
Throw an exception with a message for the editor. It appears under the cell in red, and that post isn't saved:
'set' => function ( \Extendiment\Sheetline\Draft $draft, $value ) {
$value = trim( (string) $value );
if ( '' !== $value && ! preg_match( '/^\d{4}$/', $value ) ) {
throw \Extendiment\Sheetline\Columns::invalid( 'Enter a year, such as 2026.' );
}
$draft->meta( 'year', $value );
},
Columns::invalid() returns an InvalidArgumentException; any InvalidArgumentException works.
Helpers
Extendiment\Sheetline\Columns has the helpers the built-in columns use:
Columns::option( $value, $options ): one of the options' keys; refuses anything else.Columns::bool( $value ):truefor "yes", "1", "true" or "on".Columns::integer( $value ),Columns::number( $value ): a whole number, or any number (a comma works as the decimal point).Columns::date( $value ),Columns::datetime( $value ): a valid date, or date and time, in the formats above.Columns::term_options( $taxonomy ): a taxonomy's terms asID => 'Parent › Child', ready foroptions.Columns::term_ids( $value, $taxonomy ): the IDs, each an existing term of the taxonomy.Columns::statuses(),Columns::authors( $post_type ): the status and author options the grid uses.
// A taxonomy as a terms column, for a "book" post type.
add_filter( 'sheetline_columns', function ( $columns, $post_type ) {
if ( 'book' === $post_type ) {
$columns['series'] = array(
'label' => 'Series',
'type' => 'terms',
'options' => fn() => \Extendiment\Sheetline\Columns::term_options( 'series' ),
'can' => fn() => current_user_can( get_taxonomy( 'series' )->cap->assign_terms ),
'get' => fn( $p ) => wp_get_object_terms( $p->ID, 'series', array( 'fields' => 'ids' ) ),
'set' => fn( $d, $v ) => $d->terms( 'series', \Extendiment\Sheetline\Columns::term_ids( $v, 'series' ) ),
);
}
return $columns;
}, 10, 2 );
Taxonomies registered for a post type with show_ui already get a column of their own, so you only need this for something special.
Where the column goes
Columns appear in the array's order. Adding a key puts the column at the end; to place it elsewhere, rebuild the array:
add_filter( 'sheetline_columns', function ( $columns ) {
$at = array_search( 'title', array_keys( $columns ), true ) + 1;
$new = array( 'kicker' => array( /* … */ ) );
return array_slice( $columns, 0, $at, true ) + $new + array_slice( $columns, $at, null, true );
} );
Sheetline Pro adds its columns at priority 5, so columns added at the default priority 10 come after them.