Hitting A Custom Built Rails API...With WordPress

By @zachfeldman
Written on Sep 28, 2013

A month after starting my new gig as a Developer at Contently, I was presented with an interesting project. If you weren’t aware, Contently has a Writer Portfolios product. My coworkers Shane and John wanted to create a WordPress plugin that could bring together a group of portfolios, for an organization or institution of higher learning to showcase their stables of talented journalists. A portfolio of portfolios, to put it simply and recursively.

Yo Dawg.

The solution would need two distinct items to work:

  1. An API for the Contently platform to pull user portfolio data from

  2. A WordPress plugin that could execute a search of this new API, preferably without leaving a theme or plugin configuration page, to pull in data for individual users

Shopping list item #1 was taken care of pretty handily with a little RubyGem called Grape. Inside of our Rails app, I setup a new file in app/lib/modules/api called portfolios.rb, which contained a Portfolios module with an API class inside extending the main Grape::API class:

1
2
3
4
5
6
7
module Portfolios class API < Grape::API prefix 'contently-api' version 'v1', :using => :path format :json end end

After this basic configuration code, I started out by writing a simple API endpoint, just to be sure things were up and running:

1
2
3
4
5
6
resource :users do desc "Return a user's portfolio info." get '/find' do "Hello World" end end

After seeing the obligatory Hello World in the browser at localhost:3000/api/v1/users/find, I cracked my knuckles and got to work. I wrote the following methods:

  1. check_api_key - ensures user’s API key is valid
  2. encode_user - given a user object, returns a JSON object with needed portfolio information
  3. custom_search - given terms, page number, and per page, return results of a user search. Search on Contently is done using ElasticSearch, so this ensures super-fast results.
  4. encode_users - given search results, and using the encode_user method, return a JSON object of all users found in search results
  5. error - handle errors with the correct response code and a descriptive message

Using these methods, I constructed my API endpoint with ease:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
desc "Search for portfolio users." get '/search' do if check_api_key(params[:key]) results = custom_search(params[:q], params[:page], params[:per_page]) if results.empty? { status: 200, result_count: results.count, results: [] }.to_json else encode_users(results) end else error!('401 Unauthorized', 401) end end end

Now I had an API that returned results in JSON when I hit our /search endpoint with a user, per page, page number, and API key query string:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{ "status": 200, "hits": 1, "results":[ { "full_name":"Zatch Feldman", "bio":"Zatch Feldman is totally a crazy dude.", "clips":14, "shares":2663, "link":"http://zachfeldman.contently.com", "words":12181, "image":"http://contently.com/system/avatars/15892/original/stringio.txt?1352748415", "publications":"http://www.thenation.com, http://www.alternet.org, http://www.towardfreedom.com, http://truth-out.org/, http://www.salon.com" } ] }

Bingo! Step number one successfully executed. Now it was time for some WordPress magic to tie it all together.

I began by creating a plugin, but quickly realized that with what we were trying to achieve, a theme with a custom settings page would be much better suited. I started with a basic template that Shane had ordered up for this specific project. The first order of business was to create my custom settings page:

1
2
3
4
5
6
7
8
9
<?php //hook into WordPress admin_menu system add_action('admin_menu', 'cgp_plugin_admin_add_page'); //function to add menu page to the admin menu, with custom favicon function cgp_plugin_admin_add_page() { add_menu_page('Contently Portfolios', 'Contently Portfolios', 'edit_theme_options', 'contently-options', 'cgp_plugin_options_page', '/wp-content/themes/wp-contently-portfolios/images/favicon.ico' ); } ?>

I used the cgp_ namespace, for Contently Group Portfolios. To add content to my page, I created the function referenced in my cgp_plugin_admin_add_page() function, that being cgp_plugin_options_page, the 5th argument:

1
2
3
4
5
6
7
8
<?php // display the admin options page function cgp_plugin_options_page() { ?> [PAGE CONTENT HERE] <?php } ?>

Inside of this block, I put the HTML for my custom theme page and the JavaScript necessary to retrieve search results from the Contently API. The final page looks like this:

To import users from Contently into this group’s portfolio, the user uses the search button to search for them by name or e-mail. Clicking the search button sends a request to a separate PHP file (to avoid cross-domain AJAX requests), which uses CURL to send a request to my Grape API with the desired terms and return them in the JSON format as shown above. From here, users can check off which writers they’d like to import. Clicking the blue “Import Users” button sends each user object to another PHP script through a POST request, which contains a method to create a post with user data sent. This function uses WordPress’s built in wp_insert_post function, which takes a post object.

New portfolios are saved as a post object in WordPress, with extra metadata. This way, the group portfolio admin can make manual edits to portfolio users if they’d like.

Finally, to add a bit of polish to the theme, I also allowed some view options to be set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php //update theme options on form submit if($_POST["logo"] != ""){ update_option("site_logo", $_POST["logo"]); } if($_POST["search_bar_hover_color"] != ""){ update_option("search_bar_hover_color", $_POST["search_bar_hover_color"]); } if($_POST["header_background"] != ""){ update_option("header_background", $_POST["header_background"]); } if($_POST["primary_color"] != ""){ update_option("primary_color", $_POST["primary_color"]); } ?>

Thinking that most users wouldn’t even want to be bothered with this, I added some default options the first time the user loads the theme:

1
2
3
4
5
6
7
8
<?php //set defaults on theme activation if ( is_admin() && isset($_GET['activated'] ) && $pagenow == 'themes.php' ) { update_option("search_bar_hover_color", "#bc7300"); update_option("header_background", "#222"); update_option("primary_color", "#f09200"); } ?>

Altogether, I now had a custom theme with the correct style to show off portfolio users on Contently, and admin tools to allow groups who’d like to use this technology to showcase groups of talented writers!

I hope you enjoyed hearing about the process. If you’d like to know more about it, you can find me on github @zachfeldman or on my website zfeldman.com.





Sign up for our e-mail list to hear about new posts.