Skip to content

Instantly share code, notes, and snippets.

@Marinski
Last active March 31, 2024 14:37
Show Gist options
  • Save Marinski/def2c5dfe98e2be24f3af4cf0e66f5cc to your computer and use it in GitHub Desktop.
Save Marinski/def2c5dfe98e2be24f3af4cf0e66f5cc to your computer and use it in GitHub Desktop.
A custom WordPress plugin to manage partner profiles with custom post types, taxonomies, and meta boxes.
<?php
/**
* Plugin Name: Academy Partners Module
* Description: A custom WordPress plugin to manage partner profiles with custom post types, taxonomies, and meta boxes.
* Version: 1.0
* Requires at least: 5.0
* Requires PHP: 8.0
* Author: Marin Stoyanov
*/
if ( ! defined( 'WPINC' ) ) {
die;
}
class Partners_Module {
/**
* Store properties to manage plugin behavior
*/
private $post_type = 'partners';
private $taxonomy = 'partner_type';
/**
* Constructor to initialize the plugin.
*/
public function __construct() {
// Actions for post type, taxonomy, meta boxes
add_action( 'init', array( $this, 'register_post_type_and_taxonomy' ) );
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
// Actions for saving data
add_action( 'save_post_' . $this->post_type, array( $this, 'save_logo' ) );
add_action( 'save_post_' . $this->post_type, array( $this, 'save_desktop_banner' ) );
add_action( 'save_post_' . $this->post_type, array( $this, 'save_mobile_banner' ) );
add_action( 'save_post_' . $this->post_type, array( $this, 'save_website_url' ) );
// Actions for shortcode
add_action( 'init', array( $this, 'register_shortcode' ) );
}
/**
* Registers the 'partners' post type and 'partner_type' taxonomy.
*/
public function register_post_type_and_taxonomy() {
// Register Custom Post Type: 'partners'
$labels = array(
'name' => _x( 'Partners', 'post type general name', 'textdomain' ),
'singular_name' => _x( 'Partner', 'post type singular name', 'textdomain' ),
'menu_name' => _x( 'Partners', 'admin menu', 'textdomain' ),
'name_admin_bar' => _x( 'Partner', 'add new on admin bar', 'textdomain' ),
'add_new' => _x( 'Add New', 'partner', 'textdomain' ),
'add_new_item' => __( 'Add New Partner', 'textdomain' ),
'new_item' => __( 'New Partner', 'textdomain' ),
'edit_item' => __( 'Edit Partner', 'textdomain' ),
'view_item' => __( 'View Partner', 'textdomain' ),
'all_items' => __( 'All Partners', 'textdomain' ),
'search_items' => __( 'Search Partners', 'textdomain' ),
'parent_item_colon' => __( 'Parent Partners:', 'textdomain' ),
'not_found' => __( 'No partners found.', 'textdomain' ),
'not_found_in_trash' => __( 'No partners found in Trash.', 'textdomain' )
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true, // Important for frontend display
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'partners' ),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => null,
'supports' => array( 'title', 'editor', 'thumbnail' ),
'show_in_rest' => true // Enable Gutenberg editor
);
register_post_type( $this->post_type, $args );
// Register Custom Taxonomy: 'partner_type'
$taxonomy_labels = array(
'name' => _x( 'Partner Types', 'taxonomy general name', 'textdomain' ),
'singular_name' => _x( 'Partner Type', 'taxonomy singular name', 'textdomain' ),
'search_items' => __( 'Search Partner Types', 'textdomain' ),
'all_items' => __( 'All Partner Types', 'textdomain' ),
'edit_item' => __( 'Edit Partner Type', 'textdomain' ),
'update_item' => __( 'Update Partner Type', 'textdomain' ),
'add_new_item' => __( 'Add New Partner Type', 'textdomain' ),
'new_item_name' => __( 'New Partner Type Name', 'textdomain' ),
'menu_name' => __( 'Partner Types', 'textdomain' ),
);
$taxonomy_args = array(
'hierarchical' => true,
'labels' => $taxonomy_labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'partner-type' ),
);
register_taxonomy( $this->taxonomy, array( $this->post_type ), $taxonomy_args );
}
/**
* Adds the meta boxes for logo, banners, etc.
*/
public function add_meta_boxes() {
add_meta_box( 'partners_logo_meta', __('Partner Logo', 'textdomain'), array( $this, 'logo_meta_box_html' ), $this->post_type, 'side');
add_meta_box( 'partners_desktop_banner_meta', __('Desktop Banner', 'textdomain'), array( $this, 'desktop_banner_meta_box_html' ), $this->post_type, 'side');
add_meta_box( 'partners_mobile_banner_meta', __('Partner Mobile Banner', 'textdomain'), array( $this, 'mobile_banner_meta_box_html' ), $this->post_type, 'side');
add_meta_box( 'partners_website_url', __('Partner Website URL', 'textdomain'), array( $this, 'website_url_meta_box_html' ), $this->post_type, 'normal', 'high');
}
/**
* Meta box callback functions
*/
/**
* Callback function for the partner logo meta box.
*/
public function logo_meta_box_html( $post ) {
// Security: WordPress Nonce for Verification
wp_nonce_field( 'partners_logo_upload', 'partners_logo_upload_nonce' );
// Get Existing Logo
$logo_id = get_post_meta( $post->ID, '_partners_logo_id', true );
// Placeholder Output if No Logo Exists
if ( $logo_id ) {
echo wp_get_attachment_image( $logo_id, 'thumbnail' );
} else {
echo '<p>' . __( 'No logo uploaded yet.', 'textdomain' ) . '</p>';
}
// Media Uploader JavaScript Integration
wp_enqueue_media();
?>
<div id="partners-logo-preview" style="margin-bottom: 10px;">
<?php if ( $logo_id ) : ?>
<?php echo wp_get_attachment_image( $logo_id, 'thumbnail' ); ?>
<?php endif; ?>
</div>
<button type="button" id="upload-logo-button" class="button"><?php _e( 'Add Logo', 'textdomain' ); ?></button>
<button type="button" id="remove-logo-button" class="button" <?php echo ! $logo_id ? ' style="display:none;"' : ''; ?>><?php _e( 'Remove Logo', 'textdomain' ); ?></button>
<input type="hidden" id="partners_logo_id" name="partners_logo_id" value="<?php echo esc_attr( $logo_id ); ?>" />
<script>
jQuery( document ).ready( function( $ ) {
let frame;
$( '#upload-logo-button' ).on( 'click', function( e ) {
e.preventDefault();
// If the frame already exists, use it
if ( frame ) {
frame.open();
return;
}
// Create the media frame
frame = wp.media({
title: '<?php _e( "Select or Upload a Logo", "textdomain" ); ?>',
button: {
text: '<?php _e( "Use this logo", "textdomain" ); ?>'
},
multiple: false
});
// When an image is selected in the media frame...
frame.on( 'select', function() {
const attachment = frame.state().get( 'selection' ).first().toJSON();
$( '#partners-logo-preview' ).html( '<img src="' + attachment.url + '" alt="" style="max-width:100%;"/>' );
$( '#partners_logo_id' ).val( attachment.id );
$( '#remove-logo-button' ).show();
});
// Finally, open the modal
frame.open();
});
$( '#remove-logo-button' ).on( 'click', function( e ) {
e.preventDefault();
$( '#partners-logo-preview' ).html( '' );
$( '#partners_logo_id' ).val( '' );
$( this ).hide();
});
});
</script>
<?php
}
/**
* Callback function for the partner desktop banner meta box.
*/
public function desktop_banner_meta_box_html( $post ) {
// Security: WordPress Nonce
wp_nonce_field( 'partners_desktop_banner_upload', 'partners_desktop_banner_upload_nonce' );
// Get Existing Desktop Banner ID
$banner_id = get_post_meta( $post->ID, '_partners_desktop_banner_id', true );
// Media Uploader JavaScript Integration
wp_enqueue_media();
?>
<div id="partners-desktop-banner-preview" style="margin-bottom: 10px;">
<?php if ( $banner_id ) : ?>
<?php echo wp_get_attachment_image( $banner_id, 'medium' ); ?>
<?php endif; ?>
</div>
<button type="button" id="upload-banner-button" class="button"><?php _e( 'Add Banner', 'textdomain' ); ?></button>
<button type="button" id="remove-banner-button" class="button" <?php echo ! $banner_id ? ' style="display:none;"' : ''; ?>><?php _e( 'Remove Banner', 'textdomain' ); ?></button>
<input type="hidden" id="partners_desktop_banner_id" name="partners_desktop_banner_id" value="<?php echo esc_attr( $banner_id ); ?>" />
<script>
jQuery( document ).ready( function( $ ) {
let frame;
$( '#upload-banner-button' ).on( 'click', function( e ) {
e.preventDefault();
// If the frame already exists, use it
if ( frame ) {
frame.open();
return;
}
// Create the media frame
frame = wp.media({
title: '<?php _e( "Select or Upload a Desktop Banner", "textdomain" ); ?>',
button: {
text: '<?php _e( "Use this banner", "textdomain" ); ?>'
},
multiple: false,
library: { type: 'image' } // Restrict file selection to images
});
// When an image is selected in the media frame...
frame.on( 'select', function() {
const attachment = frame.state().get( 'selection' ).first().toJSON();
$( '#partners-desktop-banner-preview' ).html( '<img src="' + attachment.url + '" alt="" style="max-width:100%;"/>' );
$( '#partners_desktop_banner_id' ).val( attachment.id );
$( '#remove-banner-button' ).show();
});
// Open the modal
frame.open();
});
$( '#remove-banner-button' ).on( 'click', function( e ) {
e.preventDefault();
$( '#partners-desktop-banner-preview' ).html( '' );
$( '#partners_desktop_banner_id' ).val( '' );
$( this ).hide();
});
});
</script>
<?php
}
/**
* Callback function for the partner mobile banner meta box.
*/
public function mobile_banner_meta_box_html( $post ) {
// Security: WordPress Nonce
wp_nonce_field( 'partners_mobile_banner_upload', 'partners_mobile_banner_upload_nonce' );
// Get Existing Mobile Banner ID
$banner_id = get_post_meta( $post->ID, '_partners_mobile_banner_id', true );
// Media Uploader JavaScript Integration
wp_enqueue_media();
?>
<div id="partners-mobile-banner-preview" style="margin-bottom: 10px;">
<?php if ( $banner_id ) : ?>
<?php echo wp_get_attachment_image( $banner_id, 'thumbnail' ); ?>
<?php endif; ?>
</div>
<button type="button" id="upload-mobile-banner-button" class="button"><?php _e( 'Add Mobile Banner', 'textdomain' ); ?></button>
<button type="button" id="remove-mobile-banner-button" class="button" <?php echo ! $banner_id ? ' style="display:none;"' : ''; ?>><?php _e( 'Remove Mobile Banner', 'textdomain' ); ?></button>
<input type="hidden" id="partners_mobile_banner_id" name="partners_mobile_banner_id" value="<?php echo esc_attr( $banner_id ); ?>" />
<script>
jQuery( document ).ready( function( $ ) {
let frame;
$( '#upload-mobile-banner-button' ).on( 'click', function( e ) {
e.preventDefault();
// If the frame already exists, use it
if ( frame ) {
frame.open();
return;
}
// Create the media frame
frame = wp.media({
title: '<?php _e( "Select or Upload a Mobile Banner", "textdomain" ); ?>',
button: {
text: '<?php _e( "Use this banner", "textdomain" ); ?>'
},
multiple: false,
library: { type: 'image' } // Restrict file selection to images
});
// When an image is selected in the media frame...
frame.on( 'select', function() {
const attachment = frame.state().get( 'selection' ).first().toJSON();
$( '#partners-mobile-banner-preview' ).html( '<img src="' + attachment.url + '" alt="" style="max-width:100%;"/>' );
$( '#partners_mobile_banner_id' ).val( attachment.id );
$( '#remove-mobile-banner-button' ).show();
});
// Open the modal
frame.open();
});
$( '#remove-mobile-banner-button' ).on( 'click', function( e ) {
e.preventDefault();
$( '#partners-mobile-banner-preview' ).html( '' );
$( '#partners_mobile_banner_id' ).val( '' );
$( this ).hide();
});
});
</script>
<?php
}
/**
* Callback function for the partner website URL meta box.
*/
public function website_url_meta_box_html( $post ) {
// Security: WordPress Nonce
wp_nonce_field( 'partners_website_url_save', 'partners_website_url_nonce' );
// Get Existing Website URL
$website_url = get_post_meta( $post->ID, '_partners_website_url', true );
?>
<p>
<label for="partners_website_url"><?php _e( 'Website URL:', 'textdomain' ); ?></label>
<input type="url" id="partners_website_url" name="partners_website_url" value="<?php echo esc_attr( $website_url ); ?>" size="30" placeholder="https://example.com" style="width: 100%;" />
</p>
<?php
}
/**
* Save functions for partner data
*/
/**
* Saves the partner logo meta data.
*
* @param int $post_id The ID of the post being saved.
*/
public function save_logo( $post_id ) {
// Security Checks
if (
!isset($_POST['partners_logo_upload_nonce']) ||
!wp_verify_nonce( $_POST['partners_logo_upload_nonce'], 'partners_logo_upload' ) ||
!current_user_can( 'edit_post', $post_id )
) {
return; // Exit if security checks fail
}
// Check if logo data is present
if ( !isset( $_POST['partners_logo_id'] ) ) {
return;
}
// Sanitize the logo ID
$logo_id = sanitize_text_field( $_POST['partners_logo_id'] );
// Save or Delete based on Input
if ( $logo_id ) {
update_post_meta( $post_id, '_partners_logo_id', $logo_id );
} else {
delete_post_meta( $post_id, '_partners_logo_id' );
}
}
/**
* Saves the partner desktop banner meta data.
*
* @param int $post_id The ID of the post being saved.
*/
public function save_desktop_banner( $post_id ) {
// Security Checks
if (
!isset($_POST['partners_desktop_banner_upload_nonce']) ||
!wp_verify_nonce( $_POST['partners_desktop_banner_upload_nonce'], 'partners_desktop_banner_upload' ) ||
!current_user_can( 'edit_post', $post_id )
) {
return; // Exit if security checks fail
}
// Check if desktop banner data is present
if ( !isset( $_POST['partners_desktop_banner_id'] ) ) {
return;
}
// Sanitize the desktop banner ID
$banner_id = sanitize_text_field( $_POST['partners_desktop_banner_id'] );
// Save or Delete based on Input
if ( $banner_id ) {
update_post_meta( $post_id, '_partners_desktop_banner_id', $banner_id );
} else {
delete_post_meta( $post_id, '_partners_desktop_banner_id' );
}
}
/**
* Saves the partner mobile banner meta data.
*
* @param int $post_id The ID of the post being saved.
*/
public function save_mobile_banner( $post_id ) {
// Security Checks
if (
!isset($_POST['partners_mobile_banner_upload_nonce']) ||
!wp_verify_nonce( $_POST['partners_mobile_banner_upload_nonce'], 'partners_mobile_banner_upload' ) ||
!current_user_can( 'edit_post', $post_id )
) {
return; // Exit if security checks fail
}
// Check if mobile banner data is present
if ( !isset( $_POST['partners_mobile_banner_id'] ) ) {
return;
}
// Sanitize the mobile banner ID
$banner_id = sanitize_text_field( $_POST['partners_mobile_banner_id'] );
// Save or Delete based on Input
if ( $banner_id ) {
update_post_meta( $post_id, '_partners_mobile_banner_id', $banner_id );
} else {
delete_post_meta( $post_id, '_partners_mobile_banner_id' );
}
}
/**
* Saves the partner website URL meta data.
*
* @param int $post_id The ID of the post being saved.
*/
public function save_website_url( $post_id ) {
// Security Checks
if (
!isset($_POST['partners_website_url_nonce']) ||
!wp_verify_nonce( $_POST['partners_website_url_nonce'], 'partners_website_url_save' ) ||
!current_user_can( 'edit_post', $post_id )
) {
return; // Exit if security checks fail
}
// Check if URL field exists
if ( !isset( $_POST['partners_website_url'] ) ) {
return;
}
// Sanitize the URL input
$website_url = esc_url_raw( $_POST['partners_website_url'] );
// Validate the URL format
if ( filter_var( $website_url, FILTER_VALIDATE_URL ) !== false ) {
// Update the meta field
update_post_meta( $post_id, '_partners_website_url', $website_url );
} else {
// Handle the invalid URL scenario
set_transient( "partners_url_validation_failed_{$post_id}", true, 45 ); // Adjust the transient's expiration time as needed
}
}
/**
* Registers our shortcode [partner_banner].
*/
public function register_shortcode() {
add_shortcode( 'partner_banner', array( $this, 'render_partner_banner' ) );
}
/**
* Shortcode rendering function - [partner_banner]
*
* @param array $atts Shortcode attributes.
* @return string The rendered HTML output of the banner.
*/
public function render_partner_banner( $atts ) {
// Extract shortcode attributes with defaults
$atts = shortcode_atts(
array(
'id' => '',
),
$atts,
'partner_banner'
);
// Sanitize the provided ID
$partner_id = intval( $atts['id'] );
// Return an error message if no valid ID is provided.
if ( !$partner_id ) {
return '<p>' . __( 'Error: Partner ID not provided or invalid.', 'textdomain' ) . '</p>';
}
// Retrieve the partner post
$partner_post = get_post( $partner_id );
// Handle scenarios where the partner post might not exist
if ( !$partner_post || $partner_post->post_type !== $this->post_type ) {
return '<p>' . __( 'Error: Invalid Partner ID or the post is not a Partner.', 'textdomain' ) . '</p>';
}
// Device Detection using wp_is_mobile()
$is_mobile = wp_is_mobile();
$banner_meta_key = $is_mobile ? '_partners_mobile_banner_id' : '_partners_desktop_banner_id';
$banner_id = get_post_meta( $partner_id, $banner_meta_key, true );
// Retrieve the partner URL
$partner_url = get_post_meta( $partner_id, '_partners_website_url', true );
// Sanitize URLs
$banner_url = $banner_id ? esc_url( wp_get_attachment_url( $banner_id ) ) : '';
$partner_url = esc_url( $partner_url );
// Construct the HTML output
$output = '';
if ( $banner_url && $partner_url ) {
$alt_text = esc_attr( $partner_post->post_title ); // Sanitize alt text
$output = "<a href='{$partner_url}' target='_blank'><img src='{$banner_url}' alt='{$alt_text}'></a>";
}
return $output;
}
}
// Instantiate the plugin class
new Partners_Module();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment