[wp-hackers] overriding pluggable.php functions

Showing 1-23 of 23 messages
[wp-hackers] overriding pluggable.php functions Will Norris 1/9/09 12:09 PM
I've been toying around with this thought for a little while, and  
would like hear what others think.  Right now I'm working on an OAuth  
plugin for WordPress.  If we can get it all done in time, it may go  
into WP 2.8, but for the time being I'm just writing it as a plugin.  
One of the things I'm doing is to override wp_authenticate for XML-RPC  
requests so that I can do OAuth authentication rather than standard  
username and password.  This much is really simple:

if (XMLRPC_REQUEST && !function_exists('wp_authenticate')) {
     function wp_authenticate($username, $password) { /* My custom  
function */ }
}

My problem is that if the current request is not using OAuth, then I'd  
like to fall back to the standard username/password logic found in  
pluggable.php.  Unfortunately, because pluggable.php works by  
completely replacing the functions, I can't call that version of  
wp_authenticate.  The only way I could fall back to that logic is to  
completely copy and paste it all into my custom wp_authenticate  
function.  This is of course bad practice, and not future-proof.  So  
I've been thinking about how it would work if pluggable.php were  
instead made up of functions like:

if (!function_exists('wp_authenticate')) {
     function wp_authenticate($username, $password) {
         return _wp_authenticate($username, $password) {
     }
}

function _wp_authenticate($username, $password) {
     /* all the normal authentication logic */
}

So basically, the functions which can be replaced by plugins don't  
actually include any logic whatsoever, they simply call "private"  
counterparts.  This way, I can override wp_authenticate, but can still  
fall back by calling _wp_authenticate myself.  Just to be clear, this  
has nothing to do with OAuth directly... that just happens to be the  
thing I'm working on right now.  I've actually run into this quite  
regularly for a number of different functions in pluggable.php.  If  
this has already been discussed, just point me to that thread so I can  
get caught up.

Thoughts?

-will
_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Otto 1/9/09 12:55 PM
I think that is a really solid idea. Make an enhancement ticket on
trac about it.
Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/9/09 1:24 PM
On Jan 9, 2009, at 12:55 PM, Otto wrote:

> I think that is a really solid idea. Make an enhancement ticket on
> trac about it.

done. http://trac.wordpress.org/ticket/8833


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Stephen Rider 1/9/09 6:11 PM
It's almost like putting a do_action at the end of every pluggable  
function -- but more powerful and cheaper. :)

Stephen

On Jan 9, 2009, at 2:09 PM, Will Norris wrote:

> I've been thinking about how it would work if pluggable.php were  
> instead made up of functions like:
>
> if (!function_exists('wp_authenticate')) {
>    function wp_authenticate($username, $password) {
>        return _wp_authenticate($username, $password) {
>    }
> }
>
> function _wp_authenticate($username, $password) {
>    /* all the normal authentication logic */
> }
>
> So basically, the functions which can be replaced by plugins don't  
> actually include any logic whatsoever, they simply call "private"  
> counterparts.  This way, I can override wp_authenticate, but can  
> still fall back by calling _wp_authenticate myself.
_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Gaarai 1/9/09 6:13 PM
I have to say Will, that's a fantastic idea. Great work.

Chris Jean
http://gaarai.com/
http://wp-roadmap.com/

Re: [wp-hackers] overriding pluggable.php functions Dougal Campbell 1/9/09 7:12 PM
Will Norris wrote:
> [...] So I've been thinking about how it would work if pluggable.php
> were instead made up of functions like:
>
> if (!function_exists('wp_authenticate')) {
>     function wp_authenticate($username, $password) {
>         return _wp_authenticate($username, $password) {
>     }
> }
>
> function _wp_authenticate($username, $password) {
>     /* all the normal authentication logic */
> }
>
> So basically, the functions which can be replaced by plugins don't
> actually include any logic whatsoever, they simply call "private"
> counterparts.  This way, I can override wp_authenticate, but can still
> fall back by calling _wp_authenticate myself. [...]

*headslap, because I didn't think of it myself*

+1 on this idea.

Sometime back, I had run into a a similar problem, wanting to override a
pluggable function, but still be able to fall back to the original code.
Of course, I went with the quick-and-dirty solution of just copying the
original function. But I knew it was an ugly solution, because it wasn't
future-proof.

This is the kind of elegant solution that's needed. It's basically the
procedural programming equivalent of being able to call a super() method
in OOP. :)

--
Dougal Campbell <dou...@gunters.org <mailto:dou...@gunters.org>>
http://dougal.gunters.org/
http://twitter.com/dougal


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/9/09 10:13 PM
On Jan 9, 2009, at 7:12 PM, Dougal Campbell wrote:

> Will Norris wrote:
>> [...] So I've been thinking about how it would work if  
>> pluggable.php were instead made up of functions like:
>>
>> if (!function_exists('wp_authenticate')) {
>>    function wp_authenticate($username, $password) {
>>        return _wp_authenticate($username, $password) {
>>    }
>> }
>>
>> function _wp_authenticate($username, $password) {
>>    /* all the normal authentication logic */
>> }
>>
>> So basically, the functions which can be replaced by plugins don't  
>> actually include any logic whatsoever, they simply call "private"  
>> counterparts.  This way, I can override wp_authenticate, but can  
>> still fall back by calling _wp_authenticate myself. [...]
>
> *headslap, because I didn't think of it myself*
>
> +1 on this idea.
>
> Sometime back, I had run into a a similar problem, wanting to  
> override a pluggable function, but still be able to fall back to the  
> original code. Of course, I went with the quick-and-dirty solution  
> of just copying the original function. But I knew it was an ugly  
> solution, because it wasn't future-proof.
>
> This is the kind of elegant solution that's needed. It's basically  
> the procedural programming equivalent of being able to call a  
> super() method in OOP. :)

I actually chatted with Peter Westwood in #wordpress-dev today and he  
suggested using filters instead... there is certainly an elegance to  
this.  pluggable.php was designed to *replace* functionality, not  
*add* it.  There is already a great mechanism in wordpress to add  
functionality... filters and actions.  So imagine something along the  
lines of...

   if (!function_exists('wp_authenticate')) {
     function wp_authenticate($username, $password) {
       return apply_filters('authenticate', null, $username, password);
     }
   }

   add_filter('authenticate', '_wp_authenticate', 10, 3);
   function _wp_authenticate($user, $username, $password) {


     /* all the normal authentication logic */
   }

Now I could do something like the following in my plugin...

   add_filter('authenticate', 'my_authenticate', 9, 3);
   function my_authenticate($user, $username, $password) {
     if ( /* some check*/) {
       /* custom authenticate logic here */

       // just remove the default authentication filter
       remove_filter('authenticate', '_wp_authenticate');

       // or remove them all
       remove_all_filters('authenticate');
     }
     return $user;
   }


This way we get all the power and flexibility that comes from the  
hooks system.  You do have to think about other plugins that may be  
implementing the same hook, but that's no different than is being done  
today.  Perhaps in the example above, the /* some check */ statement  
should include something along the lines of checking that $user is  
null?  I don't know.  What do you others think?

-will

_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions DD32 1/9/09 10:31 PM
Ooh, Now -that- would be better..

I'm building something on top of WordPress atm, and due to the nature
of it, I've had to override from pluggable functions to get the
functionality i wanted.. However, theres a huge But to that, By
overriding the functionality, I've removed the ability for users to
override the authentication methods themselves.. So right now, its
either my app, or authenticate against a 3rd party.. (App = Its not a
plugin, its not atheme, its a entire app with WP as a backend)

If it was changed to use filters like that, Then it'd be possible for
both my app and for 3rd-party authentication to work at the same
time.. (Assuming the 3rd party auth. used the filters too).. I hadnt
yet sat down and thought about a workaround, but filters definately
fit the bill :)

2009/1/10 Will Norris <wi...@willnorris.com>:


> On Jan 9, 2009, at 7:12 PM, Dougal Campbell wrote:
> I actually chatted with Peter Westwood in #wordpress-dev today and he
> suggested using filters instead... there is certainly an elegance to this.
>  pluggable.php was designed to *replace* functionality, not *add* it.  There
> is already a great mechanism in wordpress to add functionality... filters
> and actions.  So imagine something along the lines of...
_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/10/09 12:48 AM
Just implemented this to get OAuth working, and found that you don't  
need to remove other filters.  At least the default filter should  
first check the $user variable, and if set, bail out.  Plugins  
*should* do the same thing, but may not if they have good reason to.  
Updated example inline.

On Jan 9, 2009, at 10:13 PM, Will Norris wrote:
> I actually chatted with Peter Westwood in #wordpress-dev today and  
> he suggested using filters instead... there is certainly an elegance  
> to this.  pluggable.php was designed to *replace* functionality, not  
> *add* it.  There is already a great mechanism in wordpress to add  
> functionality... filters and actions.  So imagine something along  
> the lines of...
>
>  if (!function_exists('wp_authenticate')) {
>    function wp_authenticate($username, $password) {
>      return apply_filters('authenticate', null, $username, password);
>    }
>  }
>
>  add_filter('authenticate', '_wp_authenticate', 10, 3);
>  function _wp_authenticate($user, $username, $password) {
>    /* all the normal authentication logic */
>  }

this would now become...

   function _wp_authenticate($user, $username, $password) {
       if (is_a($user, 'WP_User')) return $user;

       /* all the normal authentication logic */

       return $user;
   }


> Now I could do something like the following in my plugin...
>
>  add_filter('authenticate', 'my_authenticate', 9, 3);
>  function my_authenticate($user, $username, $password) {
>    if ( /* some check*/) {
>      /* custom authenticate logic here */
>
>      // just remove the default authentication filter
>      remove_filter('authenticate', '_wp_authenticate');
>
>      // or remove them all
>      remove_all_filters('authenticate');
>    }
>    return $user;
>  }

this gets simplified, and now looks exactly like the standard function  
above:

   function my_authenticate($user, $username, $password) {
       if (is_a($user, 'WP_User')) return $user;  // or leave this out  
if I don't care about other authentication plugins

       /* custom authenticate logic here that may or may not update  
value of $user */

       return $user;


   }
_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Ryan McCue 1/10/09 1:22 AM
Will Norris wrote:
>   if (!function_exists('wp_authenticate')) {
>     function wp_authenticate($username, $password) {
>       return apply_filters('authenticate', null, $username, password);
>     }
>   }

Instead of calling apply_filters() with a null value to filter, call
do_action() instead, as that's what it's built for.

--
Ryan McCue
<http://cubegames.net/>

_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/10/09 2:36 AM

On Jan 10, 2009, at 1:22 AM, Ryan McCue wrote:

> Will Norris wrote:
>>  if (!function_exists('wp_authenticate')) {
>>    function wp_authenticate($username, $password) {
>>      return apply_filters('authenticate', null, $username, password);
>>    }
>>  }
>
> Instead of calling apply_filters() with a null value to filter, call
> do_action() instead, as that's what it's built for.


Actions are just for firing off events at a particular point in the  
code.  The different functions which implement the same action hook do  
not interact with each other at all, nor do they return any values.

Filters on the other hand, are specifically for taking a value, and  
passing it through the multiple filters, with the expectation that a  
final (perhaps modified) value will be returned at the end.  The  
functions which implement the same filter hook are each passed the  
newly updated value in turn, and have the opportunity to modify the  
value further before passing it on to the next function.

in the case of wp_authenticate(), it is expected to return either null  
or an WP_User object.  We begin by passing in null.  If any of the  
filter implementations are able to authenticate the user by whatever  
means, all they need to do is return a new WP_User object.  Otherwise,  
they just return what they were originally passed in.  If no filter  
function is able to authenticate the user, then null ends up being  
returned.

If we were to use do_action(), nothing would ever be returned by  
wp_authenticate.

-will


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions scribu 1/10/09 2:43 AM
If a filter were to be used on wp_authenticate, why would the function need
to be in pluggable.php (save for backwards compatibility)?

--
http://scribu.net


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/10/09 2:53 AM

On Jan 10, 2009, at 2:43 AM, scribu wrote:

> If a filter were to be used on wp_authenticate, why would the  
> function need
> to be in pluggable.php (save for backwards compatibility)?

that would be the only reason.


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions DD32 1/10/09 2:53 AM
Backwards compat would be the only reason to have it replaceable like
that still..
Probably makes sense really to move to filters though.

2009/1/10 scribu <scr...@gmail.com>:

Re: [wp-hackers] overriding pluggable.php functions Otto 1/10/09 12:18 PM
On Sat, Jan 10, 2009 at 12:13 AM, Will Norris <wi...@willnorris.com> wrote:
> What do you others think?

Another way to do this sort of thing is to have a special return value
on a filter.

function wp_authenticate($username, $password) {
  $pre = apply_filters( 'wp_authenticate', false, $username, $password );
  if ( false !== $pre ) return $pre;
  .. normal wp_auth logic here ..
}

Then, to hook in your function, instead of replacing the original, you
simply create your own and hook it in, like so:

function my_authenticate($value, $username, $password) {
.. do my authentication...
...oh noes, I can't authenticate, let's fall back to normal logic...
return false;
}
add_filter('wp_authenticate', 'my_authenticate',10,3);

This is the same method used in a few other places, like in the
get_option function with the pre_option_* filter. Obviously, this only
works for functions that don't return true/false normally, but most
every function has some kind of invalid value that can be returned to
trigger it.

Alternatively, one could use Exceptions. Raise the exception, catch
it, then do the default logic if it's the exception you're looking
for. This would be the ideal way, but I'm not sure exceptions are 100%
PHP4 compatible in all cases.

-Otto


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Otto 1/10/09 12:23 PM
On Sat, Jan 10, 2009 at 4:36 AM, Will Norris <wi...@willnorris.com> wrote:
> in the case of wp_authenticate(), it is expected to return either null or an
> WP_User object.  We begin by passing in null.  If any of the filter
> implementations are able to authenticate the user by whatever means, all
> they need to do is return a new WP_User object.  Otherwise, they just return
> what they were originally passed in.  If no filter function is able to
> authenticate the user, then null ends up being returned.

Hah. I like this much better.  Instead of calling wp_authenticate in
the code anywhere, we hook it to a filter. Then you say that every
authentication function needs to hook into that filter and have code
like if ($value !== null) return $value; right at the top of the
function. That way, if somebody authenticated already, it bypasses the
rest and falls on through. You can use the priority of the filter to
determine the order of authentication attempts.

-Otto


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/10/09 1:04 PM

On Jan 10, 2009, at 12:23 PM, Otto wrote:

> On Sat, Jan 10, 2009 at 4:36 AM, Will Norris <wi...@willnorris.com>  
> wrote:
>> in the case of wp_authenticate(), it is expected to return either  
>> null or an
>> WP_User object.  We begin by passing in null.  If any of the filter
>> implementations are able to authenticate the user by whatever  
>> means, all
>> they need to do is return a new WP_User object.  Otherwise, they  
>> just return
>> what they were originally passed in.  If no filter function is able  
>> to
>> authenticate the user, then null ends up being returned.
>
> Hah. I like this much better.  Instead of calling wp_authenticate in
> the code anywhere, we hook it to a filter. Then you say that every
> authentication function needs to hook into that filter and have code
> like if ($value !== null) return $value; right at the top of the
> function. That way, if somebody authenticated already, it bypasses the
> rest and falls on through. You can use the priority of the filter to
> determine the order of authentication attempts.

Well, I would still leave wp_authenticate() as a public function that  
can be called from wherever... just make it a wrapper around the  
apply_filters stuff.  And as you hinted at in your other post, we  
actually don't need to create the new private functions either...  
instead of having both wp_authenticate and _wp_authenticate which has  
the standard logic, we simply need to add the apply_filters call at  
the beginning of the existing function...

   function wp_authenticate($username, $password) {
       $pre = apply_filters( 'wp_authenticate', false, $username,  
$password );
       if ( false !== $pre ) return $pre;
       .. normal wp_auth logic here ..
   }

Of course, there is still something attractive about being able to  
call the standard logic directly anytime you want.  This only works  
cleanly if it's separated out into another function.  Otherwise, you'd  
have to clear out all the filters, then call wp_authenticate().

-will


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Norris 1/10/09 1:17 PM

The more I'm looking at the authentication code, especially  
wp_signon(), the more I think it is really a unique case.  I think  
more work needs to be done here beyond just adding a filter like we've  
talked about.  I do believe the filter will be part of the overall  
solution though.  I'm going to focus on the wp_authenticate case for  
the time being and see what I can come up with.  Once that's working,  
I suspect we can do similar things with filters (or privates  
functions, whichever seems to work best) with the other pluggable.php  
functions.

-will
_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Dougal Campbell 1/10/09 2:43 PM
Will Norris wrote:
> I actually chatted with Peter Westwood in #wordpress-dev today and he
> suggested using filters instead... there is certainly an elegance to
> this.  pluggable.php was designed to *replace* functionality, not
> *add* it.  There is already a great mechanism in wordpress to add
> functionality... filters and actions.  So imagine something along the
> lines of... [...example using filters...]

At first I thought this was just adding a couple of extra layers of
function calls without any real advantage. But then I realized that this
approach avoids a major pitfall of the existing method and the
previously suggested enhancement: function namespace collisions.
Currently, if you have two different plugins trying to replace the same
pluggable function, they can trigger a PHP fatal error unless the
plugins are *also* using function_exists() as a safety net.

Good evolution of a good idea. :)

--
Dougal Campbell <dou...@gunters.org <mailto:dou...@gunters.org>>
http://dougal.gunters.org/
http://twitter.com/dougal
_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Ryan McCue 1/10/09 2:44 PM
Otto wrote:
> Alternatively, one could use Exceptions. Raise the exception, catch
> it, then do the default logic if it's the exception you're looking
> for. This would be the ideal way, but I'm not sure exceptions are 100%
> PHP4 compatible in all cases.
>  

Exceptions are PHP5+ only, unfortunately, so they're out of the picture
until WordPress goes PHP5+ only.

--
Ryan McCue
<http://cubegames.net/>

_______________________________________________


wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Ozh 1/10/09 2:50 PM
On Sat, Jan 10, 2009 at 11:44 PM, Ryan McCue <ryan...@cubegames.net> wrote:
> Exceptions are PHP5+ only, unfortunately, so they're out of the picture
> until WordPress goes PHP5+ only.
>

Hey? It's been like... ages! since the last "Go PHP5" thread :)

Ozh
--
http://planetOzh.com ~ Blog and WordPress Stuff


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] Go PHP5 Ryan McCue 1/10/09 3:00 PM
Ozh wrote:
> On Sat, Jan 10, 2009 at 11:44 PM, Ryan McCue <ryan...@cubegames.net> wrote:
>  
>> Exceptions are PHP5+ only, unfortunately, so they're out of the picture
>> until WordPress goes PHP5+ only.
>>
>>    
>
> Hey? It's been like... ages! since the last "Go PHP5" thread :)
>
> Ozh
>  

Surely you're not suggesting something here... :-P

--
Ryan McCue
<http://cubegames.net/>

_______________________________________________


wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: [wp-hackers] overriding pluggable.php functions Will Anderson 1/10/09 4:50 PM
Along with the PHP4 compatibility issue, it's almost always a bad idea to
use exceptions for testing. Exceptions take enough time and memory to
generate that you're usually better off using an if statement if you can. Of
course there are sometimes cases where you can't use an if statement (which
is why exceptions exist in the first place) but avoiding exceptions when you
can is usually a good idea.

--
Will Anderson
http://www.itsananderson.com/


_______________________________________________
wp-hackers mailing list
wp-ha...@lists.automattic.com
http://lists.automattic.com/mailman/listinfo/wp-hackers

More topics »