Here is the question, how do we find a good WordPress community theme?

Communities are everywhere.

Online, offline. Connected, not connected.

But here is the thing. You want your community to be engaged.

You don’t want it to shade off on the side.

How to go about it?

You can build Facebook Groups, Messenger or Slack communities.

But you can also create a fully-fledged online application with more features than the usual posts/comments.

And lucky you, WordPress makes it easy to build such an application. You can find WordPress community themes that will help you spin up your application in a matter of minutes.

What is a WordPress Community Theme?

First, let’s get down to the basics: a definition.

What is a WordPress community theme?

According to the codex, here is the definition of a WordPress theme.

“A WordPress Theme is a collection of files that work together to produce a graphical interface with an underlying unifying design for a weblog. These files are called template files. A Theme modifies the way the site is displayed, without modifying the underlying software. Themes may include customized template files, image files (*.jpg, *.gif), style sheets (*.css), custom Pages, as well as any necessary code files (*.php). For an introduction to template files, see Stepping Into Templates.”

There are very generic themes, that doesn’t focus on one specific thing. Great examples are Avada or Stack.

Avada WordPress theme

But there are also more specific themes that serve a specific niche or purpose.

Community themes are such an example. They have different features, integrations, and a design that fits online communities.

Most importantly, they work with the usual WordPress community plugins, the main one being BuddyPress.

Good.

We know how to go about creating a quick and effective community.

By fostering your community on a familiar platform such as WordPress you make it easy to start, but also easy to evolve and tailor. In fact, WordPress is powering more than 30% of the web. Think up… there are tons of proficient developers out there.

The beauty? You keep and own your data. Everything is stored under your hood.

Moving on the choice of our WordPress template.  

How To Choose The Right WordPress Theme for Your Community?

Here are a few features you’ll be looking for in your WordPress theme when making the call for it.

Design and Interface

First thing first. How attractive and modern the theme is?

Do you remember this old page from Facebook?

Lucky me, I don’t.

Either way, I’d be reluctant to use such a design.

Okay, I’m going too far, exaggerating. But you get the point.

The design is timely, it was likely good for the time. But not good for today.

So we want anything but something similar to this.

Facebook in 2004

We want an attractive design that gives us the willpower. Something we want to use.

Something we feel easy to play with. We don’t have to mock around for 20 minutes before finding what we want.

Where does the theme lands on this scale? (Interaction-Design.org)
Where does the theme lands on this scale? (Interaction-Design.org)

Pro tip: make sure to check the design on your laptop, but also on tablets and smartphones. You absolutely want the theme to be responsive.

Last, but not least, make sure that the theme loads fast. You don’t want the page to hang for 2 minutes before displaying what it’s supposed to.

Social and Members-Related Features

We have an easy-to-use application.

But we still haven’t checked through our core features.

We want to make a collaborative intranet/community site where our members can thrive.

We want to bring together, at the least, the following features:

  • Social networking: whether we are talking about user profiles, activity posting, or any other social networking feature. It’s a must to have some of those basics
  • Messaging: being able to communicate with other members privately, or using group chat is required as well. We want the chat to be efficient, secure, supporting files and text formatting.
  • Forums: debating, contributing, asking public questions; these are all must-have features of our community theme.
  • Events management: sharing the next community event must be as easy as logging in! That’d be even better if our theme would support integrations with the major Calendar players (Apple Calendar, Google Calendar, Outlook).
  • File sharing: we would also want to be able to share files in private and public. This must be powerful enough to support different folders, so we can truly manage the files.

Then, if we have e-commerce and even e-learning capabilities, that’d be the icing on the cake.

LearnDash is one of the most prominent Learning Management System for WordPress.

Learndash for WordPress community

Before we dive into the comparison of the best themes out there. Let’s clear up any confusion and clarify the difference between a social network solution, and a fully-featured community theme.

Social Network Themes for WordPress vs Community Theme vs Intranet Theme

As they sound, social network themes are focused on the interaction online. Networking online.

They usually use the famous BuddyPress plugin under the hood and add their layer on top of it to make the social interaction more attractive.  

BuddyPress is a free plugin that helps you build any kind of community website using WordPress, with member profiles, activity streams, user groups, messaging, and more.

BuddyPress WordPress Community Plugin

Some of the common features include chat, groups, file sharing, commenting and posting. Think of it as a Facebook built using WordPress.

On the other hand, community theme goes one step further and provide specific features meant at driving community engagement and interaction. Some examples include event management, member map, and member research tool, matchmaking, and much more.

Lastly, the intranet themes are meant at providing a business-oriented solution for organizations and teams to collaborate effectively. They not only offer social features but also all the business-related requirements to run an efficient project and team – such as project management, knowledge base, HR, etc.

WordPress Community Themes Compared

To wrap things up, we will be looking at the best community WordPress themes and look at how they compare.

Thrive WordPress Theme

The first item on our list is Thrive.

It powers “everything you need to build a powerful intranet, extranet, and community”.

Thrive is rated 4.38 based on 137 ratings, has been available since September 2015 and counts ~4K sales.

Woffice WordPress Theme

The next one on our list is Woffice.io. It’s an all-in-one intranet and extranet theme, which means that it not only provide you with all the features mentioned above for community building but also much more.

Besides its numerous features, Woffice’ power lays in the design and user interface. The theme has been on the market since 2015 with more than 100 updates to keep it up-to-date

Member dashboard, members map and directory, forums, chats, event management, project management, Slack integration, e-commerce features, and wiki management.

Woffice is rated 4.7 based on 355 ratings, has been available since June 2015 and counts ~9.5K sales.

Woffice - WordPress Community Theme alternative


Besocial WordPress Theme

Have you heard of Besocial? We did.

And we are glad to give you more details.

Besocial is a simple and effective BuddyPress solution. It provides the usual social networking features, plus FAQ system, event management, and a clean design.  

Besocial is rated 4.94 based on 15 ratings, has been available since March 2017 and counts ~550 sales.

BeSocial

Kleo WordPress Theme

The last one on our list is Kleo, a leading BuddyPress theme.

It goes beyond the main community features and can be used for numerous purposes. On their website, I see demos about the Business directory, local community but also landing page, news magazine and restaurant website. Any website that connects with BuddyPress could be interested.

Kleo is rated 4.7 based on 1238 ratings, has been available since February 2014 and counts ~18K sales.

Kleo

Wrap Up

Setting up your online community should be a no-brainer.

The harder part remains on the human and marketing side of thing  ?

I hope this article will help you make the call as to how to approach your online community.

If you have any question or comment, feel free to leave them in the comment below!

Let’s create our BuddyPress Members Map using Vue.js.

Welcome to you.

This article will explain to you how to create a fully dynamic Google Maps of your BuddyPress Members on your WordPress site, on any page.

Easily.

This tutorial is developed as we roll out this feature to our Woffice theme, intranet/extranet WordPress solution.

It already has a members map but it was:

  • 1. Not dynamic.
  • 2. Using old jQuery code.

So time for a fresh look!

To follow this tutorial you need:

  • A WordPress setup with BuddyPress installed
  • PHP skills (OOP as well) but also WordPress development skills
  • Vue.js skills (at least the basics)
  • A Google cloud account to use the Maps JavaScript V3 API (to render the map) and Map Geolocation API (to convert locations into coordinates)

We have split this tutorial into two parts: Backend & Frontend.

Makes sense right?

Nothing new here. You will see it is pretty straightforward.

Before we start, this is developed within a theme, so designed for a child theme if you do not have your own theme, but it can also be used a plugin with a couple of changes.

Also, the final (working!) result can be found as a Zipped archive at the bottom of this page.

Last but not least, lots of functions will be prefixed woffice_, change that with your own prefix.

Enough talking! Let’s get started.

Part I: Create The Backend Side

In this first part of our BuddyPress Member Map tutorial, we will create our PHP Class to handle everything in this tutorial in one single place.

Then, create the Location field to collect the member’s address. Store it safely. Once done, we will have an Ajax callback setup (which will be called by our Frontend Vue.Js component).

And we’ll optimize it to use as less requests as possible (using some home-made cache).

Getting The Member’s Location

Firstly, let’s ask a quick question: How can we collect the user’s location, easily?

No idea. Com’on…. Remember, we are teaming up with BuddyPress on this, so let’s use it! BuddyPress has a nice extension named: xProfile.

You can activate it from the Settings > BuddyPress > Components screen.

We are going to wrap all our PHP code in a class: Woffice_Members_Map, again change Woffice with your theme/plugin’s name. This class can be called from any PHP file, ideally functions.php (child or parent theme):

new Woffice_Members_Map();

We will simply create a method that will be attached to the `xprofile_updated_profile` BuddyPress action, so our code will be executed whenever someone saves its profile.

We avoid using bp_init.

Because otherwise it’s being run on every page load. However, it means you need to save your profile to generate the field. Feel free to use any other specific action, like on theme activation.

Once hooked, we run a SQL query to see if the Location field exists and otherwise we create it.

Plain and simple.

That will (should) give you a new field when you edit your BuddyPress profile. “Location”, it will hold the member’s location inside our database.

Saving The Coordinates in Our Database

We now have nice locations getting saved, but Google Map does not eat this kind of food. The diet is Geographic coordinates.

Therefore, how do we get coordinates from human-wrote locations?

Well, we use the Google API: Google Maps Geocoding API.

This API turns addresses into coordinates.

So you need to create a new Google Cloud Account (if you do not have one yet), create a new project called “Members Map” and activate this API. You can also enable the JavaScript map API as well. We will need it later on. Once both APIs created, generate API keys from the Credentials screen.

We need those.

Here is our Woffice theme’s doc article about how to get them:
Google Map Geocoding

Then, we will save all coordinates inside our database, within the wp_options table. As a new option.

Why?

Because requests are expensive to this API.

Thus, the idea is to call it only when needed, so if we already have the coordinates for one member, we don’t need it again, unless, of course, it’s being updated.

The option name in this example will be: “woffice_map_locations“. The data inside is formatted using JSON.

Let’s do it! Three new methods in our PHP Class:

  • saveSingleMember() which is hooked to the `xprofile_updated_profile` action, so whenever a new member profile is saved, we will see if there is an existing entry in our option and if not, fetch the coordinates. Same if it’s being updated.
  • getMemberCoordinates() which will fetch the Coordinates for a given member. That’s where we will call the API and the BuddyPress xProfile field.
  • apiRequest() is a helper to call the API and returns the result.

Notes:

  • We split into 3 methods because if you want to use a more complex workflow, some methods can be reused independently. Like having a button that regenerates all coordinates, we do that in Woffice and you don’t need the first method but the other two.
  • We are using a Class attribute ($privateApiKey) to hold the API key, if you have a Theme Settings page, get it from there.

Cool!

So now, we can save addresses in our profile and get coordinates saved inside our database.

That really is all we need ? Here is an example of the result in the Database:

Database preview

Creating The Ajax callback

Third step, the goal of this part is to make the coordinates we just saved inside our wp_options table available from the Frontend side, safely. Of course.

In the __construct() method, let’s add our Ajax callback functions:

If you are not comfortable with how WordPress handles Ajax requests, please have a look at this article.

Also, we are using a WordPress nonce to make the request safer and make it can only be sent through our Vue.js component.

Here is the loadMembers() method that we can add in our class:

As you can see, we are also adding a `woffice_members_map_locations` filter to let any child theme or plugin add custom data to the response using a WordPress filter.

There is also a default response if there is no coordinates found.


Part I is over! As of right now, the backend part is done. No more PHP, well, almost. Here is a quick recap of what we’ve done:

  1. Insert automatically a new BuddyPress xProfile field in the user’s profile page to collect the Location.
  2. Use the Geocoding API to turn this Location into GPS coordinates and saved them inside our database in the wp_options table as a new option to save requests.
  3. Created an Ajax callback to return the saved coordinates as a formatted array.

Real cakewalk ?

Part II: Create The Frontend Side

What we will do in this part will be to create the Vue.js component, define it, register it and call it with a PHP function.

The goal of the component is to wrap everything in a single Vue.js component (that’s the real magic!), no dependency, just this component. Once the component loaded, it will do three pretty cool, yet simple things:

  1. Create the Google Map
  2. Fetch the Members coordinates
  3. Render the Members into the map

Define Our Vue.js Component

First off, create a new file called js/wofficeMembersMap.js, it will hold our Vue.js component.

We will “enqueue” it to the page’s footer within our __contstruct() method:

And therefore, also add a new method to register both the library and our component:

As you can see, we are also embedding the Google JavaScript Map API. Therefore you need to create another (different one than the one used before the backend side: geocoding process) public key.

Once done, register it in the class as a new attribute.

Once that’s set up, you will see both JavaScript assets loaded in your source code. Now, we can create the scaffolding of our component with our newly registered “.js” file:

What are we doing here?

  • Creating a new Vue.js instance, that’s not a required step, if you’re using Vue.js already. Then just register the new component to this instance instead. Vue power!
  • Set up the markup, very easy here as it’s going to be rendered by Google Map, not us.
  • Registering our two component properties: height, url.
  • Setting up the default Vue.js hooks that we are going to use. We could use some other ones as well, for the sake of simplicity, those 2 will do just fine! Make sure to checkout this must-read doc article from Vue.js: Lifecycle diagram.
  • Note that we are using old JavaScript markup here because we (Woffice developers) want to keep support for old browsers and care a lot about the final bundle size. But this code is easily adaptable to ES6 using Babel. Nothing tricky.

Render The Component Using PHP

There are several ways to display the Vue.js component, we can use a PHP function like woffice_render_members_map() and call it from a template.

But we can also use a shortcode. Which offers the same advantages of the first method but on top of this, you can also use it right from the editor.

So, let’s create a new shortcode: [woffice_members_map] that you can use from your editor or using the do_shortcode() function from your template. The other advantage is that you can pass attributes later on if you want to extend it easily.

Nothing new here, we need to register it from our __contstruct() method.

And then, the method itself that will simply output the Vue.js component with some HTML markup.

We also pass attributes directly there to avoid using a “Data exchanger” (registering a JavaScript object in the wp_footer hook on the PHP level to pass data between PHP and JavaScript).

Create The Google Map

At the same time, we are simply going to create a new method in our component: createMap().

Which will? … … Create the map!

Not original, but makes sense.

That method will set the map’s height and use the Google Map API to generate a simple map:

Did you notice? We are using the famous component’s data object to store the map’s zoom level and center. Feel free to improve it and use shortcode/coordinates attributes. Moreover, you can use this website to get the Latitude and Coordinates of any address.

This is a VERY simple example, you can make it a LOT more complex (custom style, custom controls, animations…).

Google showcases an excellent documentation on this API. So when you use [woffice_members_map] in any post or page, you should (will, I hope) see:

Tutorial Preview

Fetch Our Members

Okay, so we have a map.

How about we now call the Ajax callback we have defined in the first step to fetch our Members coordinates from our database and render them? Sounds good.

Update the mounted() hooks to call a new method that we will define under the methods: {} object:

Couple of things to notice here:

Firstly, we are using a “WordPress nonce” to secure the request.

Secondly, we store the fetched members coordinates in the data object to be able to use it easily in any other method of our component.

Once done, we call a new method: drawMarkers().

See the next section ?

Last but not least, install the Vue.js dev tool. You will be able to visualize the data:

First Preview of our Map in Woffice

Add The Markers To The Map

Finally, here we are, the last step!

We now have a map and members coordinates, how about we do some cooking to mix them?

Sounds good to me.

Nothing fancy, let’s define the drawMarkers() method called in the last method in the fetch members’ success callback function. This method will go through all member locations we received from our backend and create a Google Map marker (more details here).

Then, we will use the user’s info, that we pass as well in the Ajax PHP callback to have some HTML markup inside the map marker. Again, easy-peasy.

As you very likely have guessed, we are using a child theme in this tutorial for our Woffice theme.

Which provides Bootstrap 4 out of the box, so no CSS, yay! I just used helper classes to get a “nice” (not bad) layout inside my marker:

Preview of WordPress BuddyPress Members Map

Which is our final result! Just this? Wait, that’s a simple example, it’s super flexible, will support as many members you want, you can change the content, style, animations, marker and a lot more.

You can see some cool examples in our Eonet and Woffice members demo pages.


In summary, what we have done in this frontend part is:

  1. Add Vue.js and the Google map public librairies to our frontend side. Plus, registering our own Vue.js component.
  2. Create a Google Map using the Google Map API v3.
  3. Fetch our members using the Ajax callback we have defined in the first step.
  4. Render the members in the map using some pretty cool map markers.

Conclusion

Hope you liked it! You are now able to create your own BuddyPress Members Map.

For any detail or improvement you have in mind, please use the comment section below.

This being said, a couple of final notes here:

  • Vue.js can be added to WordPress, VERY easily. It’s dynamic and easy to develop with. Use ES6 if you can.
  • If you have many members and they “step” on each other, consider using Marker clusters (see this article).
  • Finally, This tutorial was designed to be as simple as possible, there are dozens of improvements you can apply: using theme options, custom attributes, better marker markup, custom map style, better error handling and so on.

You can find the complete code working in a Woffice child theme in this .zip (no, I won’t collect your email address!).

Want to create your own WordPress plugin? Check out this article.

Thanks for reading and see you in the next one!

Successful organizations choose to use an intranet. And there is a reason for that. Intranets offer a tons of benefits.

With the increasing number of applications and providers used, it is important for employees to be able to easily keep track of what’s happening in the organization.

But what is an intranet? How is it different from an extranet? How can it benefit my organization?

Without further ado, let’s get into that.

(more…)

Today, we are going to see how to create a very simple WordPress plugin for any web app that needs to insert a piece of code to your site.

To follow this tutorial, you need basics:

  • PHP and Object Oriented Programming
  • JavaScript, we’ll use jQuery and Ajax
  • WordPress development, most functions are from the WordPress core.

You can find a working result of this tutorial on this Github repository.

These web apps could be CrazyEgg, Freshbook, Google Analytic, Facebook Pixel or Feedier.

Why?

They all need to inject some HTML / JavaScript code to your site for various purposes.

This “code” is always parametrized with variables and usually is a pain for the site owner because he needs to edit the theme’s templates. So, how about we create a plugin to do that for us?

Okay, let’s do it!

Step 1: Find Your Web App – Feedier Example

The goal of this tutorial is to create a WordPress plugin that adds a WordPress admin page.

Plus, some settings  to configure the app’s in-site widget and inject the HTML / Js code in our web page automatically. Nothing fancy, just something that works fine.

So, we do need a web application for this tutorial. We will use for this example Feedier.

However, if you do have the other web application to apply this tutorial, please do. Just rename the “feedier” with your app and adapt the settings to what this app needs. 

Most of them will give you a snippet to add to your site in order to work.

Quick briefing of Feedier if you never heard of it:

  • It’s a feedback collector tool, using surveys to understand your users
  • It’s very flexible
  • It’s free! 
  • Has a good API (very important here)
  • Has an in-site widget (very important here)
  • Lets you reward your customers
  • Lets you create conditional questions
  • Has a complete analytic report dashboard
  • Lets you manage feedback individually

Here is the widget we want to add automatically:

Feedier Widget Preview

If you signed up to Feedier, then you can simply find the code in the Share tab of your survey:

Feedier Preview Sharing Method

Step 2: Setup Our Plugin and Its Architecture

WordPress plugins are by design very simple. Our plugin will only need two files.

  • feedier.php: main plugin’s PHP file.
  • assets/js/admin.js: JavaScript script to save the options using Ajax.

You can create a new “feedier” directory (or name of your web app) in your wp-content/plugins/ folder.

Directory Architecture

The most important file will be the plugin’s feedier.php class. Here is its structure:

<?php
/**
 * Plugin Name:       Feedier
 * Description:       Smart surveys start now!
 * Version:           1.0.0
 * Author:            Alkaweb
 * Author URI:        https://alka-web.com
 * Text Domain:       alkaweb
 * License:           GPL-2.0+
 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
 * GitHub Plugin URI: https://github.com/2Fwebd/feedier-wordpress
 */
/*
 * Plugin constants
 */
if(!defined('FEEDIER_URL'))
	define('FEEDIER_URL', plugin_dir_url( __FILE__ ));
if(!defined('FEEDIER_PATH'))
	define('FEEDIER_PATH', plugin_dir_path( __FILE__ ));
/*
 * Main class
 */
/**
 * Class Feedier
 *
 * This class creates the option page and add the web app script
 */
class Feedier
{
    /**
     * Feedier constructor.
     *
     * The main plugin actions registered for WordPress
     */
    public function __construct()
    {
    }
}
/*
 * Starts our plugin class, easy!
 */
new Feedier();

We are doing a few things here:

  • Declaring our plugin using the header comments
  • Defining a few handy constants to be able to find the plugin’s URL and PATH easily
  • Declaring our plugin class that will contain everything we need in this plugin. We just need a constructor method for now

You should already see the plugin in your Plugins page, even though it’s not doing anything yet:

WordPress plugin activation

Step 3: Create Our Admin Page

For this part, we will add a new Feedier admin page to our WordPress site and dynamically fetch our surveys from the Feedier’s API.

In our class’ constructor let’s register three new actions which are required to add an admin page on WordPress:

/**
 * Feedier constructor.
 *
 * The main plugin actions registered for WordPress
 */
public function __construct()
{
	// Admin page calls:
	add_action( 'admin_menu', array( $this, 'addAdminMenu' ) );
	add_action( 'wp_ajax_store_admin_data', array( $this, 'storeAdminData' ) );
	add_action( 'admin_enqueue_scripts', array( $this, 'addAdminScripts' ) );
}
  • addAdminMenu will add a new page in the WordPress left menu. There will be also a callback to another method containing the page’s content.
  • storeAdminData will be called whenever the user clicks the “Save settings” button.
  • addAdminScripts will register a new JavaScript file to our WordPress admin in order to save the form’s data. But also exchanges some variables between the PHP side and JavaScript side.

The first one is very easy, we just register the page:

/**
 * Adds the Feedier label to the WordPress Admin Sidebar Menu
 */
public function addAdminMenu()
{
    add_menu_page(
	__( 'Feedier', 'feedier' ),
	__( 'Feedier', 'feedier' ),
	'manage_options',
	'feedier',
	array($this, 'adminLayout'),
	''
     );
}

As you can see we use WordPress localization functions for all strings. Note that the:

array($this, 'adminLayout')

Is where we call another method containing the page’s content. The form needs to be adapted to your web app.

Here, we first need to get the public and private Feedier API keys. Once saved, we are going to use the private key to dynamically retrieve our surveys. Whenever we get the surveys and not an API error, we display some new options to configure the widget.

/**
 * Outputs the Admin Dashboard layout containing the form with all its options
 *
 * @return void
 */
public function adminLayout()
{
	$data = $this->getData();
	$surveys = $this->getSurveys($data['private_key']);
	?>
	<div class="wrap">
	    <h3><?php _e('Feedier API Settings', 'feedier'); ?></h3>
            <p>
	        <?php _e('You can get your Feedier API settings from your <b>Integrations</b> page.', 'feedier'); ?>
            </p>
            <hr>
            <form id="feedier-admin-form">
		<table class="form-table">
                    <tbody>
                        <tr>
                            <td scope="row">
                                <label><?php _e( 'Public key', 'feedier' ); ?></label>
                            </td>
                            <td>
                                <input name="feedier_public_key"
                                       id="feedier_public_key"
                                       class="regular-text"
                                       value="<?php echo (isset($data['public_key'])) ? $data['public_key'] : ''; ?>"/>
                            </td>
                        </tr>
                        <tr>
                            <td scope="row">
                                <label><?php _e( 'Private key', 'feedier' ); ?></label>
                            </td>
                            <td>
                                <input name="feedier_private_key"
                                       id="feedier_private_key"
                                       class="regular-text"
                                       value="<?php echo (isset($data['private_key'])) ? $data['private_key'] : ''; ?>"/>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <hr>
                                <h4><?php _e( 'Widget options', 'feedier' ); ?></h4>
                            </td>
                        </tr>
                        <?php if (!empty($data['private_key']) && !empty($data['public_key'])): ?>
                            <?php
                            // if we don't even have a response from the API
                            if (empty($surveys)) : ?>
                                <tr>
                                    <td>
	                                    <p class="notice notice-error">
                                            <?php _e( 'An error happened on the WordPress side. Make sure your server allows remote calls.', 'feedier' ); ?>
                                        </p>
                                    </td>
                                </tr>
                            <?php
                            // If we have an error returned by the API
                            elseif (isset($surveys['error'])): ?>
                                <tr>
                                    <td>
                                        <p class="notice notice-error">
                                            <?php echo $surveys['error']; ?>
                                        </p>
                                    </td>
                                </tr>
                            <?php
                            // If the surveys were returned
                            else: ?>
                                <tr>
                                    <td>
                                        <p class="notice notice-success">
	                                        <?php _e( 'The API connection is established!', 'feedier' ); ?>
                                        </p>
                                        <div>
                                            <label><?php _e( 'Choose a survey', 'feedier' ); ?></label>
                                        </div>
                                        <select name="feedier_widget_carrier_id"
                                                id="feedier_widget_carrier_id">
                                            <?php
                                            // We loop through the surveys
                                            foreach ($surveys['data'] as $survey) : ?>
                                                <?php
                                                // We also only keep the id -> x from the carrier_x returned by the API
                                                $survey['id'] = substr($survey['id'], 8); ?>
                                                <option value="<?php echo $survey['id']; ?>" <?php echo ($survey['id'] === $data['widget_carrier_id']) ? 'selected' : '' ?>>
                                                    <?php echo $survey['name']; ?>
                                                </option>
                                            <?php endforeach; ?>
                                        </select>
                                        <hr>
                                </tr>
                                <tr>
                                    <td>
                                        <div class="label-holder">
                                            <label><?php _e( 'Display probability (from 0 to 100)', 'feedier' ); ?></label>
                                        </div>
                                        <input name="feedier_widget_display_probability"
                                               id="feedier_widget_display_probability"
                                               class="regular-text"
                                               value="<?php echo (isset($data['widget_display_probability'])) ? $data['widget_display_probability'] : '100'; ?>"/>
                                    </td>
                                    <td>
                                        <div class="label-holder">
                                            <label><?php _e( 'Shaking effect (shake after 10s without click)', 'feedier' ); ?></label>
                                        </div>
                                        <input name="feedier_widget_shake"
                                               id="feedier_widget_shake"
                                               type="checkbox"
                                            <?php echo (isset($data['widget_shake']) && $data['widget_shake']) ? 'checked' : ''; ?>/>
                                    </td>
                                    <td>
                                        <div class="label-holder">
                                            <label><?php _e( 'Position', 'feedier' ); ?></label>
                                        </div>
                                        <select name="feedier_widget_position"
                                                id="feedier_widget_position">
                                            <option value="left" <?php echo (!isset($data['widget_position']) || (isset($data['widget_position']) && $data['widget_position'] === 'left')) ? 'checked' : ''; ?>>
                                                <?php _e( 'Left side', 'feedier' ); ?>
                                            </option>
                                            <option value="right" <?php echo (isset($data['widget_position']) && $data['widget_position'] === 'right') ? 'checked' : ''; ?>>
                                                <?php _e( 'Right side', 'feedier' ); ?>
                                            </option>
                                        </select>
                                    </td>
                                </tr>
                            <?php endif; ?>
                        <?php else: ?>
                            <tr>
                                <td>
                                    <p>Please fill up your API keys to see the widget options.</p>
                                </td>
                            </tr>
                        <?php endif; ?>
                        <tr>
                            <td colspan="2">
                                <button class="button button-primary" id="feedier-admin-save" type="submit"><?php _e( 'Save', 'feedier' ); ?></button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </form>
	</div>
	<?php
}

At the beginning of this method you can see that we are first getting the saved data with:

$data = $this->getData();

And getting the surveys from the Feedier API:

$surveys = $this->getSurveys($data['private_key']);

So let’s declare the first one:

/**
 * The option name
 *
 * @var string
 */
private $option_name = 'feedier_data';
/**
 * Returns the saved options data as an array
 *
 * @return array
 */
private function getData() {
    return get_option($this->option_name, array());
}

This function just reads our plugin’s option and gives us an array back so we can save multiple values in the same option.

Obviously, to get the second method working, we need the Feedier private key, which thus depends on the first one to access this key saved in the option:

/**
 * Make an API call to the Feedier API and returns the response
 *
 * @param string $private_key
 * @return array
 */
private function getSurveys($private_key)
{
    $data = array();
    $response = wp_remote_get('https://api.feedier.com/v1/carriers/?api_key='. $private_key);
    if (is_array($response) && !is_wp_error($response)) {
	$data = json_decode($response['body'], true);
    }
    return $data;
}

The Feedier API is documented here, so you can see what you will get in the response.

At this moment, we have a complete new Admin page but nothing happens when we click on the save button because there is no saving mechanism, yet.

Good enough, let’s save our data!

As mentioned before, we will save our data using AJAX. Therefore, we need to register a new JavaScript file and exchange data using the wp_localize_script() function:

/**
 * The security nonce
 *
 * @var string
 */
private $_nonce = 'feedier_admin';
/**
 * Adds Admin Scripts for the Ajax call
 */
public function addAdminScripts()
{
      wp_enqueue_script('feedier-admin', FEEDIER_URL. '/assets/js/admin.js', array(), 1.0);
      $admin_options = array(
	 'ajax_url' => admin_url( 'admin-ajax.php' ),
	 '_nonce'   => wp_create_nonce( $this->_nonce ),
      );
      wp_localize_script('feedier-admin', 'feedier_exchanger', $admin_options);
}

We also need to add a new file /assets/js/admin.js. That will simply make an Ajax call, WordPress will automatically route correctly the request to the right method (already done in the constructor). You can read more about how WordPress smartly handles AJAX requests here.

/**
 * Feedier plugin Saving process
 */
jQuery( document ).ready( function () {
    jQuery( document ).on( 'submit', '#feedier-admin-form', function ( e ) {
        e.preventDefault();
        // We inject some extra fields required for the security
        jQuery(this).append('<input type="hidden" name="action" value="store_admin_data" />');
        jQuery(this).append('<input type="hidden" name="security" value="'+ feedier_exchanger._nonce +'" />');
        // We make our call
        jQuery.ajax( {
            url: feedier_exchanger.ajax_url,
            type: 'post',
            data: jQuery(this).serialize(),
            success: function ( response ) {
                alert(response);
            }
        } );
    } );
} );

At this very moment, we can click the save button and the above script will make an HTTP POST request to WordPress.

We also append an action parameter containing: store_admin_data.

Which we declared at the beginning at this part in the constructor:

add_action( 'wp_ajax_store_admin_data', array( $this, 'storeAdminData' ) );

The method storeAdminData will receive the POST request and save the values we need in our WordPress option.

/**
 * Callback for the Ajax request
 *
 * Updates the options data
 *
 * @return void
 */
public function storeAdminData()
{
    if (wp_verify_nonce($_POST['security'], $this->_nonce ) === false)
	die('Invalid Request!');
    $data = $this->getData();
    foreach ($_POST as $field=>$value) {
        if (substr($field, 0, 8) !== "feedier_" || empty($value))
	   continue;
        // We remove the feedier_ prefix to clean things up
	$field = substr($field, 8);
        $data[$field] = $value;
    }
    update_option($this->option_name, $data);
    echo __('Saved!', 'feedier');
    die();
}

A few notes on the above method:

  • We use a “WordPress nonce” to handle the security and make sure this is coming from the website and not a hacker faking the request.
  • We identify the fields we need to save using a “feedier_” prefix. Once received, we loop through all the $_POST data and only save those fields. We also remove the prefix before saving every field.

That’s it for the saving process, when we click the save process we can see a POST request and our data is being saved on the database within the wp_options table.

Perfect, we are done with the admin page.

Step 4: Insert The Dynamic Code Automatically Into Our Pages

Now that we have our options saved, we can create a dynamic widget that will depend on the options set by the user through our admin page.

We already now what the web app expect from us.

Something like:

<div class="feedier-widget" data-type="engager" data-position="right" data-carrier-id="x" data-key="xxxxxxxxxxxxxxxxx"></div>
<!-- Include this line only one time, also if you have multiple widgets on the current page -->
<script src="https://feedier.com/js/widgets/widgets.min.js" type="text/javascript" async></script>

Thus, the first thing we want to do is to create a new method to our plugin that will print this code depending on the variables set by the user. While using the architecture we already set up in the last part:

/**
 * Add the web app code to the page's footer
 *
 * This contains the widget markup used by the web app and the widget API call on the frontend
 * We use the options saved from the admin page
 *
 * @return void
 */
public function addFooterCode()
{
   $data = $this->getData();
   // Only if the survey id is selected and saved
   if(empty($data) || !isset($data['widget_carrier_id']))
      return;
   ?>
   <div class="feedier-widget"
             data-type="engager"
             data-position="<?php echo (isset($data['widget_position'])) ? $data['widget_position'] : 'left'; ?>"
             data-display-probability="<?php echo (isset($data['widget_display_probability'])) ? $data['widget_display_probability'] : '100'; ?>"
             data-shake="<?php echo (isset($data['widget_shake'])) ? $data['widget_shake'] : 'false'; ?>"
             data-carrier-id="<?php echo (isset($data['widget_carrier_id'])) ? $data['widget_carrier_id'] : '0'; ?>"
             data-key="<?php echo (isset($data['public_key'])) ? $data['public_key'] : '0'; ?>"></div>
   <script src="https://feedier.com/js/widgets/widgets.min.js" type="text/javascript" async></script>
   <?php
}

Now, we just need to call this function on every page load to add it at the bottom of the page. To do this, we’ll hook our method to the wp_footer action.

By registering a new action into our class’ constructor:

/**
 * Feedier constructor.
 *
 * The main plugin actions registered for WordPress
 */
public function __construct()
{
    add_action('wp_footer', array( $this, 'addFooterCode'));
    ... what we had before ...
}

That’s it!

Any question, feedback, idea? Let me know in the comment!

You can find a working result of this tutorial on this Github repository.

Note that this is the first version of the plugin, many things can be improved.

Open to suggestions and improvements.

In this third customer story we have Mohammad, who uses Woffice for a notable purpose: an intranet for a government sector.
In this article you will discover how Woffice and WordPress have helped him to achieve his important goal.

1. Hello Mohammad, please let us know something about you

My name is Mohammad and I work in IT Department at government sector in Kuwait. Our department deals with many deal with many huge companies, but unfortunately I cannot provide more details for privacy. I was looking for a simple intranet and I found a lot of solutions with many with different price tags and I preferred Woffice among them.

2. Why have you chosen Woffice to build your intranet?

I didn’t find anything good for the eye, beautiful and customizable at the same time like Woffice. We need the employees to enjoy the work and I believe the interface is one of the main things that allow the users to be excited to use it. Plus there is no monthly payment per user or anything like that.

3. Did you find in Woffice what you were looking for?

Woffice gave me almost everything I need in an intranet. It help as managing all the users and keeping an eye for the next goals. And it help the users to find each other using the Member directory. It helps to manage the users easily by giving them tasks in the projects so the work will be arranged and sorted in each department and section.

4. What is the feature in Woffice that you definitely prefer and that helped more than any other one?

Projects is the best feature in Woffice, it’s not perfect yet but so useful. The manager can check all the departments’ projects in a single page and see the timeline for each department. So he can keep an eye for the whole work in a click.

5. In your opinion, is Woffice easy enough to use for a beginner?

Woffice is easy for anyone with 0 code experience. It have a lot of functions that you can customized it for months. I had many problems at the beginning but support team has helped me to solve them quickly.  You can mange to build a great intranet for any huge organization.

6. What is the most useful plugin for your application?

The Pro event is one of the best plugin in Woffice. We are using it for many things. Viewing and Booking a halls. Also posting an events for the internal employees with the ability to use each event as a single page. Plus we can know how many persons are going to attend with the booking feature.

7. Why did you picked WordPress to build your intranet?

I chose WordPress because I have tried it before and using WordPress is easy and not expensive at all.

8. Is there something that you would say to Alkaweb team or to the future Woffice customers

If you want to use a beautiful Intranet, customizable, easy to use, and without monthly fees. Woffice is what you are looking for.

Conclusion

Here’s Antonio again. Thank you so much Mohammad for your kind words, replies like these make our day!

Finally, we have a second story for our set of customer stories (if you missed the first one, you can find it here). This time is the turn of Edward A. Rodriguez, an entrepreneur from Florida (USA)Edward is an international speaker and coach in the self-empowerment business. He helped thousands of people to change their lives and to improve their results.
In this article you will discover how  Woffice has helped him and his business.

1. Hi Edward, can you talk us about yourself and your business?

My name is Edward, Transformational Trainer, Life Coach, Author and founder of the In-powerment Center.
Our main website is www.EdwardRodriguez.com and our members site: miembros.edwardrodriguez.com
In an effort to reduce my traveling and at the same time satisfy our growing international demand for our transformational programs (personal development, time management, personal leadership, public speaking, sales etc), we decided to create a membership site to deliver our digital program and courses.

2. Why have you chosen Woffice to build your application?

On one occasion I saw a colleague of mine using Woffice and I liked it right away. When I am about to make a decision, I tend not NOT go with “love at first sight”, because of this, my team did an extensive research around creating a website suitable for creating a great learning experience for members.
There are so many options out there, and the one that we kept coming back to was Woffice for its simplicity, and also because it is, in a way, a system. We did not have to do much. All we had to do was to personalize it to our liking. It comes packaged with different features and plugins to help create a private learning, communicating and interacting environment suitable for exactly what we wanted to create for our members.

3. Has Woffice respected the expectations?

Since our members website is primarily for e-learning courses, we needed to add the LearnDash plugin. It so happens that Woffice comes with LearnDash integration “out of the box”. Our team did not like the LearnDash default look and feel. Woffice has styled our Learndash courses beautifully and with no effort and without spending thousands of dollars.
Because Woffice also integrates with BuddyPress, this means, that not only we have our professional looking courses, we can also create a social learning environment for our members…..all out of the box.
We can not have asked for more. Not only we have saved time, but countless hours of custom designing a members website we feel proud of.

4. What is the feature in Woffice that you definitely prefer and that helped more than any other one?

If in real estate all is about location, location and again location, for me and our team, when it come to an application, everything is about tech support, tech support and again tech support. Needles to say, Woffice is features rich and I have mentioned all we like about it above, but without their top-notch tech support team, we would have already gone elsewhere.
Woffice tech support team is reliable, prompt and present and it has gone way beyond the norm to make sure that any challenge we face, it is rapidly addressed.

5. What is the most useful plugin for your application?

As I told earlier, LearnDash is the most important plugin for me.

6. Is Woffice easy enough to use for a beginner?

Since Woffice is a what I call a “package” application with a whole set of solutions, it is great for beginners. Everything comes already “assembled” with easy to choose features. I think it will take hours and hours, a lot of money, effort and headaches for a beginner to get what Woffice offers out of the box. In a way, it was built for beginners and a delight to those more advance because it makes their job so easy.

7. There is a specific reason behind the decision to pick WordPress to build your web app?

Yes there is and that’s an easy one. WordPress is a very flexible platform. When I am traveling, oftentimes I come up with ideas that I want to see “live” now and rather than delegating that, I do it right there. WordPress, being so flexible, allows me to do that. It has thousands and thousands of plugins which help you accomplish virtually anything you want on a website. Another thing is the ability to have a professional website along with blogging capabilities built in. WordPress is that and more.

8. Before than you go, is there something that you would say to the Alkaweb team or to their customers?

To the Alkaweb team: Congratulations! You have built a masterpiece that is allowing organizations like mine, to create a custom-private-website in no time while being supported by your top-notch tech team.
To future customers, well, waste no time, we already went through the pain doing the research for you, now all you have to do is to create your pages!!!!

Conclusion

Here’s Antonio again. Well, what I can say? Thank you so much Edward for your kind words,  I hope that Woffice will continue to satisfy you.
To you dear reader, I hope you enjoyed the story of Edward, if you would like to be the next one, or you want share any thought with us, just let me know below.

As you can see from the ThemeForest page, at the current moment, Woffice counts more than 4200 sales. But we believe even more that the number of the sales it’s not just a figure, it’s our customers, real people with real stories. Who have chosen Woffice to achieve their real goals. For this reason we realized that we would love to get more details about our customers and see what they think about Alkaweb and Woffice, so we’ve decided to collect some of these customer stories and share them with you, with a set of articles entirely dedicated to our customers.
(more…)

Today, we will discuss here how we can use the well known application Slack along with WordPress and the Woffice theme. Slack has over 5.8 million active users and powers communication in more than 60 000 teams around the world (source). Yet, we won’t go through all Slack’s milestones here. Just to say it’s a very used tool and it provides a very good way to get rid of emails. Certainly why everyone love it!
Furthermore, the biggest advantage of Slack is the ability to add 3rd-party applications in order to stay tuned about pretty much any application related to your business. Over 150 integrations actually on their apps directory, all for free.
So, what about we receive live notifications from our WordPress intranet/extranet right into our Slack channels? Sounds cool. Well, we’ve done it with Woffice and I will show you how to set it up in 5 minutes.

How to set it up?

We assume, you have WordPress set up on your side with the Woffice theme installed. That’s all you need, with a Slack account, of course.
First, we have to activate the Woffice Slack extension from Woffice (or Unyson page) > Extensions:
1
Secondly, we need to create our own Slack app in order to create a connection between your WordPress Intranet and your Slack team account. For this, you have to click the “Settings” link to go on the extension’s settings page. You can see now a “Create a new application” link that will lead you to the right place.
Click on “Create New App” and fill in the form, everything can be changed later. You should see:
 
2
Then, once you application created, you’ll get a client ID and a client Secret. You need to copy/past those two fields in the extension’s settings back on Woffice:
unyson__woffice_dev_-_wordpress
Last but not least, you need to copy/past the Call Back URL from the Woffice extension’s settings to the Slack > OAuth & Permissions > Redirect URL input field:
3
You can add your own icon to your Slack boat.
Don’t forget to save everything. At this point we have a new application on Slack, which is a good start!
Thirdly, we need to assign our notifications to a Slack channel trough our brand new application. We can do that by going to the “Slack Notifications” tab on the extension’s settings page.
Thus, we can see a pretty sweet “Add to Slack” button, well we can click on it so we can choose on which channel will the notifications be published. Once this button clicked, you need to Authorize access to one your Slack team. Then, you can select a channel from the “Post to” option. See:4
You can now choose the triggers that will push notifications from WordPress to your Slack channel.
We’re ready to go! Whenever an action (that you’ve enabled on the above form) is triggered on your Intranet, it’ll be sent in real time on your Slack channel. So you can keep all your data in one place, saving time and improving your team communication.
Note that we’ve added 5 triggers so far, but we’ll add more in the coming updates. Just let us know your thoughts if you have any idea.
The available triggers (Woffice 2.2.0) are whenever a new:

  • Comment is posted
  • User is registered (or added by an administrator)
  • BuddyPress activity (only if the activity is public)
  • Post (whether it is a blog post, page, project, wiki, product, directory item…)
  • Task on a project

Going one step further and create your own notification

The best part is that once the Slack extension enabled on your site and working. Woffice comes with a helper function to manage all the dirty API code for you. One single function to use anywhere in your Intranet/Extranet to post sweet Slack notifications that you can customize in a matter of minutes.
However, we assume here that you’ve PHP skills (you don’t need to be an expert here).
The function is defined in woffice/framework-customizations/extensions/woffice-slack/helpers.php and can be used like this:

// Our notification data:
$notification = array(
    'title' => 'Hey I\'m the title',
    'title_link' => 'Link to your site or any page', // like: get_site_url()
    'pretext' => 'Just above the title',
    'text' => 'Text content',
);
// Let's send our notification to our Slack channel
woffice_slack_send_notification($notification)

Although, if you try that PHP code in your child theme, it’ll work right out of the box but there are 2 important points:

  1. Slack API is rich! The $notification array will be passed as a Slack attachment, see their documentation for all details. So you can add images, author name, icons, buttons…
  2. You must call woffice_slack_send_notification under an add_action() callback function (see next example). So your notification is triggered on a certain event and not whenever you page is loaded.

Developer example: Contact Form 7 Slack integration

Finally, we’ll see now an example with the Contact Form 7 plugin. We’re using the default contact form but you can adapt with your own settings.

/**
 * Trigger a notification whenever an email is being sent
 * through a Contact Form 7 form
 * Note that :mail: & :bust_in_silhouette: are Emojies used by Slack
 * @param $contact_form : WPCF7_ContactForm
 */
function woffice_slack_hook_cf7($contact_form) {
    // We get the form title:
    $title = $contact_form->title();
    // We get the current submission
    $submission = WPCF7_Submission::get_instance();
    if ( $submission ) {
        // We get the submission data:
        $posted_data = $submission->get_posted_data();
        // We build our notification array:
        $notification = array(
            'title' => $posted_data['your-subject'],
            'title_link' => get_admin_url(),
            'pretext' => ':mail: ' . __('New form submission on', 'woffice') . ' ' . $title,
            'text' => $posted_data['your-message'],
            'fields' => array(
                array(
                    'title' => ':bust_in_silhouette: ' . __('Sent by', 'woffice'),
                    'value' => $posted_data['your-email'],
                    'short' => true
                )
            )
        );
        // We push the notification to Slack
        woffice_slack_send_notification($notification);
    }
}
add_action('wpcf7_mail_sent', 'woffice_slack_hook_cf7');

It’s just an example, you can do that with your favourite plugins, as long as they’re well documented. Building your custom notifications will be very easy.
We’re really looking forward to add more integrations, let us know your ideas.
 

Woffice 2.0 is finally here ! A lots of new features to make your experience even more delightful (yes, that’s possible !). We’ll have a look here to some of the features we’ve added, most of them are unique and you’ll only see them in Woffice theme.
(more…)

A new great relase of Woffice is available: Woffice 1.8.0
One of the most important things, from this new relase is that we have included Slider Revolution for FREE in our theme, so you will save more $19 buying Woffice for your website. (more…)