SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    Barefoot on the Moon! silver trophy Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,617
    Mentioned
    56 Post(s)
    Tagged
    1 Thread(s)

    A Plugin system for a PHP app

    Wordpress, Joomla, and a wide array of other webapps I've come across all have plugin systems to extend functionality. I was hoping to look into a plugin system that I could include in a webapp I'd like to build, but looking at the source code of Wordpress, Joomla, and reading up on some threads posted years ago here just makes my head spin.

    http://www.sitepoint.com/forums/showthread.php?t=619739
    http://www.sitepoint.com/forums/showthread.php?t=379440
    http://code.google.com/p/phpplexus/

    Bottom line, I don't get it the theory behind it. How does it work? I don't even know what specific questions to ask to help get me started. Those threads are the best of what I've been able to find, but either the code and/or the theory behind it seems over my head and hasn't clicked yet.

    Has anyone else looked into a plugin system for their own webapps?

  2. #2
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    WordPress's plugin API is implemented pretty simply.

    Say your program has a function that returns the current user's name.

    PHP Code:
    function get_username() { 
      
    $username some_internal_code_that_gets_the_username();
      return 
    $username;

    You can let a plugin modify the username whenever it's displayed by allowing them to register a filter for this function:

    add_filter('get_username', 'name_of_function_to_run');

    Now you modify your get_username function:

    PHP Code:
    function get_username() {
      
    $username some_internal_code_that_gets_the_username();
      
    //look up all filters registered for get_username
      //and apply their functions to $username
      
    return $username

    The other way WordPress allows extending is through "actions" which are points in the code where user code can run. For example, there's an action that fires whenever a comment is posted.

    PHP Code:
    function comment_posted($comment) {
      
    some_internal_code();
      
    do_action('comment_posted'$comment);

    What do_action() would do is look for all actions registered by plugins through an add_action('comment_posted', 'function_name') call, and execute those functions, passing them $comment as an argument, allowing them to do something with the comment that was just posted.

    So really all WordPress has done is litter all their internal code with code that looks up whether an applicable filter or action has been registered that needs to be run right then.

    The plugin files get include()'d before the pluggable code is run so that all the add_action/add_filter type calls are run first.

    I'm oversimplifying (and probably making a few mistaken assumptions) but that's what it looks like to me.

    A real example from the WP code:
    PHP Code:
    function wp_delete_comment($comment_id) {
            global 
    $wpdb;

            
    //runs any functions registered to run before comments are deleted
            
    do_action('delete_comment'$comment_id);

            
    //internal code that deletes a comment

            //runs any functions registered to run before comment status is changed
            
    do_action('wp_set_comment_status'$comment_id'delete');

            
    //internal code that changes comment status

            
    return true;


  3. #3
    Barefoot on the Moon! silver trophy Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,617
    Mentioned
    56 Post(s)
    Tagged
    1 Thread(s)
    Hmm...still hasn't clicked, but maybe it helps direct some questions.

    1) How would you know where to put these extended actions? How do you determine where it's appropriate to do so?

    2) I can see with get_username and comment_posted examples that the extended actions could be benificial for manipulating the text (the username or the comments). Word replacement, text styling, any sort of regex manipulation, touppercase, tolowercase, etc.

    But, what I don't quite get are the extended actions in the wp_delete_comment example. How would those actions be useful?

    Hmm...but I guess that sort of loops back to the first question in this post.

  4. #4
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Force Flow View Post
    Hmm...still hasn't clicked, but maybe it helps direct some questions.

    1) How would you know where to put these extended actions? How do you determine where it's appropriate to do so?
    As many places as you can imagine a plugin author ever wanting to do something. The more places you make "pluggable", the more creative they can be.

    Quote Originally Posted by Force Flow View Post
    But, what I don't quite get are the extended actions in the wp_delete_comment example. How would those actions be useful?
    What if you want to change the behavior of WordPress to not actually delete comments, but simply hide them by setting a "deleted" flag in the database? Add an action to run when a comment is deleted and re-insert that comment into the database with the deleted flag set to true. Add a filter to the code that queries for comments to amend the SQL query to ignore rows with the deleted flag.

    Or a plugin that gathers statistics on what fraction of comments you delete.

    Who knows, the point is to make the option available for someone to develop a plugin that does something when that action occurs.

  5. #5
    Barefoot on the Moon! silver trophy Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,617
    Mentioned
    56 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Dan Grossman View Post
    As many places as you can imagine a plugin author ever wanting to do something. The more places you make "pluggable", the more creative they can be.
    Hm..maybe part of the problem is that I'm not in the midset of a plugin developer. When I think of a feature that would be moderately useful, I usually just go ahead and include it. And then maybe some options in a "settings" section to control it (to turn it on/off, add custom text, etc)

    Touching again on the delete example, it seems to me that if you put in actions before every step that happens, the code would quickly become littered with these actions and be just completely overwhelming and confusing from a code standpoint (both development and maintainability) and from a plugin developer standpoint. In other words...spaghetti code.

  6. #6
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    The above mentioned CMS's pull it off anyway, and have tens of thousands of plugins to show for making all those hooks

  7. #7
    Barefoot on the Moon! silver trophy Force Flow's Avatar
    Join Date
    Jul 2003
    Location
    Northeastern USA
    Posts
    4,617
    Mentioned
    56 Post(s)
    Tagged
    1 Thread(s)
    My head is spinning again... >_<

  8. #8
    SitePoint Enthusiast
    Join Date
    Mar 2007
    Posts
    31
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    basically you need an event handling system in some way and define the events.

    A plugin should be able to receive these events and react on it. Other languages use delegates/listeners etc. What you need to is expose these events to the plugins.

    A good starting point is usually
    • application events
    • actions
    • model mutation


    application events are basic events on the flow of the application. This can be on loading the app for example.

    PRADO has a nice list of events you probably wont need here:
    http://www.pradosoft.com/demos/quick...s.Applications

    some interesting events mentioned there are Authorization and Authentication

    Actions refer to the page location so what url is called and such.

    model mutation is simply adding/changing/removing a User for example.

    Then there is the view. I'm not sure how others do this but there are several ways. Basically you change the main menu and perhaps other parts of your software to a model (if not already the case). This way plugins can choose where their links are published.

    So basically you need to make an event messaging system. And yes this generally gets messy. It makes the flow of the application harder to follow and proper documentation is needed for the plugin developers to make good use of it.

    Then you need to think about dependencies. Can plugins depend on other plugins? If so you need to keep track of which plugins are registered and preferably with a version number of their own. Also if plugins can communicate with each other they need access to the event messaging system to broadcast their messages.

    There are several ways to create such an application. You can use a messaging system from the start where your own components make use of the messaging system. This means you need to think about what events are generally needed for your application. Advantage of this is that your components can be disabled easily. or you can make your application use hooks where you manually put code in places in where you think there should be an event.

    There are also different ways to work with events. You could work with callbacks where the plugin has to register a callback to a certain event and it will get called by the eventhandler when needed. Or you could work with 1 method in the plugin which receives all messages and the plugin can decide on which message to react.

    Note: For each event there should be an before and after event. before event gets fired before the action is done and after .. well after the action is done. Then you can also add priorities to events if for example one plugin needs to be called before another plugin on the same event. So you can make sure the plugin gets called before another plugin.

    Note2: You also need to decide if only 1 event gets sent and loops the same event through the plugins. This way events can be modified by a plugin before the event gets to another plugin. Or you simply broadcast the event to all plugins without the ability for the event to be changed.

    Note3: You need to think about globals too. Before I get flamed this doesn't need to be globals. Lets call it shared objects. What information will a plugin need? It probably needs ways to communicate with the DB. It will want to know what kinda request this is. It probably wants to know what user is requesting this page and if its an admin or not etc.

    As you can see the system gets increasingly more complex depending on how far you want to take it. I wouldn't take it as far as i did here. It fully depends on what you are making and how much control you want to give to the plugin developers.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •