Last active
March 31, 2024 14:37
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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