A A

List of Favorite OS X Web Developer Apps

Sat, Jul 13, 2013

0 Comments

The following tools are either open source, shareware or freeware. For shareware, I will post freeware alternatives.DEVELOPMENT* JetBrains RubyMine (for Ruby and Rails development)

DEBUGGING
* Charles Proxy
* PHP xdebug with remote_enable = true

* SourceTree (if you use git)
* Cornerstone (if you use svn)

PRODUCTIVITY
* iTerm2
* Zshell with Oh My Zsh
* BetterSnapTool
* Mou (Markdown Editor)
* Tabs Outliner extension for Chrome

OTHER
* LittleSnitch
* Skitch
* Dropbox
* SuperDupr! or Time Machine
* RescueTime
* Solarized Theme (for shell, TextMate, etc.)

Remote repository hosting
* BitBucket.org
* GitHub.com
* GitLab.com

A dedicated IDE or Editor. Pimping Your IDE will be in another post. Here are my most used editors/workflows (not in any specific order. Usually the right one for the job.)

MacVim with solarized (light) BG but I’m constantly tweaking the colorscheme. Font is one of Anonymous, Source Code Pro, Consolas, Inconsolata, all patched for powerline (optional.)

I use NeoBundle to manage my vim packages. Here are my current bundles:

" After install, exec ~/.vim/bundle/vimproc, (n,g)make -f your_machines_makefile</pre>
NeoBundle 'Shougo/vimproc'
NeoBundle 'Shougo/vimshell'
NeoBundle 'kien/ctrlp.vim.git'
NeoBundle 'honza/writer.vim'
NeoBundle 'vim-ruby/vim-ruby'
NeoBundle 'plasticboy/vim-markdown'
NeoBundle 'juvenn/mustache.vim'
NeoBundle 'tpope/vim-rails'
NeoBundle 'tpope/vim-fugitive'
NeoBundle 'tpope/vim-unimpaired'
NeoBundle 'tpope/vim-abolish'
NeoBundle 'tpope/vim-surround'
NeoBundle 'tpope/vim-bundler'
NeoBundle 'tpope/vim-surround'
NeoBundle 'tpope/vim-characterize'
NeoBundle 'tpope/vim-haml'
NeoBundle 'tpope/vim-rake'
NeoBundle 'Lokaltog/vim-easymotion'
NeoBundle 'jeetsukumaran/vim-buffergator'
NeoBundle 'tilljoel/vim-automatic-ctags'
NeoBundle 'git://github.com/kchmck/vim-coffee-script.git'
NeoBundle 'altercation/vim-colors-solarized'
NeoBundle 'vim-scripts/Vim-R-plugin'
NeoBundle 'vim-scripts/R-MacOSX'
NeoBundle 'vim-scripts/vim-mou'
NeoBundle 'vim-scripts/ShowMarks'
NeoBundle 'vim-scripts/dbext.vim'
NeoBundle 'vim-scripts/Txtfmt-The-Vim-Highlighter'
NeoBundle 'vim-scripts/mru.vim'
NeoBundle 'vim-scripts/YankRing.vim'
NeoBundle 'majutsushi/tagbar'
NeoBundle 'mileszs/ack.vim'
NeoBundle 'ervandew/screen'
NeoBundle 'L9'
NeoBundle 'Gundo'
NeoBundle 'mattn/zencoding-vim'
NeoBundle 'scrooloose/nerdtree'
NeoBundle 'scrooloose/nerdcommenter'
NeoBundle 'jistr/vim-nerdtree-tabs'
NeoBundle 'nathanaelkane/vim-indent-guides'
NeoBundle 'git://git.wincent.com/command-t.git'
NeoBundle 'git://github.com/Lokaltog/vim-powerline.git'
NeoBundle 'http://svn.macports.org/repository/macports/contrib/mpvim/'
<pre>

Tmux + vim

Send and Receive POST Requests with PHP

Wed, Sep 19, 2012

1 Comment

This can be used to build an API or generally have different sites and scripts communicate externally.



function postback($url, $params, $optional_headers=null, $decode=true) {
$params['handshake'] = HANDSHAKE;
 $params['url'] = $url;
 $params['remote_ip'] = $_SERVER['REMOTE_ADDR'];
 $data = http_build_query($params);

$options = Array('http' => Array(
 'method' => "POST",
 'header'=> "Accept-language: en\r\n".
 "Content-type: application/x-www-form-urlencoded\r\n",
 "Content-Length: " . strlen($data) . "\r\n",
 'content' => $data));

if ($optional_headers !== null) {
 $params['http']['header'] .= $optional_headers;
 }

$ctx = stream_context_create($options);
$fp = fopen($url, 'r', false, $ctx);
 if (!$fp) throw new Exception("Problem with URL '$url' {$php_errormsg}");

$response = stream_get_contents($fp);
 if ($response === false) throw new Exception("Problem reading data from $url, $php_errormsg");

//var_dump($response);
 if ($decode) $response = json_decode(rawurldecode($response), TRUE);

// Invalid query?
 if (!isset($response['handshake']) || ($response['handshake'] !== HANDSHAKE))
 return NULL;

return $response;
}

 

Bulk Upload Images as Simple Products in Magento

Fri, Sep 14, 2012

0 Comments

The client has thousands of images, each of which is a (simple) product they want in Magento. Each image is named the associated product’s SKU number with a JPG extension. I began by using a recorded Batch script in Photoshop to resize all the images to reduce filesize and make the image more web-friendly.

The following Ruby script generates a Magento Product CSV file from JPG images in a directory. It is pasted as-is.

#!/bin/env ruby

require 'rubygems'
require 'csv'
require 'htmlentities'
require 'uri'


def main
    #Dir.glob("media/products/#{catname}/*").each_with_index do |imgpath, i|

    # Magento 1.7 CSV product headers
    csv_headers = '"store"	"websites"	"attribute_set"	"type"	"category_ids"	"sku"	"has_options"	"name"	"meta_title"	"meta_description"	"image"	"small_image"	"thumbnail"	"url_key"	"url_path"	"custom_design"	"page_layout"	"options_container"	"image_label"	"small_image_label"	"thumbnail_label"	"country_of_manufacture"	"msrp_enabled"	"msrp_display_actual_price_type"	"gift_message_available"	"price"	"special_price"	"weight"	"msrp"	"status"	"visibility"	"Featured"	"Deal"	"Hot"	"enable_googlecheckout"	"tax_class_id"	"is_recurring"	"description"	"short_description"	"meta_keyword"	"custom_layout_update"	"news_from_date"	"news_to_date"	"special_from_date"	"special_to_date"	"custom_design_from"	"custom_design_to"	"qty"	"min_qty"	"use_config_min_qty"	"is_qty_decimal"	"backorders"	"use_config_backorders"	"min_sale_qty"	"use_config_min_sale_qty"	"max_sale_qty"	"use_config_max_sale_qty"	"is_in_stock"	"low_stock_date"	"notify_stock_qty"	"use_config_notify_stock_qty"	"manage_stock"	"use_config_manage_stock"	"stock_status_changed_auto"	"use_config_qty_increments"	"qty_increments"	"use_config_enable_qty_inc"	"enable_qty_increments"	"is_decimal_divided"	"stock_status_changed_automatically"	"use_config_enable_qty_increments"	"product_name"	"store_id"	"product_type_id"	"product_status_changed"	"product_changed_websites"'

    path = "output.csv"
    open(path, 'w') { |f| f.puts csv_headers } 

    Dir.glob("*.JPG").each_with_index do |imgpath, i|
        image_name = File.basename(imgpath)
        image_url = "/#{image_name}"
        sku = image_name[0,image_name.size-4]
        name = sku
        desc_short = sku
        desc = sku
        csv = '"default"	"base"	"Default"	"simple"	"2"	"SKU"	"0"	"NAME"	"META_TITLE"	"META_DESC"	"IMAGE"	"IMAGE"	"IMAGE"	"url-key-SKU"	"url-key-SKU"	""	"No layout updates"	"Block after Info Column"	""	""	""	" "	"Use config"	"Use config"	"No"	"1.0000"	"China"	"1.0000"	""	"Enabled"	"Catalog, Search"	"0"	"0"	"0"	"Yes"	"None"	"No"	"LONG_DESC"	"SHORT_DESC"	"META_KEYWORDS"	""	""	""	""	""	""	""	"10000.0000"	"0.0000"	"1"	"0"	"0"	"1"	"1.0000"	"1"	"0.0000"	"1"	"1"	""	""	"1"	"0"	"1"	"0"	"1"	"0.0000"	"1"	"0"	"0"	"0"	"1"	"NAME"	"0"	"simple"	""	""'
        csv.gsub!('SKU', sku)
        csv.gsub!('NAME', name)
        csv.gsub!('LONG_DESC', desc)
        csv.gsub!('SHORT_DESC', desc_short)
        csv.gsub!('META_TITLE', sku)
        csv.gsub!('META_DESC', sku)
        csv.gsub!('META_KEYWORDS', sku)
        csv.gsub!('IMAGE', "#{image_url}")
        open(path, 'a') { |f| f.puts csv } 
    end

    p "Finished."
end

main


=begin

#require 'yaml'
#require 'hpricot'
#require 'tempfile'
#require 'mechanize'
#require 'open-uri'
#require 'highline/import'
#HighLine.track_eof = false

class Importer
  def initialize
    CSV.foreach('/Users/bluish/Desktop/export_ish.csv') do |row|
      p row.inspect
    end
    return
    
    CSV.open('/Users/bluish/Desktop/export_ish.csv', 'wb') do |csv|
      p 'injecting csv'
      csv << ['123', '', '456'] 
    end
  end
end

class String
  def decode
    HTMLEntities.new(:expanded).decode(self)
  end

  def encode
    #HTMLEntities.new(:expanded).encode(self)
    URI::escape(self)
  end
end
 
def saveImage(remote_url, thumb_url, dir='./media/import')
  require 'open-uri'
    begin
        base = File.basename(remote_url)
        img = "#{dir}/#{base}"
        
        unless File.exist? img
          p img
          open(img, 'wb') do |file|
            file << open(remote_url).read
          end
        end 
        
        thumb =  "#{dir}/thumb-#{base}"
        unless File.exist? thumb
          p thumb
          open(thumb, 'wb') do |file|
            file << open(thumb_url).read
         end
        end
        
        p "GOT MEDIA"

    rescue
       p "FAILED to grab #{remote_url}"
       p "or #{thumb_url}"
       p 'Possible 404? continuing...'
    end
end           

=end



Add Items to Category Programmatically in Magento

Wed, Sep 12, 2012

0 Comments

The code on the bottom will take the following array:

$categories = array(
#   "nickname" => category_id,
    "Eyeliner" => 107,
    "Lipstick" => 108,
    "General" => 18,
#   etc.
);

The $lineItems array contains a line of category+sku-items in the format “CategoryNick SKU1 SKU2 SKU3.” CategoryNick is matched against the $categories array above to figure out the Magento category ID. If the product is already in the category, it doesn’t do anything. The product will retain the categories it is already associated with rather than dropping the existing category associations.

$lineItems = Array();
$lineItems[] =     "Eyeliner 7897";
$lineItems[] =     "Eyeliner 7898 7772 7771 7770";
$lineItems[] =     "Lipstick 7909-15 7909-16 7939 7941 7984";
$lineItems[] =     "General 7940"; 

This is the full code. It should be placed in a /filename.php file and visited at /filename.php – Make a backup of your database before using this (and daily!) Don’t keep executable PHP files hanging around after use. If you need to, make sure the permissions are 600 or 700 and NOT world-writable or rename to .phps so they aren’t executable by web

<?php
define('MAGENTO', realpath(dirname(__FILE__)));
require_once MAGENTO . '/app/Mage.php';
Mage::app();

# assign duct tape to all categories
function FindBySku($sku) {
    return Mage::getModel('catalog/product')->loadByAttribute('sku', $sku);
}

function AddToCategory($product, $newcat, $save=false) {
    $cats = $product->getCategoryIds();

    # Don't double categories
    if (in_array($newcat, $cats)) return;

    $cats[] = $newcat;

    $product->setCategoryIds($cats);
    if ($save) return $product->Save();
}

# CHANGE ME
# 3 categories nicknamed and linked to respective Magento IDs
$categories = array(
    "Eyeliner" => 107,
    "Lipstick" => 108,
    "General" => 18,
);

# CHANGE ME
# Add 5 items to the Eyeliner category (107), 5 to Lipstick and 1 to General.
$lineItems = Array();
$lineItems[] =     "Eyeliner 7897";
$lineItems[] =     "Eyeliner 7898 7772 7771 7770";
$lineItems[] =     "Lipstick 7909-15 7909-16 7939 7941 7984";
$lineItems[] =     "General 7940"; 

foreach($lineItems as $line) {
    $pieces = explode(' ', $line);
    $cat = $pieces[0];

    #$skus = implode(' ', $pieces);
    #$skus = substr($skus, strpos($skus, ' ')+1, strlen($skus) - strlen($cat));
    # $cat is the category NickName and $skus is a space-delimited list of SKU #s

    $skus = array_slice($pieces, 1);
    # $cat is the category NickName and $skus is an array of SKU numbers

    if (array_key_exists($cat, $categories) && $categories[$cat] != 0) {
        $cat_id = $categories[$cat];
        echo "Adding to category $cat (id = $cat_id)\n";
        echo '\tAdding ' . sizeof($skus) . " SKUs\n";
        #$item_skus = explode(" ", $skus);
        $i = 0;

        foreach($skus as $sku) {
            $product = FindBySku($sku);
            if (!$product) {
                echo "** ERROR: NO PRODUCT FOUND SKU=$sku\n";
                continue;
            }
            AddToCategory($product, $cat_id, true);
            ++$i;
            echo "\tadded $sku to $cat ";
        }

        echo "\nTOTAL $i/" . sizeof($skus) . " items to $cat\n\n";
    } else {
        echo "** ERROR: CANNOT FIND CATEGORY '$cat'\n\n";
    }
}

?>                            

Using Rsync to Copy Remote Files to Local Machine on OS X / Linux

Mon, Sep 3, 2012

0 Comments

The following is used to copy files from a remote server to your local machine using Rsync to keep both synchronized. This is useful for things like backing up important directories on your web server to your external hard drive or elsewhere.

Rsync can incrementally synchronize files between two locations whether local or remote. This means only the updated files on your remote server are updated on your local machine.

From here on in I assume you’re using OS X but this should work on Linux as well. Press CMD+Space to open a Terminal (I use TotalTerminal.) At the command prompt, just use the following:

#!/bin/sh
rsync -a -e "ssh" --rsync-path="sudo rsync -vau " remoteusername@remote.host.com:/home .
rsync -a -e "ssh" --rsync-path="sudo rsync -vau " remoteusername@remote.host.com:/var .
rsync -a -e "ssh" --rsync-path="sudo rsync -vau " remoteusername@remote.host.com:/etc .

This will copy /home, /var, and /etc from your remote machine to the current directory.

Installing Alan Storm’s LayoutViewer in Magento (works with 1.7!)

Tue, Aug 21, 2012

0 Comments

I use the debug toolbar but nothing beats Alan Storm’s configviewer and layoutviewer. Unfortunately the only archive of this on Alan’s site is missing a module config file to activate it. Below is a simple shell script to download, install and activate the LayoutViewer in any version of Magento. I can confirm it works flawlessly in Magento 1.7. If you’d like to manually install this module, read the “manual installation” section below.

Script

#!/bin/sh

#VIEWER_HTTP_DOWNLOAD="http://alanstorm.com/2005/projects/MagentoLayoutViewer.tar.gz"
VIEWER_HTTP_DOWNLOAD="http://biodegradablegeek.com/MagentoLayoutViewer.tar.gz"

# If in root, go to app/code/local
if [ -f "index.php" ]; then
    cd app/code/local;
fi

echo "Using curl to download Magento LayoutViewer"
curl -so - $VIEWER_HTTP_DOWNLOAD | tar xvzf -

echo "Writing app/etc/modules/ config file"
(
cat <<'ConfigFile'
<?php xml version="1.0"?>
<config>
<modules>
 <Alanstormdotcom_Layoutviewer>
   <active>true</active>
   <codePool>local</codePool>
 </Alanstormdotcom_Layoutviewer>
</modules>
</config>
ConfigFile
) > ../../etc/modules/Alanstormdotcom_Layoutviewer.xml

echo "Done. Visit any page with ?showLayout=page"

Save this to a file and run “sh” in your Magento root.

Manual Installation

Download the MagentoLayoutViewer and extract the Alanstormdotcom folder to [magento-root]/app/code/local/

Create a new config file in app/etc/modules/ named Alanstormdotcom_Layoutviewer.xml  and paste in it the following:

<?php xml version="1.0"?>
<config>
<modules>
 <Alanstormdotcom_Layoutviewer>
   <active>true</active>
   <codePool>local</codePool>
 </Alanstormdotcom_Layoutviewer>
</modules>
</config>

Done. See usage below.

Module Usage

Visit any URL with ?showLayout=page (or handle or package) to retrieve the layouts XML

The module also accepts a showLayoutFormat=text argument if you’d like plain text instead of XML.

Example: http://my-store.cxm/product/123?showLayout=page&showLayoutFormat=text