Hopefully I’ve understood your question correctly, and I hope the code below helps.
First you must add a metabox to hold the option that you wish to add to each Post, and the my_add_sticky_metabox()
function will do this, in conjunction with the add_meta_boxes
action hook.
At this stage you are not actually printing anything, but rather telling WordPress to print using your declared callback (my_output_sticky_metabox()
) whenever the Post edit screen is displayed.
Using the my_output_sticky_metabox()
function the metabox content is printed, including a check as to whether or not the box should be checked and/or disabled.
Finally the correct value is saved using the my_save_sticky_metabox()
function in conjunction with the save_post
action hook.
add_action('add_meta_boxes', 'my_add_sticky_metabox');
function my_add_sticky_metabox(){
add_meta_box(
'my_sticky_post_metabox',
__('Sticky Post', 'my_text_domain'),
'my_output_sticky_metabox',
'post'
);
}
function my_output_sticky_metabox($post){
/** Grab the current 'my_sticky_post' option value */
$sp = intval(get_option('my_sticky_post'));
/** Check to see if the 'my_sticky_post' option should be disabled or checked for the current Post */
$checked = checked($sp, $post->ID, false);
if($sp > 0) :
$disabled = (!disabled($sp, $post->ID, false)) ? 'disabled="true"' : '';
else :
$disabled = '';
endif;
/** Add a nonce field */
wp_nonce_field('my_sticky_post_metabox', 'my_sticky_post_metabox_nonce');
/** Add a hidden field to check against in case it is unchecked before save */
$value = ($checked) ? '1' : '0';
echo '<input type="hidden" name="was_checked" value="' . $value . '" />';
/** Output the checkbox and label */
echo '<label for="my_sticky_post">';
echo '<input type="checkbox" id="my_sticky_post" name="my_sticky_post" value="' . $post->ID . '" ' . $checked . $disabled . ' />';
echo 'Make this the sticky post?</label>';
/** Let the user know which Post is currently sticky */
switch($sp) :
case 0:
$message="There is currently no Sticky Post.";
break;
case $post->ID:
$message="This Post is the Sticky Post.";
break;
default:
$message="<a href="" . get_edit_post_link($sp) . '" title="' . the_title_attribute('before=Edit post \'&after=\'&echo=0') . '">' . get_the_title($sp) . '</a> is the current Sticky Post';
$message.= '<br />You must remove the sticky status from that post before you can make this one sticky.';
endswitch;
echo '<p><em>' . $message .'</em></p>';
}
add_action('save_post', 'my_save_sticky_metabox');
function my_save_sticky_metabox($post_id){
/*
* We need to verify this came from our screen and with proper authorization,
* because the save_post action can be triggered at other times.
*/
/** Ensure that a nonce is set */
if(!isset($_POST['my_sticky_post_metabox_nonce'])) :
return;
endif;
/** Ensure that the nonce is valid */
if(!wp_verify_nonce( $_POST['my_sticky_post_metabox_nonce'], 'my_sticky_post_metabox')) :
return;
endif;
/** Ensure that an AUTOSAVE is not taking place */
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) :
return;
endif;
/** Ensure that the user has permission to update this option */
if(!current_user_can('edit_post', $post_id)) :
return;
endif;
/**
* Everything is valid, now the option can be updated
*/
/** Check to see if the 'my_sticky_post' option was checked */
if(isset($_POST['my_sticky_post'])) : // It was...
update_option('my_sticky_post', $_POST['my_sticky_post']); // Update the option
else : // It was not...
/** Check to see if the option was checked prior to the options being updated */
if($_POST['was_checked'] != 0) : // It was...
update_option('my_sticky_post', -1); // Set the option to '-1'
endif;
endif;
}
Now when you want to grab your custom sticky post you use this query –
$args = array(
'p' => get_option('my_sticky_post')
);
$stickyPost = new WP_Query($args);
if($stickyPost->have_posts()) : while($stickyPost->have_posts()) : $stickyPost->the_post();
{ Your code goes here }
endwhile;
endif;
wp_reset_postdata();
There is plenty of reading material I’d encourage you to take a look at here, hopefully it’ll answer any questions you may have about the code above –
- The
add_meta_boxes
action - The
save_post
action - The
add_meta_box()
function - The
checked()
function - The
disabled()
function
Edit
You mention that if no sticky post is set, you have 4 posts output on index.php (which is your standard number).
I believe that is because if the p
parameter is empty it is ignored, thus you need to check the value of the my_sticky_post
option.
Make this change to the $args
array (and note the additional line above) –
$sticky_id = get_option('my_sticky_post');
$args = array(
'p' => ($sticky_id) ? $sticky_id : '-1'
);