Extending & internals
Pages Plus exposes no hooks of its own. As of 1.5.1 there is no apply_filters() and no do_action() anywhere in it: nothing here is a public contract you can hook into, and pretending otherwise would be worse than saying so. What follows is what it attaches to, and the handles, keys and class names you can build on.
What it hooks
Everything except the textdomain load and the duplicate handler is wired inside load-edit.php, scoped to the current screen's post type.
| Hook | Callback | Removable |
|---|---|---|
manage_{$type}_posts_columns |
freshet_pagesplus_columns |
yes |
manage_{$type}_posts_custom_column |
freshet_pagesplus_render_column |
yes |
manage_edit-{$type}_sortable_columns |
freshet_pagesplus_sortable_columns |
yes |
the_title |
freshet_pagesplus_capture_path |
yes |
restrict_manage_posts |
freshet_pagesplus_parent_filter, freshet_pagesplus_template_filter |
yes |
post_row_actions, page_row_actions |
freshet_pagesplus_duplicate_link |
yes |
bulk_actions-edit-{$type} |
freshet_pagesplus_register_bulk_duplicate |
yes |
handle_bulk_actions-edit-{$type} |
freshet_pagesplus_handle_bulk_duplicate |
yes |
admin_notices |
freshet_pagesplus_bulk_notice |
yes |
admin_enqueue_scripts |
freshet_pagesplus_enqueue_assets |
yes |
admin_footer |
freshet_pagesplus_print_paths |
yes |
admin_action_freshet_pagesplus_duplicate |
freshet_pagesplus_duplicate_handler |
yes |
pre_get_posts (parent filter, template filter) |
closure | no |
posts_search (path search) |
closure | no |
posts_clauses (parent sorting) |
closure | no |
the_posts (branch re-rooting) |
closure | no |
The named callbacks can be removed; the closures cannot, because an anonymous function has no handle to pass to remove_filter(). If you need one of those four off, deactivating the plugin is the honest answer.
Removing a piece
The named callbacks are added during load-edit.php, so remove them at a later priority on that same hook — anything earlier runs before they are attached:
add_action( 'load-edit.php', function () {
remove_filter( 'post_row_actions', 'freshet_pagesplus_duplicate_link' );
remove_filter( 'page_row_actions', 'freshet_pagesplus_duplicate_link' );
}, 20 );
Dropping a column is easier from the other side — filter the columns after they are added:
add_filter( 'manage_page_posts_columns', function ( array $columns ): array {
unset( $columns['freshet_pagesplus_modified'] );
return $columns;
}, 20 );
Keys and query arguments
| String | What it is |
|---|---|
freshet_pagesplus_modified |
Modified column key |
freshet_pagesplus_parent |
Parent column key; also the filter's query arg (top, or a parent ID) |
freshet_pagesplus_template |
Template column key; also the filter's query arg (a template file, default, or empty) |
orderby=freshet_pagesplus_parent |
Sort by parent title |
freshet_pagesplus_duplicated |
Count appended to the redirect after a bulk duplicate |
Each is also available as a constant — FRESHET_PAGESPLUS_COL_MODIFIED, FRESHET_PAGESPLUS_COL_PARENT, FRESHET_PAGESPLUS_COL_TEMPLATE, FRESHET_PAGESPLUS_PARENT_QV, FRESHET_PAGESPLUS_TEMPLATE_QV, FRESHET_PAGESPLUS_TOP_VALUE, FRESHET_PAGESPLUS_DUP_ACTION, FRESHET_PAGESPLUS_VERSION. So links into a filtered view compose:
$branch = add_query_arg(
[ 'post_type' => 'page', FRESHET_PAGESPLUS_PARENT_QV => $parent_id ],
admin_url( 'edit.php' )
);
Styling
The stylesheet and script share one src-less handle, freshet-pagesplus, registered and enqueued only on the list-table screens the plugin enhances. Add your own rules to it after it is registered:
add_action( 'admin_enqueue_scripts', function () {
if ( wp_style_is( 'freshet-pagesplus', 'enqueued' ) ) {
wp_add_inline_style( 'freshet-pagesplus', '.freshet-pagesplus-path{font-size:13px}' );
}
}, 20 );
The class names are stable:
| Class | Element |
|---|---|
.freshet-pagesplus-path |
The URL path under a title (an <a> when the post is viewable, a <span> otherwise) |
.freshet-pagesplus-sub |
The #ID · age · author line in the Modified column |
.column-freshet_pagesplus_modified and friends |
The columns themselves, via WordPress' usual .column-{key} |
The path payload
Paths are collected while the table renders and printed in the admin footer as window.freshetPagesplusPaths — { postId: { path, href } }, where an empty href means "not viewable, render as text". The injector runs once and skips any row that already has a path element, so it is safe to read the payload yourself; it is not a supported API, and the shape may change.
Translation
Text domain freshet-pages-plus, loaded on init from the plugin's own /languages, so a bundled .mo works as well as one delivered by wordpress.org.