WordPress is a user-friendly CMS that even the first-timers who have never seen any WordPress Admin Panel tutorial before choosing it to power their projects. This is no small measure of the success of the CMS in a highly competitive market that sees new CMS enter very regularly. 

WordPress is renowned for its simplicity and easy-to-use interface. The WordPress Admin Dashboard allows users to manage their websites easily without writing a single line of code. 

In this article, I will explain how to use the admin dashboard and describe each section in detail. 

(more…)

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!

Is your small business growing but you are finding it difficult to cope up with it’s increasing challenges? 

Does it feel hard to skyrocket your sales volume?

Can’t figure out how to maintain a sound relationship with customers and to pull the reins of the expenditures insinuating to the revenue area?

Are you struggling to get an extra holiday from your business to spend time with your family?

Honestly, these are the pain points where almost every small business owner discovers them in. If you are overwhelmed by any of these phenomena, then it’s time to put a halt to these. To sum up, in one sentence, these challenges can easily be tackled and managed efficiently with a suitable ERP software solution.

Now, go, get your Scuba gear out, because we will take you to a deep dive to the benefits and implementation process of an ERP solution with the goodness of WordPress.

How an ERP software can give you a bump on your overall productivity?

Generally, the small business owners have to deal with the basic business managerial activities like managing the Human Resources, maintaining a sound relationship with Customers and managing Accounting and Projects. Here are some of the frequently faced scenarios by the small business owners that can be knocked down with an ERP software are:

Do the basic HRM problems challenge you?

It can be extremely hard to manually count who is present and who is absent. Besides, it can take a whole day to count all the employees’ attendance during a year.

However, if you are using an ERP solution, then it will be way easier to calculate the number of attendance of each and every employee’s attendance. What’s more! these solutions can even count the working hours, overtime hours, remaining leave days and show the data with graphical representations.

You can also use an ERP tool to effortlessly make important announcements for your human resources.

Worried about the inefficient recruitment Process?

An ERP solution provides you with an efficient recruitment process. To hire the most eligible employees you will only have to create a job post, set questionnaires for the screening test. But that’s not the end! You can also fix the interview room and the interviewer.

Want to evaluate your employees’ performance?

Measuring the work performance of employees is, undoubtedly, a tough task and requires taking feedback from the team leads and saving those feedback in employee profiles. A good ERP solution ensures doing just that. With an ERP software, you can get a complete employee report.

Can’t remember the asset possessions?

Throughout the business operations, you may need to allocate a number of assets ranging from laptops to calculators to headphones to desktops and so on to your employees. Keeping track of them will require you to prepare handwritten documents to preserve the records.

Luckily, this can easily be done with just a mere asset management feature of an ERP system.

Are your valuable company papers disappearing?

Physical papers are definitely important but the thing is they can easily be stolen and damaged. Furthermore, they consume a plenty of office spaces and more importantly, you have to spend a great deal of money on them.

This problem can easily be solved with a document management feature in an ERP solution with which you can easily share documents among your employees anytime via the internet.

Having trouble in managing the payroll?

Dealing with payrolls is definitely tough but managing payrolls as per federal tax compliance is tougher. Fortunately, an ERP tool will pave you the way to manage payrolls according to the federal tax rates by creating various pay items like allowance or deduction for your employees.

Having a tiresome experience to manage your business contacts?

Back in the days, business owners or managers were used to maintaining separate Rolodexes for registering and keeping the contacts organized. But in this analog method, finding the desired contact within a second was next to impossible.

But with a CRM tool, you can not only store unlimited contacts but can also find them instantly. Some ERP tools even come with advanced conditional search options to find a group of contacts bearing a particular set of characteristics. These characteristics include customer life stages like visitors, leads, opportunities, and customers.

Some ERP tools will help you save contacts and companies separately so that individuals do not get mixed up with companies.

Looking for integrations with other customer support solutions?

If you are already using some cloud-based services like Awesome Support, Zendesk, and Help Scout to support your customers with tickets and do not want to switch to WP ERP for these features. Not to worry. Because WP ERP can easily get integrated with these solutions nd can work simultaneously.

Want to make your workflow more automated?

In some ERP solutions, you can trigger actions based on a number of events. You can set conditions like event A will happen if someone triggers event B. This is useful if you want to automate your emails when someone subscribes to your website or does a particular action.

Guide your CRM agents more efficiently

With an ERP system, you can easily guide your CRM agents to streamline your sales process with a faster method. Whenever you make a deal with any of your contacts, the system automatically updates the status of each of the deals.


Need to manage Accounting without an accountant?
For some of us, we love to do things with the ‘DIY’ approach. But maintaining the accounting calculation will require you to have a vast technical know-how. For instance, preparing a balance sheet or income statement is pretty technical.

Adding to that, if you think that employing a professional accountant will save your day then you are wrong. Because you will have to give him or her a good amount of compensation. To this end, an ERP system will give a boost if you want to manage the accounting problems without a professional accountant.

Want to manage inventories in a whole new way?

Never feel stressed while you are trying to manage your inventories. It’s because the advanced ERP tools will let you create invoices for the stocks. Some ERP system generates reports on the purchase, stocks, and sales too.

Like to empower your teammates with the reimbursement process?

If you are not in the office, never make others feel your absence. With the reimbursement functionality of an ERP software, you can allow your employees to spend on various things. No matter how many times they spend with your business, the only thing that they need to do is to input the expenditure into the system and get repaid from you.

Does project management feel like a pain in the neck?

As we ourselves, manage a number of projects and each member go through numerous tasks simultaneously. It becomes really tough to micromanage every single task. But, with a Project Management feature of an ERP software can facilitate you with the all the nitty-gritty to manage your projects. With a project management feature, you can easily add certain employees for a particular project or tasks.

Some sophisticated ERP tools have a project management feature that will allow you to find a project or task using a search bar. Moreover, you will get a dashboard to see the overall progress of tasks or projects over time.

To manage projects, some ERP tools also come with time tracking feature in the project management section so that the employees can track their individual time spent on a particular task.

Why will you go for WordPress?

* The most popular and absolutely free CMS to date
* Powers up more than one-third of the total websites of the world.
* Getting helped easily from a massive community across the world.
* Has a ton of free themes and plugins in its official directory.
* Safe website management.
* Open-source and customizable.

Why will you choose WordPress ERP?

WordPress ERP (also known as the WP ERP) is the one of a kind ERP which is only built for WordPress. It is really hard to find a solution that has all the bells and whistles to manage a business enterprise. Even though yours has such, there is a high chance that you are paying for some features that you will never need at all.

This is why an ERP tool with scalability features according to your specific needs is a matter of utmost priority. Only a few ERP tools provide you with this scalability features. You can consider WP ERP for the following valid reasons:


* The core version is completely free.
* Ships with three free modules HRM (Human Resource Management, CRM (Customer Resource Management) and Accounting.
* Easy implementation method.
* An integrated project management tool.
* All you need is a WordPress site to implement.
* Scalable with a host of extensions in line with your advanced needs.
* Online based system will allow you and your team to access any time into the system.
* A host of comprehensive and rich documentation and on-demand customer support.
* A good customer reviews along with a good 4.5 rating out of 5.
* 7000+ active installs.
* Open source and customizable

How to implement WP ERP in your WordPress site?

If you already have a WordPress site, navigate to the WP Admin Dashboard → Plugins → Add New → Search for “wp erp” → Click on the “Install Now” button.

Install WP ERP
Install WP ERP

Next, simply hit the ‘Activate’ button to complete the installation process like any other WordPress plugins.

Activate WP Erp
Activate WP Erp

Out of the box, you will get a step by step setup wizard that will help you configure the system as per your business. You can read this thorough walkthrough to complete the setup wizard. Once you finish the Setup Wizard, you are ready to use the ERP system for your business.

The final outcome

As the core version of WordPress ERP is free, it will surely keep the implementation costs lower. And there is an opportunity to extend the functionality of the tool according to your needs over time. As a small business owner, we believe, you will be able to stay way ahead of your competitors if you are using this WordPress ERP solution.

Finally, you can also try the demo version of the tool to get a hands-on experience.

Pop-ups have become standard on WordPress websites.

Need proof?

The WordPress directory lists no less than 2,576 pop-up plug-ins.

Yet, smart pop-ups are still far from being a standard.

Remember the last time you landed on a website, just to be displayed a pop-up right away?

In this article, I’ll explain how you can design smart WordPress pop-ups that convert and don’t put off your visitors (yes, it is possible).

In this article, we’ll explain how to:

  1. Set your objectives
  2. Define your segments
  3. Find the right wording
  4. Create your design
  5. Find the right pop-up plug-in

Without further ado, let’s dive right in!

Step 1: Set Your Objectives

Pop-ups can help you achieve several different things:

  • Grow your email list. On average, our customers triple the number of emails they collect when they implement email pop-ups.
  • Collect feedback. On average, our customers notice a 5.1% feedback rate.
  • Push a product or a service. You can expect a click-through-rate between 2% and 6% for this kind of pop-ups.

In this article, we’ll focus on the main use case: list-building.

Step 2: Define Your Segments

Most webmasters create only one pop-up that they display on all pages of their website, no matter what.

That’s a huge mistake. Chances are your visitors are expecting something different from your website.

Let’s take the example of a WordPress blog dedicated to online marketing. The blog covers various themes:  SEO, PPC, web design and entrepreneurship.

Some of the visitors find the blog when searching for a SEO topic on Google.

Others come through a link to an article about PPC techniques that someone shared in a Slack channel, etc.

You get the idea, right?

It’s difficult to design a one-size-fits-all pop-up that will appeal to all these different kinds of visitors.

So the first step is to think about your different segments. Personalization is key!

You can define them in terms of:

  • Page visited
  • Category of page visited? (WordPress categories or WordPress tags)
  • Devices?
  • Traffic source?

Here’s a real-life example on WordPress-powered Skillcrush.com.

When I exit a page in the “Remote work” category, I get this pop-up:

But when I visit an article of the “Tech” category, I get this one:

Ultimate Guide WP Popup

Defining different segments and displaying pop-ups tailored to them will help you display pop-ups that are most relevant to your audience.

The result?

You’ll end up collecting more emails.

Step 3: Identify Your Offer

I’ve got to tell you the truth.

Most of your visitors won’t subscribe to your newsletter just because you ask them. You must present them with a strong incentive to join your list.

But don’t worry, there are a few options.

Promise Awesome Content

Sometimes it’s enough to explain what kind of newsletters you’ll send and why they’re interesting. Here’s this strategy in action on Nutshell.com.

Email popup

Offer Exclusive Content

Usually called a lead magnet, this strategy consists of giving away an exclusive piece of content in exchange for your visitor’s email.

Here is an example from Pickaweb.co.uk, where subscribers can receive an ebook detailing traffic building strategies.

Exclusive content

The freebie can be anything from a free ebook, an exclusive training video, a unique email series, a podcast, etc.

Other Options

Depending on your business, you can also:

  • Offer a chance to win something
  • Offer an exclusive deal/discount
  • Offer a surprise (that could sound weird, but it works!)

This goes without saying: you’ll have to pick a different offer for your different segments.

Step 4: Find the Right Words

Now that you’ve identified your segments and the offer that will get them on the hook, it’s time to work on the wording of your pop-up.

Here are a few tips that should help.

Leverage What You Know About Your Visitors

Engaging a visitor is easier when you show that your offer is tailored to her.

Here’s an example from Beacon.by. I’m reading an article about lead magnets promotion. The pop-up uses a headline that speaks to me immediately: “Everything You Need to Know About Lead Magnets.”

Get Straight to the Point

Do you know anyone who takes more than 3 seconds to read a modal copy?

You’re right, life is too short to read long pop-up copies.

Get straight to the point: focus on what the subscriber will receive and why he should subscribe now. Period.

If you need to include legal terms, make them smaller so that the user can skip them easily.

Here’s a good illustration on Volusion’s blog.

Use Social Proof

To convince potential subscribers that your newsletter is the best, nothing beats social proof.

We love to see we’re not the only one subscribed to a newsletter. It feels even better when we can think that we read the same kind of email as an influencer.

Here’s an example from Inc42 featuring pictures of high-profile startuppers and influencers.

And here is one from Hotjar, relying on big numbers to capture potential subscribers’ attention:

Step 5: Prepare Your Design

When preparing the design of your WordPress modal, there are a few elements to keep in mind.

Your Pop-up’s Position

You don’t have to position your pop-up at the exact center of the screen.

Side modals can perform just as well, and are usually less annoying.

Their advantage?

As they’re not directly in your visitor’s way, there’s less chance your visitors will want to close them without even reading what they have to offer.

A side pop-up on Iterable’s blog

Bars can provide a great alternative, too. They’re less intrusive and can be displayed more frequently than lightbox pop-ups or full screen pop-ups.

An email bar on MailUp’s WordPress website

Your Visuals

Their main role is to make your pop-up more appealing while helping drive your users’ attention to your signup fields.

Look at this example from Meetedgar.com. The right picture brings life to the pop-up, while the pose of the woman on the picture drives user’s attention to the email input. Brilliant!

Your Call-to-Actions

The only risk with your call-to-actions is if your visitors miss them.

Make sure to choose colors that help your CTA stand out from the rest of your pop-up.

Mobile Pop-ups

Mobile pop-up design is specific. Why and how you can design great mobile pop-ups is explained in an earlier article.

Step 6: Find the Right plug-in

What is the best WordPress pop-up plug-in?

There’s not a simple answer to this question. It all depends on what you need. Here are a few elements to take into consideration before making a decision.

Integrations

If you’re collecting emails, that’s probably because you want to contact these people in the near future. Right?

One of the first things to check when you choose a pop-up plug-in is whether it integrates with your email marketing solution or not.

If not, it means you’ll have to manually export and import your contacts. And trust me, this limits how soon you are able to contact your subscribers.

Targeting & Design Features

This could sound obvious, but it’s not.

There is a wide range of tools. From tools where you need to create your design in HTML and manually upload it, to tools that offer WYSIWYG design and advanced targeting.

Before choosing your pop-up maker, try to identify where the plug-in you’re checking stands in that regard.

Pricing

There are almost as many pricing models as there are pop-up tools.

Beware of plug-ins that claim to be free.

And if you go down the free plug-in road, prefer open-source tools. They’ll limit the chances of introducing a security breach or ads in your website.

Wrap-Up

It’s now up to you!

If you appreciated this tutorial, share it. Feel free to join the discussion in the comments.

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.

As promised, here is the part 2 of our tutorial to create a Facebook WordPress plugin. Thanks a lot for your feedback.

Be sure to checkout part 1 before

Before starting off, a special thanks to Ovidiu Turean who made a pull request to the repository for the admin side developed in this part 2.

The complete code of this tutorial can be found in the same repository as part 1 under the branch V2.

So what’s on our agenda?

  1. Simple AJAX powered admin page to save the Facebook app ID and secret
  2. Sending an email upon new registration in order to provide the password and username to the user
  3. CSS styling of our Facebook button

Improvement 1: creating a new WordPress page for the plugin Settings

In order to create an admin page for our plugin, we will need to re-organize it so everything is clean and make sense.

So what did we changed?

  • alka-facebook.php is the plugin main file, it’s the one called by WordPress whenever the plugin is loaded
  • assets/ is a folder that will contain all our images, javaScript files as well as stylesheets (.css)
  • classes/ contains 2 classes called in alka-facebook.php, one for the API connection and user creation / login. The other is only for the admin page.

Let’s dive in the details by starting with the main file:

/**
 * Class AlkaAdmin
 *
 * This class creates a very simple Options page
 */
class AlkaAdmin
{
  /**
   * The security nonce
   *
   * @var string
   */
  private $_nonce = 'alka_facebook_admin';
  /**
   * AlkaAdmin constructor.
   */
  public function __construct()
{
    add_action( 'admin_menu', array( $this, 'addAdminMenu' ) );
    add_action( 'wp_ajax_alka_store_admin_creeds', array( $this, 'storeFacebookAdminCreeds' ) );
    add_action( 'admin_enqueue_scripts', array( $this, 'addAdminScripts' ) );
  }
}
/*
 * Starts our admin class, easy!
 */
new AlkaAdmin();

As you can see, the main difference with part 1 is that this file is just here to call other files. The Facebook SDK and then our plugin classes. We define as well 2 constants that will be used to retrieve the different files within the plugin.

  • ALKA_FACEBOOK_PATH for the PHP includes
  • ALKA_FACEBOOK_URL for the .js, .css and image calls from our browsers

Once this done, we can create our admin page, using the brand new AlkaAdmin.php file. Our admin page is really simple, 2 fields (Facebook App ID, Facebook App Secret), the callback URL to help the user.

We save everything using AJAX so we don’t have to reload the page. Therefore we will also use a WordPress Nonce to add an extra security layer.


/**
* Class AlkaAdmin
*
* This class creates a very simple Options page
*/
class AlkaAdmin
{/** * The security nonce * * @var string */
private $_nonce = 'alka_facebook_admin'; /** * AlkaAdmin constructor. */
public function __construct()
{
add_action('admin_menu', array($this, 'addAdminMenu'));
add_action('wp_ajax_alka_store_admin_creeds', array($this, 'storeFacebookAdminCreeds'));
add_action('admin_enqueue_scripts', array($this, 'addAdminScripts'));
}
}

/** Starts our admin class, easy! */
new AlkaAdmin();

So as you can see our class’s constructor will call 3 main methods: addAdminMenu, storeFacebookAdminCreeds and addAdminScripts.

Firstly, we use addAdminMenu to register our new page for WordPress:

/**
 * Adds Alka to WordPress Admin Sidebar Menu
 */
public function addAdminMenu() {
    add_menu_page(
        __( 'Alka Facebook', 'alkaweb' ),
        __( 'Alka Facebook', 'alkaweb' ),
        'manage_options',
        'alka_facebook',
        array( $this, 'adminlayout' ),
        ''
    );
}

As you can see, there is another callback to a new method (adminlayout) that will handle the HTML displayed within this page. You can load an other file to make your plugin even cleaner.

For the sake of simplicity, the HTML will be loaded within the class method (boooo…)

/**
 * Outputs the Admin Dashboard layout
 */
public function adminlayout() {
    $facebook_creeds = AlkaFacebook::getCredentials();
    $alka_app_id = (isset($facebook_creeds['app_id']) && !empty($facebook_creeds['app_id'])) ? $facebook_creeds['app_id'] : '';
    $alka_app_secret = (isset($facebook_creeds['app_secret']) && !empty($facebook_creeds['app_secret'])) ? $facebook_creeds['app_secret'] : '';
    ?>
    <div class="wrap">
        <h3><?php _e( 'Facebook API Settings', 'alkaweb' ); ?></h3>
        <table class="form-table">
            <tbody>
            <tr>
                <td>
                    <label><?php _e( 'Your callback url', 'alkaweb' ); ?></label>
                </td>
                <td>
                    <span class="highlight"><?php echo AlkaFacebook::getCallbackUrl(); ?></span>
                </td>
            </tr>
            <tr>
                <td scope="row">
                    <label><?php _e( 'Facebook App ID', 'alkaweb' ); ?></label>
                </td>
                <td>
                    <input id="alka-fb-app-id" class="regular-text" value="<?php echo $alka_app_id; ?>"/>
                </td>
            </tr>
            <tr>
                <td>
                    <label><?php _e( 'Facebook App Secret', 'alkaweb' ); ?></label>
                </td>
                <td>
                    <input id="alka-fb-app-secret" class="regular-text" value="<?php echo $alka_app_secret; ?>"/>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <button class="button button-primary" id="alkaweb-facebook-details"><?php _e( 'Submit', 'alkaweb' ); ?></button>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
    <?php
}

The 2 static methods we call from the AlkaFacebook class (see part 1 of this tutorial) will be defined later:

  • AlkaFacebook::getCredentials() returns the saved credentials from the database as an array
  • AlkaFacebook::getCallbackUrl() returns the callback URL that must be provided  to Facebook through the app portal

Once this done, we can enjoy a clean admin page for our plugin:

But nothing happen when we click the save button so far, which is (let’s be honest) quite an issue!

In order to save the data, we’ll add a javaScript file to the WordPress admin using the method: addAdminScripts(). This file will just “listen” to the admin actions, whenever the button is pushed, a request is made to your server. WordPress will redirect the request to our class’s method storeFacebookAdminCreeds(). That easy.

We enqueue our new javaScript file: assets/js/admin.js (you need to create it) using our constant define earlier.

/**
 * Adds Admin Scripts for the Ajax call
 */
public function addAdminScripts() {
    wp_enqueue_script( 'alka-facebook-admin', ALKA_FACEBOOK_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( 'alka-facebook-admin', 'alka_facebook_admin', $admin_options );
}

As you can see we also pass 2 PHP variables to our JS file using an object  named: alka_facebook_admin.

We can know fill in the JavaScript file, we watch for the user click, build our request and send it using Ajax:

/**
 * Alka Facebook Saving process
 */
jQuery( document ).ready( function () {
    jQuery( document ).on( 'click', '#alkaweb-facebook-details', function ( e ) {
        e.preventDefault();
        var _app_id = jQuery( '#alka-fb-app-id' ).val(),
            _app_seccret = jQuery( '#alka-fb-app-secret' ).val();
        jQuery.ajax( {
            url: alka_facebook_admin.ajax_url,
            type: 'post',
            data: {
                action: 'alka_store_admin_creeds',
                security: alka_facebook_admin._nonce,
                app_id: _app_id,
                app_secret: _app_seccret
            },
            success: function ( response ) {
                alert(response);
            }
        } );
    } );
} );

The result is displayed through a basic alert(), but this can be changed with something more user friendly of course.

It’s now time to save the data we received from the page in our database using a handy method: storeFacebookAdminCreeds() which is linked to our WordPress ajax hook: alka_store_admin_creeds sent in our request. This is possible with this action we’ve added at the beginning in our constructor:

add_action( 'wp_ajax_alka_store_admin_creeds', array( $this, 'storeFacebookAdminCreeds' ) );

So the method below just takes the data sent through the Ajax request, validate them and save them in the wp_options table.

/**
 * Callback for the Ajax request
 *
 * Updates the FaceBook App ID and App Secret options
 */
public function storeFacebookAdminCreeds() {
    if ( wp_verify_nonce( $_POST['security'], $this->_nonce ) === false ) {
        die( 'Invalid Request!' );
    }
    if (
            (isset($_POST['app_id']) && !empty($_POST['app_id']))
            &&
            (isset($_POST['app_secret']) && !empty($_POST['app_secret']))
    ) {
        update_option( 'alka_facebook', array(
            'app_id'     => $_POST['app_id'],
            'app_secret' => $_POST['app_secret'],
        ) );
    }
    echo __('Saved!', 'Alkaweb');
    die();
}

That’s it! We can now receive and save the Facebook App ID as well as the Facebook App Secret from the WordPress admin dashboard. Cool! 

We now need to update the AlkaFacebook.php class defined in part 1 of this tutorial to no longer use private attributes but rather our saved option. In order to get the Facebook App ID and secret.

In the same way, we will create the method that returns the site callback url for Facebook (which was also an attribute before):

/**
 * Returns the Facebook credentials as an array containing app_id and app_secret
 *
 * @return array
 */
static function getCredentials() {
   return get_option( 'alka_facebook', array() );
}
/**
 * Returns the callback URL
 *
 * @return string
 */
static function getCallbackUrl() {
   return get_admin_url( null, 'admin-ajax.php?action=alka_facebook' );
}

We can now use them by re-defining our methods within the same class:

/**
 * Login URL to Facebook API
 *
 * @return string
 */
private function getLoginUrl() {
    if(!session_id()) {
        session_start();
    }
    $fb = $this->initApi();
    $helper = $fb->getRedirectLoginHelper();
    // Optional permissions
    $permissions = ['email'];
    $url = $helper->getLoginUrl(self::getCallbackUrl(), $permissions);
    return esc_url($url);
}

And lastly, for the credentials:

/**
 * Init the API Connection
 *
 * @return Facebook
 */
private function initApi() {
   $credentials = self::getCredentials();
   // Only if we have some credentials, ideally an Exception would be thrown here
   if(!isset($credentials['app_id']) || !isset($credentials['app_secret']))
      return null;
    $facebook = new Facebook([
        'app_id' => $credentials['app_id'],
        'app_secret' => $credentials['app_secret'],
        'default_graph_version' => 'v2.2',
        'persistent_data_handler' => 'session'
    ]);
    return $facebook;
}

Done! Our API connection is now using our options from the plugin’s options page.

You can test on your side to make sure it’s working as expected.

Improvement 2: sending the email to the user

For this one, you will need server to get the email sent as your Localhost probably don’t have any email driver.

We are simply gonna add a new method in createUser() method after the meta and before we log in the user.

// Setting the meta
update_user_meta( $new_user_id, 'first_name', $fb_user['first_name'] );
update_user_meta( $new_user_id, 'last_name', $fb_user['last_name'] );
update_user_meta( $new_user_id, 'user_url', $fb_user['link'] );
update_user_meta( $new_user_id, 'alka_facebook_id', $fb_user['id'] );
// Send a validation email
$this->sendConfirmation($username, $password, $fb_user['email']);
// Log the user ?
wp_set_auth_cookie( $new_user_id );

Now, it’s time to create this new method in our AlkaFacebook class:

/**
 * Sends a confirmation email to the new user
 *
 * @param string $username
 * @param string $password
 * @param string $email
 */
private function sendConfirmation($username, $password, $email) {
    $subject = __('Welcome! Your account has been created!', 'alkaweb');
    $headers = array('Content-Type: text/html; charset=UTF-8');
    $body = '';
    $body .= __('Your friends from', 'alkaweb') . ': <a href="' . get_site_url() . '">' . get_site_url() . '</a><br>';
    $body .= __('We are please to announce that your account has been successfully created!', 'alkaweb') . '</br>';
    $body .= __('You can login at anytime with your Facebook account, you can also always use the following credentials', 'alkaweb') .': <br>';
    $body .= __('User', 'alkaweb') . ': <b>' . $username . '</b><br>';
    $body .= __('Password', 'alkaweb') . ': <b>' . $password . '</b><br><br>';
    $body .= __('Thanks', 'alkaweb');
    wp_mail( $email, $subject, $body, $headers );
}

We simply use the wp_mail() function from WordPress to do the job for us. This function requires 4 parameters, you can find all the details on the documentation page related to that function.

You are free to customize the content and even design your own template. Note that we pass the username, password and email as method arguments to be sure we send the right data.

Improvement 3: designing our button

In part 1, the shortcode was just displaying a simple link, we’ll create a brand new button that’d impress any of your visitor.

The first thing we want to do it to change the shortcode’s HTML output:

/**
 * Render the shortcode [alka_facebook/]
 *
 * It displays our Login / Register button
 */
public function renderShortcode() {
    //... Same as Part 1
    // Button
    $logo = '<img src="'. ALKA_FACEBOOK_URL. '/assets/images/fb-logo.png" alt="Facebook logo">';
    $html .= '<a href="'.$this->getLoginUrl().'" class="btn" id="alka-facebook-button">'. $logo . $button_label .'</a>';
    $html .= '</div>';
    // Write it down
    return $html;
}

As you can see we’re adding a new icon, which can done be downloaded from the Facebook Brand Resources page. Pick up any icon from the .zip your download (possibly a white one) and place it in assets/images/, renamed as fb-logo.png.

We can also create a new css file assets/css/button-style.css:

/**
 * CSS for the Alka Facebook plugin
 */
#alka-facebook-wrapper{
    margin: 20px 0;
}
#alka-facebook-wrapper a#alka-facebook-button{
    color: #FFF;
    background: #3b5998;
    border-radius: 5px;
    box-shadow: 0 5px 0 0 #091e57;
    padding: 10px 30px 20px 30px;
    text-decoration: none;
    display: inline-block;
}
#alka-facebook-wrapper a#alka-facebook-button img{
    box-shadow: none;
    width: 30px;
    padding-right: 30px;
    box-sizing: content-box;
    display: inline-block;
    position: relative;
    bottom: -10px;
}

We now need to add our new css file whenever the page is loader. Similarly to the admin side, we just create a new action in the AlkaFacebook class’s constructor

// Add our button css file
add_action( 'wp_enqueue_scripts', array($this, 'addButtonCSS'));

So it looks like:

/**
 * AlkaFacebook constructor.
 */
public function __construct()
{
    // We register our shortcode
    add_shortcode( 'alka_facebook', array($this, 'renderShortcode') );
    // Start the session
    add_action( 'template_redirect', array($this, 'sessionInit') );
    // Callback URL
    add_action( 'wp_ajax_alka_facebook', array($this, 'apiCallback'));
    add_action( 'wp_ajax_nopriv_alka_facebook', array($this, 'apiCallback'));
    // Add our button css file
    add_action( 'wp_enqueue_scripts', array($this, 'addButtonCSS'));
}

We just have to enqueue the stylesheet with the method: addButtonCSS()

/**
 * Enqueue the plugin's css file
 */
public function addButtonCSS() {
    wp_enqueue_style( 'alka-facebook-button', ALKA_FACEBOOK_URL. '/assets/css/button-style.css' );
}

Here again, we are making great use of the constants defined at the beginning of this tutorial.

This is the expected result on a new page called “Facebook” containing only the shortcode. On the default WordPress theme:

Lastly, regarding the Facebook avatar and how to get it upon registration, well we didn’t build it in this part for a simple reason. As or right now, I have looked several plugins doing so and I find the process very “barbarian”. It’s just a filter on the get_avatar() function  to replace the path with a link to Facebook containing the user ID. Simply because it’s managed by Gravatar on WordPress. It’d be better, if we do it, to focus only on BuddyPress as their is a deeper avatar integration. With an upload process for example, which is not here by default on WordPress.

Any question? Fire away in the comments 🙂

Moderate new user registrations can be very useful in several WordPress scenarios: intranets/extranets; e-learning platforms; multi-author blogs; multi-vendor e-commerce site and many others. 

It can be also a good protection against spamming accounts, if the email confirmation isn’t enough.

If you are looking for a way to approve or deny manually the registration of your users, you will find a very good solution in this article.

(more…)

In this tutorial, we will see how to write a simple WordPress plugin in order to Login and Register your users right on your WordPress site using the Facebook API. It is very easy to do and we will go through each step one by one.
You need to have basics in PHP, WordPress development, CSS and HTML. But nothing tricky here.
You can find the complete plugin on Github: Plugin repository
Note that this is a first part, as you will see at the end, there are many things that can be improved.
Update: You can find part 2 here!
The authentication flow from Facebook is quite simple:

  • We use the Facebook SDK to generate a login link to redirects toward Facebook’s server.
  • If everything is good and the user agrees to let our application get some details. We are redirected back to our WordPress site.
  • During the redirection, Facebook gives us a temporary “Access Token”.
  • We use this token to ask the Facebook API to get the user’s details: ID, Name, Email…
  • We handle the data in WordPress by either connecting the user if there was a previous connection or by creating a new account.

What is the goal?

We want to provide our users a very simple way to login and register to WordPress. Without email, username or password to enter in order to log in. Just a single button to click.
The easiest way will be to create a new shortcode which will display a Login/Register button and any error that should be displayed. So you can use it in any page / post / widget  or theme template using the do_shortcode function.
The shortcode will display nothing if the user is currently logged in. You might want to change that behavior.
We will use a plugin to wrap our code so it can work in any site. This plugin will be using the Facebook SDK and an object oriented coding style.
Feel free to change all the “alka” word  with your organization’s name.

Step 1: Building our plugin and importing the Facebook PHP SDK

First, we need to create a new plugin so our code is run by WordPress. Create a new directory “alka-facebook” (in wp-content/plugins/) that will hold all our files. Then, let’s get started! Create a new alka-facebook.php file:

<?php
/**
 * Plugin Name:       Alka Facebook
 * Description:       Login and Register your users using Facebook's API
 * Version:           1.0.0
 * Author:            Alkaweb
 * Author URI:        http://alka-web.com/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/alka-facebook
 */
class AlkaFacebook{
    /**
     * AlkaFacebook constructor.
     */
    public function __construct()
    {
    }
}
/*
 * Starts our plugins, easy!
 */
new AlkaFacebook();

You can now enable the plugin in Plugins > Alka Facebook > Activate. All our code will now be executed by WordPress, which is good.
Then, we can now import the Facebook PHP Sdk which will help us to make our calls to the Facebook API using PHP.
There are several ways to import it, the easiest one in WordPress is to download the SDK, rename the folder as facebook-sdk and move it to our plugin’s directory:

Now, we need to call the Facebook Sdk files required by the authentication actions that will be done within our plugin.
Just add the following to the top of the plugin’s file, right after the plugin header:

/*
 * Import the Facebook SDK and load all the classes
 */
include (plugin_dir_path( __FILE__ ) . 'facebook-sdk/autoload.php');
/*
 * Classes required to call the Facebook API
 * They will be used by our class
 */
use Facebook\Facebook;
use Facebook\Exceptions\FacebookSDKException;
use Facebook\Exceptions\FacebookResponseException;

Step 2: creating our Facebook Application

Secondly, in order to make API calls to the Facebook API, we obviously need to get some access. So Facebook knows who is making the calls and requesting the user details.
You can do that by going on the Facebook Apps page: https://developers.facebook.com/apps.

  • Click the “Add a new App” button
  • Set up the name and create your APP
  • Enable the Products > Facebook Login 
  • Add your Callback URL, which is http://yoursite.com/wp-admin/admin-ajax.php?action=alka_facebook you definitely need to change yoursite.com with your site’s URL.

  • Go to the Settings to get your App Id and App Secret 

We can now save them in our Class safely:

class AlkaFacebook{
    /**
     * Facebook APP ID
     *
     * @var string
     */
    private $app_id = 'xxxxxxxxxxxx';
    /**
     * Facebook APP Secret
     *
     * @var string
     */
    private $app_secret = 'yyyyyyyyyyyyy';
    /**
     * Callback URL used by the API
     *
     * @var string
     */
    private $callback_url = 'http://yoursite.com/wp-admin/admin-ajax.php?action=alka_facebook';

We are now ready to use Facebook API safely from our site.

Step 3: Creating our Shortcode

Thirdly, we will create a very simple shortcode to display our button, you can add options to this shortcode to go further we won’t do it in this tutorial though.
The shortcode is added using the “add_shortcode” WordPress function in our constructor and calls a method “renderShortcode“, which has a pretty good name according to how we will use it.

/**
 * AlkaFacebook constructor.
 */
public function __construct()
{
    // We register our shortcode
    add_shortcode( 'alka_facebook', array($this, 'renderShortcode') );
}
/**
 * Render the shortcode [alka_facebook/]
 *
 * It displays our Login / Register button
 */
public function renderShortcode() {
    // No need for the button is the user is already logged
    if(is_user_logged_in())
        return;
    // Different labels according to whether the user is allowed to register or not
    if (get_option( 'users_can_register' )) {
        $button_label = __('Login or Register with Facebook', 'alkaweb');
    } else {
        $button_label = __('Login with Facebook', 'alkaweb');
    }
    // Button markup
    $html = '<div id="alka-facebook-wrapper">';
    $html .= '<a href="#" id="alka-facebook-button">'.$button_label.'</a>';
    $html .= '</div>';
    // Write it down
    return $html;
}

You can now use [alka_facebook /] in your editor in any page and save. For testing purpose, you can now log out.

Step4: Connecting to the API

Next, we will now create a connection between our plugin and the Facebook API using our Facebook App’s details. In order to achieve this, we will create a new method to initialize the connection as it will be called several times, we return a Facebook instance:

/**
 * Init the API Connection
 *
 * @return Facebook
 */
private function initApi() {
    $facebook = new Facebook([
        'app_id' => $this->app_id,
        'app_secret' => $this->app_secret,
        'default_graph_version' => 'v2.2',
        'persistent_data_handler' => 'session'
    ]);
    return $facebook;
}

Thus, we can now use the SDK to get a login/register URL that will be used whenever the user clicks our button. Note that we use the PHP session to pass the data through all the methods and Facebook’s authentication steps:

/**
 * Login URL to Facebook API
 *
 * @return string
 */
private function getLoginUrl() {
    if(!session_id()) {
        session_start();
    }
    $fb = $this->initApi();
    $helper = $fb->getRedirectLoginHelper();
    // Optional permissions
    $permissions = ['email'];
    $url = $helper->getLoginUrl($this->callback_url, $permissions);
    return esc_url($url);
}

So, we can now use this URL in our button (renderShortcode) method:

$html .= '<a href="'.$this->getLoginUrl().'" class="btn" id="alka-facebook-button">'.$button_label.'</a>';

Our Facebook signing button now redirects us to Facebook, we are also redirect back to our callback URL. Yi hay!

Step 5: The callback

Lastly, the Callback is the code run by our plugin whenever an user is done with the Facebook dialog. He is redirected back to our site. For this matter, we created a new URL (already used earlier) http://yoursite.com/wp-admin/admin-ajax.php?action=alka_facebook which is basically a way to run our code with our own URL in WordPress. This is using the AJAX way, it would be better to use the REST API later though.

/**
 * AlkaFacebook constructor.
 */
public function __construct()
{
    // We register our shortcode
    add_shortcode( 'alka_facebook', array($this, 'renderShortcode') );
    // Callback URL
    add_action( 'wp_ajax_alka_facebook', array($this, 'apiCallback'));
    add_action( 'wp_ajax_nopriv_alka_facebook', array($this, 'apiCallback'));
}

And we need to create our callback’s method. This callback decides whether the user must be logged in or registered. This is where all the magic happens!
We will introduce a bunch of new stuff first here:

  • A new “alka_facebook_messagesession variable that will handle any error or message that must be displayed back to the user.
  • A new “alka_facebook_urlsession variable to redirect our user properly after the callback. It saves the page’s URL (where the shortcode is located)
  • A new class property: $access_token to use the access token from the Facebook API
  • A new class property: $redirect_url to use our alka_facebook_url within our class
  • A  new class property: $facebook_details to use the user data returned by the Facebook URL.

Moreover, we use class properties so we can split our code in several methods and never pass anything as an argument but rather as a class property. Which is cleaner.
In order that we now add our new properties:

/**
 * Access token from Facebook
 *
 * @var string
 */
private $access_token;
/**
 * Where we redirect our user after the process
 *
 * @var string
 */
private $redirect_url;
/**
 * User details from the API
 */
private $facebook_details;

We can also update our shortcode render method to pass the URL and display any message that would be returned by the callback through the $_SESSION:

/**
 * Render the shortcode [alka_facebook/]
 *
 * It displays our Login / Register button
 */
public function renderShortcode() {
    // Start the session
    if(!session_id()) {
        session_start();
    }
    // No need for the button is the user is already logged
    if(is_user_logged_in())
        return;
    // We save the URL for the redirection:
    if(!isset($_SESSION['alka_facebook_url']))
        $_SESSION['alka_facebook_url'] = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
    // Different labels according to whether the user is allowed to register or not
    if (get_option( 'users_can_register' )) {
        $button_label = __('Login or Register with Facebook', 'alkaweb');
    } else {
        $button_label = __('Login with Facebook', 'alkaweb');
    }
    // HTML markup
    $html = '<div id="alka-facebook-wrapper">';
    // Messages
    if(isset($_SESSION['alka_facebook_message'])) {
        $message = $_SESSION['alka_facebook_message'];
        $html .= '<div id="alka-facebook-message" class="alert alert-danger">'.$message.'</div>';
        // We remove them from the session
        unset($_SESSION['alka_facebook_message']);
    }
    // Button
    $html .= '<a href="'.$this->getLoginUrl().'" class="btn" id="alka-facebook-button">'.$button_label.'</a>';
    $html .= '</div>';
    // Write it down
    return $html;
}

So what about we build our callback method now? The callback is split in 4 other methods:

  • getToken, to ask the Facebook API to get an authentication unique token. See the Facebook documentation here for all the details.
  • getUserDetails, once we have a token, we now ask the API to get the user’s details (name, email…). You can see all the information that you can fetch here.
  • loginUser, to login the User to WordPress.
  • createUser, to register a new user in WordPress.

Therefore, to decide if we login or register the user, we save for each user a new user meta: alka_facebook_id. Which is the Facebook user’s id. If it exists in our database, we login the user. If not, we make sure registration is allowed on the site before creating a new user.

/**
 * API call back running whenever we hit /wp-admin/admin-ajax.php?action=alka_facebook
 * This code handles the Login / Regsitration part
 */
public function apiCallback() {
    if(!session_id()) {
        session_start();
    }
    // Set the Redirect URL:
    $this->redirect_url = (isset($_SESSION['alka_facebook_url'])) ? $_SESSION['alka_facebook_url'] : home_url();
    // We start the connection
    $fb = $this->initApi();
    // We save the token in our instance
    $this->access_token = $this->getToken($fb);
    // We get the user details
    $this->facebook_details = $this->getUserDetails($fb);
    // We first try to login the user
    $this->loginUser();
    // Otherwise, we create a new account
    $this->createUser();
    // Redirect the user
    header("Location: ".$this->redirect_url, true);
    die();
}

Let’s create our 4 methods within our call back method:

/**
 * Get a TOKEN from the Facebook API
 * Or redirect back if there is an error
 *
 * @param $fb Facebook
 * @return string - The Token
 */
private function getToken($fb) {
    // Assign the Session variable for Facebook
    $_SESSION['FBRLH_state'] = $_GET['state'];
    // Load the Facebook SDK helper
    $helper = $fb->getRedirectLoginHelper();
    // Try to get an access token
    try {
        $accessToken = $helper->getAccessToken();
    }
    // When Graph returns an error
    catch(FacebookResponseException $e) {
        $error = __('Graph returned an error: ','alkaweb'). $e->getMessage();
        $message = array(
            'type' => 'error',
            'content' => $error
        );
    }
    // When validation fails or other local issues
    catch(FacebookSDKException $e) {
        $error = __('Facebook SDK returned an error: ','alkaweb'). $e->getMessage();
        $message = array(
            'type' => 'error',
            'content' => $error
        );
    }
    // If we don't got a token, it means we had an error
    if (!isset($accessToken)) {
        // Report our errors
        $_SESSION['alka_facebook_message'] = $message;
        // Redirect
        header("Location: ".$this->redirect_url, true);
        die();
    }
    return $accessToken->getValue();
}
/**
 * Get user details through the Facebook API
 *
 * @link https://developers.facebook.com/docs/facebook-login/permissions#reference-public_profile
 * @param $fb Facebook
 * @return \Facebook\GraphNodes\GraphUser
 */
private function getUserDetails($fb)
{
    try {
        $response = $fb->get('/me?fields=id,name,first_name,last_name,email,link', $this->access_token);
    } catch(FacebookResponseException $e) {
        $message = __('Graph returned an error: ','alkaweb'). $e->getMessage();
        $message = array(
            'type' => 'error',
            'content' => $error
        );
    } catch(FacebookSDKException $e) {
        $message = __('Facebook SDK returned an error: ','alkaweb'). $e->getMessage();
        $message = array(
            'type' => 'error',
            'content' => $error
        );
    }
    // If we caught an error
    if (isset($message)) {
        // Report our errors
        $_SESSION['alka_facebook_message'] = $message;
        // Redirect
        header("Location: ".$this->redirect_url, true);
        die();
    }
    return $response->getGraphUser();
}
/**
 * Login an user to WordPress
 *
 * @link https://codex.wordpress.org/Function_Reference/get_users
 * @return bool|void
 */
private function loginUser() {
    // We look for the `eo_facebook_id` to see if there is any match
    $wp_users = get_users(array(
        'meta_key'     => 'alka_facebook_id',
        'meta_value'   => $this->facebook_details['id'],
        'number'       => 1,
        'count_total'  => false,
        'fields'       => 'id',
    ));
    if(empty($wp_users[0])) {
        return false;
    }
    // Log the user ?
    wp_set_auth_cookie( $wp_users[0] );
}
/**
 * Create a new WordPress account using Facebook Details
 */
private function createUser() {
    $fb_user = $this->facebook_details;
    // Create an username
    $username = sanitize_user(str_replace(' ', '_', strtolower($this->facebook_details['name'])));
    // Creating our user
    $new_user = wp_create_user($username, wp_generate_password(), $fb_user['email']);
    if(is_wp_error($new_user)) {
        // Report our errors
        $_SESSION['alka_facebook_message'] = $new_user->get_error_message();
        // Redirect
        header("Location: ".$this->redirect_url, true);
        die();
    }
    // Setting the meta
    update_user_meta( $new_user, 'first_name', $fb_user['first_name'] );
    update_user_meta( $new_user, 'last_name', $fb_user['last_name'] );
    update_user_meta( $new_user, 'user_url', $fb_user['link'] );
    update_user_meta( $new_user, 'alka_facebook_id', $fb_user['id'] );
    // Log the user ?
    wp_set_auth_cookie( $new_user );
}

All good! We are ready to go.
Each method might require some comments, let me know if you have any question about them. I can update the article but the code is pretty commented though.
You can see the whole plugin from this Github repository.

Improvements

This plugin can be improved in several ways:

  • Create an option panel to get the APP ID and APP SECRET from the WordPress admin, which would be a bit more handy, right?
  • Styling our button using some cool CSS and a nice Facebook icon.
  • Displaying a welcome message when the user is logged in.
  • Saving the avatar from Facebook to WordPress.
  • Sending an email to the user with his password and username to be able to connect later without Facebook.

Liked this tutorial? Let us know, we could go through a part 2 where I would explain how to do all these improvements.
Update: You can find part 2 here!
 
Thanks for reading!

You could think “I just need to install a plugin, there are at least a dozen of plugins that do this”. That’s true, there are a lot of plugins that limit the access to the dashboard of WordPress, but are you sure that a plugin is always the best choose?
If you want limit the access to your WordPress dashboard avoiding side effects, or if you tried to do it programmatically by yourself and something gone wrong, this is the article which you are looking for. (more…)

Many of our users asked us how to send a private message to all members or just a notice, an update that can be displayed somewhere.

With BuddyPress, we can do both actions.

If you want to know how to send site-wide notices and how to send mass messages, continue to read this article.

(more…)