Home › Versatile Shortcode Pro <?php
/**
* Plugin Name: Versatile Shortcode Pro
* Plugin URI: https://ameliahollis.net/versatile-shortcode-pro
* Description: A versatile shortcode manager allowing manual or automatic placement of various useful shortcodes across your site.
* Version: 1.0.0
* Author: Amelia Hollis
* Author URI: https://ameliahollis.net
* Text Domain: versatile-shortcodes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Versatile_Shortcodes_Plugin {
private $option_name = 'vsp_shortcode_settings';
private $available_shortcodes = array();
public function __construct() {
$this->define_shortcodes();
add_action( 'admin_menu', array( $this, 'add_settings_page' ) );
add_action( 'admin_init', array( $this, 'register_settings' ) );
add_action( 'init', array( $this, 'register_active_shortcodes' ) );
add_action( 'wp_body_open', array( $this, 'auto_insert_header' ) );
add_action( 'wp_footer', array( $this, 'auto_insert_footer' ) );
add_filter( 'the_content', array( $this, 'auto_insert_content' ) );
}
private function define_shortcodes() {
$this->available_shortcodes = array(
'vsp_year' => array(
'title' => 'Current Year',
'description' => 'Displays the current year (useful for copyright text).',
'callback' => array( $this, 'shortcode_current_year' ),
),
'vsp_site_title' => array(
'title' => 'Site Title',
'description' => 'Displays the dynamic site title from your WordPress settings.',
'callback' => array( $this, 'shortcode_site_title' ),
),
'vsp_author_bio' => array(
'title' => 'Author Biography',
'description' => 'Displays the author box. Only visible on single posts.',
'callback' => array( $this, 'shortcode_author_bio' ),
),
'vsp_social_share' => array(
'title' => 'Social Share Links',
'description' => 'Displays simple sharing links for the current page.',
'callback' => array( $this, 'shortcode_social_share' ),
),
'vsp_recent_posts' => array(
'title' => 'Recent Posts List',
'description' => 'Displays a bulleted list of recent posts. Accepts a [vsp_recent_posts count="5"] attribute when used manually.',
'callback' => array( $this, 'shortcode_recent_posts' ),
),
);
}
public function add_settings_page() {
add_options_page(
'Versatile Shortcodes Settings',
'Versatile Shortcodes',
'manage_options',
'versatile-shortcodes',
array( $this, 'render_settings_page' )
);
}
public function register_settings() {
register_setting( 'vsp_settings_group', $this->option_name, array(
'sanitize_callback' => array( $this, 'sanitize_settings' )
) );
}
public function sanitize_settings( $input ) {
$sanitized_input = array();
$allowed_placements = array( 'manual', 'header', 'footer', 'before_content', 'after_content' );
if ( ! is_array( $input ) ) {
return $sanitized_input;
}
foreach ( $this->available_shortcodes as $tag => $data ) {
if ( isset( $input[ $tag ] ) ) {
$sanitized_input[ $tag ]['enabled'] = ! empty( $input[ $tag ]['enabled'] ) ? 1 : 0;
if ( isset( $input[ $tag ]['placement'] ) && in_array( $input[ $tag ]['placement'], $allowed_placements, true ) ) {
$sanitized_input[ $tag ]['placement'] = $input[ $tag ]['placement'];
} else {
$sanitized_input[ $tag ]['placement'] = 'manual';
}
}
}
return $sanitized_input;
}
public function render_settings_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$settings = get_option( $this->option_name, array() );
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<p>Select which shortcodes you want to enable and where they should be placed automatically. If set to "Manual", you must paste the shortcode tag (e.g., <code>[vsp_year]</code>) into your content yourself.</p>
<form action="options.php" method="post">
<?php
settings_fields( 'vsp_settings_group' );
?>
<table class="wp-list-table widefat fixed striped table-view-list">
<thead>
<tr>
<th style="width: 5%;">Enable</th>
<th style="width: 20%;">Shortcode Tag</th>
<th style="width: 20%;">Placement</th>
<th style="width: 55%;">Description</th>
</tr>
</thead>
<tbody>
<?php foreach ( $this->available_shortcodes as $tag => $data ) :
$is_enabled = isset( $settings[ $tag ]['enabled'] ) ? $settings[ $tag ]['enabled'] : 0;
$placement = isset( $settings[ $tag ]['placement'] ) ? $settings[ $tag ]['placement'] : 'manual';
?>
<tr>
<td>
<input type="checkbox"
name="<?php echo esc_attr( $this->option_name . '[' . $tag . '][enabled]' ); ?>"
value="1" <?php checked( 1, $is_enabled ); ?> />
</td>
<td>
<strong><code>[<?php echo esc_html( $tag ); ?>]</code></strong><br>
<small><?php echo esc_html( $data['title'] ); ?></small>
</td>
<td>
<select name="<?php echo esc_attr( $this->option_name . '[' . $tag . '][placement]' ); ?>">
<option value="manual" <?php selected( $placement, 'manual' ); ?>>Manual Placement Only</option>
<option value="header" <?php selected( $placement, 'header' ); ?>>Auto: Top of Page (Header)</option>
<option value="footer" <?php selected( $placement, 'footer' ); ?>>Auto: Bottom of Page (Footer)</option>
<option value="before_content" <?php selected( $placement, 'before_content' ); ?>>Auto: Before Post Content</option>
<option value="after_content" <?php selected( $placement, 'after_content' ); ?>>Auto: After Post Content</option>
</select>
</td>
<td>
<?php echo esc_html( $data['description'] ); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php submit_button( 'Save Shortcode Settings' ); ?>
</form>
</div>
<?php
}
public function register_active_shortcodes() {
$settings = get_option( $this->option_name, array() );
foreach ( $this->available_shortcodes as $tag => $data ) {
if ( ! empty( $settings[ $tag ]['enabled'] ) ) {
add_shortcode( $tag, $data['callback'] );
}
}
}
private function do_auto_placement( $target_placement ) {
$settings = get_option( $this->option_name, array() );
$output = '';
foreach ( $this->available_shortcodes as $tag => $data ) {
if ( ! empty( $settings[ $tag ]['enabled'] ) ) {
$placement = isset( $settings[ $tag ]['placement'] ) ? $settings[ $tag ]['placement'] : 'manual';
if ( $placement === $target_placement ) {
$output .= '<div class="vsp-auto-insert vsp-' . esc_attr( $tag ) . '">';
$output .= do_shortcode( '[' . $tag . ']' );
$output .= '</div>';
}
}
}
return $output;
}
public function auto_insert_header() {
echo $this->do_auto_placement( 'header' );
}
public function auto_insert_footer() {
echo $this->do_auto_placement( 'footer' );
}
public function auto_insert_content( $content ) {
if ( ! is_main_query() || ! in_the_loop() ) {
return $content;
}
$before = $this->do_auto_placement( 'before_content' );
$after = $this->do_auto_placement( 'after_content' );
return $before . $content . $after;
}
public function shortcode_current_year( $atts ) {
return esc_html( gmdate( 'Y' ) );
}
public function shortcode_site_title( $atts ) {
return esc_html( get_bloginfo( 'name' ) );
}
public function shortcode_author_bio( $atts ) {
if ( ! is_single() ) {
return '';
}
$author_id = get_post_field( 'post_author', get_the_ID() );
$author_name = get_the_author_meta( 'display_name', $author_id );
$author_description = get_the_author_meta( 'description', $author_id );
$author_avatar = get_avatar( $author_id, 64 );
if ( empty( $author_description ) ) {
return '';
}
$html = '<div class="vsp-author-bio" style="display:flex; align-items:center; background:#f9f9f9; padding: 15px; border-left: 4px solid #0073aa; margin: 20px 0;">';
$html .= '<div style="margin-right: 15px;">' . $author_avatar . '</div>';
$html .= '<div>';
$html .= '<h4 style="margin: 0 0 5px 0;">Written by ' . esc_html( $author_name ) . '</h4>';
$html .= '<p style="margin: 0; font-size: 0.9em;">' . esc_html( $author_description ) . '</p>';
$html .= '</div></div>';
return $html;
}
public function shortcode_social_share( $atts ) {
global $wp;
$current_url = home_url( $wp->request );
$post_title = get_the_title();
$twitter_url = 'https://twitter.com/intent/tweet?text=' . rawurlencode( $post_title ) . '&url=' . rawurlencode( $current_url );
$facebook_url = 'https://www.facebook.com/sharer/sharer.php?u=' . rawurlencode( $current_url );
$html = '<div class="vsp-social-share" style="margin: 15px 0;">';
$html .= '<strong>Share this: </strong>';
$html .= '<a href="' . esc_url( $twitter_url ) . '" target="_blank" rel="noopener noreferrer" style="margin-right: 10px; color: #1DA1F2;">Twitter</a> ';
$html .= '<a href="' . esc_url( $facebook_url ) . '" target="_blank" rel="noopener noreferrer" style="color: #4267B2;">Facebook</a>';
$html .= '</div>';
return $html;
}
public function shortcode_recent_posts( $atts ) {
$args = shortcode_atts( array(
'count' => 5, // Default to 5 posts
), $atts );
$count = intval( $args['count'] );
if ( $count < 1 ) {
$count = 1;
} elseif ( $count > 20 ) {
$count = 20;
}
$recent_posts = wp_get_recent_posts( array(
'numberposts' => $count,
'post_status' => 'publish'
) );
if ( empty( $recent_posts ) ) {
return '<p>No recent posts found.</p>';
}
$html = '<div class="vsp-recent-posts">';
$html .= '<ul style="list-style-type: square; padding-left: 20px;">';
foreach ( $recent_posts as $post ) {
$html .= '<li>';
$html .= '<a href="' . esc_url( get_permalink( $post['ID'] ) ) . '">' . esc_html( $post['post_title'] ) . '</a>';
$html .= '</li>';
}
$html .= '</ul>';
$html .= '</div>';
return $html;
}
}
new Versatile_Shortcodes_Plugin();