Skip to content

Instantly share code, notes, and snippets.

@19h47
Last active December 6, 2022 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 19h47/c54fd0e7a5c6fbc99a6087e7606054c0 to your computer and use it in GitHub Desktop.
Save 19h47/c54fd0e7a5c6fbc99a6087e7606054c0 to your computer and use it in GitHub Desktop.
WP Sticky Custom Post Types
<?php
/**
* Plugin Name: WP Sticky Custom Post Types
* Plugin URI: https://gist.github.com/19h47/c54fd0e7a5c6fbc99a6087e7606054c0
* Description: WP Sticky Custom Post Types is a plugin that enables support for sticky custom post types.
* Version: 0.0.1
* Author: Jérémy Levron
* Author URI: https://19h47.fr
*
* @package WordPress
* @subpackage WP_Sticky_Custom_Post_Types
*/
if ( ! function_exists( 'wp_sticky_custom_post_types' ) ) {
add_action( 'init', 'wp_sticky_custom_post_types', 20 );
/**
* WP Sticky Custom Post Types
*
* @return void
*/
function wp_sticky_custom_post_types() : void {
$post_types = get_custom_post_types();
foreach ( $post_types as $post_type ) {
add_action( 'save_post_' . $post_type->name, 'stick_custom_post', 10, 2 );
}
/**
* Post states
*
* @param string[] $post_states An array of post display states.
* @param WP_Post $post The current post object.
*
* @return array $states
*/
add_filter(
'display_post_states',
function( array $post_states, WP_Post $post ) use ( $post_types ) {
foreach ( $post_types as $post_type ) {
if ( is_sticky_post_type( $post->ID, $post_type->name ) ) {
$post_states[] = __( 'Sticky', 'wpstickycustomposttype' );
}
}
return $post_states;
},
10,
2
);
}
/**
* Get custom post types
*
* @see https://developer.wordpress.org/reference/functions/get_post_types/
*
* @return string[]|WP_Post_Type[] An array of post type names or objects.
*/
function get_custom_post_types() {
$args = array(
'public' => true,
'_builtin' => false,
);
return get_post_types( $args, 'objects' );
}
/**
* Make a custom post sticky.
*
* @param int $post_ID Post ID.
* @param WP_Post $post Post object.
*
* @return bool True if the post was stick, false otherwise.
*/
function stick_custom_post( int $post_ID, WP_Post $post ) : bool {
$post_type = get_post_type_object( $post->post_type );
$name = to_snake_case( $post_type->label );
$stickies = get_option( 'sticky_' . $name ) ? get_option( 'sticky_' . $name ) : array();
if ( ! in_array( $post_ID, $stickies, true ) && ( isset( $_POST[ "sticky_$post->post_type" ] ) && ! empty( $_POST[ "sticky_$post->post_type" ] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
array_unshift( $stickies, $post_ID );
return update_option( "sticky_$name", array_values( $stickies ) );
}
if ( in_array( $post_ID, $stickies, true ) && ! isset( $_POST[ "sticky_$post->post_type" ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
$key = array_search( $post_ID, $stickies, true );
unset( $stickies[ $key ] );
return update_option( "sticky_$name", array_values( $stickies ) );
}
return false;
}
add_action( 'post_submitbox_minor_actions', 'post_submitbox_minor_actions', 10, 1 );
/**
* Post submitbox minor actions
*
* @param WP_Post $post WP_Post object for the current post.
*
* @see https://developer.wordpress.org/reference/hooks/post_submitbox_minor_actions/
*/
function post_submitbox_minor_actions( WP_Post $post ) : void {
$post_type = get_post_type_object( $post->post_type );
if ( false === $post_type->_builtin ) {
ob_start();
}
}
add_action( 'post_submitbox_misc_actions', 'post_submitbox_misc_actions', 10, 1 );
/**
* Post submitbox misc actions
*
* @param WP_Post $post WP_Post object for the current post.
*
* @see https://developer.wordpress.org/reference/hooks/post_submitbox_misc_actions/
*
* @return void
*/
function post_submitbox_misc_actions( WP_Post $post ) : void {
$post_type = get_post_type_object( $post->post_type );
if ( false === $post_type->_builtin ) {
$temp = ob_get_clean();
// WP core need two different checkbox: on for authors, and another one for editors.
$sticky_box = '<input type="checkbox" style="display:none" name="hidden_post_sticky" id="hidden-post-sticky" value="sticky" ' . checked( is_sticky_post_type( $post->ID, $post->post_type ), true, false ) . ' />';
if ( current_user_can( 'edit_others_posts' ) ) {
$sticky_box .= sprintf(
'<span id="sticky-span"><input id="super-sticky" name="sticky_' . $post->post_type . '" type="checkbox" value="sticky" %1$s /><label for="super-sticky" class="selectit">%2$s</label><br/></span>',
checked( is_sticky_post_type( $post->ID, $post->post_type ), true, false ),
__( 'Stick this post to the front page' )
);
}
$pattern = '/(<input.*id="visibility-radio-password")/U';
$output = preg_replace( $pattern, "{$sticky_box}$1", $temp );
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
/**
* To snake case
*
* @param string $input Input string.
*/
function to_snake_case( $input ) {
$pattern = '!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!';
preg_match_all( $pattern, $input, $matches );
$ret = $matches[0];
foreach ( $ret as &$match ) {
$match = strtoupper( $match ) === $match ? strtolower( $match ) : lcfirst( $match );
}
return implode( '_', $ret );
}
/**
* Is sticky post type
*
* Check if a post type is sticky
*
* @param int $post_id Post ID.
* @param string $post_type Post type.
*/
function is_sticky_post_type( int $post_id, string $post_type ) {
$name = to_snake_case( ( get_post_type_object( $post_type ) )->label );
$stickies = get_option( "sticky_$name" );
$is_sticky = false;
if ( is_array( $stickies ) ) {
$stickies = array_map( 'intval', $stickies );
$is_sticky = in_array( $post_id, $stickies, true );
}
/**
* Filter wheter a custom post is sticky
*
* @param bool $is_sticky Whether a post is sticky.
* @param int $post_id Post ID.
*/
return apply_filters( "is_sticky_$name", $is_sticky, $post_id );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment