How to Optimize for Google’s Featured Snippets to Build More Traffic

Posted by AnnSmartyHave you noticed it’s getting harder and harder to build referral traffic from Google?And it’s not just that the competition has got tougher (which it certainly has!).It’s also that Google has moved past its ten blue links and its organic search results are no longer generating as much traffic they used to.How do you adapt? This article teaches you to optimize your content to one of Google’s more recent changes: featured snippets.What are featured snippets?Featured snippets are selected search results that are featured on top of Google’s organic results below the ads in a box.Featured snippets aim at answering the user’s question right away (hence their other well-known name, “answer boxes”). Being featured means getting additional brand exposure in search results. Here are two studies confirming the claim:Ben Goodsell reports that the click-through rate (CTR) on a featured page increased from two percent to eight percent once it’s placed in an answer box, with revenue from organic traffic increasing by 677%.Eric Enge highlights a 20–30% increase in traffic for ConfluentForms.com while they held the featured snippet for the query.Types of featured snippetsThere are three major types of featured snippets:Paragraph (an answer is given in text). It can be a box with text inside or a box with both text and an image inside.List (an answer is given in a form of a list)Table (an answer is given in a table)Here’s an example of paragraph snippet with an image:According to Getstat, the most popular featured snippet is “paragraph” type:Featured snippets or answer boxes?Since we’re dealing with a pretty new phenomenon, the terminology is pretty loose. Many people (including myself) are inclined to refer to featured snippets as “answer boxes,” obviously because there’s an answer presented in a box.While there’s nothing wrong with this terminology, it creates a certain confusion

Read the original post on  MOZ Blog

Link to original source

Implementing Push Notifications: Setting Up & Firebase

You know those the little notification windows that pop up in the top right (Mac) or bottom right (Windows) corner when, for example, a new article on our favorite blog or a new video on YouTube was uploaded? Those are push notifications.

Part of the magic of these notifications is that they can appear even when we’re not currently on that website to give us that information (after you’ve approved it). On mobile devices, where supported, you can even close the browser and still get them.

Article Series:

  1. Setting Up & Firebase (You are here!)
  2. The Back End (Coming soon!)
Notification on Mac via Chrome
Push notification on a Mac in Chrome

A notification consists of the browser logo so the user knows from which software it comes from, a title, the website URL it was sent from, a short description, and a custom icon.

We are going to explore how to implement push notifications. Since it relies on Service Workers, check out these starting points if you are not familiar with it or the general functionality of the Push API:

What we are going to create


Preview of the our push notification demo website

To test out our notifications system, we are going to create a page with:

  • a subscribe button
  • a form to add posts
  • a list of all the previously published posts

A repo on Github with the complete code can be found here and a preview of the project:

View Demo Site

And a video of it working:

Gathering all the tools

You are free to choose the back-end system which suits you best. I went with Firebase since it offers a special API which makes implementing a push notification service relatively easy.

We need:

In this part, we’ll only focus on the front end, including the Service Worker and manifest, but to use Firebase, you will also need to register and create a new project.

Implementing Subscription Logic

HTML

We have a button to subscribe which gets enabled if 'serviceWorker' in navigator. Below that, a simple form and a list of posts:

<button id="push-button" disabled>Subscribe</button>

<form action="#">
  <input id="input-title">
  <label for="input-title">Post Title</label>
  <button type="submit" id="add-post">Add Post</button>
</form>

<ul id="list"></ul>

Implementing Firebase

To make use of Firebase, we need to implement some scripts.

<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase-messaging.js"></script>

Now we can initialize Firebase using the credentials given under Project Settings → General. The sender ID can be found under Project Settings → Cloud Messaging. The settings are hidden behind the cog icon in the top left corner.

firebase.initializeApp({
    apiKey: '<API KEY>',
    authDomain: '<PROJECT ID>.firebaseapp.com',
    databaseURL: 'https://<PROJECT ID>.firebaseio.com',
    projectId: '<PROJECT ID>',
    storageBucket: '<PROJECT ID>.appspot.com',
    messagingSenderId: '<SENDER ID>'
})

Service Worker Registration

Firebase offers its own service worker setup by creating a file called `firebase-messaging-sw.js` which holds all the functionality to handle push notifications. But usually, you need your Service Worker to do more than just that. So with the useServiceWorker method we can tell Firebase to use our own `service-worker.js` file as well.

Now we can create a userToken and a isSubscribed variable which will be used later on.

const messaging = firebase.messaging(),
      database  = firebase.database(),
      pushBtn   = document.getElementById('push-button')

let userToken    = null,
    isSubscribed = false

window.addEventListener('load', () => {

    if ('serviceWorker' in navigator) {

        navigator.serviceWorker.register('https://cdn.css-tricks.com/service-worker.js')
            .then(registration => {

                messaging.useServiceWorker(registration)

                initializePush()
            })
            .catch(err => console.log('Service Worker Error', err))

    } else {
        pushBtn.textContent = 'Push not supported.'
    }

})

Initialize Push Setup

Notice the function initializePush() after the Service Worker registration. It checks if the current user is already subscribed by looking up a token in localStorage. If there is a token, it changes the button text and saves the token in a variable.

function initializePush() {

    userToken = localStorage.getItem('pushToken')

    isSubscribed = userToken !== null
    updateBtn()

    pushBtn.addEventListener('click', () => {
        pushBtn.disabled = true

        if (isSubscribed) return unsubscribeUser()

        return subscribeUser()
    })
}

Here we also handle the click event on the subscription button. We disable the button on click to avoid multiple triggers of it.

Update the Subscription Button

To reflect the current subscription state, we need to adjust the button’s text and style. We can also check if the user did not allow push notifications when prompted.

function updateBtn() {

    if (Notification.permission === 'denied') {
        pushBtn.textContent = 'Subscription blocked'
        return
    }

    pushBtn.textContent = isSubscribed ? 'Unsubscribe' : 'Subscribe'
    pushBtn.disabled = false
}

Subscribe User

Let’s say the user visits us for the first time in a modern browser, so he is not yet subscribed. Plus, Service Workers and Push API are supported. When he clicks the button, the subscribeUser() function is fired.

function subscribeUser() {

    messaging.requestPermission()
        .then(() => messaging.getToken())
        .then(token => {

            updateSubscriptionOnServer(token)
            isSubscribed = true
            userToken = token
            localStorage.setItem('pushToken', token)
            updateBtn()
        })
        .catch(err => console.log('Denied', err))

}

Here we ask permission to send push notifications to the user by writing messaging.requestPermission().


The browser asking permission to send push notifications.

If the user blocks this request, the button is adjusted the way we implemented it in the updateBtn() function. If the user allows this request, a new token is generated, saved in a variable as well as in localStorage. The token is being saved in our database by updateSubscriptionOnServer().

Save Subscription in our Database

If the user was already subscribed, we target the right database reference where we saved the tokens (in this case device_ids), look for the token the user already has provided before, and remove it.

Otherwise, we want to save the token. With .once('value'), we receive the key values and can check if the token is already there. This serves as second protection to the lookup in localStorage in initializePush() since the token might get deleted from there due to various reasons. We don’t want the user to receive multiple notifications with the same content.

function updateSubscriptionOnServer(token) {

    if (isSubscribed) {
        return database.ref('device_ids')
                .equalTo(token)
                .on('child_added', snapshot => snapshot.ref.remove())
    }

    database.ref('device_ids').once('value')
        .then(snapshots => {
            let deviceExists = false

            snapshots.forEach(childSnapshot => {
                if (childSnapshot.val() === token) {
                    deviceExists = true
                    return console.log('Device already registered.');
                }

            })

            if (!deviceExists) {
                console.log('Device subscribed');
                return database.ref('device_ids').push(token)
            }
        })
}

Unsubscribe User

If the user clicks the button after subscribing again, their token gets deleted. We reset our userToken and isSubscribed variables as well as remove the token from localStorage and update our button again.

function unsubscribeUser() {

    messaging.deleteToken(userToken)
        .then(() => {
            updateSubscriptionOnServer(userToken)
            isSubscribed = false
            userToken = null
            localStorage.removeItem('pushToken')
            updateBtn()
        })
        .catch(err => console.log('Error unsubscribing', err))
}

To let the Service Worker know we use Firebase, we import the scripts into `service-worker.js` before anything else.

importScripts('https://www.gstatic.com/firebasejs/4.1.3/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/4.1.3/firebase-database.js')
importScripts('https://www.gstatic.com/firebasejs/4.1.3/firebase-messaging.js')

We need to initialize Firebase again since the Service Worker cannot access the data inside our `main.js` file.

firebase.initializeApp({
    apiKey: "<API KEY>",
    authDomain: "<PROJECT ID>.firebaseapp.com",
    databaseURL: "https://<PROJECT ID>.firebaseio.com",
    projectId: "<PROJECT ID>",
    storageBucket: "<PROJECT ID>.appspot.com",
    messagingSenderId: "<SENDER ID>"
})

Below that we add all events around handling the notification window. In this example, we close the notification and open a website after clicking on it.

self.addEventListener('notificationclick', event => {
    event.notification.close()

    event.waitUntil(
        self.clients.openWindow('https://artofmyself.com')
    )
})

Another example would be synchronizing data in the background. Read Google’s article about that.

Show Messages when on Site

When we are subscribed to notifications of new posts but are already visiting the blog at the same moment a new post is published, we don’t receive a notification.

A way to solve this is by showing a different kind of message on the site itself like a little snackbar at the bottom.

To intercept the payload of the message, we call the onMessage method on Firebase Messaging.

The styling in this example uses Material Design Lite.

<div id="snackbar" class="mdl-js-snackbar mdl-snackbar">
  <div class="mdl-snackbar__text"></div>
  <button class="mdl-snackbar__action" type="button"></button>
</div>
import 'material-design-lite'

messaging.onMessage(payload => {

    const snackbarContainer = document.querySelector('#snackbar')

    let data = {
        message: payload.notification.title,
        timeout: 5000,
        actionHandler() {
            location.reload()
        },
        actionText: 'Reload'
    }
    snackbarContainer.MaterialSnackbar.showSnackbar(data)
})

Adding a Manifest

The last step for this part of the series is adding the Google Cloud Messaging Sender ID to the `manifest.json` file. This ID makes sure Firebase is allowed to send messages to our app. If you don’t already have a manifest, create one and add the following. Do not change the value.

{
  "gcm_sender_id": "103953800507"
}

Now we are all set up on the front end. What’s left is creating our actual database and the functions to watch database changes in the next article.

Article Series:

  1. Setting Up & Firebase (You are here!)
  2. The Back End (Coming soon!)

Implementing Push Notifications: Setting Up & Firebase is a post from CSS-Tricks

How to Create a WordPress Intranet for Your Organization

Do you want to create a WordPress intranet for your organization? WordPress is a powerful platform with tons of flexible options that makes it ideal to be used as your company’s intranet. In this article, we will show you how to create a WordPress intranet for your organization while keeping it private and secure.

Creating a WordPress intranet for your organization

What is Intranet or Extranet? Why Use WordPress as Your Intranet Platform?

Intranet or Extranet is a communications platform used by an organization for communication, file sharing, announcements, and other organizational activities.

WordPress is an excellent platform to build your organization’s intranet or extranet. It is easy to maintain, open source, and gives you access to thousands of WordPress plugins to add new features when needed.

An intranet runs on an organization’s private network. Typically, an office IT system is connected via cable or wireless network adapters. One computer on the network can be used as the web server and host a WordPress website.

Follow the instructions in our guide on how to install WordPress on a Windows network using WAMP or install WordPress on a Mac computer using MAMP to start your WordPress intranet.

On the other hand, an extranet is an intranet platform accessible to a larger network or public internet. In plain English, this could be a website publicly accessible but restricted to authorized users only.

It is particularly useful if your organization is distributed across different geographic locations.

To create your WordPress extranet, you’ll need a WordPress hosting account and a domain name. After that, you can install WordPress and then set it up to be used as your organization’s intranet.

Once you have installed WordPress as your intranet, the next step is to convert it into a communications hub for your organization.

To do that, you’ll be using several WordPress plugins. We will show you the basic setup that will serve as the foundation for your WordPress intranet to grow and meet your organization’s goals.

Setting Up BuddyPress as Your WordPress Intranet Hub

BuddyPress is a sister project of WordPress. It converts your WordPress website into a social network. Here are some of the things a BuddyPress powered intranet can do:

  • You will be able to invite users to register on company intranet
  • Users will be able to create extended user profiles
  • Activity streams allow users to follow latest updates like Twitter or Facebook
  • You will be able to create user groups to sort users into departments or teams
  • Users can follow each other as friends
  • Users can send private messages to each other
  • You can add new features by adding third-party plugins
  • You’ll have plenty of design options with WordPress themes for BuddyPress

To get started, first you will need to install and activate BuddyPress plugin. For more details, see our step by step guide on how to install a WordPress plugin.

Upon activation, head over to Settings » BuddyPress page to configure plugin settings.

BuddyPress settings

For complete step by step instructions see our guide on how to turn WordPress into a social network with BuddyPress.

Secure Your WordPress Intranet with All-in-One Intranet

If you are running a WordPress intranet on local server, then you can secure it by limiting access to internal IPs in your .htaccess file.

However, if you are running an Extranet, then your users may be accessing the intranet from different networks and IP addresses.

To make sure that only authorized users get access to your company intranet, you need to make your extranet private and accessible to only registered users.

For that, you’ll need to install and activate the All-in-One Intranet plugin. For more details, see our step by step guide on how to install a WordPress plugin.

Upon activation, head over to Settings » All-in-One Intranet page to configure the plugin settings.

All in One Intranet settings

First you need to check the box next to ‘Force site to be entirely private’ option. This will make all pages of your WordPress site completely private.

The only thing this plugin will not make private is the files in your uploads directory. Don’t worry, we will show you how to protect it later in this article.

Next, you need to provide a URL where you want users to be redirected when they are logged in. This could be any page on your intranet.

Lastly, you can automatically logout inactive users after a certain number of minutes.

Don’t forget to click on the save changes button to store your settings.

Securing Media Uploads on your WordPress Intranet

Making your website completely private doesn’t affect media files. If someone knows the exact URL of a file, then they can access it without any restriction.

Let’s change that.

For better protection, we will be redirecting all requests made to the uploads folder to a simple PHP script.

This php script will check if a user is logged in. If they are, then it will serve the file. Otherwise, the user will be redirected to the login page.

First you need to create a new file on your computer using a plain text editor like Notepad. After that you need to copy and paste the following code and save the file as download-file.php on your desktop.

<?php
require_once('wp-load.php');

is_user_logged_in() ||  auth_redirect();

list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL);

$file =  rtrim($basedir,'/').'/'.str_replace('..', '', isset($_GET[ 'file' ])?$_GET[ 'file' ]:'');
if (!$basedir || !is_file($file)) {
	status_header(404);
	die('404 — File not found.');
}

$mime = wp_check_filetype($file);
if( false === $mime[ 'type' ] && function_exists( 'mime_content_type' ) )
	$mime[ 'type' ] = mime_content_type( $file );

if( $mime[ 'type' ] )
	$mimetype = $mime[ 'type' ];
else
	$mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );

header( 'Content-Type: ' . $mimetype ); // always send this
if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) )
	header( 'Content-Length: ' . filesize( $file ) );

$last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
$etag = '"' . md5( $last_modified ) . '"';
header( "Last-Modified: $last_modified GMT" );
header( 'ETag: ' . $etag );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );

// Support for Conditional GET
$client_etag = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) : false;

if( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )
	$_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;

$client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
// If string is empty, return 0. If not, attempt to parse into a timestamp
$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;

// Make a timestamp for our most recent modification...
$modified_timestamp = strtotime($last_modified);

if ( ( $client_last_modified && $client_etag )
	? ( ( $client_modified_timestamp >= $modified_timestamp) && ( $client_etag == $etag ) )
	: ( ( $client_modified_timestamp >= $modified_timestamp) || ( $client_etag == $etag ) )
	) {
	status_header( 304 );
	exit;
}

readfile( $file );

Now connect to your website using an FTP client. Once connected, upload the file you just created to /wp-contents/uploads/ folder on your website.

Next, you need edit the .htaccess file in your website’s root folder. Add the following code at the bottom of your .htaccess file:

RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/(.*)$ download-file.php?file=$1 [QSA,L]

Don’t forget to save your changes and upload the file back to your website.

Now all user requests to your media folder will be sent to a proxy script to check for authentication and redirect users to login page.

4. Adding Forms to Your WordPress Intranet with WPForms

WPForms

The main goal of a company intranet is communication. BuddyPress does a great job with activity streams, comments, and private messaging.

However, sometimes you’ll need to collect information privately in a poll or survey. You’ll also need to sort and store that information for later use.

This is where WPForms comes in. It is the best WordPress form builder in the market.

Not only it allows you to easily create beautiful forms, it also saves user responses in the database. You can export responses for any form into a CSV file.

This allows you to organize form responses in spreadsheets, print them, and share among your colleagues.

Extending Your WordPress Intranet

By now you should have a perfectly capable intranet for your organization. However, as you test the platform or open it for users, you may want to add new features or make it more secure.

There are plenty of WordPress plugins that can help you do that. Here are some tools that you may want to add right away.

That’s all for now.

We hope this article helped you create a WordPress intranet for your organization. You may also want to see our list of most useful WordPress widgets for your site.

If you liked this article, then please subscribe to our YouTube Channel for WordPress video tutorials. You can also find us on Twitter and Facebook.

The post How to Create a WordPress Intranet for Your Organization appeared first on WPBeginner.

Read the original post on  WPBeginer Tutorials

Be Slightly Careful with Sub Elements of Clickable Things

Say you want to attach a click handler to a <button>. You almost surely are, as outside of a <form>, buttons don’t do anything without JavaScript. So you do that with something like this:

var button = document.querySelector("button");
button.addEventListener("click", function(e) {
  // button was clicked
});

But that doesn’t use event delegation at all.

Event delegation is where you bind the click handler not directly to the element itself, but to an element higher up the DOM tree. The idea being that you can rip out and plop in new DOM stuff inside of there and not worry about events being destroyed and needing to re-bind them.

Say our button has a gear icon in it:

<button>
  <svg>
    <use xlink:href="#gear"></use>
  </svg>
</button>

And we bind it by watching for clicks way up on the document element itself:

document.documentElement.addEventListener("click", function(e) {
  
});

How do we know if that click happened on the button or not? We have the target of the event for that:

document.documentElement.addEventListener("click", function(e) {
  console.log(e.target);
});

This is where it gets tricky. In this example, even if the user clicks right on the button somewhere, depending on exactly where they click, e.target could be:

  • The button element
  • The svg element
  • The use element

So if you were hoping to be able to do something like this:

document.documentElement.addEventListener("click", function(e) {
  if (e.target.tagName === "BUTTON") {
    // may not work, because might be svg or use
  }
});

Unfortunately, it’s not going to be that easy. It doesn’t matter if you check for classname or ID or whatever else, the element itself that you are expecting might just be wrong.

There is a pretty decent CSS fix for this… If we make sure nothing within the button has pointer-events, clicks inside the button will always be for the button itself:

button > * {
  pointer-events: none;
}

This also prevents a situation where other JavaScript has prevented the event from bubbling up to the button itself (or higher).

document.querySelector("button > svg").addEventListener("click", function(e) {
  e.stopPropagation();
  e.preventDefault();
});

document.querySelector("button").addEventListener("click", function() {
  // If the user clicked right on the SVG, 
  // this will never fire
});

Be Slightly Careful with Sub Elements of Clickable Things is a post from CSS-Tricks

1 2 3 595
Page 1 of 595