As we come up on the end of this series, we have two more topics to cover:
In the previous article, we looked at validation, sanitization, and implementing this functionality for the elements that we've displayed on the front-end. In this article, we're going to continue the process by saving the information to the database, retrieving the information, and displaying it on the front-end.
Along the way, we'll also look at some of the built-in WordPress API functions designed to help make this a bit easier for us as well as some tips for double-checking our work in the database to verify our information is being saved exactly as we expect.
We've got just a bit more to go in order to bring this plugin to life, so let's get started.
In order to display data on the front-end, we obviously need to get it into the database first. Since we're working with meta boxes, then we can use functions that are available via the Meta Box API in order to save this information.
Specifically, we're going to be working with the following functions:
update_post_meta
for saving information to the databasedelete_post_meta
for removing information from the databaseThere is another function, add_post_meta
, that is also available for writing information to the database; however, update_post_meta
does the same thing if the data does not already exist in the database.
Another question that I've seen come up when it comes to deleting post meta data is why? That is, why delete information rather than save an empty value?
You can argue this is a personal preference - and it is - but if you're working with an elaborate plugin that has a number of different fields, and the fields have no value, then it makes sense not to maintain an empty row.
Furthermore, unless the absence of a value is meaningful for something on the user interface, then there's also no reason to maintain an empty value as we're allowing the database to more closely mirror the information that's being displayed on the screen.
Keeping the user interface, application layer code, and database as consistent as possible is helpful when trying to write maintainable code.
So with that said, let's look into the process of saving the fields for each of our input fields.
Recall from the previous post that the Draft tab contains a single textarea
that is meant to be a place for authors to collect various notes and URLs from around the web that are relevant to the content they are preparing to publish.
When we last left this code, we had the following:
<?php // If the 'Drafts' textarea has been populated, then we sanitize the information. if ( ! empty( $_POST['authors-commentary-drafts'] ) ) { // We'll remove all white space, HTML tags, and encode the information to be saved $drafts = trim( $_POST['authors-commentary-drafts'] ); $drafts = esc_textarea( strip_tags( $drafts ) ); // More to come... }
Here, we're looking to see if the content of the $_POST
array is populated. If so, we then sanitize the information using trim
and esc_textarea
.
At this point, we're ready to write it to the database so let's replace the line that reads // More to come...
with the following code (note that we'll take a more in-depth look at the code after the block):
<?php // If the 'Drafts' textarea has been populated, then we sanitize the information. if ( ! empty( $_POST['authors-commentary-drafts'] ) ) { // We'll remove all white space, HTML tags, and encode the information to be saved $drafts = trim( $_POST['authors-commentary-drafts'] ); $drafts = esc_textarea( strip_tags( $drafts ) ); update_post_meta( $post_id, 'authors-commentary-drafts', $drafts ); } else { if ( '' !== get_post_meta( $post_id, 'authors-commentary-drafts', true ) ) { delete_post_meta( $post_id, 'authors-commentary-drafts' ); } }
Here, we're using the update_post_meta
function in order to add or update the content in the database. Note that the function takes three parameters:
Notice also that if the value of the $_POST
array is empty then we check to see if there is a value for the draft in the database and, if it exists, then we remove it.
Because we've already laid all of the ground work for sanitizing the information and we've seen how to both update and delete information in the database, doing the same for the Resources tab is more of the same.
The one exception is that since we're dealing with a dynamic set of information, we need to dynamically associate the post with a unique ID based on how many resources we're saving.
In the previous post, our code looked like this:
<?php // If the 'Resources' inputs exist, iterate through them and sanitize them if ( ! empty( $_POST['authors-commentary-resources'] ) ) { $resources = $_POST['authors-commentary-resources']; foreach ( $resources as $resource ) { $resource = esc_url( strip_tags( $resource ) ); // More to come... } }
When it comes to dynamically processing information, a foreach
loop works great; however, when saving information, we need to associate a unique key with each value.
One option would be to setup a for loop in order to suffix the meta key with a a unique key (by using the iterator for each value in the loop), but this can cause problems when it comes to deleting information. Specifically, if the user inputs a value for the first, second, and third input but then removes the second input leaving only the first and third when updating the post, we need to properly delete those empty values and shift all of the records accordingly.
This can be done in a number of different ways, but it's actually easier to save a single serialized array to a unique index rather than try to do anything fancy with database rows, queries, and so on.
As such, we update the code above to look like this:
<?php // If the 'Resources' inputs exist, iterate through them and sanitize them if ( ! empty( $_POST['authors-commentary-resources'] ) ) { $resources = $_POST['authors-commentary-resources']; $sanitized_resources = array(); foreach ( $resources as $resource ) { $resource = esc_url( strip_tags( $resource ) ); if ( ! empty( $resource ) ) { $sanitized_resources[] = $resource; } } update_post_meta( $post_id, 'authors-commentary-resources', $sanitized_resources ); }
If you peek into the database and look at this specific key, you should see something like this stored as the value:
a:3:{i:0;s:22:"http://tommcfarlin.com";i:1;s:19:"http://tutsplus.com";i:2;s:17:"http://google.com";}
We'll see how this plays out when we retrieve the information from the database later in this article. Note also that we need to account for the case when a user has removed all instances of resources.
Just as we did in the first part of the article, we simply delete the post meta data if a value exists. This can be done using very similar code:
<?php // If the 'Resources' inputs exist, iterate through them and sanitize them if ( ! empty( $_POST['authors-commentary-resources'] ) ) { $resources = $_POST['authors-commentary-resources']; $sanitized_resources = array(); foreach ( $resources as $resource ) { $resource = esc_url( strip_tags( $resource ) ); $sanitized_resources[] = $resource; } update_post_meta( $post_id, 'authors-commentary-resources', $sanitized_resources ); } else { if ( '' !== get_post_meta( $post_id, 'authors-commentary-resources', true ) ) { delete_post_meta( $post_id, 'authors-commentary-resources' ); } }
Now we need to save the values for the last meta box.
The final tab of the meta box, the Published tab, is going to be the easiest one for us to update as it pulls together everything we've looked at thus far in the article.
Specifically, we're iterating through a collection of values, writing them to an array, and then serializing the array to the database. Perhaps the most important thing to note is that we're using an associative array and we're indexing each value by the value of the comment ID.
As we'll see later in the article, this will make it much easier to set the values on the user interface.
<?php // If there are any values saved in the 'Resources' input, save them if ( ! empty( $_POST['authors-commentary-comments'] ) ) { $comments = $_POST['authors-commentary-comments']; $sanitized_comments = array(); foreach ( $comments as $comment_id => $comment_value ) { $comment = strip_tags( stripslashes( $comment_value ) ); $sanitized_comments[ $comment_id ] = $comment; } update_post_meta( $post_id, 'authors-commentary-comments', $sanitized_comments ); }
Just as we did in the previous section, if there's nothing specified in the $_POST
array, then we check the existence of the values in the database and, if they exist, we delete them:
<?php // If there are any values saved in the 'Resources' input, save them if ( ! empty( $_POST['authors-commentary-comments'] ) ) { $comments = $_POST['authors-commentary-comments']; $sanitized_comments = array(); foreach ( $comments as $comment_id => $comment_value ) { $comment = strip_tags( stripslashes( $comment_value ) ); $sanitized_comments[ $comment_id ] = $comment; } update_post_meta( $post_id, 'authors-commentary-comments', $sanitized_comments ); } else { if ( '' !== get_post_meta( $post_id, 'authors-commentary-comments', true ) ) { delete_post_meta( $post_id, 'authors-commentary-comments' ); } }
As mentioned, this final example pulls everything together that we've seen for the last two tabs, so it should be relatively clear code to follow at this point.
Before going any further, let's take a moment to understand how we may end up querying information from the database.
Let's say you have a post with the ID of 9000 (yours will vary based on your setup). You can take that ID and look in the wp_postmeta
table to see all of the meta information that's associated with the post.
Furthermore, you can specify the key to pull back only the information associated with the post ID and key.
If you only specify the post ID, you'll see all meta information associated with the post. If you specify only the key, then you'll see all post IDs that contain content for their drafts. If you specify both the post ID and the key, you'll pull back only the draft information that you've specified for a single post.
Speaking of retrieving data, let's look at the steps necessary to display the post meta data in the dashboard of our plugin.
Now that all of the information has been saved to the database, we can introduce code that will retrieve it and display it in the proper tab of each plugin. The nice thing about this is that it will be using functions and constructors (like get_post_meta
and for
) that we've already been using.
Locate admin/views/partials/drafts.php
. Assuming you've been following along with everything up to this point, the code should look like this:
<div class="inside"> <textarea id="authors-commentary-drafts" name="authors-commentary-drafts"></textarea> </div>
To populate this textarea
, we need to make a call to get_post_meta
using the current post ID and the key that we used to save information earlier in this article. Take a look at the following code:
<div class="inside"> <textarea id="authors-commentary-drafts" name="authors-commentary-drafts"><?php echo get_post_meta( get_the_ID(), 'authors-commentary-drafts', true ); ?></textarea> </div>
Note that we're passing in three parameters:
get_the_ID
function.If the value doesn't exist, then it simply returns an empty string so the textarea
is empty.
For Resources, we make a similar call; however, this time we want to iterate through the results so that we can dynamically create the user interface.
Because of the way WordPress serializes the array, we still want the information returned in a string format (though it will be a de-serialized array) that will allow us to use a foreach
loop to iterate through it.
<div class="inside hidden"> <div id="authors-commentary-resources"> <?php $resources = get_post_meta( get_the_ID(), 'authors-commentary-resources', true ); ?> <?php foreach ( $resources as $resource ) { ?> <input type="text" value="<?php echo $resource; ?>" /> <?php } ?> </div><!-- #authors-commentary-resources --> <p><input type="submit" id="authors-commentary-add-resource" value="Add Resource" class="button" /> </div>
In short, we retrieve the information from the database, loop through it creating an input
element for each value and then rendering it to the page.
This also allows us to remove elements by simply deleting a value and then updating the post. From there, the display will re-render itself such that there are no empty input elements.
Arguably, this is the easiest part of the plugin. Since we've already got so much code in the template, the only thing we really need to do is determine if the value for the checkbox is set in the meta data array.
Since we're using the comment ID as the numerical index of the array, we can simply check to see if the comment ID is contained in the array of meta keys that's returned from the meta data.
Here's how:
<div class="inside hidden"> <?php $comments = $this->load_post_comments(); ?> <ul id="author-commentary-comments"> <?php foreach ( $comments as $comment ) { ?> <li> <label for="authors-commentary-comment-<?php echo $comment->comment_ID ?>"> <?php $comments = get_post_meta( get_the_ID(), 'authors-commentary-comments', true ); ?> <input type="checkbox" name="authors-commentary-comments[<?php echo $comment->comment_ID ?>]" id="authors-commentary-comment-<?php echo $comment->comment_ID ?>" <?php echo array_key_exists( $comment->comment_ID, $comments ) ? 'checked="checked"' : ''; ?> /> This comment has received a reply. </label> <p> <em><?php echo $comment->comment_author; ?></em>: <?php echo $comment->comment_content; ?> </p> <hr /> </li> <?php } ?> </ul> </div>
Notice that we retrieve the value from the database, again passing true
as the third value.
Next, we take the current comment ID and check to see if that value is contained in the array keys (by using array_key_exists
) of the post meta data that was returned. If so, we mark the checkbox as checked; otherwise, we don't do anything.
At this point, we have a fully functioning plugin that fulfills all of the requirements that we set out to build starting with the first article in the series.
But is the plugin itself maintainable? That is, does it fulfill the primary objective of this series?
In someways, yes but there is room for improvement. Since part of development has to do working with code that we inherit, we're going to take a look at how to refactor some of the code that we've written to make it easier to understand and more maintainable.
Additionally, we'll be looking at reasons for why we're performing some of the refactoring that we're doing. After all, it wouldn't make much sense to simplify code or to move it around without any rationale.
But before doing that, go ahead and work through this article and take a look at the code from the associated GitHub repository and leave any comments, questions, or general feedback below.
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…