WooCommerce check if product in cart is in stock

Check if product in cart is in stock:

foreach (WC()->cart->cart_contents as $item) {
    $product_id = isset($item['variation_id']) ? $item['variation_id'] : $item['product_id'];
    $product = new \WC_Product_Factory();
    $product = $product->get_product($product_id);
    if ($item['quantity'] > $product->get_stock_quantity()) {
        $inStock = false;
        break;
    }
}

Custom PHP errors with int value

I needed custom PHP errors set via .htaccess

<IfModule mod_php5.c>
php_value error_reporting 674
</IfModule>

According to docs about errors predefined constants I had to add the values of errors I wanted to see.
Inspiration for the number came from comment.

So I ran it via CLI (fastest possible way I think)

php -r 'echo E_WARNING | E_USER_WARNING | E_CORE_WARNING | E_COMPILE_WARNING;'

and finally got the int value I needed.

Improving PHP autocompletion in VIM

After watching VIM as PHP IDE I revisited my config, specifically pimped ctags according to articles Vim Autocompletion for PHP and Exuberant ctags with PHP in Vim

So my current $HOME/.ctags is:

--recurse
--languages=php
--langmap=php:.inc.php
--fields=+aimS
--PHP-kinds=+cfd
--exclude=.svn
--exclude=.git
--exclude=cache
--exclude=tags
--exclude=min
--exclude=\*.min.\*
--exclude=node_modules
--regex-PHP=/abstract class ([^ ]*)/\1/c/
--regex-PHP=/interface ([^ ]*)/\1/c/
--regex-PHP=/trait ([^ ]*)/\1/c/
--regex-PHP=/(public |static |abstract |protected |private )+ function +([^ \(]*)/\2/f/

Using PHPloy for PHP project deployment in sync with GIT repo

Finally had some time to work on my deployment workflow and its automation.

Special thanks to Baki for PHPloy I think it might be a good candidate for Continuous Delivery solution for some use cases.

Made a simple screencast using it (no sound, enjoy it with your favourit music 🙂

For a more robust tool check out deployer

Link checking as cache warmup or integration testing

Sometimes I use wget awesome recursive spidering (crawling) feature (alternative to linkchecker) beside broken link check also for cache warmup or looking for PHP errors after commit.

On production for some projects I use PHP error logging into separate log directory per day:

if (!is_dir(DOC_ROOT.'/log')) {
    mkdir(DOC_ROOT.'/log');
}

ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', DOC_ROOT.'/log/php-error-'.date('d').'.log');

So after crawling I check if there is a log file.
And the wget shell script that crawls the site is:

#!/bin/bash

timestamp=$(date +"%Y%m%d%H%M%S")

cd /tmp
time wget -4 --spider -r --delete-after \
     --no-cache --no-http-keep-alive --no-dns-cache \
     -U "Wget" \
     -X/blog \
     http://www.example.com -o"/tmp/wget-example-com-$timestamp.log"

During the crawling your site is hit and cache is generated if you have some implemented, for example phpFastCache.
I just only crawl via IPv4 without HTTP keep alive (only for better performance). Setting some unique user agent is good for parsing in access_log, too.
-X stands for excluding, also handy for improving performance on large sites.
-o outputs the wget status report where you can search for HTTP status codes as 404, 403, 500, etc.
Remember the excluded path, you might run another wget in parallel if you need. Unfortunately wget can’t run parallel threads as of writing.

Compiling Xdebug for PHP

While I’m not sticking to Arch Linux’s PHP (it’s version 7 by default a long time) so I had to compile Xdebug for my PHP version. Great thing at xdebug’s site is that they provide a wizard which parses the pasted php.ini and outputs an install instruction list 🙂

For me the following worked like charm:

  1. Download xdebug-2.4.0.tgz
  2. Unpack the downloaded file with tar -xvzf xdebug-2.4.0.tgz
  3. Run: cd xdebug-2.4.0
  4. Run: phpize (See the FAQ if you don’t have phpize).As part of its output it should show:
    Configuring for:
    PHP Api Version:         20131106
    Zend Module Api No:      20131226
    Zend Extension Api No:   220131226
    

    If it does not, you are using the wrong phpize. Please follow
    this FAQ entry and skip the next step.

  5. Run: ./configure
  6. Run: make
  7. Run: cp modules/xdebug.so /usr/lib/php/modules
  8. Edit /etc/php/php.ini and add the line
    zend_extension = /usr/lib/php/modules/xdebug.so
  9. sudo systemctl restart httpd.service

Oh yeah
Xdebug 2.4

Get Facebook Page likes count via PHP with access_token

Today I had to figure out how to fetch again Facebook Page likes via PHP. Friends from FB changed the API and it was now saying An access token is required to request this resource. for the old API call. Accessing the data requires access_token from now on. Reading the docs https://developers.facebook.com/docs/graph-api/reference/page#Reading I found that a page access token exists.

How to get that page access token?

First you gonna need your FB id, visit https://developers.facebook.com/tools/explorer?method=GET&path=me& (should be the first id) Next you need to grab via API call /YOUR_FB_ID/accounts https://developers.facebook.com/tools/explorer?method=GET&path=YOUR_FB_ID%2Faccounts& After this magic should happen and you should see access_tokens for pages you manage. Now with the access token you can get data via the following URL https://graph.facebook.com/v2.3/FB_PAGE_ID?access_token=PAGE_ACCESS_TOKEN The output is a json which you can decode with PHP function json_decode().

UPDATE
I’ve got the following message: Error validating access token: Session has expired on Saturday, 20-Jun-15 00:00:00 PDT.
Token expired :/ You can check yours at https://developers.facebook.com/tools/debug/accesstoken?q=
I made a never expiring page access token thanks to https://www.rocketmarketinginc.com/blog/get-never-expiring-facebook-page-access-token/

FB neves expiring page access token

PHP error_reporting per directory with htaccess

Finally figured it out how to set custom error_reporting in specific directory without changing the global configuration, this prevents me from forgetting setting it back.
This is useful when I need to hack something in Joomla or other older CMS 😛

Just add the following line into .htaccess:

php_value error_reporting 6135

For figuring out the suitable integer for your needs check http://stackoverflow.com/a/3758453/289404

Symfony Components in Legacy Code

I just watched PHPNW13 Saturday Track 3 Talk 4: Hugo Hamon – Bringing the Symfony Components into your Legacy Code. The talk was great with the example slides.
Also the mentioned tools phploc (PHP Lines Of Code perhaps 🙂 and phpcpd (PHP Copy/Paste Detector) are great.

UPDATE 2015-04-05: Jakub Zalas posted his research data about Symfony adoption

PHPloc example output:

phploc 2.1.0 by Sebastian Bergmann.

Directories 280
Files 1426

Size
 Lines of Code (LOC) 263934
 Comment Lines of Code (CLOC) 46562 (17.64%)
 Non-Comment Lines of Code (NCLOC) 217372 (82.36%)
 Logical Lines of Code (LLOC) 90186 (34.17%)
 Classes 66072 (73.26%)
 Average Class Length 39
 Minimum Class Length 0
 Maximum Class Length 17069
 Average Method Length 4
 Minimum Method Length 0
 Maximum Method Length 1999
 Functions 4640 (5.14%)
 Average Function Length 6
 Not in classes or functions 19474 (21.59%)

Cyclomatic Complexity
 Average Complexity per LLOC 0.35
 Average Complexity per Class 14.18
 Minimum Class Complexity 1.00
 Maximum Class Complexity 10218.00
 Average Complexity per Method 2.58
 Minimum Method Complexity 1.00
 Maximum Method Complexity 1542.00

Dependencies
 Global Accesses 9177
 Global Constants 5986 (65.23%)
 Global Variables 720 (7.85%)
 Super-Global Variables 2471 (26.93%)
 Attribute Accesses 34977
 Non-Static 34535 (98.74%)
 Static 442 (1.26%)
 Method Calls 17084
 Non-Static 16260 (95.18%)
 Static 824 (4.82%)

Structure
 Namespaces 1
 Interfaces 0
 Traits 0
 Classes 1667
 Abstract Classes 9 (0.54%)
 Concrete Classes 1658 (99.46%)
 Methods 13905
 Scope
 Non-Static Methods 13662 (98.25%)
 Static Methods 243 (1.75%)
 Visibility
 Public Methods 13589 (97.73%)
 Non-Public Methods 316 (2.27%)
 Functions 728
 Named Functions 727 (99.86%)
 Anonymous Functions 1 (0.14%)
 Constants 861
 Global Constants 487 (56.56%)
 Class Constants 374 (43.44%)