Stoat’s hooks are few and deliberate. Each exists because something needed to be added without forking a template.
Actions
stoat_header_buttons
Extra links at the end of the header bar — a sign-in link, an account link, a newsletter opener. Fired twice per page with a context argument: 'bar' in the header, 'modal' in the mobile drawer, so a callback can dress the two differently.
add_action( 'stoat_header_buttons', function ( $context ) {
$class = 'modal' === $context ? 'offcanvas-link' : 'header-link';
printf(
'<a class="%s" href="%s">%s</a>',
esc_attr( $class ),
esc_url( wp_login_url() ),
esc_html__( 'Sign in', 'my-child' )
);
} );
It fires before the header button, so a plain link reads as navigation and the call-to-action keeps the last slot.
This is how OwlDraft Publisher adds its Sign in / Account link.
stoat_entry_flag
Mark an entry in a listing — a members or paid chip, an Updated badge, a sponsor label. Fired once per row with the post ID and a context: 'thumbnail' when the row has a picture to mark, 'text' when it does not.
add_action( 'stoat_entry_flag', function ( $post_id, $context ) {
if ( ! get_post_meta( $post_id, '_sponsored', true ) ) {
return;
}
echo '<span class="entry-flag entry-flag--' . esc_attr( $context ) . '">Sponsored</span>';
}, 10, 2 );
Filters
stoat_header_button_signed_in_actions
Add an answer to When the reader is signed in. Whatever you add, you must also decide on stoat_header_button_visible — the theme cannot judge a state it does not know about.
add_filter( 'stoat_header_button_signed_in_actions', function ( $actions ) {
$actions['hide_paid'] = __( 'Hide for paying members', 'my-child' );
return $actions;
} );
stoat_header_button_visible
Whether the header button renders at all, after the signed-in rule has run. Receives the boolean and the chosen action.
add_filter( 'stoat_header_button_visible', function ( $visible, $action ) {
if ( 'hide_paid' === $action && my_user_has_paid() ) {
return false;
}
return $visible;
}, 10, 2 );
stoat_subtitle_post_types
Which post types get the Subtitle field. Defaults to array( 'post' ).
add_filter( 'stoat_subtitle_post_types', function ( $types ) {
$types[] = 'page';
return $types;
} );
stoat_term_featured_taxonomies
Which taxonomies get the per-term Feature the first post field. Defaults to array( 'category', 'post_tag' ).
stoat_social_icons
The brand marks themselves — slug => <svg>. Add a slug here and, unless its domain is {slug}.com, a matching entry in stoat_social_icons_map.
stoat_social_icons_map
slug => array of domains, for detecting a link’s network from its URL.
add_filter( 'stoat_social_icons_map', function ( $map ) {
$map['mastodon'][] = 'social.example.org';
return $map;
} );
That one line teaches Stoat your own Mastodon instance. See social icons.
stoat_modals
The whole dialog registry, so you can change one the theme itself shipped rather than only adding your own.
Redeclaring a function
Every function in inc/ is wrapped in if ( ! function_exists() ), and a child theme’s functions.php loads before the parent’s. Declaring the same name in your child theme replaces the parent’s version entirely.
It is a real escape hatch and it is there on purpose. It is also a commitment: your copy stops receiving the parent’s fixes. Use a hook where one exists.
