Web Programming

Realto Theme Plus dsIDXpress Plugin Results in Double Thumbnails

Friday, October 16th, 2015

We were recently approached by a client who was having a problem with a site they were building. They are using the Realto theme, plus the dsIDXpress plugin.

The site was experiencing double / duplicate thumbnails for the home slideshow, which is clearly a problem, especially since it caused the thumbs to not correspond to the correct slide.

Through some troubleshooting, we discovered that both the plugin and the theme are loading the jquery files for the Cycle2 slideshow. With two scripts running on the same slideshow, it caused this duplicate behavior. The solution was clear: remove one of the two scripts from being loaded.

Possible solutions included:
1. Removing / Commenting out the code that loads the script in the IDX plugin. (Bad plan, because the next time the plugin is updated, the code will re-appear, and the problem will happen again).
2. Removing/ Commenting out the code that loads the script in the Realto theme. (Also a bad plan, but less so than #1, since themes usually get updated less frequently than plugins).
3. Write a plugin to de-enqueue the script. This is viable and clean, but not ideal (more work, plus another plugin in the system).
4. Fortunately, the client was using a Child Theme, so we were able to use this clean / viable solution, without adding more plugins: de-enqueue the script in the Child Theme’s function file. (This would not have been possible if the client was not using a child theme).

For reference, here’s the code that we simply added to the child theme’s functions.php file:

add_action('wp_print_scripts', 'realto_cleanup_scripts');

function realto_cleanup_scripts() {
	 wp_dequeue_script( 'nt-jquery.cycle2.min' );
}

If you needed to make this a plugin, it would actually be a simple matter. Create a new file (no need to put it in a folder), title the file something like “realto-dequeue-script.php”, and add the below code to the file. Drop it into the wp-content/plugins folder, activate the plugin, and voila!

/*
Plugin Name: Realto Remove Cycle2 
Plugin URI: http://www.alphachannelgroup.com/
Description: This plugin de-enqueues the Cycle 2 slideshow script.
Author: Alpha Channel Group
Author URI: http://www.alphachannelgroup.com/
Version: 1.0
*/

add_action('wp_print_scripts', 'realto_cleanup_scripts');

function realto_cleanup_scripts() {
	 wp_dequeue_script( 'nt-jquery.cycle2.min' );
}

Migrating a Single Site from One WordPress MultiSite to Another

Tuesday, October 28th, 2014

For Developers or Power Users

Warning: This article is designed for developers, or the technically experienced.  You should be comfortable working in databases, and utilizing FTP.

Overview:

We need to move a single site from within a WordPress MultiSite to another WordPress MultiSite.  The site is completely set up, including plugins, widgets, theme options, and other settings.

We want to preserve as much of the data as possible, without hosing the complete installation.

Note: for convenience sake, we used the following terms:

Source Install – the original site, that we are moving somewhere else

Target Install – the new site location, where the source site will be moved.

Steps:

None of the import / export that we have found tools cover this scenario, so we have developed a process:

  1. Set up the new site in your Target MU Install.  Take note of the site ID (prefixed in all of the database tables).  This will be referred to as the Target Site ID.
  2. In your existing Source Install, take note of the site ID.  This will be referred to as the Source Site ID.
  3. By accessing the database (for example, using phpMyAdmin), export the tables in your Source Install.  Only export those that pertain to the single site.  They should contain the site ID, for example “wp_3_options”.
  4. Make a comprehensive list of all relevant plugins being used in your Source Install – remember, there’s “network activated” plugins as well as “site-specific” plugins.
    1. FTP the plugins from the Source Install.
    2. FTP the theme from the Source Install.
    3. IMPORTANT: Prior to uploading the database, or trying to visit the site, it’s imperative that all of the plugin / theme files exist on the Target Install.
    4. FTP the plugins and theme to the Target Install.
  5. Open the SQL export file created from step 3 above in your favorite text editor.  Update all table names to reflect the Target Site ID.  Also change them to reflect the table prefix of the Target Install.
    1. Example: if the  Source Site ID is 3, and the Target Site ID is 5, and they both use the same table prefix of “wp_”, then you would find all table names and change them according to the following model:
      1. “wp_3_options” would be updated to “wp_5_options”.
    2. If the table prefix in the Source Install is “wp_'”, and the table prefix in the Target Install is “38921_”, then the example would look like:
      1. “wp_3_options” changes to “38291_5_options”.
    3. We are only using the options table as an example.  Currently there are 9 tables in a WP MU “site”, plus there may be additional tables depending on plugins or your theme.
    4. IMPORTANT: If you aren’t familiar with table prefixes, or any of this seems off, then we recommend you consult with someone familiar with WordPress, particularly Multi Site installations.
  6. In your Source Install, run the following query on your posts table to get a listing of all media / attachments that will need to be manually moved using FTP:
    1. “SELECT * FROM `wp_3_posts` WHERE `post_type` = ‘attachment’
    2. This will list all of your attachments.  This will help you ensure that you know all of the attachments that need to get moved.
    3. Check the source wp-content/uploads folder for a “sites” sub-folder. There should be a sub-folder that is named the same as your site ID, such as wp-content/uploads/site/3.   This would be the media for your specific site.
    4. Using FTP or rsync, move the contents of the uploads folder (wp-content/uploads/sites/3) to your target install (wp-content/uploads/sites/5).
  7. Import the SQL file that you have altered into the Target Install database.

If the site domain is changing, then the following steps may be required.

  1. Run the searchreplacedb tool on the Target Install database to update the site.  Be sure to only select the tables in your migrated site – not the entire database!
  2. After running searchreplacedb tool (available here), you may need to run it again to clean up certain paths.  These may be true for image folders, particularly if the new domain has a path in it, such as :www.mydomain.com/subfolder
  3. If the site domain is changing and you are getting 404 errors when you view the site, you may need to flush the rewrite rules. In a non-MU install, this is done by going in the dashboard to the “Permalinks” page and simply clicking “Save”.  In an MU installation, the only way we are aware of is to deactivate and reactivate the theme.

Test and Tweak

As with anything, some good testing is likely in order.  We have found that the most likely place for mistakes to happen is when running the searchreplacedb tool – be sure the new urls are correct.

 

Notes for future updates:

 

Import External Images plugin

Copy / FTP files from uploads/sites/[Site_id]

run SRDB2 to update images loading from proper site ID.

Remove Duplicate Posts from Custom WordPress Loop

Tuesday, January 14th, 2014

How to: WordPress Remove Duplicate Posts Loop

In WordPress, sometimes you want to run multiple custom queries, but you don’t want the same post to appear in each query. This can happen when you want to feature posts in different categories, but a post may exist in multiple categories, so it is possible for the post to appear under each category.

This article describes the proper way to remove duplicate posts from multiple queries, so that the proper number of posts appear, and the same post won’t appear multiple times.

Find the file you want to edit, and before your custom query, declare a new variable:

/** This is where we are going to store the post ID's for the posts we've already displayed
 * Note: this resets the variable, so be sure to only include it once.
 * Also, if it's included in a template part, beware it may get called multiple
 * times, which would allow posts to be duplicated
 **/
$do_not_duplicate = array();

Then, inside your loop, add each post ID to the $do_not_duplicate variable:

$query = new WP_Query($args);
if ($query->have_posts()) {
    while($query->have_posts()) {
        // Add the post ID to the array
        $do_not_duplicate[] = get_the_ID();

        // Your code to display the post goes here...
    }
}

Finally, to bring it all together, when you are preparing your next custom query arguments, pass in the array into the post__not_in parameter, like so:

$args = array (
    'post_type'        =>  'post',
    'posts_per_page'   => '10',
    'post__not_in'     => $do_not_duplicate
);
$query = new WP_Query($args);

And there you have it! The posts from the second custom loop will not include any duplicates from the first post.

And, you can string this together for multiple custom queries. Just keep adding post ID’s to the variable, and using the post__not_in parameter, and you will be all set. (Note: do not put the first line in the code again, otherwise it will reset the variable, and you will begin getting duplicates again! This line: $do_not_duplicate = array(); resets the variable, so only declare this once at the top of the file).

ACG gets Responsive Web Design for Mobile Devices

Monday, January 13th, 2014

As a web development company, it only seems right that our website should have a responsive web design.

Allowing us to display the same content, utilizing the same markup, images, and styles, we simply added the appropriate media queries, made a few tweaks here and there, and now the site is responsive. It will display properly regardless of the device, or browser window size.

The only weakness in the way that we styled this is that you must be viewing it in Internet Explorer 8 or higher for it to respond properly. But, so long as you are using a browser at least 960 pixels wide, it will still display even in Internet Explorer 8.

While we tested on a variety of mobile platforms, one of the cool tools we used is the Web Developer toolbar for Firefox, which allows us to see the rendering in a variety of sizes quickly, in one page. Check out the screenshots below.

Responsive Web Design for Mobile

Firefox Web Developer tool allows us to see mobile versions of our Responsive Web Design

Responsive Web Design for Tablets

Firefox Web Developer toolbar allows us to see tablet views for our Responsive Web Design

Magento Backorders – Complete with Notifications to Customers

Tuesday, July 2nd, 2013

There’s many articles out there that cover how to enable backorders in Magento, and that is simple enough.

However – there are several pieces of this puzzle that are nowhere brought together for a “full” backorder solution.

This solution allows:

  1. Your products to be set to backordered
  2. You to set a custom notification for the product page
  3. Your customers to be notified in the cart page

Enable Backorders in the Dashboard

  1. Log into your Magento admin dashboard.
  2. Hover over the “System” menu.
  3. Click “Configuration”
  4. On the left-side menu, choose “Catalog”
  5. In the Catalog sub-menu, choose “Inventory”
  6. In the pane on the right, find the select box titled “Backorders”, and choose “Allow Qty Below 0 and Notify Customer”

Now that you’ve enabled backorders, a few things happen.  First, products with a quantity of zero are still displayed, and may still be added to the cart.  However, they do not show any indication of being backordered in the product page, which these next two steps will correct:

Modify Your Theme File to Display a Custom Backorder Message

Find the following theme file:

[your theme]/[your_theme]/template/catalog/product/view/type/default.phtml

Open it up, and you should see a line of code that says

$_product = $this->getProduct()

Add the following code immediately after that line:

 // Backorder message
	$backorder_message = '';
	$inventory =  Mage::getModel('cataloginventory/stock_item')->loadByProduct($_product);

	if((int)$inventory->getQty()<=0 && $inventory->getBackorders()>=1) {
		$backorder_message = '

' . $_product->getData('backorder_message') . '

'; }

Then, immediately below / after the

endif;

line, add this:

echo $backorder_message;

Add the Custom Backorder Message to the Product
The final step in bringing this all together is adding a new attribute to the product that is going to be backordered.

This is simple to do via the Magento dashboard:

  1. Edit the product in question.
  2. On the left menu, choose “Description”
  3. Near the top of the page, click the orange button titled “Create New Attribute”
  4. Important: be sure to set the Attribute code to backorder_message (this is the exact code that the template changes are looking for, so it has to be correct).
  5. Set the rest of the attribute up as desired.
  6. Save the attribute.
  7. The attribute will now be displayed for you to fill in on the product. Enter your custom message.
  8. Save the product.

You may need to reindex in Magento, or clear cache, but when you do, your message will display if, and only if, you have zero quantity (or less) and the site is set to backorder.

Magento Staging Setup Accessing Live Database with SSL Certificate

Saturday, June 22nd, 2013

With a recent project, we needed to get the Magento staging environment on the same server and accessing the same database as the live environment.  There was lots of setup, product adjusting, etc. that needed to be done, and the client didn’t want to have to do it twice.

Setting up the staging environment was fairly straightforward, thanks to the excellent article over at Mag Life.  However, the article didn’t quite get the job done.

The live site, like all good live ecommerce sites should, was using an SSL certificate to provide a secure connection.  However, the SSL was for a fully qualified domain name (www.sitename.com) and the staging site was on a subdomain (dev.sitename.com).  Because the SSL settings are in the database, every time we attempted to hit a secure page, the dev site would no longer load, and instead would attempt to load the live site again.

Additionally, I felt lazy and didn’t want to set up server environment variables like the article at Mag Life, so I made a few other alterations to the code.

When attempting to set this up, follow the directions over at Mag Life, but utilize this code in your Store.php file:

class Alphachannel_Core_Model_Store extends Mage_Core_Model_Store
{

    /**
     *  This function is modified per the Mag Life article.
     *  With one modification to avoid setting server environment variables
     **/
    public function getBaseUrl($type=self::URL_TYPE_LINK, $secure=null)
    {
    	// This is the lazy bit.  Rather than setting 
        // environment variables, just set the url's here
    	$urls = array("www.sitename.com"=>"dev.sitename.com");
        $store_code = $this->getCode();
        $url = parent::getBaseUrl($type, $secure);
        // Several nested ifs are removed from Mag Life version 
        // that deal with the environment variables
        $host = parse_url($url, PHP_URL_HOST);
        if (isset($urls[$host]))
        {
            $url = str_replace('://'.$host.'/', '://'.$urls[$host].'/', $url);
            $url = str_replace("https:", "http:", $url);
                }
        return $url;
    }

    /**
     * This is the same function as the core files, with one 
     * minor alteration to prevent https redirects
     **/
    public function isCurrentlySecure()
    {
        $standardRule = !empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS'];
        $offloaderHeader = trim(Mage::getStoreConfig('web/secure/offloader_header'));

        if ((!empty($offloaderHeader) && !empty($_SERVER[$offloaderHeader])) || $standardRule) {
            return true;
        }

        if (Mage::isInstalled()) {
            $secureBaseUrl = Mage::getStoreConfig('web/secure/base_route_url');
            if ( ! $secureBaseUrl) 
            {
                // Here's our hack.  Lie to tell it is secure!
            	return true;
                return false;
            }
            $uri = Zend_Uri::factory($secureBaseUrl);
            $isSecure = ($uri->getScheme() == 'https' )
                && isset($_SERVER['SERVER_PORT'])
                && ($uri->getPort() == $_SERVER['SERVER_PORT']);
            return $isSecure;
        } else {
            $isSecure = isset($_SERVER['SERVER_PORT']) && (443 == $_SERVER['SERVER_PORT']);
            return $isSecure;
        }
    }
}

And, for a little icing on this cake, check out the simple debugging script I whipped up that made it fast and easy to trace back which class / method is calling the current function: Get the calling function or class method

Get the Calling Function or Class Method

Wednesday, June 19th, 2013

During a recent Magento project, I needed to get the calling class and method from a class that was being called multiple times. Due to the construction of Magento, the simplest way would be to use php’s debug_backtrace function. However, in this case when it was output there were over 82,000 lines of debug information. All I was concerned with was the calling function and class, so trying to wade through all of that information was rather overwhelming.

So, I whipped up this little function that takes care of things quite nicely, even formatting the output in the standard class->method structure:

        $callers=debug_backtrace();
        foreach($callers as $call) {
        	echo "
" . $call['class'] . '->' . $call['function']; }

Textarea Dynamic MaxLength jQuery Plugin

Tuesday, December 11th, 2012

I needed to set the max length of a textarea, but the textarea size was not known beforehand.  That is, some textareas might be large, some might be small, and there was no way to know what size they were.

Since the textareas were part of a situation where the form was absolutely positioned, it was imperative that the user could not enter more information than the textarea size.

Note that modern browsers allow you to resize a textarea – this can be overcome with some simple css:

textarea {
    resize: none;
}

Now that the textarea size is fixed, I just need to limit the amount of text the user can enter, so that it doesn’t overflow the given space.

All of the javascript solutions out there assumed a predefined maxlength for the textarea.  But that’s a bit problematic, too – most fonts aren’t fixed-width, which means that some letters take more space than others.  I wanted to allow completely dynamic, automatic calculation of the space required, and limit the text based on that real information.

So, using some creative programming, I’ve developed a jQuery plugin that can determine the dynamic maximum size of the textarea, and limits the user input to that maximum length.

The code is simple to use. Just include the script file (there’s a link for you below), and then call the following line:

jQuery(function($) {
    $("textarea").textareaMaxLength();
});

And voila! Your textareas magically will limit the amount of text to just the text that fits within the textarea.

How it works

Some of you are going to want to know how it works.  Here you go:

The plugin detects the key-up stroke in a textarea.  When the keyup takes places, it does the following:

  1. It creates a hidden div (off screen) with the same size, shape, and font properties as the textarea.
  2. It adds the text from the textarea to that div
  3. It compares the height of the hidden div (which is allowed to stretch vertically) to that of the textarea.
  4. If the hidden div is taller than the textarea, it trims characters off the end of the input until the height is no longer too tall.
  5. Once the focus has left the textarea (on blur), it removes the div from the DOM.

Using Sessions in WordPress themes and Plugins

Monday, November 12th, 2012

Without hacking core files

WordPress aims to be stateless, so it uses cookies, not sessions.

Which is fine, except for there are things you may need to do that would best be accomplished by tapping into PHP’s sessions.

But, there’s a problem: WordPress iterates over the $_SESSION variable and unsets any session data in wp-settings.php file.

There’s articles out there suggesting editing the wp-settings.php file, but I have a hard and fast rule about not modifying core files for WordPress (or Magento, or Open Cart), because the next time you update your installation (which is important for security), you may wipe your modifications.

There’s a better way.  Why not just hook the session_start AFTER wp-settings.php has run?

Simple as can be with just five lines of code. First, we set up the action to hook into wp-loaded:

add_action('wp_loaded', 'start_my_custom_session');

And then we set our function start_my_custom_session:

function start_my_custom_session() {
	if (!session_id()) {
		session_start();
	}
}

Customizing and Styling Magento Order Confirmation

Monday, July 23rd, 2012

Magento is powerful, but man does it make some things more laborious than they need to be.

Out of the box, Magento’s order confirmation is weak. The client wanted a more robust solution, and after scraping the web for resources and dumping class methods out, I was able to put together a very robust solution.
(more…)