on Expert Tips Tutorials

Custom post fields using Advanced Custom Fields WordPress plugin

25 comments
Improve WordPress speed
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon

The time when WordPress was used mainly as a blog engine has passed and WordPress has become one of the most powerful Content Management Systems on the web because of using custom post fields.

Custom post types allows flexibility and give enormous power to WordPress. Usually, we use custom post types with built-in fields like excerpt, content editor, thumbnail etc.

But often, we need some special type of fields for dealing with customer wishes like date picker, relationships, file upload etc.

This is where Advanced Custom Fields plugin comes in.

Advanced custom post fields overview

The Advanced Custom Fields Plugin gives you the tools to create your own custom edit screens. It’s a must have for any WordPress developer. Custom post fields types include: Wysiwyg, text, textarea, image, file, select, checkbox, page link, post object, date picker, repeater …

Advanced Custom Fields Plugin provides a simple to use interface allowing you to create, edit, reorder and completely customize your edit screens.

With Advanced Custom Fields Plugin it is not only possible to create new fields, but to hide WordPress’s default fields as well.

Installing the plugin

Installation is the same as for any WordPress plugin

  1. Download Advanced Custom Fields plugin
  2. Upload ‘advanced-custom-fields’ to the ‘/wp-content/plugins/’ directory
  3. Activate the plugin through the ‘Plugins’ menu in WordPress
  4. You may be prompted for a Database Upgrade. This is necessary for ACF to function. Please backup your database and click the Upgrade button

Usage

Once the plugin is uploaded and activated, go to Settings and click on the Adv Custom Fields link and then “Add New”. You can then give a name to your new set of fields (for example “Columns”) and add as many types of custom fields as you want. Currently supported types are:

Advanced Custom Fields interface is very intuitive and it is very simple to add custom fields groups and assign them to what ever you want. You can decide what Pages, Posts or Custom Post Types you want to have this new set of Custom Fields. For example, you could have all Pages, or all Posts, or only a specific page (for example Home), or all posts in a certain category:

Advanced Custom Fields options page

Advanced Custom Fields also lets you decide what other fields are available on the page. So you can remove the Content Editor, Slug, Author etc and control that and you new fields all from one place.

Advanced Custom Post Fields

Advanced Custom Fields API

Plugin also have a powerful API for dealing with your fields. For example, to display a field on the theme inside a loop:

<p><?php the_field('field_name'); ?></p>

More about the API can be read on Plugin’s official documentation page.

Extending the plugin

Now, you may think that all this is enough. Well, for an average developer it should be. But, if you want to make some really cool types of fields, you can. That is the beauty of this powerful plugin.

I am going to show you how easy it is to make your own custom post field on a real life example. At the end of this tutorial, you can download custom post field type shown here.

The problem

Your customer wants to enter Events into WordPress and wants to select a location of the event by simply clicking on Google Map.

Making the Events custom post type

To make this work, we need a custom post type named Events in which our customer will enter data. First, let us see what data will be needed:

Let’s begin by making this post type. Open your theme’s functions.php and enter this in:

function eventRegister()
{
$labels = array(
'name' => _x('Events', 'post type general name'),
'singular_name' => _x('Event', 'post type singular name'),
'add_new' => _x('Add New', 'portfolio item'),
'add_new_item' => __('Add New Event'),
'edit_item' => __('Edit Event'),
'new_item' => __('New Event'),
'view_item' => __('View Event'),
'search_items' => __('Search Events'),
'not_found' => __('Nothing found'),
'not_found_in_trash' => __('Nothing found in Trash'),
'parent_item_colon' => ''
);

$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'query_var' => true,
'capability_type' => 'post',
'hierarchical' => false,
'menu_position' => null,
'supports' => array('title', 'editor', 'thumbnail'),
'rewrite' => true,
'show_in_nav_menus' => true,
);

register_post_type('event' , $args);
}

add_action('init', 'eventRegister');

Save functions.php and go to WordPress admin dashboard. You will see newly created Custom Post type in the left hand menu. Wow, that was easy.

Click on Add Event and you will see something similar to this:

Add events custom post type

You can enter title, description and thumbnail image. Now, open your Advanced Custom Fields under Settings and click Add new. We will add other fields into field group called Events and it should look like this:

Advanced custom fields - field group

If you go to Add Event page now, you should see that you can now pick an event date and enter a time.

Wow, that was really easy. Now comes the hard part.

Making our own custom field type

Author of this great plugin has made our lives easier and give us a Class template for making our own custom field types for ACF. Download it here, unpack it and place it inside your active theme. I prefer to create a fields folder in my theme’s root and put this template in it.

Now rename this file to location.php. Open it up in your editor and rename the class, the name variable and the title:

class Location_field extends acf_Field
{
function __construct($parent)
{
// do not delete!
parent::__construct($parent);

// set name / title
$this->name = 'location'; // variable name (no spaces / special characters / etc)
$this->title = __("Location",'acf'); // field label (Displayed in edit screens)

} ...

Next, we must register this field so ACF plugin will know about it. Open your theme’s functions.php and enter this anywhere:

register_field('Location_field', dirname(__FILE__) . '/fields/location.php');

This function will register our field in the ACF. It has 2 parameters, the first is our Class name and the second is the path to the Class file.

If you go to Advanced Custom Fields Settings, you should see Location in the drop down:

Location field in the drop down

Next thing we are going to do is create our Latitude and Longitude field that will be shown on edit screen and populated with values from Google Map.

For this, we will need create_field function inside our location.php file:

function create_field($field)
{
echo '<input type="text" value="' . $field['value'] . '" id="' . $field['name'] . '" class="' . $field['class'] . '" name="' . $field['name'] . '" />';
echo '<div id="map"></div>';
}

Save this file and go add Location field to field group inside ACF settings and Update. Now, go to entering new Event and you will see our Location text field. Everything is working, field gets saved to database. Basically, we recreated the text field.

Adding Google Map

Next task is to add a Google Map and some Google Map API, so when the user clicks on the map, we will get the Latitude and Longitude of that point and fill our Location field with it.

For this use, we will use admin_head function, which is great for inserting CSS and JavaScript:

function admin_head()
	{
		?>
		<style type="text/css">
			#map {width: 100%; height: 500px; margin-top: 10px;}
		</style>
		    <script src='http://maps.googleapis.com/maps/api/js?sensor=false' type='text/javascript'></script>
			<script type="text/javascript">
				function load() {
					var exists = 0, marker;
					// get the lat and lng from our input field
					var coords = jQuery('.location').val();
					// if input field is empty, default coords
					if (coords === '') {
						lat = 45.77598686952638;
						lng = 15.985933542251587;
					} else {
						// split the coords by ;
						temp = coords.split(';');
						lat = parseFloat(temp[0]);
						lng = parseFloat(temp[1]);
						exists = 1;
					}
					// coordinates to latLng
					var latlng = new google.maps.LatLng(lat, lng);
					// map Options
					var myOptions = {
					  zoom: 8,
					  center: latlng,
					  mapTypeId: google.maps.MapTypeId.ROADMAP
					};
					//draw a map
					var map = new google.maps.Map(document.getElementById("map"), myOptions);

					// if we had coords in input field, put a marker on that spot
					if(exists == 1) {
						marker = new google.maps.Marker({
							position: map.getCenter(),
							map: map,
							draggable: true
						});
					}

					// click event
					google.maps.event.addListener(map, 'click', function(point) {
						if (exists == 0) {
							exists = 1;
							// drawing the marker on the clicked spot
							marker = new google.maps.Marker({
								position: point.latLng,
								map: map,
								draggable: true
							});
							//put the coordinates to input field
							jQuery('.location').val(marker.getPosition().lat() + ';' + marker.getPosition().lng());
							// drag event for add screen
							google.maps.event.addListener(marker, "dragend", function (mEvent) {
								jQuery('.location').val(mEvent.latLng.lat() + ';' + mEvent.latLng.lng());
							});
						} else {
							// only one marker on the map!
							alert('Marker already on the map! Drag it to desired location.');
						}
					});
					//dragend event for update screen
					if(exists === 1) {
						google.maps.event.addListener(marker, "dragend", function (mEvent) {
							jQuery('.location').val(mEvent.latLng.lat() + ';' + mEvent.latLng.lng());
						});
					}
				}

			jQuery(document).ready(function(){
				load();
			});
			</script>

		<?php
	}

There is plenty of comments above in the code, so everything is self explanatory.

When you go to add new Event, you will now see a Google Map below your Location field. When you click on a map, Lat and Long coordinates will be filled into your Location field. You can even drag a marker on a map to change the location! How cool is that?

Now, all we have to do is to show this Event in our theme, along with a Google Map.

Showing the location in the theme

Actually, it is very easy to show the coordinates we entered in our event in the theme. Advanced Custom Fields has a great API for that.

To use the coordinates, just enter this inside your WordPress loop:

the_field('location');

But, I want to show this coordinates in a map. So create a single-event.php file in your theme’s folder and enter something like this (this is just the content inside a single post loop for TwentyEleven Theme):

<div class="entry-content">
<?php the_content(); ?>
<p>Date of the event: <?php the_field('date'); ?> <?php the_field('time'); ?></p>
<div id="map" style="width: 500px; height: 350px;"></div>
<?php
$location = get_field('location');
$temp = explode(';', $location);
$lat = (float) $temp[0];
$lng = (float) $temp[1];
?>
<script src='http://maps.googleapis.com/maps/api/js?sensor=false' type='text/javascript'></script>
<script type="text/javascript">
//<![CDATA[
function load() {
var lat = <?php echo $lat; ?>;
var lng = <?php echo $lng; ?>;
// coordinates to latLng
var latlng = new google.maps.LatLng(lat, lng);
// map Options
var myOptions = {
zoom: 9,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
//draw a map
var map = new google.maps.Map(document.getElementById("map"), myOptions);
var marker = new google.maps.Marker({
position: map.getCenter(),
map: map
});
}
// call the function
load();
//]]>
</script>
<?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
</div><!-- .entry-content -->

Or, you can make a page with events and one map that will show all your events. What ever you want, is achievable now.

Conclusion

WordPress is a very powerful tool and stuff described above, makes it even more powerful. Your imagination is the limit.

Demo
Don’t hesitate to share your thoughts or ask a question below.

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon



  • EXACTLY what i was looking for, great tuorial saved me hours of digging apart the core folder!

    Thanks

  • Fedir

    I’m quite new in WordPress, and it was really interesting to know, what it’s possible to do such stuff. Normally, I used Drupal for such projects, but this technique pretty impressed me.

    Just it seems what You forgot to show in Your create_field method.

    Thank You very much Zvonko for this great tutorial.

  • Thanks Fedir, I added the div to create_field function.

  • Thanks, this is a great post!

    I am wondering, do you know if it is possible to avoid programming and use just plugins for creating (registering) the new types?

    The purpose is explained here: What I wanted is to create a new theme based on this plugin (to show Events for example) but only for certain post types that users can create on demand (ie: Events or Listings). What I really wanted is to avoid that the user need to edit functions.php – Know what I mean?

    Thanks!

  • Well, I am trying to answer myself, I think something like Custom Post Type U plugin in conjunction with ACF will do it.

  • Ok, yes. It worked. I was able to create post types using the plugin Custom Post Types UI, and then I linked these custom post types with the ACF (Advanced Custom Fields).

    For the maps, I think I will try your approach combined with the MapPress plugin.

    • Julian, I am glad you found the answer. Custom Post Type UI is great plugin to achieve something like that.

  • Hi Zvonko.

    Awesome job on the field. It’s exiting to see the public responding so well to the register_field functionality.

    I’ve recently launched the new acf website with a section for user submitted fields. If you want, have a read of this: http://advancedcustomfields.com/support/discussion/1224/important-how-to-submit-your-field

    Your field would be a great first addition to the site.

    Cheers mate
    Elliot

    • Hi Elliot,

      thanks for your comment.

      I will submit my field to your website today.

  • Hi,

    really nice tutorial. For any reason I got “undefined;undefined” when I placed the marker. To resolve the issue i had to access the lat/lng via

    jQuery(‘.location’).val(marker.getPosition().lat() + ‘;’ + marker.getPosition().lng());

    • Hi John,

      I updated above code and the one in the download and all is fixed now.

      Please try again.

      Best regards
      Zvonko

  • Veljko

    Hello,

    i have installed ACF plugin and it is really good, but i have a question.

    I’ve created custom field with 3 radio buttons and default value “0”. Now i need to assign to all of my posts (total 540) default value 0.

    I thought that the plugin will write into the database that all my posts have this default value, but i see now that i would have to enter every post and update them manually so that it gets written into the database.

    Is there some easier solution for this?

    Thanks

    • When you retrive your new fields, they will be empty and the function get_field() will return false.

      For example:


      if($variable = get_field('field_name'))
      {
      // whatever ....
      }

      • Veljko

        Ok, but i want to sort posts based on the values of this custom field and the default value is not stored into the table so i need a way to do this, but not to enter every post and do update…

        • Something like this:


          $args = array(
          'post_type' => 'your_post_type',
          'post_status' => 'publish',
          'meta_key' => 'your_custom_field_for_sorting',
          'orderby' => 'meta_value_num',
          'order' => 'ASC',
          'posts_per_page' => 10
          );

          $loop = new WP_Query( $args );

          • Veljko

            I did write the script for query and it’s working.

            The problem is that my existing posts are not showing up, because in posts_meta table there are no values from the custom field i created using the plugin.

            1. I have 540 posts already made

            2. Created custom field using ACF, but it doesn’t auttomaticaly assign value to these posts until i click on button “Update” in the post admin part

            3. So since there is no information about the value of this custom field in the db table WP can’t display the posts

            Do you know any way how to insert this default value in the WP database so that i don’t have to go into every post just to click on “Update” button?

            I hope that now it’s more clear 🙂

  • p|b

    This is brilliant.
    This extension is a FANTASTIC add-on.

    However, I’m VERY confident that my client isn’t capable of researching the latitude/longitude. I know that she’d also get frustrated at the idea of having to zoom down into a map to determine the location- especially when most of her classes are repeating at the same venues.
    (her tech-saviness isn’t very extensive to say the least.)

    Is there a way to simply use an inputted address field with Street/City/State to pull the Google Maps?

    • Hi Paul,

      I intend to extend the field in a couple of days, so you will be able to search location by user input.

      Thanks for the comment

  • Enormous thanks Zvonko for such a wonderful plugin – a very useful and constructive extension of Advanced Custom Fields.

    I’ve not yet set it up, but in having just downloaded the file from the ACF’s great Add-ons section I thought I should mention the function code you’ve included there is missing a closing parenthesis after (‘register-field’).

    Now to follow your instructions here … with eagerness.

  • You should push the plugin up to github so we can send pull requests 😉

  • This is by far the best WordPress tutorial I’ve read so far. Thanks for tutorial! Funny fact is, i came here by accident. I was looking for a solution to work with Advanced custom fields on custom post types. I needed it to build some kind of Events back-end manager. Later on I scrolled down and saw the Google maps tutorial wich was gold!!!!

    • Thanks, I am glad that you found it useful.

  • Mark

    This is pretty awesome. I’m still trying to process every line of code and see how to use 1 map with multiple markers and also include a “search by zipcode” with a 5, 10, 15, 20 mile radius.

    Any thoughts?

  • Great stuff. Really well done.

    I’d like to add my voice to those asking for a textual search. Would be great to type in an address and get the corresponding map.

  • Great addition to an already great plugin. Keep up the great work. Definitely a worthy of use.