Skip to content

Archive for the 'Example Code' Category

Programmatically Pull Attachments from WordPress Posts

One of my favorite tricks in using WordPress as a CMS is to have it handle photo resizing and insertion into pages automatically. For example, swissmiss and I just launched Convert (a NYC based Green Roof Service) today. Within the projects section they display photos of the green roofing projects they’ve done and let you download a project sheet PDF.

It would be quite a burden for the client to have to know how to create all of the appropriate image sizes, upload the photos and insert the correct HTML tags. So here’s what we’ve done instead:

First, we set the WordPress image sizes to match the thumbnail and large sizes that we needed by going to Settings->Media in the admin tool.

Next, the client just has to upload all of their photos and a PDF for the project sheet. The images are automatically scaled by WordPress and attached to the page. They can also change the order the photos appear by dragging/dropping them in the admin tool.

Finally, adding this simple snippet of code to the functions.php in their theme, I can ask for all of the images associated with the post.

// get all of the images attached to the current post
function aldenta_get_images($size = 'thumbnail') {
	global $post;

	$photos = get_children( array('post_parent' => $post->ID, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID') );

	$results = array();

	if ($photos) {
		foreach ($photos as $photo) {
			// get the correct image html for the selected size
			$results[] = wp_get_attachment_image($photo->ID, $size);
		}
	}

	return $results;
}

So, if you want all of the thumbnail images (as an array of html tags) you can make the default call:

$photos = aldenta_get_images();

If you want all of the medium sized images you pass medium as the size:

$photos = aldenta_get_images('medium');

My function has a bit more going on inside of it but you get the idea of what you can do with this. Another way I like to use it is to pull the first image from the post. Sometimes, you want to display a thumbnail image that represents a post. Here’s how I like to do that:

// get the first image attached to the current post
function aldenta_get_post_image($size = 'thumbnail') {
	global $post;

	$photos = get_children( array('post_parent' => $post->ID, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID') );

	if ($photos) {
		$photo = array_shift($photos);
		return wp_get_attachment_image($photo->ID, $size);
	}

	return false;
}

// the html tag for the first image or false if no image is found
$photo = aldenta_get_post_image();

What if you want to get the PDF attached to the post? No problem – it works the same but you change the mime type to application/pdf.

// get the first PDF attached to the current post
function aldenta_get_post_pdf() {
	global $post;

	$attachments = get_children( array('post_parent' => $post->ID, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'application/pdf', 'order' => 'ASC', 'orderby' => 'menu_order ID') );

	if ($attachments) {
		$attachment = array_shift($attachments);
		return wp_get_attachment_url($attachment->ID);
	}

	return false;
}

// the url to the first pdf or false if no pdf is found
$pdf = aldenta_get_post_pdf();

This technique has helped me tremendously and I hope it does the same for you.

Plugin Update: PDF Bookmark bug fix and French translation

If you are having problems with the bookmark plugin not working for some documents, this update (1.2) should fix that. The update also adds a French translation to the Bookmark menu and provides an installation path for Linux users. Thanks to TitCouille for help with all of those items.

The plugin should work correctly for Adobe Reader 7, 8 and 9. If you’re interested in helping add a translation for another language please let me know. There are currently only 3 items that need translating – “Bookmark”, “Bookmark This Page” and “Go To Bookmark”.

See the full details and download the plugin.

Plugin Update: PDF Bookmark for Adobe Reader 8

Some of you may already be using the PDF bookmark plugin I put together for Adobe Reader. It provides a quick and easy way to bookmark the page your on and return back to that spot later. It’s especially handy when reading large PDF books.

Thanks to the input of Michael Hartl, I updated the plugin to work properly with Adobe Reader 8. Adobe turned on some security settings by default in the new Adobe Reader which broke the previous version of the plugin.

See the full details and download the plugin.

script.aculo.us Slider Demo : Update Text Field and Change Slider

For those of you using the script.aculo.us Slider demos I’ve just added a new one. Sometimes you may have a slider and a text field to show the value. This example lets you change the value in the text box and the slider will update to match the value.

Example: Change Slider Value by Changing Text Input Field

script.aculo.us Slider Demos and Example Code

I’ve been following along the script.aculo.us Slider Demo discussion area recently and have tried to answer questions when possible. Since it’s difficult to post examples to the discussion I’ve compiled a more extensive set of Slider demos. Some are examples that I’ve wanted and others are in response to questions in the discussion area.

The demo code includes the following slider examples:

  • Standard Slider
  • Reversed Slider
  • Slider Controlled with Mouse Wheel
  • One Slider Controlling Multiple Sliders
  • Using Images to Spruce Up a Slider
  • Two Colored Slider
  • Submit the Slider Value in a Form
  • Use a Slider as a Scrollbar (added Nov 21, 2006)
  • Change Slider Value by Changing Text Input Field (added Jul 16, 2007)

It’s really amazing what you can do with the script.aculo.us library. Please let me know what you think!

has_many :through Self-referential Example

While using an association table for the first time with Ruby On Rails I had a bit of trouble finding an easy to understand example of has_many :through. I needed to build a self-referencing table where People could have other People as friends through a Friendship. I was getting “stack too deep” errors, “could not find the association” errors, and also crashing Webrick before I figured out the correct setup. Here’s how I did it:

# the people table
create_table :people do |t|
  t.column :name, :string
end

# the friendships association table
create_table :friendships do |t|
  t.column :person_id, :integer
  t.column :friend_id, :integer
  t.column :authorized, :boolean, :default => false
end

class Friendship < ActiveRecord::Base
  # don't have to give class_name or foreign_key b/c ActiveRecord reflection works here
  belongs_to :person

  # make sure to give class_name and foreign_key b/c ActiveRecord doesn't know what friend is
  belongs_to :friend, :class_name => "Person", :foreign_key => "friend_id"
end

class Person < ActiveRecord::Base
  # tell ActiveRecord that a person has_many friendships or :through won't work
  has_many :friendships

  # create the has_many :through relationship
  has_many :friends, :through => :friendships

  # an example of how to get only the authorized friends
  has_many :authorized_friends, :through => :friendships, :source => :friend, :conditions => [ "authorized = ?", true ]

  # an example of how to get only the unauthorized friends
  has_many :unauthorized_friends, :through => :friendships, :source => :friend, :conditions => [ "authorized = ?", false ]
end

Using Mouse Wheel to Control script.aculo.us Slider

You may have noticed that Google Maps will zoom in and out when you use your mouse wheel (or trackpad scrolling). If you want to do the same thing using the script.aculo.us JavaScript Slider here is an example to get you started.

The example uses a slightly modified version of Adomas Paltanavicius’ mouse wheel event code. Firefox 1.5 seems to work fine but not Safari 1.3. Please let me know how it handles in other browsers.

Example: Using Mouse Wheel to Control Slider

Update: I’ve created a more extensive set of Slider demos which includes the mouse wheel demo. (Nov. 12, 2006)

Execute Rails Code Before the View is Rendered

At one time, I was looking for a way to execute code for every action in my controller before the view was rendered. I saw this come up again yesterday in the #rubyonrails IRC channel so I looked at it a bit more. Currently, Rails provides a before_filter method which will “run before actions on this controller are performed” or an after_filter which will “run after actions on this controller are performed.” What I wanted was a before_render filter which would run right at the end of the action but before render/view was executed.

Here is one idea how to do this. Since you want the code to run right before render is executed just override the render method that’s in ActionController. You can put the following code inside any of your individual controllers or add it to your ApplicationController and it will run in all of your controllers.

protected
  def render(options = nil, deprecated_status = nil, &block)
    # your code goes here
    @rockon = "rock and roll!"

    # call the ActionController::Base render to show the page
    super
  end

This is just an example, and maybe someone will take this a step further and actually create a before_render filter plugin. It would be nice to have the same flexibility as before_filter and after_filter which allows you to include “:only” or “:exclude” certain actions.

Writing a Custom FormBuilder in Rails

I’m currently working on a Ruby on Rails application where I need lots of text fields that have the same properties. I decided to override text_field and have it output all of the extra attribues automatically. This helps keep the view code cleaner, lets me change all of these text fields in one place, and also helps me avoid typing mistakes (at least in this section of the code). Thanks to Ruby on Rails core team member Rick Olson (aka technoweenie) for pointing me to his LabeledFormHelper plugin, which taught me this technique.

Before the custom FormBuilder my initial view code looked something like:

<% form_for(:spreadsheet, @spreadsheet, :url => { :action => 'create' }) do |s| %>

    <% fields_for :numbers, @spreadsheet.numbers do |f| %>

      <%= f.text_field :field1, :onkeypress => 'return isNumberKey(event);', :maxlength => 3 %>
      <%= f.text_field :field2, :onkeypress => 'return isNumberKey(event);', :maxlength => 3 %>

      ... and so on

    <% end %>
<% end %>

So I created a custom FormBuilder in my helper to do the extra text_field work for me:

module SpeadsheetsHelper

  # tell all of these methods to use my custom FormBuilder
  [:form_for, :fields_for, :form_remote_for, :remote_form_for].each do |meth|
    src = <<-end_src
      def speadsheets_#{meth}(object_name, *args, &proc)
        options = args.last.is_a?(Hash) ? args.pop : {}
        options.update(:builder => SpeadsheetsFormBuilder)
        #{meth}(object_name, *(args << options), &proc)
      end
    end_src
    module_eval src, __FILE__, __LINE__
  end

  # the custom FormBuilder
  class SpeadsheetsFormBuilder < ActionView::Helpers::FormBuilder    

    # add onkeypress and set maxlength of field to 3 to all text fields
    def text_field(method, options={})
      super(method, options.merge(:onkeypress => 'return isNumberKey(event);', :maxlength => 3))
    end

  end
end

Now my view code is much simpler and helps avoid goofups:

<% spreadsheets_form_for(:spreadsheet, @spreadsheet, :url => { :action => 'create' }) do |s| %>

    <% spreadsheets_fields_for :numbers, @spreadsheet.numbers do |f| %>

      <%= f.text_field :field1 %>
      <%= f.text_field :field2 %>

      ... and so on

    <% end %>
<% end %>

Notice in the view that instead of using form_for and fields_for you need to use the custom methods spreadsheets_form_for and spreadsheets_fields_for which were created in SpeadsheetsHelper.

Plugin: Bookmark A Page In Your PDF

With the long, yet wonderful, books in PDF format these days (Agile Web Development with Rails by Dave Thomas and David Heinemeier Hansson with Leon Breedt, Mike Clark, Thomas Fuchs, and Andreas Schwarz [570 pages]; Programming Ruby by Dave Thomas, with Chad Fowler and Andy Hunt [864 pages]) there needs to be a better way to digitally bookmark where you left off. For some reason Adobe Reader (Acrobat Reader) doesn’t have this capability built in. I found a plugin for Acrobat Reader to do multiple bookmarks per document from PDF Hacks. However, I really just want it to be simple like a physical book – you bookmark the page you’re on when you stop and go to that page when you pick back up. So here is my plugin to bookmark your page in Adobe Reader.

Download:

PDF Bookmark 1.2

Change Log:

  • 1.2 – Nov 30, 2008 – Use documentFileName on PDFs that don’t have a docID. Add French translation (TitCouille). Add installation paths for Linux (TitCouille).
  • 1.1 – Dec 20, 2007 – Update to work with Adobe Reader 8 due to security changes (app.trustedFunction)
  • 1.0 – Sep 15, 2006 – Initial release

Installation:

Adobe Reader 9 – copy pdf_bookmark.js to:

  • Mac: ~/Library/Application Support/Adobe/Acrobat/9.0_x86/JavaScripts (or similar)
  • Linux: /home/[User Name]/.adobe/Acrobat/9.0/JavaScripts/
  • Windows: C:\Documents and Settings\[User Name]\Application Data\Adobe\Acrobat\9.0\JavaScripts (or similar)

Adobe Reader 8 – copy pdf_bookmark.js to:

  • Mac: ~/Library/Acrobat User Data/8.0_x86/JavaScripts (or similar)
  • Linux: /home/[User Name]/.adobe/Acrobat/8.0/JavaScripts/
  • Windows: C:\Documents and Settings\[User Name]\Application Data\Adobe\Acrobat\8.0\JavaScripts (or similar)

Adobe Reader 7 – copy pdf_bookmark.js to:

  • Mac: ~/Library/Acrobat User Data/7.0/JavaScripts (or similar)
  • Linux: /home/[User Name]/.adobe/Acrobat/7.0/JavaScripts/
  • Windows: C:\Documents and Settings\[User Name]\Application Data\Adobe\Acrobat\7.0\JavaScripts (or similar)

Note: you may have to create the JavaScripts folder if it doesn’t exist.

Usage:

Open your document in Adobe Reader. Then choose Tools -> Bookmark from the menu. “Bookmark This Page” adds the bookmark. “Go To Bookmark” sends you to the bookmark you created. It remembers which PDF document you bookmarked so it works on all of your PDFs simultaneously. (Tested with Acrobat Reader 7, Adobe Reader 8 (thanks Michael) and Adobe Reader 9 on Mac OS X, Linux (thanks TitCouille) and Windows)

PDF Bookmark Plugin Screenshot (8.0)