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.