This article describes how to work with WordPress custom fields, also called post meta. In it, we describe how to use WordPress’s post meta PHP functions, especially get_post_meta()
and update_post_meta()
, and provide in-depth code demos as well as practical advice for working with custom fields tools like Pods and Advanced Custom Fields.
This discussion of WordPress custom fields is a chapter from our outstanding WordPress course, Up and Running. If you want to become a knowledgeable WordPress developer, Up and Running is your best, clearest route to getting there.
The Best Way to Learn WordPress Development
Get Up and Running Today!
Up and Running is our complete "learn WordPress development" course. Now in its updated and expanded Third Edition, it's helped hundreds of happy buyers learn WordPress development the fast, smart, and thorough way.
Here's what one of them had to say:
"I think anyone interested in learning WordPress development NEEDS this course. Watching the videos was like a bunch of lights being turned on." -Jason, WordPress developer
This article is also part of a larger free series on WordPress custom fields (post meta) and custom taxonomies. If you’d like to know what custom fields are, and whether you should be adding a piece of post meta or creating a custom taxonomy, have a look in that article series.
Now, read on. 🙂
Key Takeaways:
- Custom field data can be added to a post in the “Custom Fields” section of the Post Editor, or programmatically using
update_post_meta()
.update_post_meta()
is also the function to change a custom field’s value for a specific post. - Once stored, custom field data can be accessed using
get_post_meta()
. This function always requires a post ID; in The Loop, you can find this ID withget_the_ID()
, but outside it you’ll need to use other methods. - The final noteworthy function for working with custom field data is
delete_post_meta()
, which destroys a given custom field’s data for a given post. - Creating attractive user interfaces for users to input and change custom fields is difficult and labor-intensive in WordPress. Several good plugins and projects exist to solve the problem, and it’s worth using those before attempting the process by hand.
In this chapter, we’ll discuss how to add custom field data—both from the WordPress admin interface and programmatically—and how to use, modify, and delete that data.
How Custom Fields Work
Custom fields are stored in the WordPress database’s wp_postmeta
table (note that wp_
can be changed to another database prefix), and look like this:
As you can see, custom fields are simple key/value pairings: they map a custom field name (meta_key
) to a custom field value (meta_value
) for a particular post (post_id
). The only data a custom field has beyond these three elements is a unique ID (meta_id
).
Once stored, custom field data can be retrieved and used, modified, and deleted with several simple WordPress functions.
Adding Custom Field Data to a Post
Below is the default interface for manually adding custom field data to a post:
Relative to most interfaces, this one is pretty unattractive and difficult to use; we’ll give some advice for creating new interfaces below.
Using Custom Field Data
WordPress’s most useful function for accessing a post’s custom field data is called get_post_meta()
. (Others exist, including the_meta()
and get_post_custom()
, but both behave strangely enough to be worth omitting.) To see how get_post_meta()
works, let’s examine it in a couple of environments.
In the Loop
Let’s first try get_post_meta()
inside The Loop:
<?php
/*
Plugin Name: WPShout Add Favorite Flavor to Content
*/
function wpshout_favorite_flavor_subtitle( $content ) {
$fave_flave = get_post_meta( get_the_ID(), 'wpshout_current_favorite_flavor', true );
if( empty( $fave_flave ) ) {
return $content;
}
$fave_flave_string = '<em>My current favorite flavor is: ' . $fave_flave . '</em><hr>';
return $fave_flave_string . $content;
}
add_filter( 'the_content', 'wpshout_favorite_flavor_subtitle' );
On the Post whose custom field we set in the screenshot above, we get this result:
In the Loop in a Plugin?
First off: How can we be in The Loop if we’re writing a plugin? This is an important point.
The answer is that we’ve hooked into the_content
, a filter hook that takes place inside The Loop. The the_content
hook is triggered just before the the_content()
or the_excerpt()
filter tags execute.
So going back to our factory analogy: By hooking into the_content
, we got pulled into the section of the factory that’s running The Loop. If we’d hooked in somewhere else—say, body_class
, which is our next example—the code above wouldn’t have worked.
get_post_meta()
Arguments
get_post_meta()
accepts three arguments:
- A post ID. This is required for all calls of
get_post_meta()
. In the example above, since we’re in The Loop, we can use theget_the_ID()
template tag, which gets the current post’s data automatically. - A custom field key. We set this key ourselves—
wpshout_current_favorite_flavor
—in our post’s “Custom Fields” box. This argument is optional; if you don’t fill it in, you’ll get an associative array of all the post’s custom fields. - Whether we’d like our custom field value as a string. If we set to
true
, as we did here, we get a string; if we leave it off or set it tofalse
, we’ll get back an array. To keep things simple here (and most of the time), it’s set totrue
.
if( empty( $fave_flave ) ) { }
This section of code simply “exits early” if the post meta we’re trying to fetch doesn’t have a value, so that we don’t end up changing posts that don’t have this custom field.
We’re checking if $fave_flave
is empty, because if the custom field is missing, get_post_meta()
return
s an empty string. So we’re checking whether we indeed got back a value, or just an empty string. (Note that if get_post_meta()
‘s third argument is omitted or set to false
, it return
s an empty array instead.)
Because we’re hooking onto the_content
—using a filter—we have to give back what we’ve been given, which is why we return $content
unaltered.
$fave_flave_string =
Since we know our $fave_flave
variable exists, we’re building a string using that variable.
return $fave_flave_string . $content;
This adds our created string before the main post content string, and return
s the modified content back for WordPress to work on.
add_filter( 'the_content', 'wpshout_favorite_flavor_subtitle' );
We hooked into the_content
, which runs right before a post’s main content is printed to the page. We’re hooking in our own function, wpshout_favorite_flavor_subtitle()
, so that it runs, executing the code inside it, when WordPress fires the_content
. As all filters pass an argument to their hooked functions, note that wpshout_favorite_flavor_subtitle()
has an argument, $content
, which is returned
back whether or not it’s modified.
Outside the Loop
Here’s a use of a custom field outside The Loop. It’s based on this custom field in a post:
Based on the code below, we’re going to add the custom class we’ve defined, .kitties-class
, to our post’s HTML body
element. (We’ve styled .kitties-class
for effect!) The end result will look like:
And here’s the code:
<?php
/*
Plugin Name: WPShout Add Custom Body Class
*/
function wpshout_add_custom_body_class( $classes ) {
if( ! is_singular() ) {
return $classes;
}
global $post;
$custom_body_class = get_post_meta( $post->ID, 'wpshout_custom_body_class', true );
if( empty( $custom_body_class ) ) {
return $classes;
}
$classes[] = $custom_body_class;
return $classes;
}
add_filter( 'body_class', 'wpshout_add_custom_body_class' );
Let’s walk through the bits of the code that are new—we’ll skip the few bits that are very similar to the last example.
if( ! is_singular ) {}
Because this code changes the <body>
class of the entire webpage, we don’t want multiple posts running it at once. In other words, it only makes sense as an approach on singular webpages. This code simply “exits early” if the post bundle has more than one post in it. For more on conditionals like is_singular()
, see WordPress’s Conditional Tags.
global $post
This line is very important. global
means “floating around in WordPress’s global state,” which is the set of variables and objects that exist in the background of WordPress’s processes and tell WordPress “what’s going on.” global $post;
lets us access the $post
global variable locally, in the current function, by the name $post
.
What is $post
? It’s a big PHP object, sitting in WordPress’s global state, with lots of information about the current post. We need to talk to $post
because we need to know the current post’s ID
to be able to run get_post_meta()
.
This is a tricky subject: it gets into PHP object syntax and quite a bit about global state. Think of $post
as a direct source of information about the current post that WordPress is using to create the webpage.
$post->ID
This comes right out of the previous line. We want the post’s ID—without it, we can’t run get_post_meta()
—and we don’t have access to our convenient get_the_ID()
template tag since we’re outside The Loop.
The way to ask an object like $post
for one of its properties is with PHP object syntax: in this case, $post->ID
. What this code gives us back is the ID of the current post (which is also the only post that got fetched for this page load, since we know this is a singular page).
$classes[] = $custom_body_class;
The event we’ve hooked onto, body_class
, passes us a variable, $classes
, to work with. $classes
is an array of classes that WordPress is already planning to add to the webpage’s <body>
tag. It looks something like this: array ( 'single', 'single-post', 'postid-2196', 'single-format-standard', 'logged-in', 'admin-bar' )
.
Talking to arrays is different than talking to other data types, like strings. In this case want to add an element to the $classes
array, and the PHP syntax for adding a single element to an array is: $array_name[] = $thing_to_add;
.
With our new array element added to the $classes
array, all that’s left is to pass the modified $classes
back for further processing. We do this with return $classes;
.
add_filter( ‘body_class’, ‘wpshout_add_custom_body_class’ );
This time, we’re hooking into body_class
, an event that fires long before The Loop ever runs. This is why we had to use global $post
above. When we hook into body_class
, it gives us our $classes
array to modify and give back, just as the the_content
filter gives us a $content
string. (By the way, $classes
and $content
are variable names we decide ourselves—but they’re very smart names, since they describe what’s in them.)
Programmatically Adding, Changing, and Deleting Custom Fields
So far, we’ve only covered how to retrieve data from custom fields. Another common task for developers is to programmatically change or remove this data. The functions for this are quite simple:
update_post_meta()
This is the function for either adding or updating a particular custom field value to a post. It looks as follows:
update_post_meta( $post_id, $meta_key, $meta_value, $prev_value );
Its arguments, in order, are:
$post_id
: The ID of the post to be affected$meta_key
: The name of the custom field to be affected (for the most recent example, this would be'wpshout_custom_body_class'
)$meta_value
: The value that the custom field should now take—this can be a string, integer, array, or any other data type depending on your needs$prev_value
: This optional parameter handles duplicate meta keys; you can almost always omit it
As a note, WordPress also carries a similar function called add_post_meta()
, but update_post_meta()
is better in most situations, since it will either add the custom field if it’s new or update it if it isn’t.
delete_post_meta()
delete_post_meta()
removes a custom field entirely for a post. It looks as follows:
delete_post_meta( $post_id, $meta_key, $meta_value );
Its arguments are:
$post_id
: The ID of the post to be affected$meta_key
: The name of the custom field to be deleted from the post’s metadata$meta_value
: This optional parameter handles duplicate meta keys; you can almost always omit it
Updating and Deleting a Custom Field: An Example
The following plugin is quirky behavior-wise, but is good for demonstrating update_post_meta()
and delete_post_meta()
. Its functionality is to:
- Count every time a post’s content is loaded, and display the count before the post content.
- Any time the homepage is visited, reset the count to 0 for each post that’s loaded on the homepage.
The result looks as follows:
And here’s the code:
<?php
/*
Plugin Name: WPShout Count Times Content Loaded
*/
function wpshout_count_times_content_loaded( $content ) {
// Reset the count if on the site's homepage
if ( is_front_page() ) {
delete_post_meta( get_the_ID(), 'wpshout_times_content_loaded' );
return $content;
}
// Get the count; count is 0 if custom field not found
$post_loads_count = get_post_meta( get_the_ID(), 'wpshout_times_content_loaded', true );
if( empty( $post_loads_count ) ) {
$post_loads_count = 0;
}
// Add 1 to the count and save
$post_loads_count++;
update_post_meta( get_the_ID(), 'wpshout_times_content_loaded', $post_loads_count );
// Return the updated count and the main post content
return '<p><em>Content loaded ' . $post_loads_count . ' times</em></p>' . $content;
}
add_filter( 'the_content', 'wpshout_count_times_content_loaded' );
As odd as this plugin is, there shouldn’t be anything in it that surprises you if you’ve followed the rest of this chapter.
Creating Attractive Custom Fields User Interfaces
WordPress’s default custom fields user interface is unattractive and difficult to use. Unfortunately, WordPress’s core software does not expose an API for creating an attractive interface, so doing it by hand is a fair amount of work.
We recommend you examine several options for creating custom field interfaces:
Third-Party Plugins
Several plugins exist for creating attractive custom field interfaces. Two we recommend are Pods (https://wordpress.org/plugins/pods/) and Advanced Custom Fields (https://wordpress.org/plugins/advanced-custom-fields/). These can be a good choice for many needs.
The Custom Metaboxes and Fields for WordPress Project
For more control than a custom fields plugin, we recommend CMB2, at https://wordpress.org/plugins/cmb2/. Once you’ve loaded the project’s files, you pass a single large configuration array into a custom event it registers. This greatly simplifies creating attractive custom field interfaces.
By Hand
If, for some reason, you need to create a from-scratch user interface for one or more custom fields, our favorite tutorial on the subject is by Justin Tadlock, at: http://wp.smashingmagazine.com/2011/10/04/create-custom-post-meta-boxes-wordpress/.
Understanding the Power of WordPress Custom Fields
Custom fields are a crucial way to extend WordPress past its default role as an article-publishing engine. You should now understand custom fields’ nature as a key/value store for post-level data, and how to store, modify, and access custom field data.
Summary Limerick
To use custom fields can be sweet,
If you know get_()
, update_()
, and delete_()
.
Now, to build a UI?
That’s a job you can try,
Or use third-party code to complete.
Quiz Time!
- In most situations, the best function to add custom field data to a post is:
update_post_meta()
add_post_meta()
get_post_meta()
get_post_meta()
always requires:- A post ID to target
- A key to target
- A value to search for and retrieve
- Omitting
get_post_meta()
‘s third argument, or setting it tofalse
, results in:- The custom field data not being sanitized for output
- An error if the targeted custom field does not exist for the targeted post
- The custom field data being passed in as an array rather than a string
Answers and Explanations
A.
add_post_meta()
behaves strangely by default if the custom field already exists for the post.update_post_meta()
behaves sensibly, adding the custom field if it doesn’t exist and updating it if it does.A.
This ID is the function’s first argument. IfB
(the second argument) is omitted, the function will return an associative array of all custom fields associated with the post.C
is unrelated to howget_post_meta()
works.C.
Setting this argument totrue
makes working with single custom field values slightly more convenient.
[…] flexible. As the name suggests, it does that by making it easy for you to add a variety of custom fields to your WordPress […]
E,g Suppose I add custom field from front end from to submit keyword and i want to go that keyword to yoast’s keyword field ?
how to link custom field from some other plugin’s field backend (DB)?
Is there any way to hide : Custom fields can be used to add extra metadata to a post that you can use in your theme. for a custom post type?
[…] Everything you need to know about Custom Fields […]
Thanks David, this is very helpful article for getting started people like me
[…] color they want their theme’s background — you need the WordPress Options API. Just as with WordPress custom fields we addressed recently you can store discrete bits of data about a post in WordPress, the options API lets you store […]
[…] The easiest actual example of “custom fields” is an SEO plugin. There the data — your custom meta description, your customized page title, etc — is really stored in a custom field, and for reasons very similar to the title of a post. That data is unique to each post, not likely to be reused, unlikely to be desirable to change in bulk (in the way I was elaborating with the “wapo” tag). These are the key qualities or custom fields — they’re data that’s unique to the post, not likely to be identical in another context, and stored in a way that doesn’t facilate (but doesn’t prohibit) cross-referencing. For more about actually using custom fields in WordPress, check out my recent post. […]
A potentially interesting subject, but I don’t feel much more enlightened about the custom fields box than I was before. Unless this article was written with plugin authors in mind, it would perhaps be more useful to a broader range of readers if some more useful examples of the value and use of custom fields were included. “cool to be able to link to things elsewhere on the internet […] we’re doing that by storing the link to each post in a custom field” – how does this differ from a slug, and what, practically, might I do with it?
Thanks,
E.
That’s a very fair point, Edward. I assumed a bit more familiarity with the topic than was probably wise. I find it really hard to know where all readers and and adjust accordingly, but I think you’re spot on that a more thorough introduction may have been helpful.
The short summary of what custom fields are why you would use them is that sometimes you want to attach data to a post, or something else in WordPress, and that data doesn’t match very well to the default properties of post. Maybe I have posts that all refer to historical events, and I want to record the date of those events in a field other than the body of the post. I might try to change the “published” time of the post, but that would quickly cause massive confusion. That’s where you’d want to create a custom field for that “date_of_event” and be able to get it using the functions of custom fields. Does that shed any light?
I am just coming from Google blogger platform to WordPress. I never seen in my server inside. I just installed WordPress and just going keep updating my blog. But today I realize that I want to see inside the hosting.
My question is How can I take a full of my site backup.?
Hi Anna, thanks for writing! If you’d like help backing up your site, please feel free to write us directly at contact@pressupinc.com.
[…] Everything You Should Know about WordPress Custom Fields – Hopefully at the end you have a sense of what WordPress custom fields are — a basic key-value store for post-entities in WordPress — store your data simply that doesn’t lend itself to a five word summary. […]
[…] Everything You Should Know about WordPress Custom Fields […]