Integrate WordPress into your ColdFusion app
Thursday, January 13th, 2011
Lately I’ve been working on a few ColdFusion apps that require a comprehensive blog system. While I could easily install Mango Blog or Blog CFC, nothing really rivals the functionality of WordPress when it comes to blog apps – but of course, WordPress is a PHP based system.
Installing WordPress alongside a ColdFusion app isn’t too difficult, but I need to customise the blog so that it looks identical to the rest of the site, and allow the user to switch seamlessly between the two.
This level of integration requires two main bits of functionality. Firstly I need to use ColdFusion to connect to the WordPress database and pull out articles and comments for use in summary blocks around the rest of the site, and secondly I need to be able to embed CFML templates directly into the WordPress blog to generate headers and footers whilst keeping any session based information such as login status, cart contents etc. – Essentially I need a CFINCLUDE equivalent for PHP.
Using ColdFusion to pull in WordPress content
I created a few components to pull data from a WordPress database. One to grab published articles, one to grab approved comments and one to remove any formatting and strip out extra HTML such as embedded images or videos.
The components are fairly self explanatory, and for the moment provide only basic functionality. It would be possible to build on these to provide greater integration, but for now these do the job nicely.
Pull published blog posts
<cffunction name="getBlogPosts" access="public" returntype="query" hint="Pulls published blog posts from a wordpress database (Tested in 2.7)"> <cfargument name="sDSN" type="string" required="yes" hint="Datasource name assigned to the WordPress database" /> <cfargument name="ID" type="numeric" default="0" hint="Blog post ID - Leave blank to pull all published posts" /> <cfargument name="iLimit" type="numeric" default="0" hint="Limit the number of posts to pull back" /> <!--- Get blog posts ---> <cfquery name="Local.qGetBlogPosts" datasource="#Arguments.sDSN#"> SELECT wp_posts.* FROM wp_posts WHERE 0 < 1 <cfif Arguments.ID NEQ 0> AND wp_posts.ID = <cfqueryparam value="#Arguments.ID#" cfsqltype="CF_SQL_INTEGER" /> </cfif> AND wp_posts.post_type = "post" AND wp_posts.post_status = "publish" ORDER BY wp_posts.post_date DESC <cfif Arguments.iLimit GT 0> LIMIT #Arguments.iLimit# </cfif> ; </cfquery> <cfscript> // Return the query object return Local.qGetBlogPosts; </cfscript> </cffunction>
Pull approved comments
<cffunction name="getComments" access="public" returntype="query" hint="Pulls approved comments from a wordpress database (Tested in 2.8)"> <cfargument name="sDSN" type="string" required="yes" hint="Datasource name assigned to the WordPress database" /> <cfargument name="iCommentID" type="numeric" default="0" hint="Comment ID - use to pull back a specific comment record" /> <cfargument name="iPostID" type="numeric" default="0" hint="Post ID - Use to pull back all approved comments from a specific post" /> <cfargument name="iLimit" type="numeric" default="0" hint="Limit the number of comments pulled back" /> <!--- Get comments ---> <cfquery name="Local.qGetBlogComments" datasource="#Arguments.sDSN#"> SELECT wp_comments.*, wp_posts.post_name, wp_posts.ID, wp_posts.post_type, wp_posts.post_status, wp_posts.post_title FROM wp_comments INNER JOIN wp_posts ON wp_comments.comment_post_ID = wp_posts.ID WHERE 0 < 1 <cfif Arguments.iCommentID NEQ 0> AND wp_comments.comment_ID = <cfqueryparam value="#Arguments.iCommentID#" cfsqltype="CF_SQL_INTEGER" /> </cfif> <cfif Arguments.iPostID NEQ 0> AND wp_comments.comment_post_ID = <cfqueryparam value="#Arguments.iPostID#" cfsqltype="CF_SQL_INTEGER" /> </cfif> AND wp_comments.comment_approved = 1 AND wp_posts.post_type = "post" AND wp_posts.post_status = "publish" ORDER BY wp_comments.comment_date DESC <cfif Arguments.iLimit GT 0> LIMIT #Arguments.iLimit# </cfif> ; </cfquery> <cfscript> // Return the query object return Local.qGetBlogComments; </cfscript> </cffunction>
Strip HTML from posts
This function uses the ‘TagStripper’ custom tag by Rick Root / Ray Camden, available from http://www.cflib.org
<cffunction name="unformatPost" output="no" hint="Removes HTML from the string" access="public" returntype="string"> <cfargument name="sString" type="string" required="Yes" hint="Data to strip HTML from - pass the post contents here" /> <cfargument name="bShowSummary" type="boolean" default="0" hint="If you use the 'more' tag to split posts into summary and content, set this flag to pull back the summary only" /> <cfinclude template="/customTags/tagStripper.cfm" /> <cfscript> // If we're only showing a summary, strip out everything after wordpress' '<!--more-->' tag. if (Arguments.bShowSummary) { Arguments.sString = REReplace(Arguments.sString, "<!--more-->.*", ""); } // Stip out any HTML tags and return the output return tagStripper(Arguments.sString,'strip','p,strong,em,a'); </cfscript> </cffunction>
Embedding CFM templates into WordPress / PHP
I don’t know a great deal about PHP, but I can’t find any equivalent to CFINCLUDE – even if I could it would be safe to assume that the PHP version wouldn’t be able to parse the CFML code contained in my CFM pages – what’s needed is some equivalent to CFHTTP that can hit the CFM page as a standard HTTP request, let the CFML server parse the code and return HTML that is then displayed within the PHP template.
Currently I’m using a function in PHP which wraps around ‘fsockopen’ to do exactly this. I found this function a while ago on another project – I’m not sure who wrote it.
<?php function fetchURL( $url ) { $url_parsed = parse_url($url); $host = $url_parsed["host"]; $port = $url_parsed["port"]; if ($port==0) $port = 80; $path = $url_parsed["path"]; if ($url_parsed["query"] != "") $path .= "?".$url_parsed["query"]; $out = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n"; $fp = fsockopen($host, $port, $errno, $errstr, 30); fwrite($fp, $out); $body = false; while (!feof($fp)) { $s = fgets($fp, 1024); if ( $body ) $in .= $s; if ( $s == "\r\n" ) $body = true; } fclose($fp); return $in; } ?>
With that function set up at the top of the php template, you can use the following code to embed a parsed CFM template.
echo fetchURL(http://pathto.your.cfm);
Now the only issue remaining is session data. As it’s the PHP server hitting your CFML template and not the user’s browser, the ColdFusion server is assigning a new session to PHP, and so any session specific data such as the contents of the user’s cart or login status, is lost in the displayed page.
So to combat this, we’ll need to check the user’s browser for a session cookie using PHP, and pass that along as a URL parameter to the CFML template.
<?php $sURL = "http://pathto.your.cfm?CFID=" . $_COOKIE['CFID'] . "&CFTOKEN=" . $_COOKIE['CFTOKEN']; echo fetchURL($sURL); ?>
Now we should find that the contents of the CFML page is parsed correctly, using the current CF session.
It’s worth noting that while this technique could be used to pull in your CFML header and footer template, providing a quick way to skin the blog without delving too deeply into the WordPress theme you’re using, this is not the ideal way to go. WordPress themes use variables in the head section of the document to deal with Meta information and other internal functionality, and these often provide hooks for WordPress plugins. If you replace this information with parsed HTML from your CFML templates, you may run into difficulties down the line.
A better method is to abstract individual elements of your site into separate CFML templates, and allow WordPress to create the finished page, pulling in elements where needed.
I’d love to hear what people think of these techniques and if anyone has a better way of integrating WordPress into their ColdFusion apps. Specifically, I’d be interested to know if anyone has combined the login functionality of WordPress with their CFML system – the holy grail, if you will!
Tags: ColdFusion, php, wordpress
Filed under: ColdFusion, Railo, Website Development.
Apr 5th, 2011
12:23 am
I’m going to be trying your techniques the next couple of days. I’m a fairly season CF developer but havn’t touched any PHP code so I think this blog may just what I’m looking for.
Apr 28th, 2011
4:13 am
I’m not really familiar with CF but I have a wordpress site I’m trying to include some CF into. So, would the “Embedding CFM templates into WordPress / PHP” part be what I do to embed a single page of CF data into a WP template page. The CF data just returns a list of members to a club. I don’t have direct access to the code that creates the list, just a link to the template.
May 9th, 2011
8:31 am
This seems like an excellent article although I have tried to embed some CF templates into WP based on the instructions and had no joy. I am new to WP and PHP so I’m probably doing it all wrong. It would be a great help if you could describe exactly where to include the PHP function and the function call (which files within the WP folder) and possibly provide a sample file. Any help you could give me would be greatly appreciated. Thanks!
May 18th, 2011
11:09 am
I’ve integrated phpBB with a CF application before, it wasn’t fun!
I went about it a slightly different way, which i think would also work for WordPress, but i’ve not tried it.
phpBB (like WordPress) has an api, so i created a php script designed to be called from the command line with a variety of options, then i run that php script using cfexecute, if the script needs to return data to CF it will be serialized to xml
It does things like login against the phpBB user table, get recent posts, add/remove users to groups, set default group etc.
Integrating with an API is always preferable to dipping into the database as you may find your integration breaks if you upgrade wordpress.
May 18th, 2011
6:08 pm
Quote:
You sure you don’t mean datasource=”#Arguments.sDSN#” and name=”local.qGetBlogComments” ?
Aug 25th, 2011
2:39 pm
@Bardnet – Doh! Yes, that’s exactly what I mean! Thanks for pointing that out, I’ve updated the post now… I use a different naming convention in the system I wrote this for, so did a search and replace to before posting. Must have messed up.
@Michael – The first function goes at the top of the template. Ignore the second, it’s just an example – the third is the one you want, which you use as an equivalent to cfinclude.
@Chris – I wasn’t aware when I wrote this, that WordPress had an API you could hook into, but I agree that is definitely the way to go if you can. I’ll take a look at it when I get some time.
Oct 27th, 2011
12:47 pm
Not sure what you mean by “With that function set up at the top of the php template”. Are you talking about the functions.php page within a theme or a file within the root of WP?
Jan 31st, 2012
8:41 pm
Hey Gary,
Interesting post…although i feel its a little too late to respond
I have a similar issue having to deal with WordPress and CF… i have done it in a different way though!
Just wanted to jump in and contribute my 2 cents……We have a load balancer in front of the websites…..So, i had to redirect the user onto a CF box based on the content served! This way i can handle CF on its own and wordpress on its own.
But i like your idea on integration. Good work…Keep it up.
Cheers,
Sam.
Feb 1st, 2012
12:02 am
@Bill
I have that function at the top of any php template I want to pull in CF content from – so namely my header.php and footer.php. There’s probably a better way to do that inside the functions.php though.
@Sam
I think we’re achieving different things there – I have php and ColdFusion on the same box… my issue is that I want to include .cfm templates in a WordPress theme, so that I can have a uniform header and footer that includes session information (such as number of items in a CF based basket).
May 13th, 2012
3:40 am
Hi – I’d just like to thank you for this – It’s been the inspiration for a project I’m working on now – ColdPress.. I’ve taken your original code but formed it into a complete(ish) set of components complete with automated installation of wordpress etc – I’ll be posting it onto SourceForge at http://sourceforge.net/projects/coldpress/ – I’ll make sure to give you a big thank you!
Martin
May 13th, 2012
3:45 am
Whoops – Forgot to put a link to the actual ColdPress page… http://www.coldfusion.com.au/coldpress/ (BTW I used to live in the UK till moving out to Oz last year)
May 13th, 2012
3:56 am
@Martin
That’s awesome! I’d always wanted to bridge the gap between WordPress and CF a bit better – the functions in this post are quite a slapdash solution really, in that they rely on the WordPress database not changing in any significant way, and have limited functionality.
I’ve always thought there was a need for a comprehensive CF library of components to integrate with WordPress, as I find more and more of my CF sites have a WordPress blog alongside them.
I’d be very interested to take a look at what you’ve come up with!
While we’re on the subject, have you found any way to get the permalink out of the WordPress database? It seems to generate the link on the fly based on the settings, but doesn’t actually store the URL anywhere, which means if we want to link to a post from CF, we either have to use the ID (as I’m doing) or parse a version of the permalink from the settings table.
Anyway, thanks for commenting and good luck with ColdPress!
May 30th, 2012
1:21 am
Hey Gary – Sorry for not getting back to you sooner!
Regarding the “slugs”, I use a query to get the parent and grandparent’s (if applicable) post name then build a URL from the install folder e.g. /blog/ – so /blog/[grandparent post name]/[parent post name]/[post name]. Although most posts are usually in the format /blog/how-to-write-cool-apps the above allows me to get at least 2 sub categories
I will try and get round to posting on sourceForge soon at least to show how far I’ve got.
Oct 15th, 2012
6:22 pm
We’re currently changing over from a Cold Fusion based site to a WordPress based site. Our problem is that there are many important backlinks out there in hyperspace that link back to a Cold Fusion .cfm page. We don’t want to lose that connectivity in the new site. Do you have a suggestion?
Oct 16th, 2012
10:02 am
Hi Phil,
I’m afraid there really is no easy way of doing this, but I’ve managed it with a bit of messing about.
Firstly you’ll need to get all the content into the WordPress database. You could do this by manually adding records, or you could export the content to XML compatible with WP’s import functionality.
Personally, I put the records in manually, using CF. My old CF site had IDs included in the link (/blog/the-name-of-the-post-123.cfm) so using CF I could loop through the records and insert them as posts in WordPress using the same ID.
This makes things a little easier as you could feasibly get the ID of the post from the original .cfm URL and redirect straight to the WP generic link (/blog/?p=123).
If you want to redirect to the full URL generated in WP, presumably for SEO, you’ll need to manually set up each redirect.
I have a redirects table in my database, with an old URL and a new URL. Then in my error handler in Application.cfc, I run a query on any 404 errors to see if the URL exists in the table. If it does, I can do a 301 redirect straight to the new URL.
Hope that’s some help to you… Best of luck!
Nov 6th, 2013
2:59 pm
Gary, thank you for this post!
I never worked with WP before – and this seems like the only decent article online I could find about pulling the blogs in CF. Can you elaborate on how to obtain the “Datasource name assigned to the WordPress database”? I tried to research that as well, but with no luck.
Nov 6th, 2013
3:46 pm
Hi Mark,
Glad you’re finding it helpful, but this post is a bit old now – I’m not sure what may have changed in WordPress since it was written. Hopefully it’s all still valid.
With regard to the datasouce, you just need to set one up via the CF Administrator to point to the WordPress database, so that CF can access the data.
Sep 12th, 2014
4:30 am
DUH I found an iframe will encapsulate a CF template on a PHP page. Naturally there are some limitations but as long as you maintain state you’re gonna be okay. Let WordPress do what it does best and the same for CF!