5

What is the best way to instantiate a class of a plugin in your WordPress theme? To be clear, let's say that there is a class called Get_Meta_Data() and it is being used to get the metadata from DB for any post type. So, I had defined a metadata price and get_price() is a function in the Get_Meta_Data() class, which exists in our plugin. How would you invoke that class in the theme to access the price of a post inside the loop.

Solutions I found: — Classes defined in plugins are not accessible by themes so build methods in plugins outside the class to be able to use those methods in themes. While these methods in a plugin can call the class. Which is not an ideal situation.

Building an API around add_action: Create a custom action get_price_action in the constructor to hook the get_price function. One can call do_action( 'get_price_action', 50 ); somewhere in the theme or in another plugin, and you don't have to care about the inner workings of the class anymore.

If you deactivate the plugin you are still safe: WordPress just ignores unknown actions and the do_action() will do no harm. Plus, other plugins are able to remove or replace the action, so you have build a nice mini API with one add_action().

But I also want my class to take an argument of get_the_ID(). And that complicates the singleton classes.

I open to all kind of suggestions and class architectures. What do you guys do in a similar situation?

At the moment, my class looks like this and it is simply being required in the base file of a plugin.

    <?php
/**
 * Get The Car
 *
 * Gets car related stuff likes meta.
 *
 * @since   1.0.0
 * @package VRC
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * VR_Get_Car.
 *
 * Get class for the car post_type.
 *
 * @since 1.0.0
 */

if ( ! class_exists( 'VR_Get_Car' ) ) :

class VR_Get_Car {

    /**
     * The Car ID.
     *
     * @var     int
     * @since   1.0.0
     */
     public $the_car_ID;


     /**
      * The Meta Data.
      *
      * @var    array
      * @since  1.0.0
      */
      public $the_meta_data;


      /**
       * Meta Keys.
       *
       * @var   array
       * @since 1.0.0
       */
       private $meta_keys = array(
            // TAB                 : Basic Information.
            'price'                => 'vr_car_price',
            'price_postfix'        => 'vr_car_price_postfix',
        );


     /**
      * Constructor.
      *
      * Checks the car ID and assigns
      * the meta data to $the_meta_data.
      *
      * @since 1.0.0
      */
     public function __construct( $the_car_ID = NULL ) {
        // Check if there is $the_car_ID.
        if ( ! $the_car_ID ) {
            $the_car_ID = get_the_ID();
        } else {
            $the_car_ID = intval( $the_car_ID );
        }

            // Assign values to the class variables.
            if ( $the_car_ID > 0 ) {
            $this->the_car_ID    = $the_car_ID;
            $this->the_meta_data = get_post_custom( $the_car_ID );
        }
     }


     /**
      * Get Car: Meta.
      *
      * Gets the car meta_value if passed
      * a meta_key through argument.
      *
      * @since 1.0.0
      */
     public function get_car_meta( $meta_key ) {
        // If meta is set then return value else return false.
        if ( isset( $this->the_meta_data[ $meta_key ] ) ) {
            // Returns the value of meta.
            return $this->the_meta_data[ $meta_key ][0];
        } else {
            return false;
        }
     }


    /**
     * Get Car: ID.
     *
     * @since 1.0.0
     */
    public function get_car_ID() {
        return $this->$the_car_ID;
    }


    /**
     * Get Car: Price.
     *
     * @since 1.0.0
     */
    public function get_car_price() {
        // Returns false if ID is not present.
        if ( ! $this->the_car_ID ) {
            return false;
        }
        return $this->get_car_meta( $this->meta_keys['price'] );
    }


    /**
     * Get Car: Price Postfix.
     *
     * @since 1.0.0
     */
    public function get_car_price_postfix() {
        // Returns false if ID is not present.
        if ( ! $this->the_car_ID ) {
            return false;
        }
        return $this->get_car_meta( $this->meta_keys['price_postfix'] );
    }
   } // class `VR_Get_Car`  ended.

endif;

And I am trying to access the car price in my theme inside the loop like this

// Object of VR_Get_Rental class.

$vr_get_rental = new VR_Get_Car( get_the_ID() );

$vr_this_rental['price'] = $vr_get_rental->get_car_price();

And this doesn't work. Theme doesn't reconginze the class.

EDIT: Thanks to Alain, I figured it out. The issue was with my code inside get_car_meta() function instead of the_meta_data I was using meta_data variable. I just corrected the code above.

But from this discussion, I learned that I could use only one function to return the complete instance of this class. Which was very helpful. I am going to correct the code above and explain.

Now I have a method in my plugin which helps me instantiate the class in the theme. That method is:

/**
 * Get an object of VR_Get_Car class.
 *
 * @since 1.0.0
 */
if ( ! function_exists( 'vr_get_car_obj' ) ) {
    function vr_get_car_obj( $the_car_ID ) {
        // Bails if no ID.
        if ( ! $the_car_ID ){
            return 'No Car ID provided!';
        }

        return new VR_Get_Car( $the_car_ID );
    }
}

And inside the theme I am using the following code to interact with this class.

// Object of VR_Get_Car class.
        if ( function_exists( 'vr_get_car_obj' ) ) {

            $vr_get_car = vr_get_car_obj( get_the_ID() );

            $vr_car_price = $vr_get_car->get_price();

        }

And it works :)

1
  • Removed my comment, as you question relates to a theme.
    – Adam
    Mar 10, 2016 at 10:01

1 Answer 1

4

There are two common solutions to access classes in a plugin from inside a theme:

1. Use an autoloader in the plugin (preferred).

You tell the autoloader how to relate a class name to a PHP file name that contains the class. Then, when you access a class that is not yet known to PHP, the autoloader checks for the file that relates to that class and loads it.

An easy way to use an autoloader is through Composer, but without any additional setup, this will bump your PHP requirement to PHP5.3.2+.

More details on Composer autoloading: https://getcomposer.org/doc/01-basic-usage.md#autoloading

2. Use a function to retrieve an instance.

You can provide one function that returns a reference to an instance of your plugin's class.

Your theme can then check whether that function exists and retrieve the needed reference. After it has access to that reference, it can use the class as if it was within the plugin.

General notes.

As with most things in WordPress, you need to make sure that you correctly manage the WordPress lifecycle. If code from the plugin is only executed on a specific WP action, you must make sure that your theme only references that code after the corresponding action has been triggered.

9
  • 1
    Hey, Alain! Thanks for dropping by. Path #1 sounds interesting, but I would need to research it more (I have already added it in my to-do list). So, for now, I am more interested in path #2. Can you explain by example how would it be? In a real world example, how will I do this You can provide one function that returns a reference to an instance of your plugin's class. When I need one argument to pass through. Once I am done with it, how will I access more functions of a class as in what would be the syntax? Mar 10, 2016 at 10:12
  • To be more specific about my "General notes" section above: A common issue is that you try to directly access the plugin from your theme's functions.php file, and the plugin only gets properly set up on init hook. In such a case, you need to hook the code that you want to execute in your theme to the init action at a higher priority number, or to any later action. Mar 10, 2016 at 10:13
  • @AhmadAwais Yes, sure. Give me a sec. I'll create a gist. Mar 10, 2016 at 10:14
  • I understand the "General Notes" section very well. The problem is, I am new to OOP with WP thingie. And trying to not give in and find a way to do it with OOP inside WP. Thanks looking forward. Mar 10, 2016 at 10:15
  • Here's the link to a Gist: gist.github.com/schlessera/8be67a0b7d10502f17b6 Mar 10, 2016 at 10:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.