Skip to content
Case Studies

WordPress Site Loading Without CSS, JavaScript, or Images: A File Permission Fix

July 25, 2026 · Webnorly · 8 min read

A WordPress website can look completely broken while its pages, database, and admin area are all still working. This site was loading as mostly unformatted HTML: the layout gone, images broken, navigation reduced to plain links, and parts of the dashboard unstyled. The cause was not malware, and not a failed update. It was a single directory permission on wp-content, quietly blocking the server from delivering every stylesheet, script, and image on the site.

This case study walks through the investigation, the actual server-level cause, and why reading the browser’s own error responses mattered more than reinstalling anything. If your site has lost its styling and you want the short version first, our WordPress help page covers what to check and what not to touch.

The problem: text loaded, everything else 404’d

The public site was serving its HTML content, but almost none of the visual or interactive assets came with it. To a visitor, the site looked like it had been stripped back to raw markup.

The symptoms:

  • Pages rendering without their normal design
  • Broken images across the whole site
  • Unstyled navigation and page elements
  • Missing plugin and theme styling
  • Parts of the WordPress dashboard loading incorrectly
  • Hundreds of errors in the browser console

The WordPress installation itself was reachable, which told us the database and the core PHP application were still running. The failure was specifically in retrieving files from the wp-content directory. That distinction, application works but static files do not, is what pointed the whole investigation toward the server rather than the site.

Ruling out the obvious suspects

A symptom this dramatic invites a quick guess, and quick guesses here are expensive. A site loading as raw HTML could plausibly be malware, an incomplete migration, missing plugin files, a PHP configuration fault, or damaged rewrite rules. Each of those leads to a different repair, and the wrong repair can cause more damage than the original problem. So we ruled them out rather than assuming.

Malware. A scanner had flagged an infection warning, and because malware can modify files, database entries, and server rules, it had to be taken seriously. We inspected the files the scanner pointed at. Nothing was actually corrupted or injected. The warning was a false positive, of the kind these scanners routinely produce, and we set malware aside as the cause of the display problem rather than letting a scary label steer the diagnosis.

PHP configuration. We reviewed the server’s PHP settings and brought them up to sensible production values along the way: a 512 MB memory limit, 64 MB upload and POST limits, a 120 second execution limit, and a higher input variable limit. Worth doing for the health of the server, but we did not expect it to be the cause, and it was not. PHP limits govern how the application runs; they do not make static .css, .js, and image files return 404 Not Found. This was elimination, not the fix.

Rewrite rules. We inspected .htaccess. The WordPress rules were standard, with no unusual redirects or rewrites that could explain missing asset files. A malformed rewrite is a genuinely common cause of WordPress breakage, so much so that we have written a separate guide on how AI-generated .htaccess rules break WordPress, but it was not the culprit here.

The browser’s Network panel showed the pattern

The decisive evidence came from Chrome DevTools, in the Console and Network panels. The browser was receiving 404 Not Found responses for assets belonging to several unrelated plugins and the active theme at once.

The failing requests spanned assets from WooCommerce, Yoast SEO, Popup Maker, WP Mail SMTP, Click to Chat, and the YOOtheme framework. The URLs sat under:

  • /wp-content/plugins/ (CSS and JavaScript)
  • /wp-content/themes/ (CSS and JavaScript)
  • /wp-content/uploads/ (images)

This is the detail that cracked it. If one plugin’s files had gone missing, that plugin alone would misbehave. But assets from many independent plugins, the theme, and the uploads folder were all failing together. Unrelated components do not corrupt themselves simultaneously. The one thing they share is their parent directory, so the problem almost certainly lived at the wp-content level, not inside any individual plugin or theme.

The cause: a directory permission the public could not traverse

We checked the permissions on the wp-content directory. It was set to 750.

That value grants read, write, and traverse to the owner, read and traverse to the group, and nothing at all to everyone else. Whether that breaks a public website depends entirely on which user the web server serves files as. On many stacks the server runs as the site’s owner or group, and 750 would be fine. On this host it did not: the process serving static files reached them as “other”, and “other” had no permission to enter the directory. So every request for a file inside wp-content came back 404, even though the files were sitting right there on disk.

This is why the site’s text loaded while its design did not. The PHP application, executed by the owner, could read everything it needed. The browser, fetching static assets through the public path, was locked out of the same folder.

The fix: 755 on the directory, nothing looser

We changed the wp-content directory from 750 to 755. That adds traverse access for everyone while keeping write access with the owner alone:

  • Owner: read, write, traverse
  • Group: read, traverse
  • World: read, traverse

We then confirmed the standard WordPress permission structure across the site, which the official documentation sets out in its file permissions guide:

  • Directories: 755
  • Files: 644

We did not apply 755 to files that did not need it, and we did not reach for 777, which is a common and dangerous shortcut that makes files writable by anyone. The goal was the least access that lets the server do its job, not the most access that makes the error go away.

After the permission change and a refresh, the theme styling, navigation, scripts, and the great majority of visual components loaded again.

The result

The site’s layout was restored without rebuilding the WordPress installation or touching the database. Back in place: theme styling, plugin CSS, JavaScript behaviour, structured navigation, page layouts, most imagery, and normal front-end presentation.

One honest caveat. After the main issue was resolved, a smaller set of image URLs kept returning 404. Those were a different problem from the permission fault: specific media files that were genuinely missing from the uploads directory, or database references pointing at files that no longer existed. Our record confirms the design and asset-loading problem was resolved. It does not confirm that every last missing media file was later re-uploaded, and we would rather say so than imply a tidier ending than the evidence supports.

Why the diagnosis mattered

It would have been easy to file this under malware, a failed update, a broken theme, an incomplete plugin install, a PHP 8.3 compatibility fault, or a corrupted .htaccess. Any of those readings leads somewhere destructive: reinstalling WordPress, replacing plugins, or rolling back to an old backup, each carrying its own risk and none of them addressing a directory permission. The site would very likely have ended up in worse shape, with the actual cause untouched.

Checking the browser’s response codes and looking for a pattern across unrelated assets isolated the fault to a single shared setting. This is the same approach behind our other recoveries: we traced a legacy site that broke after a PHP update back to its real cause the same way, and separated a genuine security incident from ordinary breakage when we investigated and recovered a hacked Multisite network.

Takeaway: when a site loses its design, read the Network panel first

When WordPress serves its text but loses its styling, the visible page is only half the diagnosis. The most useful evidence is usually in the browser’s Network panel, in the response codes attached to each failed asset.

A systematic check works through:

  • Whether CSS and JavaScript requests return 404, 403, or 500
  • Whether the requested files physically exist on the server
  • Whether the domain points to the correct document root
  • Whether .htaccess contains any abnormal rules
  • Whether directory and file permissions are correct for the host
  • Whether any genuinely missing media explains the remaining errors

Here, a single directory-permission correction brought back the majority of the site. That is the case for evidence-led troubleshooting over reinstalling WordPress or swapping out components that were never broken.

Need help with a WordPress site that lost its design?

When a site suddenly loads without styling, shows broken images, or throws widespread asset errors, the cause is often in the hosting configuration rather than the theme or the page builder. We investigate the full request path, from the browser through the WordPress installation to the server, before applying any repair. If that is where you are right now, start with a free diagnosis on our WordPress help page or read more about our WordPress troubleshooting service. If the site is working but you suspect it is fragile underneath, a one-time WordPress health check will tell you what is at risk before it becomes an emergency.