How We Made LearnDash 75 Times Faster
Important: This article examines how we modified certain parts of LearnDash to improve performance on high volume/enterprise sites. LearnDash itself is not slow, but some parts of it are designed for convenience rather than performance. For the vast majority of LearnDash sites, the optimizations discussed below are unnecessary and could be dangerous. This article is intended for very large sites where scalability and performance are critical.
We see a lot of projects that really push LearnDash to its limits, and for a sub-$200 WordPress plugin, those limits are surprisingly high. LearnDash is generally an efficient plugin that serves the vast majority of its customers very well, but every so often, an organization wants to see how well it can really perform at scale.
The typical LearnDash site we see might expect up to 15 simultaneous learners (even on sites with upwards of 1,000 users) and perhaps 200 LearnDash posts. We support several, however, that have hundreds of simultaneous learners and thousands of LearnDash posts (courses, lessons, topics and quizzes). At that level, everything gets harder and keeping everything running smoothly requires tuning performance wherever we can.
What we observed on extremely large sites, especially after total courses crossed the 100 level, total quizzes exceeded 1,000 and we started going over the 100 simultaneous user mark, was that performance significantly deteriorated in 3 main areas: user profile pages in /wp-admin/, quiz listing pages, and quiz submissions. In some cases users and admins were even seeing 503 errors, which is catastrophic for any live LearnDash site, but especially ones with hundreds of people online at the same time.
In user profiles we found that database operations could often exceed 150 seconds of processing times and require 10s of thousands of SQL queries to render (perhaps 200 queries is typical on most pages). What we found was that the “Course Progress Details” section of the profile page was looping through all courses to retrieve records for the user and the courses for every course the user was enrolled in. It was pulling everything down on page load too, so even if an admin were just going in to change a password or something else unrelated to LearnDash, the site would be affected by severe load.
Loading all of this data does make things a lot more convenient for admins, and in most cases this section wouldn’t be an issue. But when loading tens of thousands of records on a site with lots of courses, it’s a problem. Fortunately, our developers were able to override this section completely with an alternative solution that combines queries and reduces loops when the admin drills down into that specific course. The approach means we only load data when it’s needed and only as much as is needed. We also removed the edit links to LearnDash posts from the profile page, which are generally rarely used, and we added some transients to speed things up further.
The net effect of these changes?
We took profile page load time for admins from 150 seconds to 2 seconds.
The difference was night and day. It made profile pages usable again.
The list of quizzes inside LearnDash was another interesting performance challenge. With well over 1,000 quizzes (and thousands of lessons and topics) on a site, just listing the quizzes was a 120 second exercise that adversely affected learners on the site at the same time. Why so slow? Well, LearnDash adds filters to quizzes to make it easy to choose a course (or something else) and only see quizzes under it. But to populate that list of filters, it needs to look up all the associations between quizzes, courses, lessons and topics—which takes a long time on a big site.
This was a case where we really gave up convenience for performance. We didn’t care about only showing objects with quizzes in the filters. So instead we just loaded all courses, then on course selection in a filter we showed all lessons and topics. If the administrator filtered and there were quizzes, great. And if not, we just showed a message that there were no quizzes. That change took loading the quiz listing from 120 seconds to 2 seconds. It was well worth the slight inconvenience.
Next we looked at quiz submission performance. On sites with a lot of content, saving quiz answers that include essay questions can be extremely slow—in the case of a site with 120,000 rows in the wp_posts table, it was taking 35 seconds to save quizzes with essay questions. Obviously that was trying learner patience and slowing down the site. To address this one we took a shortcut, and instead of looking for a matching post title or name to avoid duplicates when saving an essay answer, we skipped the check and just forced a unique post name.
That new approach took quiz saving time from 35 seconds to 3 seconds.
As you can see from our results, it is possible to significantly increase LearnDash performance on big sites. What’s especially nice is that LearnDash allows us to make 2 out of the 3 overrides above without changes to LearnDash code (and we’re hoping the third can be handled outside of LearnDash in a future LearnDash release if additional filters are added). This means it’s easy to bundle our performance improvements into a portable plugin and the optimizations will survive updates.
Another factor that did help us really push LearnDash performance on these sites was assistance from Pressidium, who are hosting the sites. They went out of their way to help us look at opportunities for performance enhancements and they applied some database changes to their environment to improve performance further.
Can Learndash support thousands of simultaneous users?
A clean WordPress install with a light theme and LearnDash, with few courses and very robust hosting, can certainly scale vary high. There are too many variables besides LearnDash itself though, and in most cases LearnDash won’t be the limiting factor.
Are these excellent optimisations now part of the LearnDash core, or is there an Uncanny Owl plugin that can implement them?
I’m afraid the answer is “not really”. We did some code sharing around this with LearnDash, and while a few things were implemented, keep in mind that LearnDash needs to focus on convenience for most of their market vs. performance. Most of their buyers aren’t handling thousands of quizzes and topics and it wouldn’t make sense to remove features for the few enterprise users. Then on our side, things we’ve done are very specific to client needs and wouldn’t make sense for everyone. As such, we haven’t added things described here to a public plugin and don’t plan to; we instead prefer to look at sites individually to see where they’re having performance issues and then implement specific interventions that make sense for that site.
Hi Ryan, after a search for optimizing LearnDash I came here.
Is it still possible to point your reader in the right direction by listing the filters / actions / hooks or a simple GitHub gist?
Thank you in advanced!
We get a number of emails about this article, so I’ll post more detail here about why there’s no code available.
First, the article is almost 2.5 years old now. 🙂 The solutions described were build around the LearnDash 2.4 codebase. We shared some of our changes with LearnDash, many improvements have been made to core LearnDash since the 2.4 release. Any code we had is no longer valid.
Some of it also made it into our products. Take https://www.uncannyowl.com/knowledge-base/lazy-loading-course-navigation/, it’s loosely based on work for this site’s optimizations.
We don’t really maintain any type of “learndash optimizations” code because it changes between versions and the solutions we’ve built have been really client-specific. Some sites are okay trading performance for convenience, where LearnDash couldn’t release updates that make things inconvenient (and we don’t really want to support them either). The sites we do this kind of work for tend to have different types of performance issues, so rather than a blanket solution we look at each one to assess where things are slowing down and then look at possible interventions.
Sorry about that.
Thank you for your quick reply and the link to the knowlegde base / lazyloaded navigation. I will suggest this to my client.
I hope other readers will now also read the comments and follow your link to the Pro version.
Have a good day and stay safe!
Ps. The link to the Lazy mode module via https://www.uncannyowl.com/downloads/uncanny-learndash-toolkit-pro/ returns a 404.
Yikes, thanks for the note; it’s fixed now!
If i have approx 500 students that finish a learndash quiz at the same time will learndash be able to handel that?
It’s not really a function of LearnDash (it depends what else you have on the site, the environment, etc.), but if you’re asking what will happen if 500 users submit a big quiz at exactly the same moment, it’s definitely a heavy load. It’s not really heavier than many other actions though and that scenario wouldn’t happen in practice.