Have you every used GoToWebinar from Citrix? No? Don't worry, you aren't alone. However, have you ever tried tying any service into WordPress? MailChimp, Mad Mimi, PayPal, Twitter? While these services differ in many specific, the general idea of how we can bring in data from external APIs into WordPress is the same. In this article I'll explore this through the eyes of an example integration with GoToWebinar from Citrix.
GoToWebinar allows you to schedule live webcast events where the audience and presenters join a common user interface. The presenters can then share slides, their screen, their webcams and do all sorts of cool things.
The service has been around for a while so the inevitable has happened: it now has an API—and a pretty good one at that.
In a recent project I led, we wanted to keep the registrations on-site, and we also wanted registrant data available within WordPress. Without the API, this just isn't possible. By default, each webinar has a registration link which takes you off-site into GoToWebinar's system, where users register. It works just fine, but we didn't want to confuse users with this sudden jump.
I thought I'd walk you through the process of how we achieved some of this using surprisingly little code!
Before we dive into the abyss, you'll need a few things. You should have a GoToWebinar account, and you should also sign in to the Developer Center with your account. Once there, click on the big Add a new App button.
Follow the on-screen instructions and fill out all fields, making sure to select that you are building a GoToWebinar application. For the Application URL make sure to use https://api.citrixonline.com
. You'll need to change this when using OAuth, but in our examples we'll be using direct login authentication, which makes this URL the best option.
Once your application has been created, note the Consumer Key. We will be using this later in our API calls. Otherwise, that's it for the setup, so now it's time to get our hands dirty.
APIs nowadays mostly follow REST guidelines, which stands for Representational State Transfer. Without going into the nitty-gritty, it boils down to a simple interface you can communicate with in a very natural way.
As I mentioned, each API is different in its specifics, but the general way in which we use them is roughly the same:
It really is that simple. If you've tried reading PayPal documentation from scratch (which is horrible), you may have found yourself under the impression that working with APIs is some terribly taxing process. I think part of the confusion comes from the difficulty of authentication and the fact that developers who are only familiar with PHP aren't really used to HTTP calls that are usually represented without any PHP code next to them. Let's clear all that up, shall we?
A prerequisite for everything we're about to do is making HTTP calls properly. Most of the time you'll see tutorials using CURL or just raw HTTP, but WordPress has us covered (as usual) with its HTTP API.
Since HTTP calls can have a number of different parts, I thought it would be a good idea to delve into this a bit deeper. Let's look very briefly at what an HTTP request really is.
An HTTP request is submitted to a specific URL, and this is where API endpoints and specific routes come from. For example, the URL in the GoToWebinar documentation for getting all registrants for a webinar is:
https://api.citrixonline.com/G2W/rest/organizers/{organizerKey}/webinars/{webinarKey}/registrants
Even if you have your actual Organizer Key and Webinar ID, using the URL is not enough. An HTTP request is more than just a URL. It contains a bunch of other information, chiefly a number of headers and maybe even a body.
This is pretty easy to understand when you are receiving data. Whenever you visit a website, your browser issues a request and gets an HTTP response. The response is not just the website you see before you. It contains a number of headers, like the status code, for example, which will probably be a 200 OK. The code that the browser interprets and displays for you is sent in the body of the response.
Due to this, the documentation goes into some more detail—it gives an example HTTP request:
GET https://api.citrixonline.com/G2W/rest/organizers/7913299991555673093/webinars/2575999967611407361/registrants HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: OAuth oauth_token=hdKAifAke73JTJR5GABCdByGz4kp
This mess of strings is actually not that difficult to decipher. Even if you don't understand what everything is, you can pretty easily build this request with WordPress's native functions.
It all starts with GET
, which means this will be a get request. WordPress offers the wp_remote_get()
function, which will work just fine. This is followed by the URL, which we'll pass as the first parameter to this function. Next we see the HTTP version, which can be set in the second argument which is an array of options.
Everything afterwards is a header. The Accept
header's value is application/json
, the Content-Type
header's value is application/json
and so on. With this information in mind, let's craft our HTTP request in WordPress:
$url = 'https://api.citrixonline.com/G2W/rest/organizers/7215599994255673093/webinars/2575945029611407361/registrants'; $args = array( 'httpversion' => '1.1', 'headers' => array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Authorization' => 'OAuth oauth_token=hdKAifAke73gh885ghJTJR5GA4kp' ) ); $http_request = wp_remote_get( $url, $args );
While this a specific example we'll look at in more detail soon, the takeaway point is this: HTTP requests are not that intimidating. You usually need to set a URL, some headers and in some cases a body, and that's it. You then receive some data back, usually in JSON form, which you can run through json_decode()
and then use as a normal array or object.
Now that we know the basic structure of an HTTP Request, let's figure out how to authenticate ourselves and be able to make any calls we want.
In this example I'll be looking at the direct login method of authentication. The flow for OAuth is slightly more complex, but the basics are the same—you just need to make two HTTP calls instead of one.
That being said, I highly recommend using OAuth because it is more secure, and more and more APIs are integrating it, or even requiring it!
The documentation for direct login makes what we want to achieve very clear. In fact, what I noticed in my own programming is that when I figured out how HTTP requests can be made easily, I found all API documentation a lot easier to comprehend. Hopefully this article will do the same for you!
According to the documentation, we can make a GET
call to https://api.citrixonline.com/oauth/access_token
with the appropriate Accept
and Content-Type
headers in addition to setting the grant_type
, user_id
and password
URL parameters, and GoToWebinar will spit back our authentication credentials. Let's try that now:
$url = 'https://api.citrixonline.com/oauth/access_token?grant_type=password&user_id=myaccount@email.com&password=mysecretpass&client_id=mycitrixapikey'; $args = array( 'headers' => array( 'Accept' => 'application/json', 'Content-Type' => 'application/json' ) ); $http_request = wp_remote_get( $url, $args );
Note that the values of all these parameters are fake. You will need to use the user_id
(email) and password of an actual GoToWebinar account. The client_id
should be the "Consumer Key" of your application, which we set up in the "Before We Begin" section above.
If you use var_dump()
to display the contents of the $http_request
variable, you'll find that it is an array consisting of a number of members such as "headers", "body", "response" and so on. For our purposes the "body" holds the most important information:
As you may well have noticed, this is a JSON string which we'll need to convert to a usable form. Running it through json_decode()
will give us a proper PHP array if we set the second parameter to true (otherwise it will be an array).
$body = json_decode( $http_request, true );
Out of all this data you'll need two things: the access_token
and your organizer_key
. The access token is your "temporary password". The idea is to prevent the need to send your actual password with every request—you request a temporary access token with your credentials only once, then use it to "sign" each subsequent request.
Let's revisit our example from the HTTP Calls section, and perhaps the example will be a lot clearer now. Here is the same code with placeholders for all the information we now have:
$organizer_key = '2893726'; $webinar_id = '849927254829281838'; $access_token = 'h7dwo20vAsXI8GLaGvun0wOJ6H5I'; $url = "https://api.citrixonline.com/G2W/rest/organizers/$organizer_key/webinars/$webinar_id/registrants"; $args = array( 'httpversion' => '1.1', 'headers' => array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Authorization' => "OAuth oauth_token=$access_token" ) ); $http_request = wp_remote_get( $url, $args );
The webinar_id
in there comes from an actual webinar I've created in GoToWebinar, and you can find the ID in the URL at the very end. At this stage it should be clear where the data comes from, but in the example it's still essentially hard-coded—let's clear that right up!
Do we need to store authentication data, and does it expire? Yes and yes, and since the word "expire" was used in conjunction with "store", we're talking about a transient situation here, so enter the Transients API.
If you have no idea what that is, worry not! It's quite simple—it allows you to store things using WordPress functions with a timestamp at which time the data expires. Let's write ourselves a mini class to be able to handle the creation of an access token simply. This will seem scary at first, but it's super-simple—explanation ensues!
class Citrix_WP { var $client_id; var $password; var $user_id; var $access; function __construct() { $this->client_id = 'sI48T4iXP0J6720G9wAB0Ghfg37576301'; $this->user_id = 'email@email.com'; $this->password = 'superpassword'; $this->access_field = 'citrix_access'; $this->set_access(); } function set_access() { $access = $this->get_access(); $this->access = $access; } function get_access() { $access = get_transient( $this->access_field ); if ( empty( $access ) ) { $access = $this->request_access(); $this->set_access_transient( $access ); } return $access; } function set_access_transient( $access ) { set_transient( $this->access_field, $access, DAY_IN_SECONDS ); } function request_data( $url, $args = array() ) { $defaults = array( 'httpversion' => '1.1', 'headers' => array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Authorization' => 'OAuth oauth_token=' . $this->access[ 'access_token' ] ) ); $args = wp_parse_args( $args, $defaults ); $http_request = wp_remote_get( $url, $args ); $body = json_decode( $http_request[ 'body' ], true ); if ( ! empty( $body[ 'int_err_code' ] ) ) { $this->get_access(); $this->request_data( $url, $args ); } else { return $body; } } function request_access() { $url = 'https://api.citrixonline.com/oauth/access_token?grant_type=password&user_id=' . $this->user_id . '&password=' . $this->password . '&client_id=' . $this->client_id; $args = array( 'headers' => array( 'Accept' => 'application/json', 'Content-Type' => 'application/json' ) ); $result = wp_remote_get( $url, $args ); return json_decode( $result[ 'body' ], true ); } }
What the heck is going on here?! There's a perfectly simple explanation—we want to write as little code as possible when handling actual HTTP calls. We already know that we need an access token for each one and that this access token will expire at some point. So for each and every call we make, we would need to check if the access token is valid. If it isn't, we would need to request a new one and then redo the original call. This class takes care of all that.
In the construct function, which runs as soon as an object is instantiated, I've hard-coded my client_id
, user_id
and password
. In reality it is a good idea to use constants or even pass them to the construct function, but I just thought I'd make it all self-contained for this lesson.
One more thing we need is a place to store the access credentials we receive from Citrix. I will be using a transient, and its name will be "citrix_access". I store this field name as a property of the class. Finally we run the set_access()
method.
This makes sure that we have valid credentials and stores them in the access
property for easy access. How does it make sure everything is valid? It uses the get_access()
method. This method retrieves the access credentials from our transient. If the transient is not empty, it returns the transient's value. If the transient is empty, it uses the request_access()
method to get new credentials from Citrix, sets the transient value to the new credentials, and returns it as well.
At this stage we have access credentials available to us, so we can start making requests. There is one other issue: the credentials on the Citrix side may have expired for safety reasons. If this is the case, our requests will come back with an error. Due to this, I've added a request_data()
method which can handle this for us.
This method contains almost the same code we wrote before, using the properties of the class to populate the call. Note that I've added some headers as defaults. These will most likely not change from call to call, removing the need to pass arguments in most cases.
In addition, the method checks the body response. If it contains an error code, it generates new access credentials and recalls the method with the same parameters.
Here's where our hard work pays off. To grab a list of registrants, here's all we need to do:
$citrix = new Citrix_WP; $registrants = $citrix->request_data( 'https://api.citrixonline.com/G2W/rest/organizers/' . $citrix->access[ 'organizer_key' ] . '/webinars/849927252521582337/registrants');
We don't need to add any args, just the URL and we receive all the yummy data from Citrix right back.
A note of warning: the class I've written is a very quick demonstration class. It works just fine for me right now, but I don't recommend using it as-is in production. Here are just some issues:
request_data()
function is not great. If the request fails for any other reason than an invalidated token, you may go into an infinite loop.As a case-in-point, the example is just fine, but just be cautious of errors when using it.
As always, someone has already been nice enough to make a class for us to use which is a lot more complete than the one I just showed you as a case study. Teodor Talov wrote a Wrapper Class for the Citrix APIs which is available via GitHub.
I will be using his class to interact with GoToWebinar from this point on. To achieve the same thing we did above, you'll need some preparation and a few lines of code. First of all, using the class is easiest if you get it via Composer. Composer is super easy to install if you don't already have it—follow the Getting Started Guide and meet me back here in five minutes.
Use the terminal or command prompt to go into the directory of your plugin and type the following command:
composer require teodortalov/citrix
This will grab the files you need and put them in the vendor directory. Then, within your plugin you'll need to include the autoload file like so:
include( plugin_dir_path( __FILE__ ) . '/vendor/autoload.php' );
That's it for preparation, so we can now use the class. Here's a snippet that will pull upcoming webinars from Citrix.
$client = new \Citrix\Authentication\Direct( 'sI48T4iXP0J6720G9wAB0GHIHiIoyw20' ); $client->auth( 'nick@bitesizebio.com', 'gnasher1' ); $goToWebinar = new \Citrix\GoToWebinar( $client ); $webinars = $goToWebinar->getUpcoming();
Easy-peasy, right? With this more powerful class in our toolbelt, let's build something nice! Part of our plan was to use custom post types to store webinars to list them on-site. All we need is a meta field that stores the Citrix Webinar ID and we can pull everything else from Citrix, for example: the registrants. Let's create a meta box that lists a webinar's registrants now!
Let's get the core WordPress stuff out of the way first: the meta box itself. Here's some code that will display an empty meta box with a nice title:
function my_registrants_metabox() { add_meta_box( 'webinar_registrants', 'Registrants', 'my_registrants_metabox_content', 'webinar' ); } function my_registrants_metabox_content( $post ) { // Here be metabox content. }
You will of course need a custom post type with the name "webinar" to get this to show up. If you need to read up on that, we have a handy custom post type creation guide.
I like to do a little HTML prototype of what the intended end result is, so let's do just that. Dummy data but a real UI. I plan on using Datatables, a jQuery table plugin, so I'll enqueue the scripts and styles for that as well. Here goes:
function my_backend_assets() { wp_register_script( 'datatables', '//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js', array( 'jquery', 'customselect' ), '1.0', true ); wp_register_style( 'datatables', '//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css' ); wp_enqueue_script( 'my-app', plugin_dir_path( __FILE__ ) . '/js/app.js', array( 'datatables' ), '1.0', true ); } function my_registrants_metabox() { add_meta_box( 'webinar_registrants', 'Registrants', 'my_registrants_metabox_content', 'webinar' ); } function my_registrants_metabox_content( $post ) { wp_enqueue_script( 'datatables' ); wp_enqueue_style( 'datatables' ); ?> <div class="my-data-table"> <table data-order=\'[[ 3, "desc" ]]\'>'; <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Email</th> <th>Date</th> <th>Zone</th> </tr> </thead> <tbody> <tr> <td>Daniel</td> <td>Pataki</td> <td>lolz@stillnotmyemail.com</td> <td>2015-08-12</td> <td>New York</td> </tr> <tr> <td>Someone</td> <td>Else</td> <td>anotherpeep@mail.com</td> <td>2015-08-13</td> <td>Paris</td> </tr> </tbody> </table> </div> <?php }
This will create the markup we need and enqueue the styles. All we need to do is create js/app.js
in our plugin with the following content:
(function( $ ){ $( document ).ready( function( $ ) { $( '.my-data-table table' ).DataTable(); }); })( jQuery );
The result should look something like the screenshot below.
It's not super-pretty, but I'll fix that by enqueuing another stylesheet and overwriting some of the defaults imposed by Datatables. The next step is to grab data from Citrix instead of faking it.
I decided to use transients again to make sure we don't bombard Citrix with requests each time an edit webinar page is viewed. We'll grab the list of registrants and store them in a transient with an hour's worth of expiration time. This means that the list will only refresh each hour, but it does reduce our requests to one per hour instead of one per visit.
We'll also need to use a meta field for the webinar ID. I usually use Advanced Custom Fields, but since this is a simple example, let's just use the default custom fields option in WordPress and store a webinar ID in with the key webinar_id
. Here's the final code:
function my_backend_assets() { wp_register_script( 'datatables', '//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js', array( 'jquery', 'customselect' ), '1.0', true ); wp_register_style( 'datatables', '//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css' ); wp_enqueue_script( 'my-app', plugin_dir_path( __FILE__ ) . '/js/app.js', array( 'datatables' ), '1.0', true ); wp_register_style( 'my-datatables', plugin_dir_path( __FILE__ ) . '/css/my-datatables.css' ); } function my_registrants_metabox() { add_meta_box( 'webinar_registrants', 'Registrants', 'my_registrants_metabox_content', 'webinar' ); } function my_registrants_metabox_content( $post ) { wp_enqueue_script( 'datatables' ); wp_enqueue_style( 'datatables' ); wp_enqueue_style( 'my-datatables' ); $webinar_id = get_field( 'webinar_id', $post->ID ); $registrants = get_transient( 'registrants_' . $webinar_id ); if ( empty( $registrants ) ) { $client = new \Citrix\Authentication\Direct( 'consumer_key' ); $client->auth( 'user_id', 'password' ); $goToWebinar = new \Citrix\GoToWebinar( $client ); $webinars = $goToWebinar->getRegistrants( $webinar_id ); set_transient( 'registrants_' . $webinar_id, $registrants, HOUR_IN_SECONDS ); } if ( count( $registrants ) > 0 ) { echo '<div class="my-data-table">'; echo'<table data-order=\'[[ 3, "desc" ]]\'>'; echo '<thead>'; echo '<tr>'; echo '<th>First Name</th>'; echo '<th>Last Name</th>'; echo '<th>Email</th>'; echo '<th>Date</th>'; echo '<th>Zone</th>'; echo '</tr>'; echo '</thead>'; echo '<tbody>'; foreach ( $registrants as $registrant ) { $time_zone = explode( '/', $registrant[ 'timeZone' ] ); echo '<tr>'; echo '<td>' . $registrant[ 'firstName' ] . '</td>'; echo '<td>' . $registrant[ 'lastName' ] . '</td>'; echo '<td>' . $registrant[ 'email' ] . '</td>'; echo '<td class="date">' . date( 'Y-m-d', strtotime( $registrant[ 'registrationDate' ] ) ) . '</td>'; echo '<td>' . str_replace( '_', ' ', $time_zone[ 1 ] ) . '</td>'; echo '</tr>'; } echo '</tbody>'; echo '</table>'; echo '</div>'; } }
A couple of things have happened here. First of all, I added a new stylesheet, just to add some visual distinction to the list which you'll see in the screenshot below.
I then try to get the registrants list from the transients. If this returns empty, that means that the transient was either never set, or it has expired. If this is the case, we retrieve registrants and put them in a transient.
We then loop through the registrants to populate the table, and we're all done! Here's what this all looks like with some added styles:
And there you have it: data pulled from an external API, cached and displayed, all with native WordPress mechanisms and functions. While this takes some time to read and digest, especially if you are doing something like this for the first time, it really doesn't take very long once you wrap your head around it.
In fact, once you have some experience with external APIs, most of your time will be spent figuring out what methods and options they have, not how to make HTTP requests and how to store data and so on.
I can heartily recommend using the HTTP API coupled with the Transients API. It has proved to be a valuable and speedy asset in my toolbelt.
The Best Small Business Web Designs by DesignRush
/Create Modern Vue Apps Using Create-Vue and Vite
/Pros and Cons of Using WordPress
/How to Fix the “There Has Been a Critical Error in Your Website” Error in WordPress
/How To Fix The “There Has Been A Critical Error in Your Website” Error in WordPress
/How to Create a Privacy Policy Page in WordPress
/How Long Does It Take to Learn JavaScript?
/The Best Way to Deep Copy an Object in JavaScript
/Adding and Removing Elements From Arrays in JavaScript
/Create a JavaScript AJAX Post Request: With and Without jQuery
/5 Real-Life Uses for the JavaScript reduce() Method
/How to Enable or Disable a Button With JavaScript: jQuery vs. Vanilla
/How to Enable or Disable a Button With JavaScript: jQuery vs Vanilla
/Confirm Yes or No With JavaScript
/How to Change the URL in JavaScript: Redirecting
/15+ Best WordPress Twitter Widgets
/27 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/21 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/30 HTML Best Practices for Beginners
/31 Best WordPress Calendar Plugins and Widgets (With 5 Free Plugins)
/25 Ridiculously Impressive HTML5 Canvas Experiments
/How to Implement Email Verification for New Members
/How to Create a Simple Web-Based Chat Application
/30 Popular WordPress User Interface Elements
/Top 18 Best Practices for Writing Super Readable Code
/Best Affiliate WooCommerce Plugins Compared
/18 Best WordPress Star Rating Plugins
/10+ Best WordPress Twitter Widgets
/20+ Best WordPress Booking and Reservation Plugins
/Working With Tables in React: Part Two
/Best CSS Animations and Effects on CodeCanyon
/30 CSS Best Practices for Beginners
/How to Create a Custom WordPress Plugin From Scratch
/10 Best Responsive HTML5 Sliders for Images and Text… and 3 Free Options
/16 Best Tab and Accordion Widget Plugins for WordPress
/18 Best WordPress Membership Plugins and 5 Free Plugins
/25 Best WooCommerce Plugins for Products, Pricing, Payments and More
/10 Best WordPress Twitter Widgets
1 /12 Best Contact Form PHP Scripts for 2020
/20 Popular WordPress User Interface Elements
/10 Best WordPress Star Rating Plugins
/12 Best CSS Animations on CodeCanyon
/12 Best WordPress Booking and Reservation Plugins
/12 Elegant CSS Pricing Tables for Your Latest Web Project
/24 Best WordPress Form Plugins for 2020
/14 Best PHP Event Calendar and Booking Scripts
/Create a Blog for Each Category or Department in Your WooCommerce Store
/8 Best WordPress Booking and Reservation Plugins
/Best Exit Popups for WordPress Compared
/Best Exit Popups for WordPress Compared
/11 Best Tab & Accordion WordPress Widgets & Plugins
/12 Best Tab & Accordion WordPress Widgets & Plugins
1 /New Course: Practical React Fundamentals
/Preview Our New Course on Angular Material
/Build Your Own CAPTCHA and Contact Form in PHP
/Object-Oriented PHP With Classes and Objects
/Best Practices for ARIA Implementation
/Accessible Apps: Barriers to Access and Getting Started With Accessibility
/Dramatically Speed Up Your React Front-End App Using Lazy Loading
/15 Best Modern JavaScript Admin Templates for React, Angular, and Vue.js
/15 Best Modern JavaScript Admin Templates for React, Angular and Vue.js
/19 Best JavaScript Admin Templates for React, Angular, and Vue.js
/New Course: Build an App With JavaScript and the MEAN Stack
/Hands-on With ARIA: Accessibility Recipes for Web Apps
/10 Best WordPress Facebook Widgets
13 /Hands-on With ARIA: Accessibility for eCommerce
/New eBooks Available for Subscribers
/Hands-on With ARIA: Homepage Elements and Standard Navigation
/Site Accessibility: Getting Started With ARIA
/How Secure Are Your JavaScript Open-Source Dependencies?
/New Course: Secure Your WordPress Site With SSL
/Testing Components in React Using Jest and Enzyme
/Testing Components in React Using Jest: The Basics
/15 Best PHP Event Calendar and Booking Scripts
/Create Interactive Gradient Animations Using Granim.js
/How to Build Complex, Large-Scale Vue.js Apps With Vuex
1 /Examples of Dependency Injection in PHP With Symfony Components
/Set Up Routing in PHP Applications Using the Symfony Routing Component
1 /A Beginner’s Guide to Regular Expressions in JavaScript
/Introduction to Popmotion: Custom Animation Scrubber
/Introduction to Popmotion: Pointers and Physics
/New Course: Connect to a Database With Laravel’s Eloquent ORM
/How to Create a Custom Settings Panel in WooCommerce
/Building the DOM faster: speculative parsing, async, defer and preload
1 /20 Useful PHP Scripts Available on CodeCanyon
3 /How to Find and Fix Poor Page Load Times With Raygun
/Introduction to the Stimulus Framework
/Single-Page React Applications With the React-Router and React-Transition-Group Modules
12 Best Contact Form PHP Scripts
1 /Getting Started With the Mojs Animation Library: The ShapeSwirl and Stagger Modules
/Getting Started With the Mojs Animation Library: The Shape Module
/Getting Started With the Mojs Animation Library: The HTML Module
/Project Management Considerations for Your WordPress Project
/8 Things That Make Jest the Best React Testing Framework
/Creating an Image Editor Using CamanJS: Layers, Blend Modes, and Events
/New Short Course: Code a Front-End App With GraphQL and React
/Creating an Image Editor Using CamanJS: Applying Basic Filters
/Creating an Image Editor Using CamanJS: Creating Custom Filters and Blend Modes
/Modern Web Scraping With BeautifulSoup and Selenium
/Challenge: Create a To-Do List in React
1 /Deploy PHP Web Applications Using Laravel Forge
/Getting Started With the Mojs Animation Library: The Burst Module
/10 Things Men Can Do to Support Women in Tech
/A Gentle Introduction to Higher-Order Components in React: Best Practices
/Challenge: Build a React Component
/A Gentle Introduction to HOC in React: Learn by Example
/A Gentle Introduction to Higher-Order Components in React
/Creating Pretty Popup Messages Using SweetAlert2
/Creating Stylish and Responsive Progress Bars Using ProgressBar.js
/18 Best Contact Form PHP Scripts for 2022
/How to Make a Real-Time Sports Application Using Node.js
/Creating a Blogging App Using Angular & MongoDB: Delete Post
/Set Up an OAuth2 Server Using Passport in Laravel
/Creating a Blogging App Using Angular & MongoDB: Edit Post
/Creating a Blogging App Using Angular & MongoDB: Add Post
/Introduction to Mocking in Python
/Creating a Blogging App Using Angular & MongoDB: Show Post
/Creating a Blogging App Using Angular & MongoDB: Home
/Creating a Blogging App Using Angular & MongoDB: Login
/Creating Your First Angular App: Implement Routing
/Persisted WordPress Admin Notices: Part 4
/Creating Your First Angular App: Components, Part 2
/Persisted WordPress Admin Notices: Part 3
/Creating Your First Angular App: Components, Part 1
/How Laravel Broadcasting Works
/Persisted WordPress Admin Notices: Part 2
/Create Your First Angular App: Storing and Accessing Data
/Persisted WordPress Admin Notices: Part 1
/Error and Performance Monitoring for Web & Mobile Apps Using Raygun
/Using Luxon for Date and Time in JavaScript
7 /How to Create an Audio Oscillator With the Web Audio API
/How to Cache Using Redis in Django Applications
/20 Essential WordPress Utilities to Manage Your Site
/Introduction to API Calls With React and Axios
/Beginner’s Guide to Angular 4: HTTP
/Rapid Web Deployment for Laravel With GitHub, Linode, and RunCloud.io
/Beginners Guide to Angular 4: Routing
/Beginner’s Guide to Angular 4: Services
/Beginner’s Guide to Angular 4: Components
/Creating a Drop-Down Menu for Mobile Pages
/Introduction to Forms in Angular 4: Writing Custom Form Validators
/10 Best WordPress Booking & Reservation Plugins
/Getting Started With Redux: Connecting Redux With React
/Getting Started With Redux: Learn by Example
/Getting Started With Redux: Why Redux?
/Understanding Recursion With JavaScript
/How to Auto Update WordPress Salts
/How to Download Files in Python
/Eloquent Mutators and Accessors in Laravel
1 /10 Best HTML5 Sliders for Images and Text
/Site Authentication in Node.js: User Signup
/Creating a Task Manager App Using Ionic: Part 2
/Creating a Task Manager App Using Ionic: Part 1
/Introduction to Forms in Angular 4: Reactive Forms
/Introduction to Forms in Angular 4: Template-Driven Forms
/24 Essential WordPress Utilities to Manage Your Site
/25 Essential WordPress Utilities to Manage Your Site
/Get Rid of Bugs Quickly Using BugReplay
1 /Manipulating HTML5 Canvas Using Konva: Part 1, Getting Started
/10 Must-See Easy Digital Downloads Extensions for Your WordPress Site
/22 Best WordPress Booking and Reservation Plugins
/Understanding ExpressJS Routing
/15 Best WordPress Star Rating Plugins
/Creating Your First Angular App: Basics
/Inheritance and Extending Objects With JavaScript
/Introduction to the CSS Grid Layout With Examples
1Performant Animations Using KUTE.js: Part 5, Easing Functions and Attributes
Performant Animations Using KUTE.js: Part 4, Animating Text
/Performant Animations Using KUTE.js: Part 3, Animating SVG
/New Course: Code a Quiz App With Vue.js
/Performant Animations Using KUTE.js: Part 2, Animating CSS Properties
Performant Animations Using KUTE.js: Part 1, Getting Started
/10 Best Responsive HTML5 Sliders for Images and Text (Plus 3 Free Options)
/Single-Page Applications With ngRoute and ngAnimate in AngularJS
/Deferring Tasks in Laravel Using Queues
/Site Authentication in Node.js: User Signup and Login
/Working With Tables in React, Part Two
/Working With Tables in React, Part One
/How to Set Up a Scalable, E-Commerce-Ready WordPress Site Using ClusterCS
/New Course on WordPress Conditional Tags
/TypeScript for Beginners, Part 5: Generics
/Building With Vue.js 2 and Firebase
6 /Best Unique Bootstrap JavaScript Plugins
/Essential JavaScript Libraries and Frameworks You Should Know About
/Vue.js Crash Course: Create a Simple Blog Using Vue.js
/Build a React App With a Laravel RESTful Back End: Part 1, Laravel 5.5 API
/API Authentication With Node.js
/Beginner’s Guide to Angular: Routing
/Beginners Guide to Angular: Routing
/Beginner’s Guide to Angular: Services
/Beginner’s Guide to Angular: Components
/How to Create a Custom Authentication Guard in Laravel
/Learn Computer Science With JavaScript: Part 3, Loops
/Build Web Applications Using Node.js
/Learn Computer Science With JavaScript: Part 4, Functions
/Learn Computer Science With JavaScript: Part 2, Conditionals
/Create Interactive Charts Using Plotly.js, Part 5: Pie and Gauge Charts
/Create Interactive Charts Using Plotly.js, Part 4: Bubble and Dot Charts
Create Interactive Charts Using Plotly.js, Part 3: Bar Charts
/Awesome JavaScript Libraries and Frameworks You Should Know About
/Create Interactive Charts Using Plotly.js, Part 2: Line Charts
/Bulk Import a CSV File Into MongoDB Using Mongoose With Node.js
/Build a To-Do API With Node, Express, and MongoDB
/Getting Started With End-to-End Testing in Angular Using Protractor
/TypeScript for Beginners, Part 4: Classes
/Object-Oriented Programming With JavaScript
/10 Best Affiliate WooCommerce Plugins Compared
/Stateful vs. Stateless Functional Components in React
/Make Your JavaScript Code Robust With Flow
/Build a To-Do API With Node and Restify
/Testing Components in Angular Using Jasmine: Part 2, Services
/Testing Components in Angular Using Jasmine: Part 1
/Creating a Blogging App Using React, Part 6: Tags
/React Crash Course for Beginners, Part 3
/React Crash Course for Beginners, Part 2
/React Crash Course for Beginners, Part 1
/Set Up a React Environment, Part 4
1 /Set Up a React Environment, Part 3
/New Course: Get Started With Phoenix
/Set Up a React Environment, Part 2
/Set Up a React Environment, Part 1
/Command Line Basics and Useful Tricks With the Terminal
/How to Create a Real-Time Feed Using Phoenix and React
/Build a React App With a Laravel Back End: Part 2, React
/Build a React App With a Laravel RESTful Back End: Part 1, Laravel 9 API
/Creating a Blogging App Using React, Part 5: Profile Page
/Pagination in CodeIgniter: The Complete Guide
/JavaScript-Based Animations Using Anime.js, Part 4: Callbacks, Easings, and SVG
/JavaScript-Based Animations Using Anime.js, Part 3: Values, Timeline, and Playback
/Learn to Code With JavaScript: Part 1, The Basics
/10 Elegant CSS Pricing Tables for Your Latest Web Project
/Getting Started With the Flux Architecture in React
/Getting Started With Matter.js: The Composites and Composite Modules
Getting Started With Matter.js: The Engine and World Modules
/10 More Popular HTML5 Projects for You to Use and Study
/Understand the Basics of Laravel Middleware
/Iterating Fast With Django & Heroku
/Creating a Blogging App Using React, Part 4: Update & Delete Posts
/Creating a jQuery Plugin for Long Shadow Design
/How to Register & Use Laravel Service Providers
2 /Unit Testing in React: Shallow vs. Static Testing
/Creating a Blogging App Using React, Part 3: Add & Display Post
/Creating a Blogging App Using React, Part 2: User Sign-Up
20 /Creating a Blogging App Using React, Part 1: User Sign-In
/Creating a Grocery List Manager Using Angular, Part 2: Managing Items
/9 Elegant CSS Pricing Tables for Your Latest Web Project
/Dynamic Page Templates in WordPress, Part 3
/Angular vs. React: 7 Key Features Compared
/Creating a Grocery List Manager Using Angular, Part 1: Add & Display Items
New eBooks Available for Subscribers in June 2017
/Create Interactive Charts Using Plotly.js, Part 1: Getting Started
/The 5 Best IDEs for WordPress Development (And Why)
/33 Popular WordPress User Interface Elements
/New Course: How to Hack Your Own App
/How to Install Yii on Windows or a Mac
/What Is a JavaScript Operator?
/How to Register and Use Laravel Service Providers
/
waly Good blog post. I absolutely love this…