The question:
I have a baseball related website with multiple authors. I use the “Stick this post to the front page” to denote an “Editor’s Pick” on an article. I would like to add a link/button to allow editor to do this from the front end. The method can either be in the article itself or in the Admin Bar. I do not really have a preference.
I have looked through many, many different “Admin Bar” plugins, but haven’t been to find anything relating to “Stick this post to the front page”.
Thanks
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 1
I think this small source code is your solution. It currently doesn’t have frontend feedback for the Sticky Post change, but you can enhance this string, class or whatever you want in the function fb_stick_post
.
The first function adds the item in the Admin Bar and creates a new Url with a param value. Also, on click
calls a function to read the Url param and, if it’s true, then do the change to the sticky status of this post id.
add_action( 'admin_bar_menu', 'fb_add_admin_bar_sticky', 35 );
function fb_add_admin_bar_sticky() {
global $wp_admin_bar;
if ( ! is_super_admin() || ! is_admin_bar_showing() )
return;
$current_object = get_queried_object();
if ( empty($current_object) )
return;
if ( ! empty( $current_object->post_type ) &&
( $post_type_object = get_post_type_object( $current_object->post_type ) ) &&
current_user_can( $post_type_object->cap->edit_post, $current_object->ID )
) {
$wp_admin_bar->add_menu(
array(
'id' => 'sticky_post',
'title' => __('Sticky'),
'href' => get_permalink() . '?stick_post=true',
'meta' => array(
'title' => __( 'Click me' ),
'onclick' => fb_stick_post( get_the_ID() )
)
)
);
}
}
function fb_stick_post( $post_id ) {
if ( isset($_GET['stick_post']) && 'true' == htmlspecialchars( $_GET['stick_post'] ) )
stick_post( $post_id );
}
Update 07/30/2012
Now an small plugin with easy solution. The plugin adds an item inside the Admin Bar. The string of the button check for is sticky and give the possibility to stick or unstick the current post.
I change the hook for add the admin bar item to ´template_redirect` for use an redirect after update the stick flag on post.
<?php
/**
* Plugin Name: Stick/Unstick post via Admin bar
*
*/
if ( ! function_exists( 'fb_add_admin_bar_sticky' ) ) {
add_action( 'template_redirect', 'fb_add_admin_bar_sticky' );
function fb_add_admin_bar_sticky() {
global $wp_admin_bar;
if ( ! is_super_admin() || ! is_admin_bar_showing() )
return;
$current_object = get_queried_object();
if ( empty($current_object) )
return;
if ( ! empty( $current_object->post_type ) &&
( $post_type_object = get_post_type_object( $current_object->post_type ) ) &&
current_user_can( $post_type_object->cap->edit_post, $current_object->ID )
) {
// check, if an sticky post
if ( is_sticky( get_the_ID() ) ) {
$title = __('Unsticky');
$link = '?unstick_post=true';
$attr_title = __( 'Make this post unsticky' );
} else {
$title = __('Sticky');
$link = '?stick_post=true';
$attr_title = __( 'Make this post sticky' );
}
$wp_admin_bar->add_menu(
array(
'id' => 'sticky_post',
'title' => $title,
'href' => get_permalink() . $link,
'meta' => array(
'title' => $attr_title,
'onclick' => fb_stick_post( get_the_ID() )
)
)
);
}
}
function fb_stick_post( $post_id ) {
if ( isset($_GET['stick_post']) && 'true' == htmlspecialchars( $_GET['stick_post'] ) ) {
stick_post( $post_id );
wp_redirect( get_permalink( $post_id ) );
exit();
}
if ( isset($_GET['unstick_post']) && 'true' == htmlspecialchars( $_GET['unstick_post'] ) ) {
unstick_post( $post_id );
wp_redirect( get_permalink( $post_id ) );
exit();
}
}
}
or download this plugin Gist 3214922
Method 2
There are a few functions that come in handy here:
unstick_post
– Unstick a poststick_post
– Stick a postis_sticky
– Figure out if a post is sticky
With those three in mind, all we need to do is stick them together with some admin menu bar glue.
First off, let’s wrap everything in a class for fun and profit. This class will have some constants that we’ll use later: a nonce, an action for unsticking the post and an action for sticking the post.
class WPSE_58818_Stick_Post
{
/**
* Ajax nonce.
*
* @since 1.0
*/
const NONCE = 'wpse58818_nonce_';
/**
* Unstick ajax action
*
* @since 1.0
*/
const UNSTICK = 'wpse58818_unstick';
/**
* Stick Ajax action
*
* @since 1.0
*/
const STICK = 'wpse58818_stick';
} // end class
Then let’s add an init function to add our actions. The first action being that we hook into template_redirect.
<?php
class WPSE_58818_Stick_Post
{
// snip snip
/**
* Adds actions and such.
*
* @since 1.0
* @access public
* @uses add_action
*/
public static function init()
{
add_action(
'template_redirect',
array(__CLASS__, 'template_r')
);
}
}
NOTE: from here on out I’ll be omitting the class
bit. You can view the entire thing here.
In the function hooked into template_redirect
, we’ll check to see if we’re on a single post page and whether or not the user can edit it. If they can, we’ll hook into admin_bar_menu
and wp_footer
.
/**
* Hooked into `template_redirect`. Adds the admin bar stick/unstick
* button if we're on a single post page and the current user can edit
* the post
*
* @since 1.0
* @access public
* @uses add_action
*/
public static function template_r()
{
if(
!is_single() ||
!current_user_can('edit_post', get_queried_object_id())
) return; // not a single post or the user can't edit it
// Hook into admin_bar_menu to add stuff
add_action(
'admin_bar_menu',
array(__CLASS__, 'menu'),
100
);
// Hook into the footer and spit out some JavaScript
add_action(
'wp_footer',
array(__CLASS__, 'footer')
);
}
In the menu
function, hooked into admin_bar_menu
, we can add our new item:
/**
* Hooked into `admin_bar_menu`. Adds our stick/unstick node.
*
* @since 1.0
* @access public
*/
public static function menu($mb)
{
// get the current post ID
$post_id = get_queried_object_id();
$mb->add_node(array(
'id' => 'wpse58818-sticker',
'meta' => array(
'class' => 'wpse58818-sticker',
'title' => is_sticky($post_id) ? 'unstick' : 'stick'
),
'title' => is_sticky($post_id) ? __('Unstick') : __('Stick'),
'href' => self::get_url($post_id)
));
}
Here we get our first “utility function” that builds a URL for the admin menu bar node. It’s just a wrapper around add_query_arg
to nonce, and build a url that we’ll use with AJAX later on:
/**
* Get an Ajax URL to use for a given post
*
* @since 1.0
* @access protected
*/
protected static function get_url($post_id)
{
return add_query_arg(array(
'post_id' => absint($post_id),
'action' => is_sticky($post_id) ? self::UNSTICK : self::STICK,
'nonce' => wp_create_nonce(self::NONCE . $post_id)
), admin_url('admin-ajax.php'));
}
The footer
function just spits out some JavaScript to make the AJAX calls. Basic overview: when someone clicks on our new link, make a GET request to the given URL. If it’s successful, change the (un)stick link’s href, text, and title.
/**
* Hooked into `wp_footer`. Spits out a bit of JS to stick/unstick a post
*
* @since 1.0
* @access public
*/
public static function footer()
{
?>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('.wpse58818-sticker a').on('click', function(e) {
e.preventDefault();
var action = $(this).attr('title');
var that = this;
$.get(
$(this).attr('href'),
{},
function(data) {
if('0' == data)
{
console.log(data);
alert('<?php echo esc_js(__('An error occurred')); ?>');
return;
}
$(that).attr('href', data);
if('stick' == action) {
$(that).html('<?php echo esc_js(__('Unstick')); ?>');
$(that).attr('title', 'unstick');
} else {
$(that).html('<?php echo esc_js(__('Stick')); ?>');
$(that).attr('title', 'stick');
}
}
);
});
});
</script>
<?php
}
And now we come to the AJAX callbacks. Ajax in plugins/themes is worth reading up on.
We’ll modify our init
function a bit to add two more actions:
/**
* Adds actions and such.
*
* @since 1.0
* @access public
* @uses add_action
*/
public static function init()
{
add_action(
'template_redirect',
array(__CLASS__, 'template_r')
);
// Ajax actions
add_action(
'wp_ajax_' . self::STICK,
array(__CLASS__, 'stick')
);
add_action(
'wp_ajax_' . self::UNSTICK,
array(__CLASS__, 'unstick')
);
}
And our AJAX callbacks. These could very easily be the same function. I split them up here because it seemed easier to extend/change in the future. Both of these check to see if the AJAX request is valid, (un)stick the post accordingly, and echo out the new URL for future (un)sticking.
/**
* Ajax callback for the stick function
*
* @since 1.0
* @access public
*/
public static function stick()
{
$post_id = self::can_ajax();
stick_post($post_id);
echo self::get_url($post_id);
die();
}
/**
* Ajax callback for the unstick function
*
* @since 1.0
* @access public
* @uses unstick_post
*/
public static function unstick()
{
$post_id = self::can_ajax();
// nonces checked, everything is good to go. Unstick!
unstick_post($post_id);
echo self::get_url($post_id);
die();
}
Our second “utility function” makes an appearance here. can_ajax
verifies our nonces and user permissions and returns post ID to (un)stick. If any checks fail, it exits (via die('1')
).
/**
* Check to see if the current user can ajax. Returns the post ID to
* stick/unstick if successful. Kills the program otherwise
*
* @since 1.0
* @access protected
*/
protected static function can_ajax()
{
$post_id = isset($_REQUEST['post_id']) ? $_REQUEST['post_id'] : '';
if(
!$post_id ||
!check_ajax_referer(self::NONCE . $post_id, 'nonce', false)
) die('0');
if(!current_user_can('edit_post', $post_id))
die('0');
return $post_id;
}
Here is that whole mess as a plugin.
Method 3
Here is a much simpler solution that will get the job done using the_content
filter hook
add_filter('the_content','simplest_sticky_solution');
function simplest_sticky_solution($content){
global $post;
//early exit if not needed
if (!is_single() || !current_user_can('edit_post',$post->ID))
return $content;
//check if form is submitted and act as needed
if (isset($_POST['sticky_action']) && isset($_POST['sticky_id']) && isset($_POST['sticky_nonce']) && wp_verify_nonce($_POST['sticky_nonce'], 'StickIt')){
if (is_sticky($post->ID)){
stick_post($post->ID);
}else{
unstick_post($post->ID);
}
}
//create the form
$label = (is_sticky())? "Unstick": "Stick";
$form = '
<form action="" method="POST">
<input type="hidden" name="sticky_id" value="'.$post->id.'">
<input type="hidden" name="sticky_action" value="stickit">
<input type="hidden" name="sticky_nonce" value="'.wp_create_nonce('StickIt').'">
<input type="button" name="submit" value="'.$label.'">
</form>';
return $form.'<br/>'.$content;
}
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0