RESTful Web Services in a WordPress Plugin?

UPDATE (2011-04-15):

Since I wrote this post I’ve learned a tremendous amount about WordPress plugin development; so much so that I can’t overstate how much more I know today than when I wrote this post years ago.  So, while the following post might be a novelty to read, I highly recommend that you don’t use this approach.

The only way that a RESTful approach to web services in WordPress would make sense to me is if a team of rockstar WordPress plugin developers were to create a fully fleshed-out extension to WordPress that offered a complete RESTful web service implementation including one that addressed all edge cases and security concerns; only then I would consider not defaulting to the non-RESTful approach WordPress uses for AJAX.  

In summary I recommend not trying to swim upstream today and instead use the approach provided by WordPress. Who knows, maybe in the future there will be a viable method of doing RESTful web services in WordPress.


So I’ve got a project where I need to have a Flash component built in Flex to call to a WordPress blog and get information about it’s latest post. Should be no problem right?  The easy way to do this would be to just write a "rest.php" file and brute-force all the setup that WordPress does but I thought it would be so much more valuable to implement this as a plug-in.

I figured that I’d just quickly learn how to build a WordPress plug-in and create one for exposing RESTful web services; after all with a year of programming Drupal modules WordPress’ plug-in API can’t be that hard, right?  Well turns out it wasn’t that easy and I think I have run into a design limitation with WordPress and I’m beginning to wish I’d just taken the brute-force approach and said to hell with writing a plug-in.

Although I am not 100% certain, and I hope someone can point out that I’m just doing something wrong, it seems sadly like I’m pushing the edges of the WordPress API and exposing where it’s design falls short. By the way, I’m working with WordPress v2.5 because why upgrade mid-project when god knows if WordPress will release another in the remaining days before this project is done and I’ll just have to do again before deployment?

Here’s the details.  I started writing a plug-in called "RESTful Services" with a goal of implementing URLs that behave in the following fashion; {format} could potentially be html, xhtml, json, xml, rss, atom, etc.:

http://example.com/services.{format}
Provide a list of RESTful services in specified {format}, defaults to html
http://example.com/services/{service}.{format}/{data}?{params
Provide a RESTful service in specified {format}, defaults to html, with optional provided data and parameters.

But before I got all those options working I just wanted to service a page from my RESTful Services plugin where Content-Type: text/plain. I found this page that professes to explain how to hook into the URL routing and after a few fits and starts I can came up with the following code for my plugin that would indeed response to my http://example.com/services URL:

wp-content/plugins/restful-services/restful-web-services.php:

add_action('init', 'restful_services_flush_rewrite_rules');
function restful_services_flush_rewrite_rules() {    
  global $wp_rewrite;
  $wp_rewrite->flush_rules();
}       

add_filter('generate_rewrite_rules', 'restful_services_add_rewrite_rules');
function restful_services_add_rewrite_rules( $wp_rewrite ) {      
  $new_rules = array(        
    'services' => 'wp-content/plugins/restful-services/rest.php',     
  );
  $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
}

The problem with the above was that it wouldn’t call "wp-content/plugins/restful-services/rest.php"; it would simply continued to call "index.php" and display the home page!  After literally hours and hours of debugging with my trusty PhpEd IDE & debugger I was able to find that the code on lines 737 & 738 of "wp-includes/query.php" told WordPress that my service was the home page! It is almost seems like the "generate_rewrite_rules" was implemented as "a good idea" yet no testing has ever been done on it because for the best I can tell it doesn’t work. (Note I’ve reformatted the code to multiple lines so that it is easier to read and does not extend past the right margin of my blog):

wp-includes/query.php:

if ( !(  $this->is_singular                           
      || $this->is_archive                           
      || $this->is_search                           
      || $this->is_feed                           
      || $this->is_trackback                           
      || $this->is_404                           
      || $this->is_admin                           
      || $this->is_comments_popup ) )   
       $this->is_home = true;

I could possibly hack it to get past this by setting one of those to "true", but none of them are really appropriate; there is nothing there quite like an "is_service" instance variable. Setting something like "this->is_singular" or "this->is_feed" might work but it could manifest incompatibility problems with other plugins or future versions of WordPress. Frankly it was rather disappointing to discover this because it tells me that WordPress has hard-coded all the potential scenarios and doesn’t really have a way around it. Seems to me there should really be a hook here and the type of pages should be allowed to be expanded by plugins rather than be hardcoded as only one of ‘singular’, ‘archive’, ‘search’, ‘feed’, … and ‘home.’

Anyway, where this manifests itself is "wp-includes/template-loader.php" file which I have included in it’s entirety below.  It is on lines 24 and 25 where the template loader loaded the home page because it’s not possible to specify otherwise:

wp-includes/template-loader.php:

/**
 * Loads the correct template based on the visitor's url
 * @package WordPress
 */
if ( defined('WP_USE_THEMES') && constant('WP_USE_THEMES') ) {
  do_action('template_redirect');
  $is_home = is_home() ;
  if ( is_robots() ) {
    do_action('do_robots');
    return;
  } else if ( is_feed() ) {
    do_feed();
    return;
  } else if ( is_trackback() ) {
    include(ABSPATH . 'wp-trackback.php');
    return;
  } else if ( is_404() && $template = get_404_template() ) {
    include($template);
    return;
  } else if ( is_search() && $template = get_search_template() ) {
    include($template);
    return;
  } else if ( is_home() && $template = get_home_template() ) {
    include($template);
    return;
  } else if ( is_attachment() && $template = get_attachment_template() ) {
    remove_filter('the_content', 'prepend_attachment');
    include($template);
    return;
  } else if ( is_single() && $template = get_single_template() ) {
    include($template);
    return;
  } else if ( is_page() && $template = get_page_template() ) {
    include($template);
    return;
  } else if ( is_category() && $template = get_category_template()) {
    include($template);
    return;
  } else if ( is_tag() && $template = get_tag_template()) {
    include($template);
    return;
  } else if ( is_tax() && $template = get_taxonomy_template()) {
    include($template);
    return;
  } else if ( is_author() && $template = get_author_template() ) {
    include($template);
    return;
  } else if ( is_date() && $template = get_date_template() ) {
    include($template);
    return;
  } else if ( is_archive() && $template = get_archive_template() ) {
    include($template);
    return;
  } else if ( is_comments_popup() && $template = get_comments_popup_template() ) {
    include($template);
    return;
  } else if ( is_paged() && $template = get_paged_template() ) {
    include($template);
    return;
  } else if ( file_exists(TEMPLATEPATH . "/index.php") ) {
    include(TEMPLATEPATH . "/index.php");
    return;
  }
} else {
  // Process feeds and trackbacks even if not using themes.
  if ( is_robots() ) {
    do_action('do_robots');
    return;
  } else if ( is_feed() ) {
    do_feed();
    return;
  } else if ( is_trackback() ) {
    include(ABSPATH . 'wp-trackback.php');
    return;
  }
}

Still another problem in this puzzle is the $wp->send_headers() method shown being called here on line 293 of "wp-includes/classes.php":

wp-includes/classes.php:

function main($query_args = '') {   
  $this->init();   
  $this->parse_request($query_args);   
  $this->send_headers(); 
  $this->query_posts();  
  $this->handle_404();   
  $this->register_globals();   
  do_action_ref_array('wp', array(&$this));   
} 

The problem with the $wp->send_headers(), also from "wp-includes/classes.php", is that it seems to have the option of either serving an HTML content type on line 183 and 185, or a content type based on a feed (the content types for the feeds are set in their respective "wp-includes/feed-*.php" files) but no custom content types as far as I can determine as there seems to be no way to override calling this function or the logic path contained within:

wp-includes/classes.php:

function send_headers() {
  @header('X-Pingback: '. get_bloginfo('pingback_url'));
  if ( is_user_logged_in() )
    nocache_headers();
  if ( !empty($this->query_vars['error']) && '404' == $this->query_vars['error'] ) {
    status_header( 404 );
    if ( !is_user_logged_in() )
      nocache_headers();
    @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
  } else if ( empty($this->query_vars['feed']) ) {
    @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
  } else {
    // We're showing a feed, so WP is indeed the only thing that last changed
    if ( !empty($this->query_vars['withcomments'])
      || ( empty($this->query_vars['withoutcomments'])
        && ( !empty($this->query_vars['p'])
          || !empty($this->query_vars['name'])
          || !empty($this->query_vars['page_id'])
          || !empty($this->query_vars['pagename'])
          || !empty($this->query_vars['attachment'])
          || !empty($this->query_vars['attachment_id'])
        )
      )
    )
      $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
    else
      $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
    $wp_etag = '"' . md5($wp_last_modified) . '"';
    @header("Last-Modified: $wp_last_modified");
    @header("ETag: $wp_etag");

    // Support for Conditional GET
    if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
      $client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
    else $client_etag = false;

    $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    // If string is empty, return 0. If not, attempt to parse into a timestamp
    $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;

    // Make a timestamp for our most recent modification...
    $wp_modified_timestamp = strtotime($wp_last_modified);

    if ( ($client_last_modified && $client_etag) ?
         (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
         (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
      status_header( 304 );
      exit;
    }
  }

  do_action_ref_array('send_headers', array(&$this));
}

Still, I was able to come up with a solution although it is so very hackish.  My solution was to hook the "template_redirect" action on line 7 of "wp-includes/template-loader.php" (see code from that file above.) Though it seems to works thus far, my solution just feels wrong for the following reasons:

  1. It ignores the fact that WordPress continues to think that my web service URL is the home page,
  2. It first lets "$wp->send_headers()" set the content type before it overrides it,
  3. It uses an "exit" rather than a return to keep WordPress from serving up the home page template, and
  4. It doesn’t use the routing mechanism apparent built into WordPress (see "null" on line 30 of "wp-content/plugins/restful-services/restful-web-services.php" below, I assume it should have been the URL of the .php file I plan to execute but WordPress doesn’t see to use what I put there.)

The function "restful_web_services_exec_service()" is what is called to execute the appropriate web service:

wp-content/plugins/restful-services/restful-web-services.php:

/*
Plugin Name: RESTful Web Services
Plugin URI: http://mikeschinkel.com/wordpress/restful-web-services/
Description: This plugin enables REST-based API web services for WordPress.
Author: Mike Schinkel
Version: 0.1
Author URI: http://mikeschinkel.com/
*/

define('RESTFUL_WEB_SERVICES_DIR', dirname(__FILE__));
define('RESTFUL_WEB_SERVICES_URL_PATTERN','services(/?.*)?');
$abspath = trim(str_replace('\\','/',ABSPATH),'/');
$rest_services_dir = str_replace('\\','/',RESTFUL_WEB_SERVICES_DIR);
$rest_services_path = trim(str_replace($abspath,'',$rest_services_dir),'/');
define('RESTFUL_WEB_SERVICES_PATH', $rest_services_path);

// NOTE, See: http://codex.wordpress.org/Custom_Queries#Permalinks_for_Custom_Archives
add_action('init', 'restful_web_services_flush_rewrite_rules');
add_filter('generate_rewrite_rules', 'restful_web_services_add_rewrite_rules');
add_action('template_redirect', 'restful_web_services_exec_service');

add_action('init', 'restful_web_services_flush_rewrite_rules');
function restful_web_services_flush_rewrite_rules() {
 global $wp_rewrite;
 $wp_rewrite->flush_rules();
}

add_filter('generate_rewrite_rules', 'restful_web_services_add_rewrite_rules');
function restful_web_services_add_rewrite_rules( $wp_rewrite ) {
  $new_rules = array(
    RESTFUL_WEB_SERVICES_URL_PATTERN => null,
  );
  $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
}

function restful_web_services_exec_service() {
  global $wp;
  if ($wp->matched_rule==RESTFUL_WEB_SERVICES_URL_PATTERN) {
    if ($wp->request == 'services') {
      header('Content-Type: text/plain');
      print 'TODO: Generate a list of RESTful Web Services here for this WordPress Blog.';
    } else {
      list($dummy,$service_name) = explode('/',$wp->request);
      if (file_exists($service_php = (RESTFUL_WEB_SERVICES_DIR . '/services/' . $service_name . '.php'))) {
        include_once $service_php;
      } else {
        header('Content-Type: text/plain');
        status_header(404);
        print '404 - Service not found.';
      }
    }
    exit;
  }
}

You’ll note that my function "restful_web_services_exec_service()" is very bare-bones at the moment serving only a plain text message "TODO:" for the path http://example.com/services, and assuming that any path http://example.com/services/{service} will execute a same-named .php file in the services subdirectory, i.e. for http://example.com/services/latest-post it will look for "wp-content/plugins/restful-web-services/services/lastest-post.php" and then delegate all the work to that .php file.

wp-content/plugins/restful-services/services/latest-vidclip.php:

/*
Filename: latest-post.php
Service Name: Latest Post
*/
global $wp_query;
$post = $wp_query->post;
$file = get_attached_file($post->ID);
if (empty($file)) {
  list($file)= get_enclosed($post->ID);
}
$charset = get_option('blog_charset');
header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
$link = get_permalink($post->ID);
$html = < <         $link    POST; print $html; 

Here is an example output returned by calling http://example.com/services/latest-post:

< ?xml version="1.0" encoding="UTF-8"?> 
         http://example.org/sample-post-1/   

While bare-bones, that will meet my needs for the moment since I really only have the need for one service that responds to the HTTP GET verb. However, I can see where I might end up fleshing this out and create lots of helper functions that would streamline the creation of web services for RESTful access to the entirety of the WordPress database. If I do so I’ll be happy to donate this plugin to the community.  In the mean time if you’d like to use this for your own use feel free but caveat emptor. However, if you’d like to use this code to create a plugin to contribute to the community, please contact me for collaboration.  Of course if you’d like to retain me to fully flesh it out for you, I’m always open to that too! :-)

Finally, if anyone who knows the WordPress API better than I do can tell me where I erred in my analysis, and I really hope I did, please let me know so I can architect this thing better. On the other hand, if I was spot-on in my analysis maybe this will help the WordPress team understand what needs to be done so they can empower WordPress to generate any arbitrary content type without having to resort to hacks or bypassing the WordPress index.php startup code. 

38 Replies to “RESTful Web Services in a WordPress Plugin?”

  1. Hey Mike, have you seen the add_feed() function in the wp-includes/rewrite.php file? It seems like a way to add a feed like the default rss or rss2.

  2. Mike,

    Thanks for this post. I’ve written a whole slew of WP plugins but never anything that plays with http. Anyway, I’m working on a dashboard widget plugin that displays updates via CURL on the dashboard and I had everything working individually but when I tried to load the request through the plugin I kept getting a “headers already sent” error. I think, I got now, thanks to your post.

    Good work!

  3. Hi Jamie:

    Thanks for the comment. The Joseph Scott article is a good one. OTOH, I want to point out that “RPC” is anathema to those of us who appreciate RESTful architectures. Just google “REST vs. RPC” to read more about it. Better yet, pick up a copy of “RESTful Web Services” as it covers the differences in depth.

    -Mike

  4. I’ll skip the stab at XML-RPC for now and simply ask why you didn’t use the existing AtomPub API? Most REST fans usually hold that up as the model.

  5. @Joseph Scott:

    Thanks for the comment. Why don’t I use AtomPub API? Because I view using it for most webservices as using a sledgehammer to swat a gnat; it’s hard to do, you get tired very quickly, and the gnat almost always gets away.

    Much like we all entered the era of SOAP with high hopes, most of us have come to realize that it was way overarchitected and got it the way far more often then it helped. Similarly I’ve felt that the AtomPub initiative has been founded on “a great idea at the time” but in practice its overkill most of the time. I’m also seeing some of the “powers that be” in the REST community backing away from it as a panacea, at least the ones whose reputations are not too attached to the success of AtomPub.

    For example Tim Bray writes [1] “but many REST converts see complicated magic where I see a few simple easy-to-understand virtues” and [2] “I’m increasingly inclined to believe that there is a large class of simple administrative-CRUD apps where you can send those name-value pairs upstream, and the advantages may make it worthwhile living with both fighting the i18n fires and a certain loss of RESTafarian purity.” Then there is Joe Gregorio [3] who writes “I’m not 100% in agreement with Tim, but I’m a lot closer than I was a few years ago….On a simpler alternative to an Atom body.”

    Frankly, after much pondering and a reasonable amount of implementation I’ve come to the conclusion that one of the best content types for GET is “application/json” and one of the best content types for POST and PUT is “application/x-www-form-urlencoded.”

    I think we should follow one overridding principle whenever possible: “Simpler is almost always better.”

    -Mike
    P.S. I will say though that compared to SOAP, REST+AtomPub is light years better.

    [1] http://www.tbray.org/ongoing/When/200x/2007/04/30/REST-is-easy
    [2] http://www.tbray.org/ongoing/When/200x/2009/01/29/Name-Value-Pairs
    [3] http://bitworking.org/news/405/webhooks

  6. Simplicity is one of the reasons that I like XML-RPC (aside from the fact that it’s already there and works). Using XML for the markup (instead of say JSON, which would be much nicer) makes it more verbose than needed, but I like that it only needs a few simple concepts to make it work. There’s an XML-RPC library for just about everything under the sun, making it easy to let the library deal with the encoding and focus just on the app and logic.

    I’ve looked at the JSON-RPC options, which looks appealing, but isn’t likely to get much traction this late in the game I’m afraid.

  7. There are so many reasons I prefer REST over (any)-RPC but it’d have to write a book to do the subject justice. OTOH, since someone already has written a book on it (O’Reilly’s RESTful Web Services) I’ll defer to it. Hopefully you’ll consider adding it to you backlog and come back to discuss after you’ve read their arguments for REST and against RPC?

  8. Pardon my ignorance, Mike, do you have that search engine friendly .htaccess rule that reroutes all requests to index.php ? If that were so, that would explain a lot ;)

  9. If you want to write it as plugin, without modifying .htaccess or hacking into the codebase, the only option I can think of is adding the service endpoint file to your template folder as page template :
    http://www.wordpressmax.com/customize-wordpress/custom-page

    And then adding the services as pages, based on the service broker template. That way wordpress handles them through ‘is_single’, and has the template handle the request. As long as you dont call get_header(); in the template you can dish out any filetype or data :
    as poc : http://www.juust.org/index.php/services/?data=test

  10. Hey Mike, have you seen the add_feed() function in the wp-includes/rewrite.php file? It seems like a way to add a feed like the default rss or rss2.

  11. This was a great start in the right direction. I just got this all figured out. This is the appropriate way to implement a web service api in WordPress:

    function add_my_rewrite_rules() {
    global $wp_rewrite;
    $my_non_wp_rule = array
    (
    ‘services/(.*)\.(.*)/(.*)$’ => sprintf( ‘%s?action=my_service_handler&service=$1&format=$2&params=$3’, ‘wp-admin/admin-ajax.php’ )
    );
    $wp_rewrite->non_wp_rules = array_merge( $my_non_wp_rule, $wp_rewrite->non_wp_rules );
    }
    add_action( ‘generate_rewrite_rules’, ‘add_my_rewrite_rules’ );

    function my_service_handler() {
    $service = $_REQUEST[‘service’];
    $format = $_REQUEST[‘format’];
    $params = parse_str( $_REQUEST[params’] );

    // any service logic here

    // set the output content type by sending the proper html header for content type requested
    header( ‘Content-Type: text/xml’ ); // for xml

    // send my service api response based on format choosen
    echo $my_service_response_xml->asXML(); // example for xml

    exit(); // seems to leave a trailing status code if not exited but not the home page!
    }

    This should solve all of your concerns mentioned in the method you proposed.

  12. @R’pael: Thanks for the comment.

    Yeah, I think my way shown is not the way WordPress normally implements it. I was coming from a RESTful perspective new to WordPress but since writing this I’ve been using WordPress a lot and would do it differently. BTW, FWIW, I don’t like exactly how WordPress does it but I’d rather be compatible with the defacto-standard approach even if it has warts.

    So thanks again for your comment.

  13. Hi did this evolve in a downloadable plugin for WP? Unfortunately I have not a clue on how to implement this but I really need to make a call to a Web Service to and display the returning xml file.

  14. There’s an XML-RPC library for just about everything under the sun, making it easy to let the library deal with the encoding and focus just on the app and logic.

    thanks MikeSchinkel

  15. Mike,

    I was reading your post about the macbook. Are you insane? You’re the first person to speak negatively about apple. I didn’t get a chance to finish the rest of the post because my eyes started hurting. “Dissing” the mac is like speaking disrespectfully towards Tupac or Elvis.

  16. I’m having a similar problem now! How would you suggest I handle it. Im using the template_redirect to recognize the pattern and send to my plugin, but its still reading as a wordpress 404.

  17. Im having a similar problem now! How would you suggest I handle it. Im using the template_redirect to recognize the pattern and send to my plugin, but its still reading as a wordpress 404.

  18. Hi @Rich,

    I wrote this article back in 2008; almost 5 years ago! So much I’ve learned since then so reading this post is painful! As of end of 2012 I am now blogging much better techniques here: http://hardcorewp.com.

    Without looking at your code I’m wondering if you remembered to include an exit; immediately after you’ve output your representation?

  19. I have this codes for wordpress

    add_action(‘generate_rewrite_rules’, ‘cs_rewrite_rules’);
    add_filter(‘init’, ‘eduFlush’);
    function cs_rewrite_rules() {
    global $wp_rewrite;
    $new_non_wp_rules = array(
    ‘^generator/?$’ => ‘educontent/wp-content/plugins/wordwork/admin/templates/tcpdf/samp/flashcards.php’,
    );
    $wp_rewrite->non_wp_rules += $new_non_wp_rules;
    }

    function eduFlush(){
    global $wp_rewrite;
    $wp_rewrite->flush_rules();
    }

    i need to rewrite the url in wordpress but its not working.,. Here are my questions
    1. Where I should put this codes? I tried to put it on the top of my php codes but its not working.
    2. Is my codes correct?

    Thx sir .. :)

  20. Hi @NoobMe,

    Thanks for your comment and your code. However, you don’t really explain what you are trying to accomplish. I can guess by looking at your code but since your code is not working then I will probably guess wrong. Please explain in English what you want to achieve.

    -Mike

  21. I need to change this url

    educontent/wp-content/plugins/wordwork/admin/templates/tcpdf/samp/flashcards.php

    to

    educontent/generator

    I successfully made it work by using .htaccess, but I want to do this without using htaccess, so I used wp_rewrite in wordpress. But I cant make it work.

  22. Hi @NoobMe,

    If you use WordPress’ URL routing it will do a lot of work that you don’t need before it loads /flashcards.php. Actually no matter what you do WordPress will do more work than you need so modifying .htaccess is the best way from a server perspective, but not the best way if you are trying to distribute a plugin.

    For what you want to do I much prefer to use the ‘do_parse_request’ filter hook which allows you to see the URL before WordPress inspects it, and if it’s the URL you want then you can simple load the file you want.

    I’ve created a Gist that has the working code I tested. The code needs to be put in the root directory of the plugin, i.e. in the same directory as the /admin/ subdirectory:

    https://gist.github.com/mikeschinkel/7112588

    Hope this helps.

    -Mike

  23. Hi sir, I added a educontent-generator-url.php on the root folder of my plugin, but it still redirect to this url

    educontent/wp-content/plugins/wordwork/admin/templates/tcpdf/samp/flashcards.php

    I have form that redirect to the url above that submit data and generate a PDF.

    $site_title = get_bloginfo( ‘wpurl’ );
    $pdfmaker_path = $site_title.’/wp-content/plugins/wordwork/admin/templates/tcpdf/samp/flashcards.php’;

    ‘;

    I just shortened the codes.
    1st is for the dynamic path of the page
    2nd is for the form that will submit the data to another page.
    Im sorry for my english sir.

  24. Im not sure if I will create a new php page or just add the codes you made to my existing php page. I did tried both but still displaying the same url

    educontent/wp-content/plugins/wordwork/admin/templates/tcpdf/samp/flashcards.php

  25. Hi @NoobMe,

    I don’t understand what you are describing. If you have a form and it is “redirecting” (?) to the URL, you should be using the new URL in your code: educontent/generate

    If that is not it, maybe it would be better if you either create a Gist for me with the code for your plugin (if it is in a single file) or zip it up and send to me so I can see it.

    -Mike

  26. Hi this is the gist https://gist.github.com/anonymous/7129407
    in this example, it just passed the value of the textbox to another page,

    origpage.php to targetpage_is_very_long.php

    What we need to do is to rewrite the long url.. to just lets say
    targetpage.php
    Im sorry for my bad english, I hope you get what I’m saying.

  27. Hi Mike I’ll explain what I did.
    1. I added a file called educontent-generator-url.php and place your codes there.
    2. I saved the the educontent-generator-url.php to the root folder of the plugin.
    3. On the form where in the
    “educontent/wp-content/plugins/wordwork/admin/templates/tcpdf/samp/flashcards.php”
    is called I changed it to educontent-generator-url.php
    so it looks like this

    form action=”educontent-generator-url.php” method=”POST” enctype=”multipart/form-data” target =”blank” id=”flashcontent” onsubmit=”return check_submit(this);”>’;

    4. After submitting, i only get this error

    Fatal error: Call to undefined function add_filter() in C:\xampp\htdocs\educontent\educontent-generator-url.php on line 7

    I hope I explain it well XD Thx again for your help

  28. @NoobMe – Your Gist did not provide the complete plugin. If you want help you need to provide me the complete plugin otherwise I have to guess at what you are trying to do, and it’s taking a lot of my time to do that.

    However, the error you get about undefined function add_filter() tells you that WordPress is not loaded when you run my code. Why is your form action educontent-generator-url.php? If you do that of course it won’t work, and it’s not what you are trying to accomplish anyway. Your form’s action should be /educontent/generator.

    If that does not help then email me a ZIP file of your complete plugin so I can see exactly what you are doing wrong.

    -Mike

Leave a Reply

Your email address will not be published.