WordPress-Plugin-Boilerplate icon indicating copy to clipboard operation
WordPress-Plugin-Boilerplate copied to clipboard

Using the plugins_api filter.

Open multiplehats opened this issue 7 years ago • 17 comments

Hey guys!

I feel I'm missing something incredibly obvious. I'm trying to use the plugins_api filter to show the View Details link on the plugins.php page. The function is working correctly for all plugins except mine. I feel it has something to do with how I register the filter.

Here's is my function. When I remove if( $this->plugin_name !== $args->slug ) I can see the View Details on other plugins except mine. I checked the $args->slug and $this->plugin_name and they are identical.

    public function view_details( $res, $actions, $args ){

      $action = 'plugin_information';

    	// do nothing if this is not about getting plugin information
    	if( $action !== 'plugin_information' )
    		return false;

    	//do nothing if it is not our plugin
    	if( $this->plugin_name !== $args->slug )
    		return false;


    	// trying to get from cache first
    	if( false == $remote = get_transient( 'xxx' ) ) {

    		// info.json is the file with the actual plugin information on the server
    		$remote = wp_remote_get( 'http://xxx.local/info.json', array(
    			'timeout' => 10,
    			'headers' => array(
    				'Accept' => 'application/json'
    			) )
    		);

    		if ( !is_wp_error( $remote ) && isset( $remote['response']['code'] ) && $remote['response']['code'] == 200 && !empty( $remote['body'] ) ) {
    			set_transient( 'xxx, $remote, 43200 ); // 12 hours cache
    		}

    	}

    	if( $remote ) {

    		$remote = json_decode( $remote['body'] );
    		$res = new stdClass();
    		$res->name = $remote->name;
    		$res->slug = $this->plugin_name;
    		$res->version = $remote->version;
    		$res->tested = $remote->tested;
                $res->tested = $remote->homepage;
    		$res->requires = $remote->requires;
    		$res->author = '<a href="https:/xxx.com">Chris Schwartze</a>';
    		$res->author_profile = 'https://profiles.wordpress.org/xxx';
    		$res->download_link = $remote->download_url;
    		$res->trunk = $remote->download_url;
    		$res->last_updated = $remote->last_updated;
    		$res->sections = array(
    			'changelog' => $remote->sections->changelog
    		);
        
    		if( !empty( $remote->sections->screenshots ) ) {
    			$res->sections['screenshots'] = $remote->sections->screenshots;
    		}
               	return $res;
    	}
    	return false;
    }

Here's my class-plugin-name.php

   /**
     * Register all of the hooks related to the admin area functionality
     * of the plugin.
     *
     * @since    1.0.0
     * @access   private
     */
    private function define_admin_hooks() {
      $this->loader->add_filter('plugins_api' , $plugin_admin, 'view_details', 10, 3);
    }

Any pointers would be really appreciated!

multiplehats avatar Jun 05 '18 09:06 multiplehats

What is $plugin_admin in the define_admin_hooks() method? :)

dingo-d avatar Jun 05 '18 10:06 dingo-d

Thanks for the quick reply @dingo-d

$plugin_admin = new My_Plugin_Name_Admin($this->get_plugin_name(), $this->get_version());

multiplehats avatar Jun 05 '18 10:06 multiplehats

Did you put it inside the method? Because you'll either need to add it inside the method to make this variable available inside the method, or maybe add it in the constructor like $this->plugin_admin, and then use it as such inside the method

$this->loader->add_filter('plugins_api' , $this->plugin_admin, 'view_details', 10, 3);

dingo-d avatar Jun 05 '18 12:06 dingo-d

@dingo-d Apologies, maybe I wasn't clear enough with my example.

I believe $this->plugin_name' is setup in public function __construct()' out of the box. At least, I haven't made much changes to that function. Here it is in full:

    public function __construct()
    {
        if (defined('PLUGIN_NAME_VERSION')) {
            $this->version = PLUGIN_NAME_VERSION;
        } else {
            $this->version = '1.0.0';
        }
        $this->plugin_name = 'juggle-for-woocommerce';
        $this->load_dependencies();
        $this->set_locale();
        $this->define_admin_hooks();
        $this->define_public_hooks();
    }

multiplehats avatar Jun 05 '18 12:06 multiplehats

Ok, I wanted you to do this yourself (learning experience) but I'll help :D

Either do this:

 public function __construct()
    {
        if (defined('PLUGIN_NAME_VERSION')) {
            $this->version = PLUGIN_NAME_VERSION;
        } else {
            $this->version = '1.0.0';
        }
        $this->plugin_name = 'juggle-for-woocommerce';
        $this->load_dependencies();
        $this->set_locale();
        $this->define_admin_hooks();
        $this->define_public_hooks();
        $this->plugin_admin = new My_Plugin_Name_Admin( $this->plugin_name, $this->version );
    }

   /**
     * Register all of the hooks related to the admin area functionality
     * of the plugin.
     *
     * @since    1.0.0
     * @access   private
     */
    private function define_admin_hooks() {
      $this->loader->add_filter('plugins_api' , $this->plugin_admin, 'view_details', 10, 3);
    }

or do this:

   /**
     * Register all of the hooks related to the admin area functionality
     * of the plugin.
     *
     * @since    1.0.0
     * @access   private
     */
    private function define_admin_hooks() {
      $plugin_admin = new My_Plugin_Name_Admin($this->get_plugin_name(), $this->get_version());

      $this->loader->add_filter('plugins_api' , $plugin_admin, 'view_details', 10, 3);
    }

I'm usually doing the second way, even though it's not perfect.

Hope this helps :)

dingo-d avatar Jun 05 '18 13:06 dingo-d

@dingo-d Appreciate that! I actually have $plugin_admin = new My_Plugin_Name_Admin($this->get_plugin_name(), $this->get_version()); in my private function define_admin_hooks(), I didn't mention it at first because I assumed it was common practice, since it's included in the boilerplate: https://github.com/DevinVinson/WordPress-Plugin-Boilerplate/blob/60940a97614170845242849d0b78e6def0d06073/plugin-name/includes/class-plugin-name.php#L155

My bad... any other ideas?

multiplehats avatar Jun 05 '18 13:06 multiplehats

Is your plugin hosted on wordpress.org?

dingo-d avatar Jun 05 '18 13:06 dingo-d

@dingo-d No it isn't, but I know it's possible to override the plugin details. I'm trying to do this basically: https://rudrastyh.com/wordpress/self-hosted-plugin-update.html

multiplehats avatar Jun 05 '18 13:06 multiplehats

Ok, then you need to turn on the debugging, and put a bunch of error_log()s around and see where your method breaks. See if it's called at all, if not, why.

dingo-d avatar Jun 05 '18 13:06 dingo-d

@dingo-d Yeah, I've been digging for a while—hence why I'm here. it's being called, everywhere except on my plugin. Last resort is probably Stackoverflow ;)

multiplehats avatar Jun 06 '18 07:06 multiplehats

So after some more debugging, I can see it's working fine except on my own plugin instance. Heck another function that hooks into site_transient_update_plugin is working and I can see WordPress showing an update notification (the red icon in the menu) but not below my plugin. I feel this has to do with how it loads in the plugin boilerplate as I just tried it on a vanilla plugin and it worked fine.

If anyone ever tried to set up a View Details link on the plugins.php page let me know. I'd love to figure this one out.

multiplehats avatar Jun 06 '18 08:06 multiplehats

I just pasted the code and got an error

set_transient( 'xxx, $remote, 43200 ); // 12 hours cache

You're missing a ' in xxx :)

set_transient( 'xxx', $remote, 43200 ); // 12 hours cache

dingo-d avatar Jun 06 '18 10:06 dingo-d

But besides that, the filter won't fire. It did fire when I viewed 'view details' of another plugin when I tested this.

Try asking on wordpress.stackowerflow :/

dingo-d avatar Jun 06 '18 10:06 dingo-d

@dingo-d thanks for sticking with me, I appreciate it.

I was probably missing an ' because I removed some code when I was editing my first post. I just checked my code, and it's there.

But exactly, it only fires when you view 'view details' of another plugin... 👎

i guess i'll reside to SO.

multiplehats avatar Jun 06 '18 10:06 multiplehats

I've worked it out as I was facing the exact same problem with Boilerplate and the referenced plugins_api code. The issue is in the Update function where the plugin filename is set. It's set using plugin_basename( FILE ) which actually returns 'plugin/admin/class-plugin-admin.php' but you want it to return plugin/plugin.php. Hardcode that (replacing it with the name of your plugin) and it'll work.

1jump2 avatar Apr 24 '22 10:04 1jump2

@1jump2 Thank you Sir, it works :)

connectwithAbhishek avatar Aug 18 '22 05:08 connectwithAbhishek

@1jump2 Yes, it works!

The example had the plugin_basename( __FILE__ ) because it was the main plugin file. In my case, and probably yours and the OP's, the updater was in a different file. Hardcoding the plugin slug fixed the issue.

wolffe avatar Nov 22 '22 18:11 wolffe