• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

My Monkey Do

A Log of Coding Solutions

  • Home
  • Web Hosts
  • Tools
  • About

google

Free up Email Storage

June 2, 2021 by Webhead

Now that Google Photos is no longer free, Google storage will be eaten up pretty quickly if you’re still using them. One area you can free up some space is your email in gmail.

Search, Select All, Delete

To reduce space, first you would need to find the emails you want to remove. Searching is Google’s specialty so this is no problem. Google lists the search operators you can use on this page. But you can also use some of my hand dandy searches below.

Once you find the emails to delete, you can select all by checking the select all checkbox in the upper left corner, then you can click on “Select all conversations that match this search”.

Now that you have all the email you want to delete selected, click on the Trash icon to delete. You’ll have 30 days to change your mind. After that it will be deleted forever. Of course you can also go into your trash and Delete Forever right now.

Now onto some helpful hand dandy search queries:

Search for the big stuff.

Find all emails with attachments larger than 5mb, 10mb, or larger and older than so many years. A pretty conservative search would be to find attachments 15mb or larger older than 4 years old. To find more mail, reduce the size or the years.

size:15mb has:attachment older_than:4y 

Search for the un important stuff

No one reads all the promotions that reach your mailbox, so why keep them? If your gmail is automatically categorizing emails, you can find all your promotional emails older than so many years and remove them.

category:promotions older_than:2y

Search for that specific one

Sometimes deleting a category may be too much. You can also target emails from specific senders or unread emails.

from:([email protected]) older_than:2y is:unread 

Filed Under: Random Thoughts Tagged With: gmail, google

How to stop redirect from http:// to https:// in Chrome

December 11, 2017 by Webhead

Problem

I’ve been trying like crazy to get to my local website at site.dev, but I keep getting redirected to https://site.dev and of course it doesn’t work because I don’t have a SSL certificate for that domain.

Solution

As of December 2017, Chrome 63, Chrome is forcing all .dev domains to be redirected to HTTPS via a preloaded HTTP Strict Transport Security (HSTS) header.  The .dev TLD is an actual legitimate TLD so you will need to change your local development setup to use something like http://site.localhost .

A more detailed explanation can be found here:

https://ma.ttias.be/chrome-force-dev-domains-https-via-preloaded-hsts/

Filed Under: Coding, Server Stuff Tagged With: chrome, google

Google Analytics Measurement Protocol for Subscriptions

January 11, 2014 by Webhead

Send Analytics Data Directly From Your Server

Google Analytics Measurement Protocol is available for Google’s Universal Analytics.  It was released in the first part of 2013 and is as of this writing still in public beta.  It allows developers to make HTTP requests to send raw data directly to Google Analytics.

Subscription Renewals for eCommerce Sites

I found and used the Measurement Protocol specifically to solve a problem with tracking subscription renewals.  I was using WooCommerce and the Subscription extension as my eCommerce subscription site and found a couple things not working for me when I was using the built-in Analytics eCommerce tracking.

For one, I had Universal Analytics but WooCommerce was using the legacy ga.js analytics.  So nothing was being tracked.

Secondly, the WooCommerce code to track purchases was done on the Thank You page.  While this is fine for normal purchases, I wanted to track renewals via the wp cron jobs also.

How to Use Google Measurement Protocol in WordPress and WooCommerce

First, let me say at the time of this writing there are very little examples on implementing the code.  While Google’s documentation is great, I still had questions.  This post on using the measurement protocol from Stu Miller got me started and almost completed the work for me.  I am in no way an expert at WooCommerce or Subscriptions so I didn’t want to put this code into a plugin.  Also, WooCommerce may soon update their analytics plugin making this code obsolete.

1. The CID – The Client Id

The most confusing thing about the Measurement Protocol is how to link up the user to Google’s “anonymous” user.  As of this writing Google is intending to have a user ID field, but it is not yet available.  From the google groups forum and the documentation, the CID field should be either a UUID Version 4 or their legacy anonymous identifier format “X.Y” where each are 32-bit random numbers.  The X and Y are actually the Google assigned random id and the timestamp which the id was assigned as noted in this stackoverflow post.

So to link a Google Analytics user with your user/subscriber you would need to parse the “_ga” cookie and save the id.timestamp portion like I do in my_ga_parse_user() and my_setup_new_user().

2. The Renewal Order (WooCommerce)

The second most confusing thing (for me anyway) was recording the correct order.  In WooCommerce every subscription renewal creates a new order.  In my case the original order is a 7 day free trial and then $10 every month after that.  So the original order’s total price along with the transaction is $0.  The renewal order should be $10, but analytics was not recording it.  The reason is that when a renewal order is created almost all of the original orders postmeta data is copied into the renewal order.  This means that _ga_tracked is also copied. In my_ga_track_payment() the _ga_tracked postemeta is checked first to make sure an order isn’t recorded more than once.  If this is copied to the renewal order the renewal order will never get tracked.  The function hooked to the  woocommerce_subscriptions_renewal_order_meta_query filter solved this problem.

3. Debugging

I had a tough time trying things out in subscriptions because a renewal order is created once a day at most.  To get around this I created my_ga_debug_next_payment() to speed up the payment process.  This method sets the next payment date to 5 minutes from the current time.  I was using the Stripe payment gateway so I’m not sure if this will work for PayPal or any other gateways.

Here’s the Code

<?php
/**
* See https://groups.google.com/forum/#!msg/google-analytics-measurement-protocol/rE9otWYDFHw/8JlJJV-UmKcJ
* a person from Google says cid should be X.Y format.
* and https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
* Apparently whether hit is recorded or not 200 is returned.
* Returns true if ga was contacted.
*/
function my_ga_fire_hit( $user_id, $data ) {
if ( !defined( 'GOOGLE_ANALYTICS_ID' ) )
return;

$defaults = array(
'v' => 1,
'tid' => GOOGLE_ANALYTICS_ID,
'cid' => my_ga_user_id($user_id)
);

$payload_data = array_merge($defaults, $data);
$endpoint = 'https://ssl.google-analytics.com/collect?';
$parameters = http_build_query( $payload_data );
$result = wp_remote_post( $endpoint . $parameters );
if ( isset( $result['response'] ) ) {
return ( $result['code'] == 200 );
}
return false;
}

/**
* Save the google analytics UUID.
*/
function my_ga_parse_user($my_user_options) {
if ( is_user_logged_in() && isset($_COOKIE['_ga'])) {
$my_user_options = get_user_meta($user_id, 'my_user_options', true);
if ( empty($my_user_options) ) {
list($version,$domainDepth, $id, $ts) = split('[.]', $_COOKIE["_ga"], 4);
$contents = array('version' => $version, 'domainDepth' => $domainDepth, 'cid' => $id . '.' . $ts);

//3rd spot is the cid according to multiple sources
$my_user_options['ga_cid'] = $contents['cid'];

update_user_meta( $user_id, 'my_user_options', $my_user_options);
}
}
}
add_action('template_redirect', 'my_ga_parse_user');

/**
* Return the ga cid. (or what will be called user_id)
*/
function my_ga_user_id($user_id) {
$my_user_options = get_user_meta($user_id, 'my_user_options', true);
$cid = isset( $my_user_options['ga_cid'] ) ? $my_user_options['ga_cid'] : '';
if ( empty( $cid ) ) {
$my_user_options = my_ga_parse_user($my_user_options);
$cid = isset( $my_user_options['ga_cid'] ) ? $my_user_options['ga_cid'] : '';
}
return $cid;
}

/**
* Don't copy over _ga_tracked meta.
*/
function my_ga_remove_renewal_order_meta( $order_meta_query, $order_id ) {
$order_meta_query .= " AND `meta_key` NOT IN ("
. "'_ga_tracked' ) ";
return $order_meta_query;
}
add_filter ( 'woocommerce_subscriptions_renewal_order_meta_query', 'my_ga_remove_renewal_order_meta', 10, 2);

/**
* Let ga know a subscription payment has been processed.
*/
function my_ga_track_payment( $order_id ) {
$order = new WC_Order( $order_id );
if ( empty($order) || get_post_meta( $order->id, '_ga_tracked', true ) == 1 || !defined('GOOGLE_ANALYTICS_ID') )
return;

$tracking_id = GOOGLE_ANALYTICS_ID;
if ( empty( $tracking_id ) )
return;

$user_id = $order->customer_user;

my_ga_fire_hit( $user_id, array(
't' => 'transaction', // Transaction hit type.
'ti' => $order->get_order_number(), // transaction ID. Required.
'ta' => get_bloginfo('name'), // Transaction affiliation.
'tr' => $order->get_total(), // Transaction revenue.
// Transaction shipping. (not required)
'tt' => $order->get_total_tax() // Transaction tax.
) );

if ( $order->get_items() ) {
foreach ( $order->get_items() as $item ) {
$_product = $order->get_product_from_item( $item );
$_category = "";
if ( isset( $_product->variation_data ) ) {

$_category .= woocommerce_get_formatted_variation( $_product->variation_data, true );

}
else {
$out = array();
$categories = get_the_terms($_product->id, 'product_cat');
if ( $categories ) {
foreach ( $categories as $category ){
$out[] = $category->name;
}
}
$_category .= join( "/", $out);
}
$item_name = $item['name'];
// If we have a child renewal order, we need the original order's ID
if ( WC_Subscriptions_Renewal_Order::is_renewal( $order_id, array( 'order_role' => 'child' ) ) ) {
$original_order_id = WC_Subscriptions_Renewal_Order::get_parent_order_id( $order_id );
$original_order = new WC_Order( $original_order_id );
$order_items = WC_Subscriptions_Order::get_recurring_items( $original_order );
if ( !empty( $order_items ) ) {
$order_item = end($order_items);
$item_name = sprintf( __( 'Renewal of "%s"', 'lis' ), $order_item['name'] );
}
}

my_ga_fire_hit( $user_id, array(
't' => 'item', // Transaction hit type.
'ti' => $order->get_order_number(), // transaction ID. Required.
'in' => $item_name, // Item name. Required.
'ip' => $order->get_item_total( $item ), // Item price.
'iq' => $item['qty'], // Item quantity.
'ic' => $_product->get_sku() ? __( 'SKU:', 'woocommerce' ) . ' ' . $_product->get_sku() : $_product->id, // Item code / SKU.
'iv' => $_category // Item variation / category.
) );
}
}

update_post_meta( $order->id, '_ga_tracked', 1 );

}
add_action( 'woocommerce_payment_complete', 'my_ga_track_payment');

/*
// set next payment ot be in 5 minutes.
function my_ga_debug_next_payment() {
$subscription_key = '1234_5678';
$user_id = '1';

$next_payment_date = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $user_id, 'timestamp');
$new_next_payment_date = strtotime("+5 minutes");

if ($next_payment_date > strtotime("+7 minutes") ) {
//update the next payment date for referrer
$ret = WC_Subscriptions_Manager::update_next_payment_date($new_next_payment_date, $subscription_key, $user_id);
}

}
add_action('init', 'my_ga_debug_next_payment');
*/

Filed Under: Coding Tagged With: eCommerce, google, google analytics, php, woocommerce, wordpress

Google CDN

October 3, 2013 by Webhead

A lot of scripts and even styles can be retrieved from google’s cdn.  Save yourself some time, save your server some time, and save your visitors some time.

jQuery UI themes:

http://stackoverflow.com/questions/820412/downloading-jquery-css-from-googles-cdn

Scripts in WordPress:

Use the Use Google Libraries plugin.

Filed Under: Coding, Off the Shelf Tagged With: google, jquery

Z-Index, iFrames, and IE

May 5, 2013 by Webhead

Problem

I’m using the Apprise jQuery plugin to show a fancy alert box on a webpage.  The problem is I also have the embedded iFrame code from YouTube on the page.  When the fancy alert box shows in Internet Explorer, it shows behind the video.  It works in all other browsers.

 

Solution

The solution is to add the wmode=transparent or wmode=opaque parameter to the youtube url.  Have the iframe point to something like the following:

https://youtube.com/watch?v=xyz%3Fwmode%3Dtransparent

 

Source: http://stackoverflow.com/questions/5281002/z-index-and-iframes

Filed Under: Coding Tagged With: google, html, IE crap

HTML 5 Flash Fallback Video Player w/ RTMP

April 24, 2013 by Webhead

There are a ton of video player that use HTML5 with flash fallback.  A few years ago I found one named JW Player.  This was a great player that was fully featured.  Keyword being “was”.  I was developing a website that would be using this player, but for the time being I used the free version of the player because I was hoping for a promo code to show up.  As I was developing the site, the company that owns JW Player upped the price from a simple $79 fee to a yearly $99 fee.  This was a big jump in price and developers complained a whole lot, including myself.  (i got the CEO to respond! woohoo!)  but no changes came of it (as of now anyway).

 

When One Door Closes…

Onto a search for a new javascript player that could do HTML5, Flash fallback, and RTMP streaming when flash is used.  A few players I found were jPlayer, videoJS, MediaElement.js, Flowplayer.  Flowplayer costed about $99(to remove the watermark) plus I wasn’t sure if I needed to purchase the flash player for flash fallback.  Confusion is not good to a potential buyer.  jPlayer was the most popular of the free ones, but I couldn’t get the RTMP to work with my video for some reason.  I got the sample to work, but not mine, weird.  videoJs scared me because I saw a post were the flash fallback used Flowplayer which means I could not use it commercially without purchasing.  Would’ve been a legal disaster if I used it and didn’t pay for it.  MediaElementJs was the only one I had no opinion.  It was actually the least popular of all the open source players.  But then I saw that it would be in WordPress core 3.6!  Case closed.  MediaElement.js would be the replacement.

 

Another one Opens

As it turns out MediaElement does not get Firefox to fallback to flash if I use a mp4 video file.  It simply errors out.  It does however, support the webm format.  The WebM format is sponsored by Google and is supposedly the next industry standard for web videos so it would be a good thing if I converted to it.  I found a free converter called Miro Video Converter to convert my mp4 to webm format.  In the end I have a video player that will be integrated into WordPress, a more standard video format, smaller footprint for HTML5 users (mp4 size: 163mb webm:78mb), and no money spent… but a whole lot of time spent looking for this… oh well, the client wins at least.

 

The Old

JW Player, mp4 format

The New

MediaElementJS (WordPress 3.6), webm format, Miro Video Converter

Filed Under: Off the Shelf Tagged With: firefox, google, html 5, open source, wordpress

  • Go to page 1
  • Go to page 2
  • Go to Next Page »

Primary Sidebar

Topics

apache apple block editor chrome cms css debug eCommerce embed firebug firefox git gmail goDaddy google hosting htaccess html html 5 IE crap image iPad iPhone javascript jquery linux localization mac os x ms sql mysql open source optimize php php 5.3 responsive rest api seo svg tinymce woocommerce wordpress wpengine xss yii youtube




Categories

  • Coding
  • Off the Shelf
  • Plugins
  • Random Thoughts
  • Server Stuff
  • Tools