Get The Caller (Plugin / Theme / Core) For All actions & Hook in WordPress

As I said in my comment to the question, you can use the PHP internal ReflectionFunction class to get the filename of the callable. The below code should be a good start to help you. It needs more logic for determining the callbacks and most of that should be abstracted out of the Monitor class anyway. I also didn’t write the code that would get the nice name of the theme, plugin, core, or whatever else might have added the hook from the filename. That should be relatively easy to do though once you know the file that added the hook.

<?php
/**
 * Plugin Name:  Monitor
 */

namespace WPSE\Monitor;

class Monitor {
  protected $callbacks = [];

  protected function addCallback( $callback ) {
    $this->callbacks[] = $callback;
  }

  public function shutdown() {
    var_dump( $this->callbacks );
  }

  public function monitor() {
    global $wp_filter;
    $name = \current_filter();
    if( ! isset( $wp_filter[ $name ] ) ) {
      return;
    }

    $action = $wp_filter[ $name ];

    foreach ( $action->callbacks as $priority => $callbacks ) {
      foreach( $callbacks as $callback ) {
        try {
          if( \is_array( $callback[ 'function' ] ) ) {
            if( \is_object( $callback[ 'function' ][ 0 ] ) ) {
              $class = \get_class( $callback[ 'function' ][ 0 ] );
              $callback[ 'name' ] = $class . '->' . $callback[ 'function' ][ 1 ] . '()';
              $ref = new \ReflectionMethod( $class, $callback[ 'function' ][ 1 ] );
            }
            elseif( \is_string( $callback[ 'function' ][ 0 ] ) ) {
              $callback[ 'name' ] = $callback[ 'function' ][ 0 ] . '::' . $callback[ 'function' ][ 1 ];
              $ref = new \ReflectionMethod( $callback[ 'function' ][ 0 ], $callback[ 'function' ][ 1 ] );
            }
          }
          elseif( $callback[ 'function' ] instanceOf Closure ) {
            $callback[ 'name' ] = 'closure';
            $ref = new \ReflectionMethod( $callback[ 'function' ] );
          }
          elseif( \is_string( $callback[ 'function' ] ) ) {
            $callback[ 'name' ] = $callback[ 'function' ] . '()';
            $ref = new \ReflectionMethod( $callback[ 'name' ] );
          }
          else{
            return;
          }

          $callback[ 'filename' ] = $ref->getFileName();

          $this->addCallback( $callback );

        } catch( \ReflectionException $e ) {
          $callback['error'] = new \WP_Error( 'reflection_exception', $e->getMessage() );
        }
      }
    }
  }
}
class MonitorInit {

  private static $monitor;

  public static function init() {
    self::$monitor = new Monitor();
    \add_action( 'all', [ self::$monitor, 'monitor' ] );
    \add_action( 'shutdown', [ self::$monitor, 'shutdown' ] );
  }
}
\add_action( 'plugins_loaded', __NAMESPACE__ . '\MonitorInit::init', 0 );

The plugins_loaded hook is the first that’s available to regular plugins. So if you want to catch hooks that are added before this, you’ll need to do something tricky.

error code: 523