Setting Plesk Permissions for WordPress & FTP

Since I started using WordPress (and more importantly developing for WordPress) I have been plagued by what seems to be a very common issue – allowing WordPress to simultaneously have internal writing permissions without breaking FTP. When using WordPress on a linux/*nix server combined with Parallels Plesk, you’re subject to dealing with not only Apache and its permissions, but also the permissions setup by Plesk groups, Plesk users, and Plesk FTP restrictions.

The following steps are what I took to enable full FTP access and full Apache/PHP/system write access to the same directories and files. This was tested on Parallels Plesk v 10.1.1 on a Media Temple (dv) Dedicated Virtual 4.0 running Linux version 2.6.18-028stab093.2. In this configuration, Apache is running under the username Apache, but on other servers may run as www-data, nobody, or something else. You will need shell and sudo access to complete the following tasks.

1. Add the apache user to the psacln (plesk) writable group.
You only need to do this once, however, at this time we have not tested what happens when apache is updated (so you may have to repeat after an update/upgrade)

$ usermod -a -G psacln apache

If the user running the web server is not apache (may be www-data or nobody) simply use that user at the end of this command.

2. You now have to give the group write access on the directories and/or files necessary. In wordpress, you’ll want to do this on the entire directory that wordpress is living in.

$ chmod g+w {file}
$ chmod -R g+w {directory/}

NOTE: After further testing, I’ve updated this to reflect better settings. Essentially we’re giving all folders group write access and all files normal 644 access

$ find wp-content/ -type f -exec chmod 644 {} \;
$ find wp-content/ -type d -exec chmod 775 {} \;

3. Now you have to give ownership to the directories and/or files. The psacln group is specific to plesk and is subject to change based on your environment.

$ chown -R {ftp_username}:psacln {directory}/

4. I suggest you restart Apache once you’re done with these steps, and you may need an Apache restart after step 1 as well. On the Media Temple (dv) 4.0 Dedicated Virtual Apache runs as process httpd, though it may run as apache or something else in your server environment.

$ service httpd restart

5. (Optional) Force WordPress to use the filesystem to run updates. WordPress runs through a routine determining how it’s going to write data (directly, FTP, SSH, etc.) but sometimes fails to use the direct method even though it’s available. Usually there is a reason when WordPress does or doesn’t do something even though it’s possible, so this may be a concern (or it may be a dumb bug). Andrew Nacin has kindly chimed in via the comments to explain this -

The reason WordPress sometimes doesn’t use the direct filesystem method even when it would work is because it only detects that the user on the PHP process is the owner. It doesn’t support detecting group-writeable. … essentially, we’re trying to avoid a situation where we create and therefore own a file, when normally we would not be the owner, and that then locks out the FTP user.

That said, if you’d like to force WordPress to use the direct filesystem to write and modify data, simply add the following line to your wp-config.php file:

define('FS_METHOD', 'direct');

I would love to hear if this worked or didn’t work for you in your own server environment – again, this was a very specific test and I haven’t verified on other hosts, versions of Plesk, or versions of Linux. Please feel free to comment and let everyone know if it worked for you and where.

Want a great API? Don’t use Goodreads’

I’m in the middle of a client project for a local public library – building a simple mobile site that makes book recommendations based on genres. The titles come from their RSS feeds and we grab additional data from Goodreads. Easy and fun right?

No. Wrong. Very Wrong.

To put it plainly, the Goodreads API is a mess. A convoluted, poorly designed, agonizingly slow mess. To demonstrate, I thought I’d walk you through a few of their API terms (found here).

1. Not request any method more than once a second. Goodreads tracks all requests made by developers.

This sucks. If in your app you want to query a book, grab a review, show the author’s bio, and recommend other books in that series, you need to make 4 API calls. To abide by Goodreads’ terms, you need to make that request last 4 seconds. Seriously?! It’s 2011 – I can make thousands of requests in that time from hundreds of other APIs. But the best part? It actually takes longer than 4 seconds because the response time from Goodreads per request is over 1 second. Plus, if you read term #5, they say you can’t store anything – so every pageload is going to take several seconds. Sounds like an awesome user experience, right?

3. Link back to the page on Goodreads where the data data [sic] appears. For instance, if displaying a review, the name of the reviewer and a “more…” link at the end of the review must link back to the review detail page. You may not nofollow this link.

I had no idea a webservice could be so selfishly greedy. What this is really saying is “We will NOT give you the full review of anything, you must link back to our site to see it, and you must give us link credit for every review you display in your app.”

This is all very frustrating. Goodreads has fantastic data – I’ll be the first to admit that – but they’re actively DISCOURAGING developers from using it!

But the worst part is the developer support.

I was building the application and came across the fact that only a handful of API endpoints returned JSON – the others only returned XML. Not a huge deal, but when trying to save as much time as possible due to aforementioned request time, I wanted to parse JSON in PHP rather than load the SimpleXML resources. I thought this was odd (maybe a bug) so I searched in the developer forums; lo and behold, someone else had the same request. They explained that they were using the Goodreads API as an example in a classroom setting and wanted to give the students JSON to work with. Here’s the response from a Goodreads employee:

“It’s a bit of work to add this. Someday it will likely happen, but probably not that soon. If you were using an API for a class, I don’t think our documentation is that great either. I think flickr has a much more mature api.”

Yes. A Goodreads employee said “That’s too hard so we won’t do it, and our API and documentation isn’t good enough for you to use in a class. Use something else.”

(You can read this entire thread here: http://www.goodreads.com/topic/show/453508-can-we-get-json-for-all-calls?page=1#comment_27316799)

In the end, I’m saddened and appalled. I can’t deliver the product a client wants, I’ve spent several hours fighting an API that is simply poorly documented, developed, and supported, and as someone working on building an API for another product I’m utterly shocked that something like this can be called an active release from a company that has raised nearly $3 Million in venture funding.

It’s 2011 guys. Catch up.

Twilio + Ripstyles Ecommerce = Amazing!

I’ve known about Twilio for awhile – I actually build 90% of the app I’m about to demonstrate here about 4 months ago, but after seeing the contest they were running this week, I decided I’d give it some quick polish and make it useful. Essentially what I’ve created is a custom PBX for Ripstyles. It’s simple, clean, but directs people to the correct phone number and will give them order status over the phone by simply typing in an order number.

Please keep in mind that since I haven’t had a chance to fully test this, it is not yet implemented into the Ripstyles phone system. You’ll still get a legit, live human being when you call us :-)

Call 1.866.960.9433 – you’ll get a “Thanks for calling Ripstyles” message. It’ll give you some options to choose by pressing a number on your phone keypad. 1, 3, and 4 will take you to sales, support, and the operator respectively (though for now the demo just tells you where you would be connected to and hangs up on you). Option 2 is cool – it asks you for your 7 digit order number and then will tell you the status and some info about that status, followed by an option to talk to the operator.

Try it: dial 1.866.960.9433, press 2 at the prompt, and then enter 1001588 as your order number.

Cool huh? Twilio queries my web application that is used to administer the entire Ripstyles system, grabs an order status via your order number, and reads the status along with a description. No personal data is given out, so there’s not a security issue there. This system is also tied to a test database, so don’t get too inquisitive kids!

Option 5 is also neat, and makes use of some of Twilio’s really super duper cool features – it lets you leave a message, then enters into my database all of the info about your call and queries Twilio for a transcription of the audio. Cool huh? After you leave a message, I get an email with the phone number and transcription, and can log into my system and see all the call information (see pic to left).

I can also see debug database info on that call just in case it looks like something went wrong. Transcriptions sometimes come back wonky, but they’re more of a convenience in order to get an idea of what a customer would like before we call them back.

An automated system like this will be new for Ripstyles; we’ve always answered the phone with a human, so moving to something that is computer controlled will be a little strange. However, Twilio has made it so that there is a level of control that not only allows us to get great data at every stage, but also get our customers to a human as soon as possible while alleviating some of our call load.