Use WordPress as a CMS in an AngularJS application: part 1

My most recent project is a large AngularJS, which ties into a custom API to push and pull the main application data. The majority of the text will be coded into the templates, but there’s a lot of text on the home, help pages, etc.

The options

  1. Write a custom CMS to push content into Angular (do I really need to reinvent that wheel?)
  2. Hard-code all the content (urgh)
  3. Something else…

Something else

I could use something like Thermal to pull the content into an AngularJS template,  but then I’d miss out on half of the functionality in Advanced Custom Fields and end up re-building the templates. If WordPress were powering a large portion of the site this might be the best option, but we’re only using a few basic pages.

The way I’ve gone, the static pages are rendered using WordPress, then loaded into the ng-view asynchronously by Angular. For the routing:

angular.module('app').config(['$routeProvider', function($routeProvider) {
    $routeProvider.when("/help", {
        templateUrl: "/help?content"
    });
}]);

When Angular loads /help it makes a request to /help?content from WordPress. The important part here is ?content, which I’ve coded into the header.php and footer.php to prevent them from showing. Without this Angular loads into the ng-view and causes an infinite loop.

if (isset($_GET['content'])) return;

The beauty of this approach is that all of my CMS pages still load as intended by WordPress when visited by search engines and browsers without Javascript.

In part 2, I’ll cover the method I’ve used to avoid hard-coding all my URLs in routes.

Newsletter module is required in Magento

It’s not listed in the dependencies, but Magento’s Customer module requires the Newsletter module in order to show the admin interface.

Unlike most dependencies, this one won’t cause an error as soon as you remove the dependent module, instead simply breaking the customer page within the admin.

Products not showing in Magento search

So you’ve got a Magento store, you’ve added and enabled your product. You’ve set the visibility to ‘Catalog, Search’ but it still doesn’t show when you search for it.

It turns out that if your product is not assigned to the root category for your store it will not appear in search results. This is the case even if you’ve assigned it to one or more sub-categories.

Find the current tax rate in Magento

If you need to calculate your own prices with or without tax (you might be inserting orders…) you can use the following to grab the current tax rate.

$tax_rate = Mage::getModel('tax/calculation_rate')->loadByCode('UK')->rate;

Missing catalog page titles

If your product detail and listing pages are only showing Magento’s default page title it might be because you’ve removed the breadcrumb from the layout XML.

For some reason it appears that this is how the title is set.

Set Zend Framework configuration in PHP

A lot of the examples given for Zend Framework applications suggest that you add configuration to your application.ini file to enable functionality. But if you work collaboratively it’s a hassle to keep your configuration files in sync, especially if they cannot be checked in to version control because they include database configuration.

However, it is possible to set these values in your code if you’re using Zend_Application by calling something like:

$app = new Zend_Application();
$options = array(
    'resources' => array(
        'modules' => array()
    )
);
$app->setOptions($options);

Magento grid: filter by calculated column

If you have a custom column with a Magento grid containing a calculated value (perhaps it’s pulled from another model, or a concatenation of a few fields) you won’t be able to filter on it using the built-in tool.

However, you can hack into the process and find the matching rows yourself, while keeping the standard user interface.

Within your Grid.php, modify your _prepareCollection() method with the following.

class My_Items_Block_Adminhtml_Items_Grid extends Mage_Adminhtml_Block_Widget_Grid {

	protected function _prepareCollection()
	{

		$items = Mage::getModel('my/item_collection');

		// Copied from Mage_Adminhtml_Block_Widget_Grid to avoid 
		// calling parent::_prepareCollection twice.
		// We only want the filter part of it, not the collection loading.
		$filter   = $this->getParam($this->getVarNameFilter(), null);

		if (is_null($filter)) {
			$filter = $this->_defaultFilter;
		}

		if (is_string($filter)) {
			$data = $this->helper('adminhtml')->prepareFilterString($filter);
			$this->_setFilterValues($data);
		}
		else if ($filter && is_array($filter)) {
			$this->_setFilterValues($filter);
		}
		else if(0 !== sizeof($this->_defaultFilter)) {
			$this->_setFilterValues($this->_defaultFilter);
		}

		$item_filter = $this->getColumn('products')->getFilter()->getValue();
		if ($item_filter) {

			// Replace this with your own code to find the appropriate IDs
			// $item_filter is the typed-in value and will be null if empty
			$item_ids = array(1, 4, 5, 9, 10);

			$items->addFieldToFilter('item_id', array('in' => $item_ids));

		}

		$this->setCollection($items);
		return parent::_parentCollection();

	}

}

This builds an array of IDs based on the search criteria (you’ll need to bring your own code for that) and searches on that instead.

The good thing about this approach is that it works in conjunction with other column filters like it would in a standard grid.

Force layered categories in Magento

If you develop in Magento it’s difficult to miss the fact that there are 2 sets of category and product models: standard (which I’m calling layered) and flat.

The layered ones are flexible and easily extensible with new attributes, but they are also slow. The flat tables mirror the layered data into a single table, great for query speed but a little inelegant. When you call Mage::getModel('catalog/category'); Magento will load the best type.

The problem comes when you need to find inactive categories since they aren’t compiled into the flat table. If you’re using a cron script, you can trick Magento into thinking you’re within the admin area, which makes it use the layered models.

False admin for Magento

Sometimes you might need to convince Magento that you’re within the admin area when actually you aren’t. Perhaps it’s a cron script, or you’re writing your own admin tool.

To achieve it, simply call:

Mage::app()->getStore()->setStoreId(0);