version = '3.3.3';
$this->url = ATTACHMENTS_URL;
$this->dir = ATTACHMENTS_DIR;
// includes
include_once( ATTACHMENTS_DIR . 'upgrade.php' );
include_once( ATTACHMENTS_DIR . '/classes/class.field.php' );
// include our fields
$this->fields = $this->get_field_types();
// deal with our legacy issues if the user hasn't dismissed or migrated already
$this->check_for_legacy_data();
// set our image sizes
$this->image_sizes = array_merge( $this->image_sizes, get_intermediate_image_sizes() );
// hook into WP
add_action( 'admin_enqueue_scripts', array( $this, 'assets' ), 999, 1 );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_pointer' ), 999 );
// register our user-defined instances
add_action( 'init', array( $this, 'do_actions_filters' ) );
// determine which instances apply to the current post type
add_action( 'init', array( $this, 'set_instances_for_current_post_type' ) );
add_action( 'add_meta_boxes', array( $this, 'meta_box_init' ) );
add_action( 'admin_footer', array( $this, 'admin_footer' ) );
add_action( 'save_post', array( $this, 'save' ) );
// only show the Settings screen if it hasn't been explicitly disabled
if( !( defined( 'ATTACHMENTS_SETTINGS_SCREEN' ) && ATTACHMENTS_SETTINGS_SCREEN === false ) )
add_action( 'admin_menu', array( $this, 'admin_page' ) );
// with version 3 we'll be giving at least one admin notice
add_action( 'admin_notices', array( $this, 'admin_notice' ) );
add_action( 'admin_head', array( $this, 'field_inits' ) );
add_action( 'admin_print_footer_scripts', array( $this, 'field_assets' ) );
// set our attachments if necessary
if( !is_null( $instance ) )
$this->attachments = $this->get_attachments( $instance, $post_id );
}
/**
* Stores whether or not this environment has active legacy Attachments/Pro data
*
* @since 3.1.3
*/
function check_for_legacy_data()
{
// deal with our legacy issues if the user hasn't dismissed or migrated already
if( false == get_option( 'attachments_migrated' ) && false == get_option( 'attachments_ignore_migration' ) )
{
$legacy_attachments_settings = get_option( 'attachments_settings' );
if( $legacy_attachments_settings && is_array( $legacy_attachments_settings['post_types'] ) && count( $legacy_attachments_settings['post_types'] ) )
{
// we have legacy settings, so we're going to use the post types
// that Attachments is currently utilizing
// the keys are the actual CPT names, so we need those
foreach( $legacy_attachments_settings['post_types'] as $post_type => $value )
if( $value )
$post_types[] = $post_type;
// set up our WP_Query args to grab anything with legacy data
$args = array(
'post_type' => isset( $post_types ) ? $post_types : array( 'post', 'page' ),
'post_status' => 'any',
'posts_per_page' => 1,
'meta_key' => '_attachments',
'suppress_filters' => true,
);
$legacy = new WP_Query( $args );
$this->legacy = empty( $legacy->found_posts ) ? false : true;
}
}
// deal with our legacy Pro issues if the user hasn't dismissed or migrated already
if( false == get_option( 'attachments_pro_migrated' ) && false == get_option( 'attachments_pro_ignore_migration' ) )
{
$post_types = get_post_types();
// set up our WP_Query args to grab anything (really anything) with legacy data
$args = array(
'post_type' => !empty( $post_types ) ? $post_types : array( 'post', 'page' ),
'post_status' => 'any',
'posts_per_page' => 1,
'meta_key' => '_attachments_pro',
'suppress_filters' => true,
);
$legacy_pro = new WP_Query( $args );
$this->legacy_pro = empty( $legacy_pro->found_posts ) ? false : true;
}
}
/**
* Facilitates searching for Attachments
*
* @since 3.3
*/
function search( $query = null, $params = array() )
{
$defaults = array(
'attachment_id' => null, // not searching for a single attachment ID
'instance' => 'attachments', // default instance
'post_type' => null, // search 'any' post type
'post_id' => null, // searching all posts
'post_status' => 'publish', // search only published posts
'fields' => null, // search all fields
);
$query = is_null( $query ) ? null : sanitize_text_field( $query );
$params = array_merge( $defaults, $params );
// sanitize parameters
$params['attachment_id'] = is_null( $params['attachment_id'] ) ? null : intval( $params['attachment_id'] );
$params['instance'] = !is_string( $params['instance'] ) ? 'attachments' : sanitize_text_field( $params['instance'] );
$params['post_type'] = is_null( $params['post_type'] ) ? 'any' : sanitize_text_field( $params['post_type'] );
$params['post_id'] = is_null( $params['post_id'] ) ? null : intval( $params['post_id'] );
$params['post_status'] = sanitize_text_field( $params['post_status'] );
if( is_string( $params['fields'] ) )
$params['fields'] = array( $params['fields'] ); // we always want an array
// since we have an array for our fields, we need to loop through and sanitize
for( $i = 0; $i < count( $params['fields'] ); $i++ )
$params['fields'][$i] = sanitize_text_field( $params['fields'][$i] );
// prepare our search args
$args = array(
'nopaging' => true,
'post_status' => $params['post_status'],
'meta_query' => array(
array(
'key' => 'attachments',
'value' => $query,
'compare' => 'LIKE'
)
),
);
// append any applicable parameters that got passed to the original method call
if( $params['post_type'] )
$args['post_type'] = $params['post_type'];
if( $params['post_id'] )
$args['post__in'] = array( $params['post_id'] ); // avoid using 'p' or 'page_id'
// we haven't utilized all parameters yet because they're meta-value based so we need to
// do some parsing on our end to validate the returned results
$possible_posts = new WP_Query( $args );
$potential_attachments = false; // stores valid attachments as restrictions are added
if( $possible_posts->found_posts )
{
// we have results from the reliminary search, we need to quantify them
while( $possible_posts->have_posts() )
{
$possible_posts->next_post();
$possible_post_ids[] = $possible_posts->post->ID;
}
// now that we have our possible post IDs we can grab all Attachments for all of those posts
foreach( $possible_post_ids as $possible_post_id )
{
$possible_attachments = $this->get_attachments( $params['instance'], $possible_post_id );
foreach( $possible_attachments as $possible_attachment )
$potential_attachments[] = $possible_attachment;
}
}
// if there aren't even any potential attachments, we'll just short circuit
if( !$potential_attachments )
return;
// first we need to make sure that our query matches each attachment
// we need to do this because the LIKE query returned the entire meta record,
// not necessarily tied to any specific Attachment
$total_potentials = count( $potential_attachments );
for( $i = 0; $i < $total_potentials; $i++ )
{
$valid = false;
// if we need to limit our search to specific fields, we'll do that here
if( $params['fields'] )
{
// we only want to check certain fields
foreach( $params['fields'] as $field )
if( isset( $potential_attachments[$i]->fields->$field ) ) // does the field exist?
if( strpos( strtolower( $potential_attachments[$i]->fields->$field ),
strtolower( $query ) ) !== false ) // does the value match?
$valid = true;
}
else
{
// we want to check all fields
foreach( $potential_attachments[$i]->fields as $field_name => $field_value )
if( strpos( strtolower( $field_value) , strtolower( $query ) ) !== false )
$valid = true;
}
if( !$valid )
unset( $potential_attachments[$i] );
// now our potentials have been limited to each match the query based on any field
}
// limit to attachment ID if applicable
if( $params['attachment_id'] )
{
$total_potentials = count( $potential_attachments );
for( $i = 0; $i < $total_potentials; $i++ )
if( $potential_attachments[$i]->id != $params['attachment_id'] )
unset( $potential_attachments[$i] );
}
$this->attachments = array_values( $potential_attachments );
}
/**
* Returns whether or not the current object has any Attachments
*
* @since 3.0
*/
function exist()
{
return !empty( $this->attachments );
}
/**
* Returns the number of Attachments
*
* @since 3.0.6
*/
function total()
{
return count( $this->attachments );
}
/**
* Returns the next Attachment for the current object and increments the index
*
* @since 3.0
*/
function get()
{
$this->attachments_ref++;
if( !count( $this->attachments ) || $this->attachments_ref >= count( $this->attachments ) )
return false;
return $this->attachments[$this->attachments_ref];
}
/**
* Returns a specific Attachment
*
* @since 3.2
*/
function get_single( $index )
{
return isset( $this->attachments[$index] ) ? $this->attachments[$index] : false;
}
/**
* Returns the asset (array) for the current Attachment
*
* @since 3.0.6
*/
function asset( $size = 'thumbnail', $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
// do we have our meta yet?
if( !isset( $this->attachments[$index]->meta ) )
$this->attachments[$index]->meta = wp_get_attachment_metadata( $this->attachments[$index]->id );
// is it an image?
if(
isset( $this->attachments[$index]->meta['sizes'] ) && // is it an image?
in_array( $size, $this->image_sizes ) ) // do we have the right size?
{
$asset = wp_get_attachment_image_src( $this->attachments[$index]->id, $size );
}
else
{
// either it's not an image or we don't have the proper size, so we'll use the icon
$asset = $this->icon();
}
return $asset;
}
/**
* Returns the icon (array) for the current Attachment
*
* @since 3.0.6
*/
function icon( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
$asset = wp_get_attachment_image_src( $this->attachments[$index]->id, null, true );
return $asset;
}
/**
* Returns an appropriate for the current Attachment if it's an image
*
* @since 3.0
*/
function image( $size = 'thumbnail', $index = null )
{
$asset = $this->asset( $size );
$image_src = $asset[0];
$image_width = $asset[1];
$image_height = $asset[2];
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
$image_alt = get_post_meta( $this->attachments[$index]->id, '_wp_attachment_image_alt', true );
$image = '
';
return $image;
}
/**
* Returns the URL for the current Attachment if it's an image
*
* @since 3.0
*/
function src( $size = 'thumbnail', $index = null )
{
$asset = $this->asset( $size );
return $asset[0];
}
/**
* Returns the formatted filesize of the current Attachment
*
* @since 3.0
*/
function filesize( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
if( !isset( $this->attachments[$index]->id ) )
return false;
$url = wp_get_attachment_url( $this->attachments[$index]->id );
$uploads = wp_upload_dir();
$file_path = str_replace( $uploads['baseurl'], $uploads['basedir'], $url );
$formatted = '0 bytes';
if( file_exists( $file_path ) )
{
$formatted = size_format( @filesize( $file_path ) );
}
return $formatted;
}
/**
* Returns the type of the current Attachment
*
* @since 3.0
*/
function type( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
if( !isset( $this->attachments[$index]->id ) )
return false;
$attachment_mime = explode( '/', get_post_mime_type( $this->attachments[$index]->id ) );
return isset( $attachment_mime[0] ) ? $attachment_mime[0] : false;
}
/**
* Returns the subtype of the current Attachment
*
* @since 3.0
*/
function subtype( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
if( !isset( $this->attachments[$index]->id ) )
return false;
$attachment_mime = explode( '/', get_post_mime_type( $this->attachments[$index]->id ) );
return isset( $attachment_mime[1] ) ? $attachment_mime[1] : false;
}
/**
* Returns the id of the current Attachment
*
* @since 3.0
*/
function id( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
return isset( $this->attachments[$index]->id ) ? $this->attachments[$index]->id : false;
}
/**
* Returns the $post->ID of the current Attachment
*
* @since 3.3
*/
function post_id( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
return isset( $this->attachments[$index]->post_id ) ? $this->attachments[$index]->post_id : false;
}
/**
* Returns the URL for the current Attachment
*
* @since 3.0
*/
function url( $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
return isset( $this->attachments[$index]->id ) ? wp_get_attachment_url( $this->attachments[$index]->id ) : false;
}
/**
* Returns the field value for the submitted field name
*
* @since 3.0
*/
function field( $name = 'title', $index = null )
{
$index = is_null( $index ) ? $this->attachments_ref : intval( $index );
return isset( $this->attachments[$index]->fields->$name ) ? $this->attachments[$index]->fields->$name : false;
}
/**
* Fires all of our actions
*
* @since 3.0
*/
function do_actions_filters()
{
// implement our default instance if appropriate
if( !defined( 'ATTACHMENTS_DEFAULT_INSTANCE' ) )
$this->register();
// facilitate user-defined instance registration
do_action( 'attachments_register', $this );
}
/**
* Enqueues our necessary assets
*
* @since 3.0
*/
function assets( $hook )
{
global $post;
// we only want our assets on edit screens
if( !empty( $this->instances_for_post_type ) && 'edit.php' != $hook && 'post.php' != $hook && 'post-new.php' != $hook )
return;
// we only want to enqueue if appropriate
if( empty( $this->instances_for_post_type ) )
return;
$post_id = isset( $post->ID ) ? $post->ID : null;
wp_enqueue_media( array( 'post' => $post_id ) );
wp_enqueue_style( 'attachments', trailingslashit( $this->url ) . 'css/attachments.css', null, $this->version, 'screen' );
wp_enqueue_script( 'attachments', trailingslashit( $this->url ) . 'js/attachments.js', array( 'jquery', 'jquery-ui-sortable' ), $this->version, true );
}
/**
* Registers meta box(es) for the current edit screen
*
* @since 3.0
*/
function meta_box_init()
{
$nonce_sent = false;
if( !empty( $this->instances_for_post_type ) )
{
foreach( $this->instances_for_post_type as $instance )
{
$instance_name = $instance;
$instance = (object) $this->instances[$instance];
$instance->name = $instance_name;
$position = isset($instance->position) ? $instance->position : 'normal';
$priority = isset($instance->priority) ? $instance->priority : 'high';
add_meta_box( 'attachments-' . $instance_name, __( esc_attr( $instance->label ) ), array( $this, 'meta_box_markup' ), $this->get_post_type(), $position, $priority, array( 'instance' => $instance, 'setup_nonce' => !$nonce_sent ) );
$nonce_sent = true;
}
}
}
/**
* Callback that outputs the meta box markup
*
* @since 3.0
*/
function meta_box_markup( $post, $metabox )
{
// single out our $instance
$instance = (object) $metabox['args']['instance'];
if( $metabox['args']['setup_nonce'] )
wp_nonce_field( 'attachments_save', 'attachments_nonce' );
?>
". __( esc_html( 'It is very important that you take a few minutes to see what has been updated. The changes will affect your themes/plugins.' ), 'attachments' ) ."
"; ?>