Alec Cumming

Programming, Productivity, System Administration

  • Wordpress Multisite And Localization

    At work we’re tring to create a multisite, internationalized, multi-language Wordpress installation for a client, and I immediately ran into issues getting i18n working out of the box on network sites with a custom theme. Wordpress has good(ish) documentation about i18n and gettext but it’s missing a lot of detailed instructions on how to get your multisite installation set up with multilanguage support in your custom theme. So I thought I’d make an attempt at providing them here.

    Install Wordpress Multisite And Set Up Your Language Sites

    I won’t go into detail here on how to get WP MS up and running – you can find that here – but install, set up, and create your sites.

    What To Put In functions.php

    First off, you need to instruct your theme to use your translations. Create a directory called “languages” (or whatever you want to call it) in the root of your theme directory. Then, in functions.php, insert the following code, replacing “your_theme_directory” and “languages” with your theme name and translations folder, respectively:

    add_action( 'after_setup_theme', 'theme_textdomain_setup' );
    function theme_textdomain_setup() {
        load_theme_textdomain('your_theme_directory', get_template_directory() . "/languages");
    }

    This code instructs the theme to add an action on the after_theme_setup hook. That action loads the theme’s translation files into the domain “your_theme_name”

    Use A Plugin To Manage Your Strings

    PoEdit is a mess to use, but I found a Wordpress plugin called CodeStyling Localization which scans your theme files for translatable strings and loads them into an administrative interface for you to edit, It seems to work really well so far, although I needed to do some setup to get it running. Basically, you need to;

    Wrap your theme’s translatable strings in __ notation and specify a text domain, which should be the your theme’s directory name:

    <?php echo __('Your string here', 'your_theme'); ?>
    <?php _e('Your string here', 'your_theme') ?>

    Also, make sure you’re not getting errors in the plugin itself. I got textdomain errors for a while before I realized I needed to add the domain to every string and to the function in functions.php. You may also get errors until you hit “rescan” and generate a .mo file from your strings.

    You Need The Wordpress Core Language Files

    Next, download the version of wordpress you need for localization. For the french version of the site, for example, it’s at http://fr.wordpress.org. Copy the .po and .mo files from wp-config/languages into your_theme/wp-content/languages (create this directory if it doesn’t exist). This enables Wordpress to use the language in the network site you’re setting up.

    You Need To Create .po And .mo Files For Your Theme

    Go into the plugin and edit your strings. I won’to go into detail here on how to use the plugin, since its webpage explains it pretty well. Generate your .mo files once you’re done editing and navigate to the Network Admin – NOT the regular WP admin, the site settings under “My Sites” in the Admin bar – for your site.

    You Need To Set The Site’s WP_LANG

    Under the Settings tab on this page, down at the bottom, there is a variable called WP_LANG - set this to the country_language code you want to use for the site. For example, French (for France) is fr_FR, just like the .mo and .po files you downloaded from wordpress. Hit save.

    Note that if you did not move the .po and .mo files into wp-content/languages this option will not be saved. I was mystified as to why the option would come up blank after saving, until I realized that Wordpress needs translation files before you try setting the language for a network site. It’s a shame there’s no error messaging around this – it would have saved me a bunch of time.

    All Done

    Once you do all of this, the administration panel and site should appear in your desired language. Repeat this process for the languages you want to use and the sites you want to use them on.

    So far I have not tried to set a different language for the admin panel as the frontend of the site, but it should be possible, since there are plugins that (apparently) do this. Hopefully this will all be helpful for other developers trying to get multisite Wordpress working with translations.

    Comment on this post!

    Categories:

    tech

    Tags:

    wordpress
  • When mongod Won't Start On OS X

    mongod can be fickle. This morning I logged into my Mac to find that my applications couldn’t create a connection to the database, and I quickly discovered that my launchctl mongod daemon had crashed. My system.log was filled with messages like this one

    Feb 21 10:44:57 alec com.apple.launchd[1] (org.mongodb.mongod[1165]): Exited with exit code: 100
    Feb 21 10:44:57 alec com.apple.launchd[1] (org.mongodb.mongod): Throttling respawn: Will start in 10 seconds

    and my mongodb log file had messages like

    **************
    old lock file: /usr/local/mongodb_data/mongod.lock.  probably means unclean shutdown
    recommend removing file and running --repair
    see: http://dochub.mongodb.org/core/repair for more information
    *************

    Soemthing is definitely wrong.

    So the first thing to do is try to repair your databases. Unload the launchctl daemon with

    sudo launchctl unload -w /Library/LaunchDaemons/org.mongodb.mongod.plist

    (replace /Library/LaunchDaemons/org.mongodb.mongod.plist with the path to your launchctl plist file). Delete the lock file, wherever your data is:

    rm /usr/local/mongodb_data/mongod.lock

    Then run (NOT as sudo, replacing the config path as needed):

    mongod --repair --config /usr/local/mongodb/mongodb.conf

    Make sure there’s no lock file back in your data directory, and reload the launchctl daemon, again substituting the path to your plist file:

    sudo launchctl load -w /Library/LaunchDaemons/org.mongodb.mongod.plist

    And you should be back up and running. One gotcha here is that mongod --repair does not remove the lockfile (as I had assumed) - you have to remove it yourself.

    Comment on this post!

    Categories:

    tech

    Tags:

    mongodb
  • MongoDB, NodeJS, Express, And Text Search

    I recently implemented text search functionality with MongoDB and Express/mongoskin in a blog/cms project I’m working on. Getting text search (I won’t call it “full-text” search, since I don’t think this method qualifies) isn’t straightforward in MongoDB, but it’s not hard if you set up your post objects with some care and normalize the text sufficiently. I found that with some tweaking it works well, and on NodeJS and Express it’s blazing fast. Also, remember to ensure indexes on the fields you’re searching!

    The Post Object

    Here’s the post object, with some extraneous data removed. Note that there’s several “content” fields here: content, stripped_content, and keywords. Content contins the plaintext html/Textile text of the post, while stripped_text contains the text with the HTML stripped out. Keywords contains an array of the words in the post. Notice too that the embedded comment object has its own stripped_content and keywords fields.

    I ensured indexes on stripped_content, keywords, comments.stripped_content and comments.keywords. In practice you’d probably only want either the stripped content OR the keywords, not both, but for the sake of experimentation we’ll use both here.

    {
    	"_id": ObjectId("4f1990f8226ab5d601000001"),
    	"author": ObjectId("4ee6906af67b772c1b000001"),
    	"comments": [
    		{
    			"content": "noodle poodle ewok",
    			"stripped_content": "noodle poodle ewok",
    			"keywords": {
    				"0": "noodle",
    				"1": "poodle",
    				"2": "ewok"
    			},
    			"created": ISODate("2012-01-23T18: 01: 55.604Z"),
    			"_id": ObjectId("4f1da093ca9abccd06000001"),
    			"author": {
    			"_id": ObjectId("4ee6906af67b772c1b000001")
    		}
    	],
    	"content": "Problem with windows!",
    	"created": ISODate("2012-01-20T16: 06: 16.926Z"),
    	"keywords": [
    		"Problem",
    		"with",
    		"windows"
    	],
    	"modified": ISODate("2012-01-23T17: 42: 40.756Z"),
    	"stripped_content": "Problem with windows!"
    }

    Setting Up The Model

    Using mongoskin’s bind() method, we attach a method to the mongo client, like so:

    // require the client
    var mongo_client = require("../config/db").client;
    // Our post collection
    var collection = "posts";
    
    // Bind methods to the client
    mongo_client.bind(collection, {
    
    	/**
    	 * @param string term The term to search for
    	 * @param function fn The callback function
    	 */
    	search: function(term, fn) {
    
    		// RexExp object - search for term, case insensitive
    		var regex = new RegExp(term, "i");
    
    		// "this" in this context refers to the mongoskin collection object
    		this.find({
    			"$or": [
    				{
    					"stripped_content": regex
    				},
    				{
    					"comments.stripped_content": regex
    				},
    				{
    					"keywords": regex
    				},
    				{
    					"comments.keywords": regex
    				}
    			]
    		}, {}).toArray(fn);
    	}
    });
    
    // Export the model
    exports.model = mongo[collection];

    The $or clause searches the keyword arrays and the stripped_content field for the term as a case-insensitive regular expression. This function doesn’t take into account any sorting, skipping, or limiting, but that’s trivial to implement with mongoskin.

    The Controller

    In the search controller, we can call the method:

    // Require the model
    var postModel = require("../../models/post").model;
    
    exports.index = function(req, res) {
    
    	// URL is like http://example.com/search?q=foo
    	var term = req.query.q;
    
    	// Call our method
    	postModel.search(term, function(err, documents) {
    
    		// No error
    		if(!err) {
    			// Render the view
    			res.render("search/index", {
    				, results: documents
    				, term: term
    				, title: "Result(s) For <em>" + term + "</em>"
    			});
    		}
    		// Error
    		else {
    			req.flash("error", "Error searching!");
    			res.redirect("back");
    		}
    	});
    };

    The controller function returns an array of post objects or an empty array. It’s easy from there to paginate your results and make the whole thing more user-friendly.

    Keep in mind that what I’m doing here uses two simultaneous methods to search; it’s no doubt better to use one of the two and stick with that. That is, decide whether you want to use a keywords array or run the regex on that or use the string and run the regex on only the string and forget the keywords array entirely.

    I hope this is helpful for people setting up applications with Express and MongoDB! Any feedback is appreciated.

    Comment on this post!

    Categories:

    tech

    Tags:

    mongodb express nodejs
  • Blogging With Jekyll And GitHub Pages

    This blog is build using GitHub Pages and Jekyll (which in turn uses Liquid for layout rendering). I started out using Wordpress, but I quickly realized that it provided more functionality than I needed, and I am concerned about its security. So I started looking around for other options and realized that the site that I’d been hosting with GitHub was really all I need for a simple blog and portfolio site.

    A few notes on how it all works:

    • Jekyll comes with a Webrick server which is really handy when you’re editing locally since you don’t need to restart it every time you change a file; you DO, however, need to reload it every time you make a change to the _config.yml Jekyll file.
    • Jekyll pagination leaves a lot to be desired; it only works on the index.html page and (supposedly) doesn’t support markdown files, only files with the .html extension. I got it working locally using markdown files (don’t ask me how, I’m not sure), but we’ll see if it actually works once I have a few more posts.
    • GitHub pages work really well. The docs are here and relevant blog posts are here and here for CNAME support.
    • One thing I haven’t gotten working is category pages for my blog; they work locally, but not when I push to GitHub. I’m not sure why – the category pages are being generated and function fine locally but produce 404 errors when I try to access them on the web, so I pulled them for now. [ EDIT: per this issue it appears that GitHub Pages don’t support plugins at all; apparently they’re generating the HTML on their servers and ignoring the plugins directory. Bummer. One option appears to be using a different repo for Jekyll and one for the generated HTML, but that seems sort of inelegant and would be hard to use, for instance, at more than one computer at a time. ]
    • Jekyll has no native commenting ability, but comments (FWIW) are super easy to implement using DISQUS.

    I hope this is helpful to people out there also starting out with Jekyll and GitHub pages!

    Comment on this post!

    Categories:

    tech

    Tags:

    jekyll github
  • Express and S3, Part One: Uploading

    We’re using the excellent Express NodeJS web framework for an internal project here at Big Spaceship, and it’s come time to figure out uploading files to Amazon’s S3 service.

    I looked at the options on NPM and gave knox a try. It seemed pretty straightforward, although I could only get uploads working via the putStream() method, not via put().

    My route file looks like the following (we’re using express-resource):

    var Resource = require("express-resource");
    
    module.exports = function(app) {
    
    	app.get(
    		"/file*"
    		, function(req, res, next) { next(); }
    	);
    	app.post(
    		"/file/create"
    		, require("../controllers/file/index").create
    	);
    	var file = app.resource("file", require("../controllers/file/index"));
    }

    Our /file/new page is just a simple multipart form with a file input and a submit button.

    My controller looks like the following:

    var fs = require("fs");
    var knox = require("knox"); // s3 Library
    var s3_config = require("../../config/s3").config; // our s3 configuration file
    var s3_client = knox.createClient({
    	key: s3_config.key
    	, secret: s3_config.secret
    	, bucket: s3_config.bucket
    });
    
    exports.index = function(req, res) {
    
    };
    
    exports.new = function(req, res) {
    	res.render("files/new", {
    		title: "Upload a new file"
    	})
    };
    
    exports.create = function(req, res) {
    	var file = req.files.file;
    	var s3_stream = fs.createReadStream(file.path);
    	s3_client.putStream(s3_stream, "/uploads/" + file.name, function(err, s3_res) {
    		if(s3_res.statusCode === 200) {
    			req.flash("message", "Upload saved.");
    			res.redirect("/file");
    		} else {
    			req.flash("error", "Error saving upload! " + s3_res.statusCode);
    			res.redirect("/file/new");
    		}
    	});
    };

    We require() our necessary files at the top and create the knox client.

    The important part is in the exports.create, which is out HTTP POST route. We’re receiving data from the file form (req.files.file) and passing it off to the filesystem module, which creates a stream resource using createReadStream(). Then that stream is passed to the knox putStream() method, which uploads it to S3 as the filename we specify and fires a callback with the S3 response object as its second parameter.

    Keep in mind that we’re uploading to a folder inside out bucket called “uploads” here - that’s why the file name is “/uploads/” + file.name.

    After that it’s just a check to see if the S3 server returns a 200 statusCode and we can do our redirection logic.

    So, with a couple of caveats, getting a file up onto S3 using NodeJS and Express isn’t that hard. I’ll write another post once I have file deletion and management figured out.

    Comment on this post!

    Categories:

    tech

    Tags:

    s3 nodejs express