Mouse events through transparent areas of a PNG image

Create canvas

var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");

Set element listeners:

$(document).on('mousedown mousemove', '.element', function(event) {

	var $element = $(this);

	// Get mouse coordinates
	var x = event.pageX - $element.offset().left,
		y = event.pageY - $element.offset().top,
		w = context.canvas.width = $element.width(),
		h = context.canvas.height = $element.height(),
		alpha;

	// Image creation
});

If image is from <img>:

ctx.drawImage($element, 0, 0, w, h);
alpha = context.getImageData(x, y, 1, 1).data[3]; // [0]R [1]G [2]B [3]A

// Set actions here

If image is from background:

// Get image URL (works for dataURL images)
var backgroundImage = $element.css('background-image');
backgroundImage = backgroundImage.replace('url(','').replace(')','').replace('"','').replace('"','');

// Create image
var image = new Image(w, h);

// Must wait image to load
image.onload = function() {
	context.drawImage(image, 0, 0, w, h);
	alpha = ctx.getImageData(x, y, 1, 1).data[3]; // [0]R [1]G [2]B [3]A

	// Set actions here
}

// Set image source
image.src = backgroundImage;

Set actions:

// If pixel is transparent, retrieve the element underneath and trigger its events
if (alpha == 0) {
	// Hide element, trigger events and the show it again
	$($element).hide();

	// Set cursor from object behind
	$($element).css('cursor', $(document.elementFromPoint(event.clientX, event.clientY)).css('cursor'));

	// Set same listeners
	$(document.elementFromPoint(event.clientX, event.clientY)).trigger(event.type);

	// Show element again
	$($element).show();
} else {
	// Set cursor (optional)
	$($element).css('cursor', 'pointer');

	// Insert other actions here
}
Advertisements

Useful Sass mixins

Transitions

Basic transition mixin

@mixin transition($transition...) {
    -moz-transition: $transition;
    -o-transition: $transition;
    -webkit-transition: $transition;
    transition: $transition;
}

Cache JSON responses using WordPress Transients API

Get transient; if empty, get new data.

$transient_key = 'my-transient-key'; 
$data = get_transient( $transient_key ); 

if ( false === ( $data = get_transient( $transient_key' ) ) ) { 
	$args = array(
		'post_type' => 'brand', 
		'posts_per_page' => 50,
	);
	$data = get_posts( $args );
	set_transient( $transient_key, $data, 12 * HOURS_IN_SECONDS );
}

wp_send_json_success( $data );
wp_die();

Expiration

The third parameter of set_transient is expiration in seconds.

Constants are available:

MINUTE_IN_SECONDS  = 60 (seconds)
HOUR_IN_SECONDS    = 60 * MINUTE_IN_SECONDS
DAY_IN_SECONDS     = 24 * HOUR_IN_SECONDS
WEEK_IN_SECONDS    = 7 * DAY_IN_SECONDS
YEAR_IN_SECONDS    = 365 * DAY_IN_SECONDS

Delete transient when saving

Create a hook:

add_action( 'save_post', 'delete_transient' );

Create a function to delete transients:

function delete_transient() {
	delete_transient( 'transient-key' );
}

Delete multiple transients

If a function can produce different results, transient keys must be different. So, when you need to delete its transients, all keys must be saved somewhere. Let’s save it as an option.

In the JSON request function:

$transients = get_option( 'transients', '' );
if ( '' == $transients || is_string( $transients ) ) {
	$transients = array();
}
$transients[] = $transient_key;
update_option( 'cs_transients', $transients );

The hook function:

add_action( 'save_post', 'delete_transients' );

function delete_transients() {
	$transients = get_option( 'transients' );
	if ( $transients && is_array( $transients ) ) {
		foreach ( $transients as $transient ) {
			delete_transient( $transient );
		}
	}
}

A function to set a new transient may be added, so cache is set before an user accessess the site.

References

Elastic videos

HTML5 video

video {
	max-width: 100%;
	height: auto;
}

iframe, object, embed

CSS:

.video-container {
	position: relative;
	padding-bottom: 56.25%;
	padding-top: 30px;
	height: 0;
	overflow: hidden;
}
.video-container iframe,
.video-container object,
.video-container embed {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}

HTML:

Source

Spiderfy markers on same position with Leaflet.markercluster

Considering a map set as:

map = new L.Map( map_id, {
	minZoom: 10,
	maxZoom: 18,
});

Set cluster group, disabling clustering after maxZoom, so spiderfy will be still on:

clusterGroup = L.markerClusterGroup({
	disableClusteringAtZoom: map.options.maxZoom + 1,
});

Set listener:

clusterGroup.on( 'clusterclick', function ( a ) {
	if ( map.options.maxZoom == a.layer._zoom ) {
		a.layer.spiderfy();
	}
});

So, if you are at maximum zoom and markers are still clustered, it spiderfies on click.

References

StackOverflow, Limit Zoom level when markers are on the same position

Add title tag automatically in WordPress

Basic implementation

On functions.php:

add_theme_support( 'title-tag' );

<head> must not have any <title> tag declared.

Backwards compatibility

In case WordPress version is less than 4.1:

if ( ! function_exists( '_wp_render_title_tag' ) ) {
	function theme_slug_render_title() {
?>
<title><?php wp_title( '|', true, 'right' ); ?></title>
<?php
	}
	add_action( 'wp_head', 'theme_slug_render_title' );
}

Custom queries

Custom queries depends on type of query, so title may be rendered in a wrong way.

add_filter( 'document_title_parts', 'change_title_part', 10 );

function change_title_part( $title ) {
	if ( get_query_var( 'favorites' ) ) {
		$title['title'] = 'Favorites';
	}
	return $title;
}

Sources