Categories
Web Development

Loop and Print Page Children Content in WordPress

This is ideal for when you need to loop through pages to create a list or grid of page content.  Wordpress makes this pretty simple for posts, but it’s not so easy for pages.

In this case I am trying to generate a list of all children of the “Ambassadors” page and create clickable links.

Set up the WP Query

<?php
    // Set up the objects needed
    $my_wp_query = new WP_Query();
    $all_wp_pages = $my_wp_query->query(array('post_type' => 'page', 'orderby' => 'menu_order title'));

    // Get the page as an Object
    $ambassadorPage =  get_page_by_title('Ambassadors');

    // Filter through all pages and find Portfolio's children
    $ambassadorPageChildren = get_page_children( $ambassadorPage->ID, $all_wp_pages );
    $childIds = array();
    // Get the IDs so you can loop through a page as normal
    foreach ($ambassadorPageChildren as $childData) {
        $childIds[] = $childData->ID;

    }
    ?>

Loop through the content

<?php // By using a foreach you can use normal printout fields like the_title() etc.
        foreach ($childIds as $childId) { ?>
            <?php $pageloop = new WP_Query("page_id=" . (int) $childId); ?>
                <?php while ( $pageloop->have_posts() ) : $pageloop->the_post(); ?>
                    <div class="small-12 medium-6 large-3 columns">
                        <article id="post-<?php the_ID(); ?>">
                            <a href="<?= get_the_permalink(); ?>"><img src="<?php echo the_post_thumbnail_url(); ?>" alt="<?php the_title(); ?>"></a>
                            <header>
                                <p>Ambassador</p>
                                <h2 class="entry-title"><?php the_title(); ?></h2>
                                <h3><?php echo the_field('ambassador_specialism'); ?></h3>
                            </header>
                            <div>
                                <footer>
                                    <p><a href="<?= get_the_permalink(); ?>">Read More</a></p>
                                </footer>
                        </article>
                    </div>
                <?php endwhile;?>
            <?php wp_reset_postdata(); ?>
        <?php } ?>

 

Categories
Web Development

Releasing Content over Time / Drip Campaign with WordPress

Using the Date Registered field in WordPress you can create a page that releases content over time. In this example we are creating a Drip Campaign for content released in a specific category.

In this example I have set up a category called “Campaigns” and within it I have added subcategories called Week 1, Week 2, Week 3 etc. The goal is that every week a new section will be released, so if the user registered, week 1 is available instantly, then 1 week later week 2 becomes available and so on.

$dateRegistered = strtotime($current_user->user_registered);
$now = date('Y-m-d H:i:s', strtotime('now'));
$categoryId = 99;

$catArgs = array('taxonomy' => 'category', 'parent' => $categoryId, 'hide_empty' => false);
$categories = get_terms($catArgs);
$dripIncrement = 7;
$startNumber = 0;
$counter = 0;
$number = 0;
$weeks = array();

foreach ($categories as $category) {

    if ($counter != 0) {
        $number = $number + $dripIncrement;
    }
    $weeks[$category->term_id] = date('Y-m-d H:i:s', strtotime('+' . $number . ' day', $dateRegistered));
    $counter++;
}

$listStyle = '';
foreach ($weeks as $weekId => $releaseDate) {

    // If is enabled
    if ($now >= $releaseDate) {
        $listStyle .= '
            li.cat-item.cat-item-'. $weekId .',
            li.cat-item.cat-item-'. $weekId .' a
             {
                color: green;
            }
        ';
    } else {
        $listStyle .= '
            li.cat-item.cat-item-'. $weekId .',
            li.cat-item.cat-item-'. $weekId .' a {
                color: red;
                pointer-events: none;
                cursor: default;
            }
        ';
    }
}

The above create a loop for for the subcategories in my Category Id, and using an increment of 7 days it will add one type of css if the registered date is within range and another if it is not. We then take the following and add it before the tag.

<style type="text/css">
    <?= $listStyle ?>
</style>

Finally, we use the WordPress list categories function to print a list of all the subcategories, the $args variable allows to tweak things like printing a title, printing if the subcategory has no content, etc.

<?php
    // List subcategories of Campaign
    $args = array(
        'child_of'            => $categoryId, // 10 Week Plan ID
        'title_li'            => false, // Hide Title
        'hide_empty'          => false
    );
?>

<?php wp_list_categories($args) ?>
Categories
OSX Web Development

Install ext-intl on Mac OSX using homebrew and XAMPP

This was a painful process for me, it took quite a while to figure out why such a simple implementation when using ubuntu, can be so much work in a Mac.

We can’t just install the extension with apt-get like ubuntu, and its not already waiting to be uncommented like in windows, we have to install the the shared object intl.so our selves.  and the easiest way of doing this is by using homebrew and pecl.

Step 1 – Install Homebrew

Homebrew Website: http://brew.sh

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Step 2 – Install Install icu4c

ICU4C Website: http://site.icu-project.org

brew install icu4c

Step 3 – Install Autoconf

More about Autoconf: http://brewformulas.org/Autoconf

brew install autoconf

Step 4 – Install Intl via PECL

PECL Website: https://pecl.php.net

sudo pecl update-channels
sudo pecl install intl

Step 5 – Enable intl.so in php.ini

Go to your php.ini file and at the end, add the following line:

extension=intl.so

This will enable the extension that we have just installed.

Step 6 – Restart your server

Use XAMPP to restart your server, this will reload the php.ini file with the new configuration.

Step 7 – Check it worked!

You can check if Intl was installed successfully by using the following command to list the loaded php modules.  If ‘intl‘ it is listed then it has been successfully loaded.

php -m

I am running php via Terminal and it didn’t work?

One common problem is that terminal is using the the wrong version of php, sometimes a system default is loaded rather than the php version you are using in XAMPP.  First lets check what version we are using:

which php

If you are using XAMPP correctly it should return:

  • /Applications/XAMPP/xamppfiles/bin/php 

If not and it loads from:

  • /usr/bin/php

Then we can temporarily change the path of the default php version to the XAMPP version by running the following in terminal:

PATH="/Applications/XAMPP/xamppfiles/bin:${PATH}"

Now if you run “which php” in terminal again you should get the correct path.

 

 

Categories
Web Development

Integrating Zurb Foundation with Sass into WordPress

1. Installing WordPress locally with a Child Theme.

The first step is to install WordPress locally and setup a child theme. For more information on how to install and setup WordPress check out This Post. Both the style.css and functions.php files should look like the following:

style.css

/*
 Theme Name: Twenty Sixteen Child
 Author: Mammoth
 Author URI: http://www.elegantthemes.com
 Template: twentysixteen
 Version: 1.0.0
*/

functions.php

<?php
add_action( 'wp_enqueue_scripts', 'enqueue_parent_styles' );

function enqueue_parent_styles() {
 //wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css' );
}

As you can see in functions.php the get parent-style has been commented out as we don’t want to inherit any styling.

2. Copy over the ZURB template into WordPress.

Copy all of the root files and drop them into the themes folder. This may take a while dependant on how large the ZURB build is. Once copied the next stage is to move over the dist folder into the child theme you created in step 1, during this stage you can rename the folder to whatever you like in our example we we renamed the dist folder to zurb as you can see in the screenshot below:

screen-shot-2016-09-21-at-15-39-28

To ensure ZURB compiles the project we need to edit the config.yml dist path. In this case we have changed the dist path to the following:

# Gulp will reference these paths when it copies files
PATHS:
 # Path to dist folder
 dist: "twentysixteenchild/zurb"

Now if you run foundation watch within the themes root folder you will see the the project compile.

3. Getting WordPress to load our Zurb files.

The first file we would like to load is our app.css file. To do this navigate to header.php within your child theme and add the following link:

<link rel='stylesheet' href="/wp-content/themes/twentysixteenchild/zurb/assets/css/app.css">

Carry out this process for both your .js files and img files. Now if you open the link for you WordPress build your zurb project should be loaded.

4. Additional Thoughts

Once the process is complete the editing of the design can be carried out by editing the src files located in the root of your themes folder, this would then require you to copy across any html changes within the dist folder to the corresponding .php files.

In addition if you would like to compile just the .css .js and img files and not compile pages or html files, navigate to the gulpfile.babel.js and remove pages from the following:

// Build the "dist" folder by running all of the below tasks
gulp.task('build',
 gulp.series(clean, gulp.parallel(pages, sass, javascript, images, copy), styleGuide));

In addition to this deletion you also need to comment out the following located at the bottom of the gulpfile.babel.js:

// Watch for changes to static assets, pages, Sass, and JavaScript
function watch() {
 gulp.watch(PATHS.assets, copy);
 //gulp.watch('src/pages/**/*.html').on('all', gulp.series(pages, browser.reload));
 //gulp.watch('src/{layouts,partials}/**/*.html').on('all', gulp.series(resetPages, pages, browser.reload));
}
Categories
Web Development

WordPress: Multiple layouts in single.php, depending on post category

This snippet allows you to server different views depending on post category.

if($wp_query->query['category_name'] == 'categoryname1') {
	include_once( 'template1.php' );
} else if($wp_query->query['category_name'] == 'categoryname2') {
	include_once( 'template2.php' );
} else {
	include_once( 'template3.php' );
}

 

Categories
Web Development

CakePHP 3+ .htaccess for troublesome servers

The Ideal .htaccess for CakePHP, with File Compression and Expires headers.

Enable either mod_gzip or mod_deflate for compression.

<IfModule mod_rewrite.c>
	RewriteEngine On	
	Options +FollowSymLinks
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !-f
	# enable symbolic links
	RewriteCond %{REQUEST_FILENAME} !-l
	RewriteRule ^(.+) index.php [L]
</IfModule>

<ifModule mod_gzip.c>
# mod_gzip_on Yes
# mod_gzip_dechunk Yes
# mod_gzip_item_include file .(html?|txt|css|js|php|pl|ctp)$
# mod_gzip_item_include handler ^cgi-script$
# mod_gzip_item_include mime ^text/.*
# mod_gzip_item_include mime ^application/x-javascript.*
# mod_gzip_item_exclude mime ^image/.*
# mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>

<IfModule mod_deflate.c>
        # Insert filter
        SetOutputFilter DEFLATE

        # Netscape 4.x has some problems...
        BrowserMatch ^Mozilla/4 gzip-only-text/html

        # Netscape 4.06-4.08 have some more problems
        BrowserMatch ^Mozilla/4\.0[678] no-gzip

        # MSIE masquerades as Netscape, but it is fine
        # BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

        # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
        # the above regex won't work. You can use the following
        # workaround to get the desired effect:
        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

        # Don't compress images
        SetEnvIfNoCase Request_URI \
        \.(?:gif|jpe?g|png)$ no-gzip dont-vary

        # Make sure proxies don't deliver the wrong content
        Header append Vary User-Agent env=!dont-vary
</IfModule>

## EXPIRES CACHING ##
<IfModule mod_expires.c>
	ExpiresActive On
	ExpiresByType image/jpg "access 1 year"
	ExpiresByType image/jpeg "access 1 year"
	ExpiresByType image/gif "access 1 year"
	ExpiresByType image/png "access 1 year"
	ExpiresByType text/css "access 1 month"
	ExpiresByType text/html "access 1 month"
	ExpiresByType application/pdf "access 1 month"
	ExpiresByType text/x-javascript "access 1 month"
	ExpiresByType application/x-shockwave-flash "access 1 month"
	ExpiresByType image/x-icon "access 1 year"
	ExpiresDefault "access 1 month"
</IfModule>
## EXPIRES CACHING ##

 

Categories
Ubuntu

Clone Entire Website with WGET in Terminal

Option 1:

wget --recursive --no-clobber --page-requisites --html-extension --convert-links --domains www.yourdomain.com www.yourdomain.com

Option 2:

wget -r --convert-links --html-extension --no-parent www.yourdomain.com

 

Categories
Web Development

Optimise video for Web using HandbrakeCLI

HandBrakeCLI -i original.mp4 -o output.mp4 --encoder x264 --vb 1800 --ab 128 --maxWidth 1920 --maxHeight 1080 --two-pass --optimize;

No Audio:

HandBrakeCLI -i original.mov -o output.mp4 --encoder x264 -q 28 --audio none --maxWidth 1920 --maxHeight 1080 --two-pass --optimize;

 

Categories
Web Development

Create SEO Friendly urls with this Slugify PHP Method

	/**
	 * slugify
	 * @param string $str
	 * @return mixed
	 *
	 * Converts nasty URLs to clean, SEO friendly ones
	 */
	public function slugify($str) {
	    $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $str);
		$clean = strtolower(trim($clean, '-'));
		$clean = preg_replace("/[\/_|+ -]+/", '-', $clean);
		return $clean;
	}

 

Categories
Web Development

CakePHP3 User Authorisation with Cake Bake

Create Users Table:

CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`role` varchar(20) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

In Terminal, Cake bake the MVC

bin/cake bake model users && 
bin/cake bake controller users && 
bin/cake bake template users &&
bin/cake bake controller --prefix admin users && 
bin/cake bake template --prefix admin users

Load Auth component in App Controller Initialize method:

public function initialize()
{
    $this->loadComponent('Flash');
    $this->loadComponent('Auth', [
    'loginRedirect' => [
    'controller' => 'Users',
    'action' => 'index',
    'prefix' => 'admin'
    ],
    'logoutRedirect' => [
    'controller' => 'Pages',
    'action' => 'display',
    'home'
    ]
    ]);
}

Set up password hashing to encrypt the password by going to Model->Entity->User.php

Add the PasswordHasher library after the namespace

use Cake\Auth\DefaultPasswordHasher;

Add the password hasher method:

protected function _setPassword($password)
{
    return (new DefaultPasswordHasher)->hash($password);
}

Add BeforeFilter, Login and Logout method to App Controller

public function beforeFilter(Event $event)
{
    parent::beforeFilter($event);
    // Allow users to register and logout.
    // You should not add the "login" action to allow list. Doing so would
    // cause problems with normal functioning of AuthComponent.
    $this->Auth->allow(['logout']);
}

public function login() {
  if ($this->request->is('post')) {
       $user = $this->Auth->identify();

if ($user) {
    $this->Auth->setUser($user);
    return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Invalid username or password, try again'));
     }
}

public function logout()
{
    return $this->redirect($this->Auth->logout());
}

Create the file login.ctp in Template->Users

<section id="content">

<div class="row">

<div class="large-6 large-centered columns text-center">

<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>

</div>

</section>

Temporarily allow the add method to function without being logged in by addinf the following in Controller->UsersController.php

public function beforeFilter(Event $event) {
    parent::beforeFilter($event);
    $this->Auth->allow('add');
}

Visit myappurl.com/users/add which should show an add user form, fill this in with your details.

Now that we have created a user, remove public access to the add user url in Controller->UsersController.php, remove the line “$this->Auth->allow(‘add’);”.