Autoload new PHP Class in Sage 10

Hey there,

Long time Sage builder here finally making the switch to version 10. I’m trying to upgrade my approach by utilizing the autoloader feature after seeing it in play on some recent non-sage projects.

I believe I am following the PSR-4 namespace, as shown in the below screenshot, but the file doesn’t seem to be loading. I don’t fully understand how PHP classes work but what I’m working with is loosley based on the previous project I mentioned. Trying to echo out test data into the wp_footer hook isn’t producing anything either.

I have also run composer dump-autoload and the class count does include my new Event class.

file path: app/PostTypes/Event.php

<?php

Namespace App\PostTypes;

class Event
{
    private $slug = 'event';

    private $options = [
        'rewrite' => false,
        'public' => false,
    ];

    public function __construct()
    {
        add_action('init', [$this, 'register']);
    }

    public function register()
    {
        register_extended_post_type( $this->slug, $this->options );
    }
}

I’m not sure where to go from here. Any help would be appreciated. Thanks!

If you were having a hard time calling that class from other files by name.

I believe what you are experiencing is case sensitivity… app vs App although that could be handled safely in the composer.json it is best to match case.

Case sensitivity issues will also present themselves differently on some systems, as some systems (like local envs) aren’t case sensitive but most production servers you will be using are.

I’m running pretty close to an unchanged Sage 10. The app namespace is lowercase in composer.json and everywhere else in the theme. I have matched the case everywhere else in the path.

Screenshot 2023-03-02 at 19.03.19

  "autoload": {
    "psr-4": {
      "App\\": "app/"
    }
  },
1 Like

LGTM @SnazzyCreative! That seems like it should work.

How are you calling the constructor?

Apologies if you are aware of the following, but since you mention you’re new to classes, this may help:

Although composer will load PSR-4 classes, the code in your constructor - public function __construct() {} - will never run, unless you create an instance of the class. This can be done simply: $post_type_event = new \App\Event\PostType();

The new operator will call your __construct() method for you.

Alternatively, as registering a post type is a generally only done once, you could use a static method, and call that via add_action('init', ['\App\PostTypes\Event', 'my_static_register_method']). There is no need to create an instance if calling a static method, but remember $this is not available - use self:: to access static properties.


PS. If you could use backticks and code instead of screenshots that would be great - makes the thread much more accessible.

1 Like

Thanks @talss89!

I am not calling the constructor so that explains why this code isn’t running. I missed this from the project I’m basing this on. There would be a line for each class in one of the base files.

use App\PostTypes\Event; (full namespace path / class name)

This feels like it goes against the autoloading approach if each file has to be declared anyway. I’m basically looking to re-create the simplicity of soberwp/models on Sage 9 using johnbillion/extended-cpts, with a separate file for each custom post type.

My old approach would be to make a separate file for each post type and loop through them to require_once each file.

register_extended_post_type( $postType, $options );

I’m trying to modernise and the composer autoloading only triggering when needed sounds like the right way to go. I also don’t want to be needlessly complicated.

Ah, understood! PSR-4 autoloading may not be the solution you’re looking for, although it’s a great standard to adhere to anyway for maintainability.

Here’s a function I’ve quickly put together which will instantiate all classes and fire constructors in your App/PostTypes namespace. If keeping a reference to your instance is important, you may want to modify, as the instance new $class() is just left on the stack.

function load_all_post_types($ns = 'App\PostTypes') {
    foreach(glob(__dir__ . '/PostTypes/*.php') as $fn) {
        $class = $ns . '\\' . basename($fn, '.php');
        new $class();
    }
}

This assumes you’re calling this function from your ./app dir. If not, modify the glob() call. Also, please bear in mind this isn’t tested production code - globbing on each request isn’t performant, and there may be other issues.

For a bit of background; Composer autoloading works by registering an autoload handler (spl_autoload_register()) which is only fired if a class name is referenced, but cannot be found. It’s almost like a final error handler before throwing an exception. That’s why just adding files to the directory won’t execute any code without a reference to it.

2 Likes