'MAKE_Compatibility_MethodsInterface',
'thememod' => 'MAKE_Settings_ThemeModInterface',
);
/**
* Stores the logo image, width, and height information.
*
* This var acts as a "run-time" cache. Since the functions in this class are called in different places throughout
* the page load, once the logo information is computed for the first time, it is cached to this variable.
* Subsequent requests for the information are pulled from the variable in memory instead of recomputing it.
*
* @since 1.0.0.
*
* @var array Holds the image, width, and height information for the logos.
*/
var $logo_information = array();
/**
* Stores whether or not a specified logo type is available.
*
* @since 1.0.0.
*
* @var array Holds boolean values to indicate if the logo type is available.
*/
var $has_logo_by_type = array();
/**
* Indicator of whether the hook routine has been run.
*
* @since 1.7.0.
*
* @var bool
*/
private static $hooked = false;
/**
* Hook into WordPress.
*
* @since 1.7.0.
*
* @return void
*/
public function hook() {
if ( $this->is_hooked() ) {
return;
}
// Add styles
add_action( 'make_style_loaded', array( $this, 'print_logo_css' ) );
// Refresh logo cache
add_action( 'customize_save_after', array( $this, 'refresh_logo_cache' ) );
// Hooking has occurred.
self::$hooked = true;
}
/**
* Check if the hook routine has been run.
*
* @since 1.7.0.
*
* @return bool
*/
public function is_hooked() {
return self::$hooked;
}
/**
* Get the ID of an attachment from its image URL.
*
* @author Taken from reverted change to WordPress core http://core.trac.wordpress.org/ticket/23831
* @since 1.0.0.
*
* @param string $url The path to an image.
*
* @return int|bool ID of the attachment or 0 on failure.
*/
private function get_attachment_id_from_url( $url = '' ) {
// If there is no url, return.
if ( '' === $url ) {
return false;
}
// Literal URL matches should always match canonical scheme for the site.
$upload_dir_paths = wp_upload_dir();
if ( set_url_scheme( $upload_dir_paths['baseurl'], 'https' ) === $upload_dir_paths['baseurl'] ) {
$url = set_url_scheme( $url, 'https' );
} else {
$url = set_url_scheme( $url, 'http' );
}
global $wpdb;
$attachment_id = 0;
// Function introduced in 4.0
if ( function_exists( 'attachment_url_to_postid' ) ) {
$attachment_id = absint( attachment_url_to_postid( $url ) );
if ( 0 !== $attachment_id ) {
return $attachment_id;
}
}
// First try this
if ( preg_match( '#\.[a-zA-Z0-9]+$#', $url ) ) {
$sql = $wpdb->prepare(
"SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND guid = %s",
esc_url_raw( $url )
);
$attachment_id = absint( $wpdb->get_var( $sql ) );
if ( 0 !== $attachment_id ) {
return $attachment_id;
}
}
// Then try this
if ( false !== strpos( $url, $upload_dir_paths['baseurl'] ) ) {
// If this is the URL of an auto-generated thumbnail, get the URL of the original image
$url = preg_replace( '/-\d+x\d+(?=\.(jpg|jpeg|png|gif)$)/i', '', $url );
// Remove the upload path base directory from the attachment URL
$url = str_replace( $upload_dir_paths['baseurl'] . '/', '', $url );
// Finally, run a custom database query to get the attachment ID from the modified attachment URL
$sql = $wpdb->prepare(
"SELECT wposts.ID FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = '_wp_attached_file' AND wpostmeta.meta_value = '%s' AND wposts.post_type = 'attachment'",
esc_url_raw( $url )
);
$attachment_id = absint( $wpdb->get_var( $sql ) );
}
return $attachment_id;
}
/**
* Get the dimensions of a logo image from cache or regenerate the values.
*
* @since 1.0.0.
*
* @param string $url The URL of the image in question.
* @param bool $force Cause a cache refresh.
*
* @return array The dimensions array on success, and a blank array on failure.
*/
private function get_logo_dimensions( $url, $force = false ) {
// Build the cache key
$key = 'ttfmake-' . md5( 'logo-dimensions-' . $url . TTFMAKE_VERSION );
// Pull from cache
$dimensions = get_transient( $key );
// If the value is not found in cache, regenerate
if ( false === $dimensions || is_preview() || true === $force ) {
$dimensions = array();
// Get the ID of the attachment
$attachment_id = ( is_int( $url ) ) ? $url : $this->get_attachment_id_from_url( $url );
// Get the dimensions
$info = wp_get_attachment_image_src( $attachment_id, 'full' );
if ( false !== $info && isset( $info[0] ) && isset( $info[1] ) && isset( $info[2] ) ) {
// Detect JetPack altered src
if ( false === $info[1] && false === $info[2] ) {
// Parse the URL for the dimensions
$pieces = parse_url( urldecode( $info[0] ) );
// Pull apart the query string
if ( isset( $pieces['query'] ) ) {
parse_str( $pieces['query'], $query_pieces );
// Get the values from "resize"
if ( isset( $query_pieces['resize'] ) || isset( $query_pieces['fit'] ) ) {
if ( isset( $query_pieces['resize'] ) ) {
$jp_dimensions = explode( ',', $query_pieces['resize'] );
} elseif ( $query_pieces['fit'] ){
$jp_dimensions = explode( ',', $query_pieces['fit'] );
}
if ( isset( $jp_dimensions[0] ) && isset( $jp_dimensions[1] ) ) {
// Package the data
$dimensions = array(
'width' => $jp_dimensions[0],
'height' => $jp_dimensions[1],
);
}
}
}
} else {
// Package the data
$dimensions = array(
'width' => $info[1],
'height' => $info[2],
);
}
} else {
// Get the image path from the URL
$wp_upload_dir = wp_upload_dir();
$path = trailingslashit( $wp_upload_dir['basedir'] ) . get_post_meta( $attachment_id, '_wp_attached_file', true );
// Sometimes, WordPress just doesn't have the metadata available. If not, get the image size
if ( is_file( $path ) && is_readable( $path ) ) {
$getimagesize = getimagesize( $path );
if ( false !== $getimagesize && isset( $getimagesize[0] ) && isset( $getimagesize[1] ) ) {
$dimensions = array(
'width' => $getimagesize[0],
'height' => $getimagesize[1],
);
}
}
}
// Store the transient
if ( ! is_preview() ) {
set_transient( $key, $dimensions, 86400 );
}
}
return $dimensions;
}
/**
* Determine if a custom logo should be displayed.
*
* @since 1.0.0.
*
* @return bool True if a logo should be displayed. False if a logo shouldn't be displayed.
*/
public function has_logo() {
return ( $this->has_logo_by_type( 'logo-regular' ) || $this->has_logo_by_type( 'logo-retina' ) || $this->has_logo_by_type( 'custom_logo' ) );
}
/**
* Determine if necessary information is available to show a particular logo.
*
* @since 1.0.0.
*
* @param string $type The type of logo to inspect for.
* @return bool True if all information is available. False is something is missing.
*/
private function has_logo_by_type( $type ) {
// Clean the type value
$type = sanitize_key( $type );
// If the information is already set, return it from the instance cache
if ( isset( $this->has_logo_by_type[ $type ] ) ) {
return $this->has_logo_by_type[ $type ];
}
// Grab the logo information
$information = $this->get_logo_information();
// Set the default return value
$return = false;
// Verify that the logo type exists in the array
if ( isset( $information[ $type ] ) ) {
// Verify that the image is set and has a value
if ( isset( $information[ $type ]['image'] ) && ! empty( $information[ $type ]['image'] ) ) {
// Verify that the width is set and has a value
if ( isset( $information[ $type ]['width'] ) && ! empty( $information[ $type ]['width'] ) ) {
// Verify that the height is set and has a value
if ( isset( $information[ $type ]['height'] ) && ! empty( $information[ $type ]['height'] ) ) {
$return = true;
}
}
}
}
// Cache to the instance var for future use
$this->has_logo_by_type[ $type ] = $return;
return $this->has_logo_by_type[ $type ];
}
/**
* Utility function for getting information about the theme logos.
*
* @since 1.0.0.
*
* @param bool $force Update the dimension cache.
* @return array Array containing image file, width, and height for each logo.
*/
private function get_logo_information( $force = false) {
// If the logo information is cached to an instance var, pull from there
if ( ! empty( $this->logo_information ) ) {
return $this->logo_information;
}
// Set the logo slugs
$logos = array(
'logo-regular',
'logo-retina',
'custom_logo',
);
// For each logo slug, get the image, width and height
foreach ( $logos as $logo ) {
$this->logo_information[ $logo ]['image'] = $this->thememod()->get_value( $logo );
// Set the defaults
$this->logo_information[ $logo ]['width'] = '';
$this->logo_information[ $logo ]['height'] = '';
// If there is an image, get the dimensions
if ( ! empty( $this->logo_information[ $logo ]['image'] ) ) {
$dimensions = $this->get_logo_dimensions( $this->logo_information[ $logo ]['image'], $force );
// Set the dimensions to the array if all information is present
if ( ! empty( $dimensions ) && isset( $dimensions['width'] ) && isset( $dimensions['height'] ) ) {
$this->logo_information[ $logo ]['width'] = $dimensions['width'];
$this->logo_information[ $logo ]['height'] = $dimensions['height'];
}
}
}
// Check for deprecated filter.
if ( has_filter( 'ttfmake_custom_logo_information' ) ) {
$this->compatibility()->deprecated_hook(
'ttfmake_custom_logo_information',
'1.7.0',
sprintf(
esc_html__( 'Use the %s hook instead.', 'make' ),
'make_logo_information
'
)
);
/**
* Filter the URL and dimensions of the custom logo.
*
* This filter may be useful if you encounter problems getting your custom
* logo to appear. Note, however, that using this filter will hard-code the logo
* information and settings in the Logo interface in the Customizer won't be
* reflected.
*
* @since 1.0.0.
* @deprecated 1.7.0.
*
* @param array $logo_information The array of information.
*/
$this->logo_information = apply_filters( 'ttfmake_custom_logo_information', $this->logo_information );
}
/**
* Filter the URL and dimensions of the custom logo.
*
* This filter may be useful if you encounter problems getting your custom
* logo to appear. Note, however, that using this filter will hard-code the logo
* information and settings in the Logo interface in the Customizer won't be
* reflected.
*
* @since 1.7.0.
*
* @param array $logo_information The array of information.
*/
$this->logo_information = apply_filters( 'make_logo_information', $this->logo_information );
return $this->logo_information;
}
/**
* Print CSS in the head for the logo.
*
* @since 1.0.0.
* @since 1.7.0. Added $style parameter
*
* @hooked action make_style_loaded
*
* @param MAKE_Style_ManagerInterface $style
*
* @return void
*/
public function print_logo_css( MAKE_Style_ManagerInterface $style ) {
// Is this necessary?
if ( ! $this->has_logo() ) {
return;
}
// Max logo width
$size = 960;
// Check for deprecated filter.
if ( has_filter( 'ttfmake_custom_logo_max_width' ) ) {
$this->compatibility()->deprecated_hook(
'ttfmake_custom_logo_max_width',
'1.7.0',
sprintf(
esc_html__( 'Use the %s hook instead.', 'make' ),
'make_logo_max_width
'
)
);
/** This filter is documented in inc/logo/methods.php */
$size = apply_filters( 'ttfmake_custom_logo_max_width', $size );
}
/** This filter is documented in inc/logo/methods.php */
$size = apply_filters( 'make_logo_max_width', $size );
// Grab the logo information
$info = $this->get_logo_information();
// Core custom logo
// We are still outputting CSS for the Core custom logo in case a child theme is using a custom header
// template file that doesn't include the template tag that outputs the logo markup.
if ( $this->has_logo_by_type( 'custom_logo' ) ) {
$final_dimensions = $this->adjust_dimensions( $info['custom_logo']['width'], $info['custom_logo']['height'], $size );
$image = wp_get_attachment_image_src( $info['custom_logo']['image'], 'full' );
$style->css()->add( array(
'selectors' => array( 'div.custom-logo' ),
'declarations' => array(
'background-image' => 'url("' . addcslashes( esc_url_raw( $image[0] ), '"' ) . '")',
'width' => absint( $final_dimensions['width'] ) . 'px'
)
) );
$style->css()->add( array(
'selectors' => array( 'div.custom-logo a' ),
'declarations' => array(
'padding-bottom' => (float) $final_dimensions['ratio'] . '%'
)
) );
}
// Both logo types are available
else if ( $this->has_logo_by_type( 'logo-regular' ) && $this->has_logo_by_type( 'logo-retina' ) ) {
$final_dimensions = $this->adjust_dimensions( $info['logo-regular']['width'], $info['logo-regular']['height'], $size, false );
$style->css()->add( array(
'selectors' => array( '.custom-logo' ),
'declarations' => array(
'background-image' => 'url("' . addcslashes( esc_url_raw( $info['logo-regular']['image'] ), '"' ) . '")',
'width' => absint( $final_dimensions['width'] ) . 'px'
)
) );
$style->css()->add( array(
'selectors' => array( '.custom-logo a' ),
'declarations' => array(
'padding-bottom' => (float) $final_dimensions['ratio'] . '%'
)
) );
$style->css()->add( array(
'selectors' => array( '.custom-logo' ),
'declarations' => array(
'background-image' => 'url("' . addcslashes( esc_url_raw( $info['logo-retina']['image'] ), '"' ) . '")'
),
'media' => '(-webkit-min-device-pixel-ratio: 1.3),(-o-min-device-pixel-ratio: 2.6/2),(min--moz-device-pixel-ratio: 1.3),(min-device-pixel-ratio: 1.3),(min-resolution: 1.3dppx)'
) );
}
// Regular logo only
else if ( $this->has_logo_by_type( 'logo-regular' ) ) {
$final_dimensions = $this->adjust_dimensions( $info['logo-regular']['width'], $info['logo-regular']['height'], $size );
$style->css()->add( array(
'selectors' => array( '.custom-logo' ),
'declarations' => array(
'background-image' => 'url("' . addcslashes( esc_url_raw( $info['logo-regular']['image'] ), '"' ) . '")',
'width' => absint( $final_dimensions['width'] ) . 'px'
)
) );
$style->css()->add( array(
'selectors' => array( '.custom-logo a' ),
'declarations' => array(
'padding-bottom' => (float) $final_dimensions['ratio'] . '%'
)
) );
}
// Retina logo only
else if ( $this->has_logo_by_type( 'logo-retina' ) ) {
$final_dimensions = $this->adjust_dimensions( $info['logo-retina']['width'], $info['logo-retina']['height'], $size, true );
$style->css()->add( array(
'selectors' => array( '.custom-logo' ),
'declarations' => array(
'background-image' => 'url("' . addcslashes( esc_url_raw( $info['logo-retina']['image'] ), '"' ) . '")',
'width' => absint( $final_dimensions['width'] ) . 'px'
)
) );
$style->css()->add( array(
'selectors' => array( '.custom-logo a' ),
'declarations' => array(
'padding-bottom' => (float) $final_dimensions['ratio'] . '%'
)
) );
}
}
/**
* Scale the image to the width boundary.
*
* @since 1.0.0.
*
* @param int $width The image's width.
* @param int $height The image's height.
* @param int $width_boundary The maximum width for the image.
* @param bool $retina Whether or not to divide the dimensions by 2.
*
* @return array Resulting height/width dimensions.
*/
private function adjust_dimensions( $width, $height, $width_boundary, $retina = false ) {
// Divide the dimensions by 2 for retina logos
$divisor = ( true === $retina ) ? 2 : 1;
$width = $width / $divisor;
$height = $height / $divisor;
// If width is wider than the boundary, apply the adjustment
if ( $width > $width_boundary ) {
$change_percentage = $width_boundary / $width;
$width = $width_boundary;
$height = $height * $change_percentage;
}
// Height / Width ratio
$ratio = $height / $width * 100;
// Arrange the resulting dimensions in an array
return array(
'width' => $width,
'height' => $height,
'ratio' => $ratio
);
}
/**
* Refresh the logo cache after the Customizer is saved.
*
* @since 1.0.0.
* @since 1.7.0. Changed from global function to method.
*
* @hooked action customize_save_after
*
* @return void
*/
public function refresh_logo_cache() {
$this->get_logo_information( true );
}
}