<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj" -->

---
title: Rethinking do_action(): Events as objects, hooks as...
description: A technique for improving WordPress action hooks by passing typed event objects instead of loose positional arguments. Using `do_action($event::class, $event)`...
canonical: https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Rethinking do_action(): Events as objects, hooks as class names | daily.dev
og:description: A technique for improving WordPress action hooks by passing typed event objects instead of loose positional arguments. Using `do_action($event::class, $event)`...
og:url: https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj
og:image: https://api.daily.dev/og/posts/OXKbbiObJ.png
og:image:alt: Rethinking do_action(): Events as objects, hooks as class names
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Rethinking do_action(): Events as objects, hooks as class names

**[WordPress Developer](https://daily.dev/sources/wordpressdev)** · 13 min read · 2 upvotes · 0 comments

## Summary

A technique for improving WordPress action hooks by passing typed event objects instead of loose positional arguments. Using `do_action($event::class, $event)` gives you namespaced hook names via fully-qualified class names, IDE autocomplete and static analysis on payloads, and filter-like mutation through mutable object properties — all without any new dependencies. The approach mirrors the PSR-14 event dispatcher pattern and works with WordPress's existing hook API. The post covers event class design with readonly vs mutable properties, observer vs mutator listener patterns, and the tradeoffs between using class names vs fixed strings as hook identifiers.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://developer.wordpress.org/news/2026/08/rethinking-do_action-events-as-objects-hooks-as-class-names>

## Questions this post answers

### How do I pass a typed object to WordPress's do_action() instead of multiple positional arguments?

Create an event class holding the relevant data as properties, then call do_action( $event::class, $event ) so the hook name becomes the fully-qualified class name and the payload is the single object. Listeners type-hint the event class in their callback signature, giving autocomplete and static analysis instead of untyped positional arguments.

_See how daily.dev surfaces practical WordPress and PHP hook patterns like this for plugin developers._

### How can I avoid using apply_filters() and still let listeners modify a value in WordPress?

Make the relevant property on the event object mutable (not readonly) and dispatch it with do_action(). A listener changes the property directly, and because objects are passed by handle, the dispatching code reads the updated value back after do_action() runs, eliminating the risk of a listener forgetting to return a value in a filter chain.

_Developers weighing WordPress hook patterns can find deeper PHP architecture writeups on daily.dev._

### What is the difference between naming a WordPress hook after a class versus a custom string?

Using the class name (via ::class) gives a namespaced, zero-ceremony hook name that automatically updates when an IDE renames the class, but the hook name changes if the class is moved or renamed, breaking old add_action() calls silently. A custom string like 'myplugin/member-registered' stays fixed regardless of future class refactors, guaranteeing long-term stability for listeners.

_For WordPress developers deciding on hook naming conventions, daily.dev tracks PHP ecosystem best practices._

## Similar posts on daily.dev

- [Beyond Fat Controllers: Mastering Event-Driven Decoupling in Laravel](https://daily.dev/posts/beyond-fat-controllers-mastering-event-driven-decoupling-in-laravel-rkl3ao0vg) · CodeCraft Diary · 1 upvotes · 0 comments
- [Delegates and events in C\# explained](https://daily.dev/posts/delegates-and-events-in-c-explained-p282unysa) · Round The Code · 19 upvotes · 0 comments
- [Stop Using CustomEvent – Frontend Masters Blog](https://daily.dev/posts/stop-using-customevent-frontend-masters-blog-3ffym3p4d) · Frontend Masters · 66 upvotes · 5 comments
- [Ingress is not the owner of the invariant](https://daily.dev/posts/ingress-is-not-the-owner-of-the-invariant-uvprn2asu) · arkency · 0 upvotes · 0 comments

---

Tags: [#architecture](https://daily.dev/tags/architecture), [#php](https://daily.dev/tags/php), [#wordpress](https://daily.dev/tags/wordpress), [#react-hooks](https://daily.dev/tags/react-hooks)

[View this post on daily.dev](https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Rethinking do_action(): Events as objects, hooks as class names","url":"https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj"},"datePublished":"2026-08-03T21:10:34.106Z","dateModified":"2026-09-13T21:57:07.821Z","description":"A technique for improving WordPress action hooks by passing typed event objects instead of loose positional arguments. Using `do_action($event::class, $event)`...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/26167449f4adbf6ac49533fbdd7a32d4?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/26167449f4adbf6ac49533fbdd7a32d4?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"WordPress Developer","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"WordPress Developer","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/cf1b3c66d466440aac9b5e5092d93e86","url":"https://daily.dev/sources/wordpressdev"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"architecture,php,wordpress,react-hooks","timeRequired":"PT13M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"WordPress Developer","item":"https://daily.dev/sources/wordpressdev"},{"@type":"ListItem","position":3,"name":"Rethinking do_action(): Events as objects, hooks as class names"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/rethinking-do-action-events-as-objects-hooks-as-class-names-oxkbbiobj#faq","mainEntity":[{"@type":"Question","name":"How do I pass a typed object to WordPress's do_action() instead of multiple positional arguments?","acceptedAnswer":{"@type":"Answer","text":"Create an event class holding the relevant data as properties, then call do_action( $event::class, $event ) so the hook name becomes the fully-qualified class name and the payload is the single object. Listeners type-hint the event class in their callback signature, giving autocomplete and static analysis instead of untyped positional arguments. See how daily.dev surfaces practical WordPress and PHP hook patterns like this for plugin developers."}},{"@type":"Question","name":"How can I avoid using apply_filters() and still let listeners modify a value in WordPress?","acceptedAnswer":{"@type":"Answer","text":"Make the relevant property on the event object mutable (not readonly) and dispatch it with do_action(). A listener changes the property directly, and because objects are passed by handle, the dispatching code reads the updated value back after do_action() runs, eliminating the risk of a listener forgetting to return a value in a filter chain. Developers weighing WordPress hook patterns can find deeper PHP architecture writeups on daily.dev."}},{"@type":"Question","name":"What is the difference between naming a WordPress hook after a class versus a custom string?","acceptedAnswer":{"@type":"Answer","text":"Using the class name (via ::class) gives a namespaced, zero-ceremony hook name that automatically updates when an IDE renames the class, but the hook name changes if the class is moved or renamed, breaking old add_action() calls silently. A custom string like 'myplugin/member-registered' stays fixed regardless of future class refactors, guaranteeing long-term stability for listeners. For WordPress developers deciding on hook naming conventions, daily.dev tracks PHP ecosystem best practices."}}]}
```

