|
<?php |
|
|
|
/** |
|
* Plugin Name: Movies |
|
* Description: Add movies to WordPress and feature them at the end a post. |
|
* Version: 1.0 |
|
* Author: Ryan Sechrest |
|
* Author URI: https://ryansechrest.com/ |
|
*/ |
|
|
|
namespace RyanSechrest\Plugin\Movies; |
|
|
|
use WP_Post; |
|
|
|
class Main |
|
{ |
|
/** |
|
* Prefix |
|
* |
|
* Use prefix with IDs and database keys to prevent collisions. |
|
*/ |
|
const PREFIX = 'rsm'; |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register plugin components |
|
*/ |
|
public function __construct() |
|
{ |
|
$this->register_main_plugin_hooks(); |
|
$this->register_movie_post_type(); |
|
$this->register_movie_admin_columns(); |
|
$this->register_movie_details_meta_box(); |
|
$this->register_movie_admin_settings(); |
|
$this->register_movie_display(); |
|
} |
|
|
|
/** |
|
* Initialize plugin |
|
* |
|
* @return Main |
|
*/ |
|
public static function init(): Main |
|
{ |
|
return new Main(); |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Get option name with plugin prefix |
|
* |
|
* @param string $name |
|
* @return string |
|
*/ |
|
private function db_prefix(string $name): string |
|
{ |
|
return $this->prefix($name, '_'); |
|
} |
|
|
|
/** |
|
* Get HTML ID with plugin prefix |
|
* |
|
* @param string $id |
|
* @return string |
|
*/ |
|
private function id_prefix(string $id): string |
|
{ |
|
return $this->prefix($id, '-'); |
|
} |
|
|
|
/** |
|
* Get key with plugin prefix |
|
* |
|
* @param string $key |
|
* @param string $separator |
|
* @return string |
|
*/ |
|
private function prefix(string $key, string $separator): string |
|
{ |
|
return $this::PREFIX . $separator . $key; |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register main plugin hooks |
|
* |
|
* @uses register_activation_hook() |
|
* @uses register_deactivation_hook() |
|
* @uses register_uninstall_hook() |
|
* @return void |
|
*/ |
|
private function register_main_plugin_hooks(): void |
|
{ |
|
register_activation_hook(__FILE__, [$this, 'run_when_activated']); |
|
register_deactivation_hook(__FILE__, [$this, 'run_when_deactivated']); |
|
register_uninstall_hook(__FILE__, ['RyanSechrest\Plugin\Movies\Main', 'run_when_uninstalled']); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Run when plugin is activated |
|
* |
|
* @return void |
|
*/ |
|
public function run_when_activated(): void |
|
{ |
|
// ... |
|
} |
|
|
|
/** |
|
* Run when plugin is deactivated |
|
* |
|
* @return void |
|
*/ |
|
public function run_when_deactivated(): void |
|
{ |
|
// ... |
|
} |
|
|
|
/** |
|
* Run when plugin is uninstalled |
|
* |
|
* @return void |
|
*/ |
|
public static function run_when_uninstalled(): void |
|
{ |
|
delete_option(self::PREFIX . '_movie_display_total'); |
|
delete_option(self::PREFIX . '_movie_display_enabled'); |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register movie post type |
|
* |
|
* @uses add_action() |
|
* @return void |
|
*/ |
|
private function register_movie_post_type(): void |
|
{ |
|
add_action( |
|
'init', |
|
[$this, 'hook__register_movie_post_type'] |
|
); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Hook: Register movie post type |
|
* |
|
* @uses register_post_type() |
|
* @return void |
|
*/ |
|
public function hook__register_movie_post_type(): void |
|
{ |
|
register_post_type('movie', |
|
[ |
|
'labels' => [ |
|
'name' => __('Movies', 'movies'), |
|
'singular_name' => __('Movie', 'movies'), |
|
'add_new' => __('Add Movie', 'movies'), |
|
'add_new_item' => __('Add New Movie', 'movies'), |
|
'edit_item' => __('Edit Movie', 'movies'), |
|
'new_item' => __('New Movie', 'movies'), |
|
'view_item' => __('View Movie', 'movies'), |
|
'search_items' => __('Search Movies', 'movies'), |
|
'not_found' => __('No movies found', 'movies'), |
|
'not_found_in_trash' => __('No movies found in trash', 'movies'), |
|
|
|
], |
|
'menu_icon' => 'dashicons-editor-video', |
|
'public' => true, |
|
'show_in_rest' => true, |
|
'supports' => ['title', 'editor', 'thumbnail'], |
|
] |
|
); |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register movie admin columns |
|
* |
|
* @uses add_filter() |
|
* @uses add_action() |
|
* @return void |
|
*/ |
|
private function register_movie_admin_columns(): void |
|
{ |
|
add_filter( |
|
'manage_edit-movie_columns', |
|
[$this, 'hook__add_movie_admin_columns'] |
|
); |
|
add_action( |
|
'manage_movie_posts_custom_column', |
|
[$this, 'hook__render_movie_admin_column'], |
|
10, |
|
2 |
|
); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Hook: Add movie admin columns |
|
* |
|
* @param array $columns |
|
* @return array |
|
*/ |
|
public function hook__add_movie_admin_columns(array $columns): array |
|
{ |
|
$new_columns = []; |
|
foreach ($columns as $index => $column) { |
|
$new_columns[$index] = $column; |
|
if ($column === 'Title') { |
|
$new_columns['director'] = __('Director', 'movies'); |
|
$new_columns['producer'] = __('Producer', 'movies'); |
|
} |
|
} |
|
|
|
return $new_columns; |
|
} |
|
|
|
/** |
|
* Hook: Render movie admin column |
|
* |
|
* @param string $column |
|
* @param int $id |
|
* @return void |
|
*/ |
|
public function hook__render_movie_admin_column(string $column, int $id): void |
|
{ |
|
if (!$value = get_post_meta($id, $column, true)) { |
|
return; |
|
} |
|
|
|
echo $value; |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register movie details meta box |
|
* |
|
* @uses add_action() |
|
* @return void |
|
*/ |
|
private function register_movie_details_meta_box(): void |
|
{ |
|
add_action( |
|
'add_meta_boxes', |
|
[$this, 'hook__add_movie_details_meta_box'] |
|
); |
|
add_action( |
|
'save_post', |
|
[$this, 'hook__save_movie_details_fields'] |
|
); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Hook: Add movie details meta box |
|
* |
|
* @uses add_meta_box() |
|
* @return void |
|
*/ |
|
public function hook__add_movie_details_meta_box(): void |
|
{ |
|
add_meta_box( |
|
$this->id_prefix('movie-details'), |
|
__('Details', 'movies'), |
|
[$this, 'hook__render_movie_details_fields'], |
|
'movie', |
|
'side' |
|
); |
|
} |
|
|
|
/** |
|
* Hook: Render movie details fields |
|
* |
|
* @uses get_post_meta() |
|
* @param WP_Post $post |
|
* @return void |
|
*/ |
|
public function hook__render_movie_details_fields(WP_Post $post): void |
|
{ |
|
$director = get_post_meta($post->ID, 'director', true) ?: ''; |
|
$producer = get_post_meta($post->ID, 'producer', true) ?: ''; |
|
|
|
$output = '<div class="components-base-control__field" style="margin-bottom:15px;">'; |
|
$output .= '<label for="director" class="components-base-control__label css-uc0dzf">Director</label>'; |
|
$output .= '<input type="text" name="director" value="' . $director . '" id="director" class="components-text-control__input">'; |
|
$output .= '</div>'; |
|
|
|
$output .= '<div class="components-base-control__field">'; |
|
$output .= '<label for="producer" class="components-base-control__label css-uc0dzf">Producer</label>'; |
|
$output .= '<input type="text" name="producer" value="' . $producer . '" id="producer" class="components-text-control__input">'; |
|
$output .= '</div>'; |
|
|
|
echo $output; |
|
} |
|
|
|
/** |
|
* Hook: Save movie details fields |
|
* |
|
* @uses sanitize_text_field() |
|
* @uses update_post_meta() |
|
* @param int $post_id |
|
* @return void |
|
*/ |
|
public function hook__save_movie_details_fields(int $post_id): void |
|
{ |
|
if (isset($_POST['director'])) { |
|
update_post_meta( |
|
$post_id, |
|
'director', |
|
sanitize_text_field($_POST['director']) |
|
); |
|
} |
|
if (isset($_POST['producer'])) { |
|
update_post_meta( |
|
$post_id, |
|
'producer', |
|
sanitize_text_field($_POST['producer']) |
|
); |
|
} |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register movie admin settings |
|
* |
|
* @uses add_action() |
|
* @return void |
|
*/ |
|
private function register_movie_admin_settings(): void |
|
{ |
|
add_action('admin_init', [$this, 'hook__register_movie_admin_section']); |
|
add_action('admin_init', [$this, 'hook__register_movie_admin_settings']); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Hook: Register movie admin section |
|
* |
|
* @uses add_settings_section() |
|
* @return void |
|
*/ |
|
public function hook__register_movie_admin_section(): void |
|
{ |
|
add_settings_section( |
|
$this->id_prefix('movies-section'), |
|
'Movies', |
|
function() { |
|
echo '<p>Preferences to enable and customize the Movies plugin.</p>'; |
|
}, |
|
'reading' |
|
); |
|
} |
|
|
|
/** |
|
* Hook: Register movie admin settings |
|
* |
|
* @return void |
|
*/ |
|
public function hook__register_movie_admin_settings(): void |
|
{ |
|
$this->register_movie_display_enabled_field(); |
|
$this->register_movie_display_total_field(); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Register movie display enabled field |
|
* |
|
* @uses register_setting() |
|
* @uses add_settings_field() |
|
* @return void |
|
*/ |
|
private function register_movie_display_enabled_field(): void |
|
{ |
|
register_setting( |
|
'reading', |
|
$this->db_prefix('movie_display_enabled'), |
|
[ |
|
'type' => 'string', |
|
'sanitize_callback' => [$this, 'hook__sanitize_movie_display_enabled_field'], |
|
'default' => 'no', |
|
] |
|
); |
|
add_settings_field( |
|
$this->id_prefix('movie-display-enabled-field'), |
|
'Display movies', |
|
[$this, 'hook__render_movie_display_enabled_field'], |
|
'reading', |
|
$this->id_prefix('movies-section') |
|
); |
|
} |
|
|
|
/** |
|
* Hook: Sanitize movie display enabled field |
|
* |
|
* @uses add_settings_error() |
|
* @param string $value |
|
* @return string |
|
*/ |
|
public function hook__sanitize_movie_display_enabled_field(string $value): string |
|
{ |
|
$valid_values = ['yes', 'no']; |
|
if (!in_array($value, $valid_values)) { |
|
add_settings_error( |
|
'reading', |
|
'movie', |
|
__('Movies: Display movies was set to an invalid value. Using default: Nowhere', 'movies') |
|
); |
|
return 'no'; |
|
} |
|
|
|
return $value; |
|
} |
|
|
|
/** |
|
* Hook: Render movie display enabled field |
|
* |
|
* @uses esc_html() |
|
* @uses get_option() |
|
* @return void |
|
*/ |
|
public function hook__render_movie_display_enabled_field(): void |
|
{ |
|
$option_name = esc_html($this->db_prefix('movie_display_enabled')); |
|
$value = esc_html(get_option($option_name)); |
|
|
|
// Start Wrapper |
|
$output = '<fieldset>'; |
|
$output .= '<p>'; |
|
|
|
// Option 1 |
|
$output .= '<label>'; |
|
$output .= '<input name="' . $option_name . '" type="radio" value="no" '; |
|
if ($value === 'no') { |
|
$output .= 'checked="checked"'; |
|
} |
|
$output .= '>'; |
|
$output .= ' Nowhere</label>'; |
|
|
|
// New Line |
|
$output .= '<br>'; |
|
|
|
// Option 2 |
|
$output .= '<label>'; |
|
$output .= '<input name="' . $option_name . '" type="radio" value="yes" '; |
|
if ($value === 'yes') { |
|
$output .= 'checked="checked"'; |
|
} |
|
$output .= '>'; |
|
$output .= ' After a blog post'; |
|
$output .= '</label>'; |
|
|
|
// End Wrapper |
|
$output .= '</p>'; |
|
$output .= '</fieldset>'; |
|
|
|
echo $output; |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Register movie display total field |
|
* |
|
* @uses register_setting() |
|
* @uses add_settings_field() |
|
* @return void |
|
*/ |
|
private function register_movie_display_total_field(): void |
|
{ |
|
register_setting( |
|
'reading', |
|
$this->db_prefix('movie_display_total'), |
|
[ |
|
'type' => 'integer', |
|
'sanitize_callback' => [$this, 'hook__sanitize_movie_display_total_field'], |
|
'default' => 1, |
|
] |
|
); |
|
add_settings_field( |
|
$this->id_prefix('movie-display-total-field'), |
|
'Display up to', |
|
[$this, 'hook__render_movie_display_total_field'], |
|
'reading', |
|
$this->id_prefix('movies-section') |
|
); |
|
} |
|
|
|
/** |
|
* Hook: Sanitize movie display total field |
|
* |
|
* @uses add_settings_error() |
|
* @param string $value |
|
* @return string |
|
*/ |
|
public function hook__sanitize_movie_display_total_field(string $value): string |
|
{ |
|
$value = (int) $value; |
|
if ($value < 1 || $value > 5) { |
|
add_settings_error( |
|
'reading', |
|
'movie', |
|
__('Movies: Display up to must be between 1-5. Using default: 1', 'movies') |
|
); |
|
return 1; |
|
} |
|
|
|
return $value; |
|
} |
|
|
|
/** |
|
* Hook: Render movie display total field |
|
* |
|
* @uses esc_html() |
|
* @uses get_option() |
|
* @return void |
|
*/ |
|
public function hook__render_movie_display_total_field(): void |
|
{ |
|
$option_name = esc_html($this->db_prefix('movie_display_total')); |
|
$value = esc_html(get_option($option_name)); |
|
|
|
$output = '<fieldset>'; |
|
$output .= '<p>'; |
|
$output .= '<input name="' . $option_name . '" type="number" value="'; |
|
$output .= $value; |
|
$output .= '" step="1" min="1" max="5" id="movie-display-total" class="small-text"> movie(s)'; |
|
$output .= '</p>'; |
|
$output .= '</fieldset>'; |
|
|
|
echo $output; |
|
} |
|
|
|
/************************************************************************************/ |
|
|
|
/** |
|
* Register movie display |
|
* |
|
* @uses add_filter() |
|
* @return void |
|
*/ |
|
private function register_movie_display(): void |
|
{ |
|
add_filter('the_content', [$this, 'hook__render_movies_end_of_post']); |
|
} |
|
|
|
/*----------------------------------------------------------------------------------*/ |
|
|
|
/** |
|
* Hook: Render movies end of post |
|
* |
|
* @uses get_option() |
|
* @uses get_permalink() |
|
* @uses get_posts() |
|
* @uses get_the_post_thumbnail() |
|
* @param string $content |
|
* @return string |
|
*/ |
|
public function hook__render_movies_end_of_post(string $content): string |
|
{ |
|
$enabled = get_option($this->db_prefix('movie_display_enabled')); |
|
if ($enabled !== 'yes') { |
|
return $content; |
|
} |
|
$total = get_option($this->db_prefix('movie_display_total')); |
|
$movies = get_posts([ |
|
'post_type' => 'movie', |
|
'post_status' => 'publish', |
|
'posts_per_page' => $total, |
|
'orderby' => 'date', |
|
'order' => 'DESC', |
|
]); |
|
if (count($movies) === 0) { |
|
return $content; |
|
} |
|
$content .= '<p>Here are our latest movies:</p>'; |
|
$content .= '<div style="display:flex;gap:15px;">'; |
|
/** @var WP_Post $movie */ |
|
foreach ($movies as $movie) { |
|
$thumbnail = get_the_post_thumbnail($movie, [200, 300]); |
|
$url = get_permalink($movie); |
|
$content .= '<div>'; |
|
$content .= '<div><a href="' . $url . '">' . $thumbnail . '</a></div>'; |
|
$content .= '<div><a href="' . $url . '">' . $movie->post_title . '</a></div>'; |
|
$content .= '</div>'; |
|
} |
|
$content .= '</div>'; |
|
|
|
return $content; |
|
} |
|
} |
|
|
|
Main::init(); |