Changelog

Release Notes

Every feature, every improvement, every fix since v1.0.0.

Page 11 of 24 - 710 releases, newest first.

v2.66.34

Video Studio: sturdier YouTube and Instagram publishing

  • A Reels or Shorts upload that got stuck while the platform was still processing it could keep polling for up to a day. Such a job now gives up after a reasonable window and is marked failed, so one stuck upload no longer ties up the publishing queue or the daily quota.
  • A video scheduled for a future time is no longer mistakenly timed out because of the wait before its scheduled moment - the timeout window now starts from the scheduled time, not from when the job was created.
  • The full multi-step publishing flow for both platforms - Instagram's create / wait / publish sequence and YouTube's resumable upload that continues after an interruption - was verified end to end, including recovery when a connection drops or a session expires.
v2.66.33

License security hardening

  • The admin license screen now shows only a masked version of the license key instead of the full value.
  • License activation and deactivation now require an admin login on every install, including freshly installed sites that do not yet have an active license.
  • Demo-license validation now relies on the site's configured address rather than a value taken from the request, so activation stays tied to the real domain.
  • Premium features, plugins and themes now follow the installed edition: a paid package (already purchased to download) keeps everything unlocked even if its token lapses, while the free package is correctly limited.
  • The update-download endpoint now rate-limits per address and only responds to expected origins.
v2.66.32

New: Video Studio - turn posts into narrated Shorts and Reels

  • Video Studio (in the Social plugin): pick a post and the studio writes a ~60-second narration script in your site's language, reads it aloud with a natural AI voice (30 voices, Turkish included - uses your existing Gemini key's free tier, so it costs nothing), and renders a 1080×1920 vertical video with your post's images, animated captions and your site's name - right in your browser. No server video software is needed, so it works on ordinary shared hosting; rendering requires Chrome or Edge.
  • One-click publishing to YouTube Shorts and Instagram Reels through the existing social queue, with retries and rate limiting handled for you. Instagram connects with your own Meta app in development mode - publishing to your own account needs no app review. For YouTube, connect your own Google Cloud app; note Google locks videos from unverified API projects to private, so until you complete Google's verification the studio's "Download + open YouTube Studio" button is the recommended path - it saves the video, copies the title and description to your clipboard and opens YouTube Studio, making manual upload a 30-second task.
  • Every text the studio produces - narration, YouTube title and description, Instagram caption, hashtags - is fully editable before anything is voiced, rendered or published. A "draft job" can be opened automatically whenever you publish a post, so fresh posts wait for you in the studio.
v2.66.31

Comments and the contact form: lost messages found their way back

  • On the Personal theme the contact form posted to an address that did not exist: every message a visitor sent ended in a 404 and was never stored anywhere. The address now reaches the protected handler, and when JavaScript is off the visitor is brought back to the page with a clear "received" or "failed" notice instead of a raw code screen.
  • On the Entertainment theme comments were broken twice over: approved comments were never shown (the list pulled in a file that did not exist), and a signed-in reader's comment was always rejected asking for a name the form never collects. The list renders again and the handler now fills in the reader's name and email from their account.
  • On eight of fourteen sites the spam capture log still had an old table layout, so every catch failed silently: blocked bots left no trace, the admin screen showed zero blocks, and the "repeat offender" signal never fired. The table now completes its own missing columns on first use.
  • Thirteen themes' comment forms used a spam-trap field literally named "website" (one theme even added "phone"). Browsers recognise those names and auto-fill them - and a real reader whose browser did so had their comment silently thrown away. The trap fields now use a neutral name browsers ignore.
  • Every comment and contact submission was counted twice against the flood limits, so the caps the admin configured were effectively halved.
  • All three settings on the contact form panel were dead: the recipient address was saved but notifications kept going to the general address, the custom success message was never shown, and the auto-reply was never sent at all. All three now do what the screen says - auto-replies also carry a once-per-hour-per-address brake.
  • The site-wide comments feed now includes only comments from published, public posts. It is also reachable now: the feed advertised its own address but the address had no route and bounced to the home page.
  • The comment moderation screen and the panel reply endpoint now require full moderation permission, not just any signed-in account.
  • A reply written from the panel did not update the post's comment counter, and the person being replied to never got the "someone replied to you" email even when that notification was switched on.
  • Comment notification emails were always in Turkish, even on English sites; they now follow the site language. The contact form's success and error notices also had no colour in themes without their own styling.
v2.66.30

A/B tests: the numbers are now real visitors' numbers

  • A/B test results counted search engines and automated crawlers as if they were readers: every crawl added impressions, and a crawler following the conversion link added conversions. A test could crown the wrong winner on traffic no human ever saw. Crawlers still see the page content as before, but they no longer touch the statistics.
  • On a site installed in a subfolder, a conversion goal written as a plain path ("/contact") redirected the visitor to the server's root instead of the site's own page - usually a 404. Plain paths now resolve against the site's own address.
  • Behind services like Cloudflare, every visitor appeared to arrive from the same address, so which variant a visitor saw depended almost entirely on their browser make - most people got the same variant and the split was badly lopsided. The variant assignment now uses the visitor's real address when a trusted proxy provides it; sites not behind a proxy are unaffected.
  • Turning a plugin off left its placement codes ("[ab id=3]", "[form id=5]"…) sitting in the middle of published posts as raw text for every reader. Leftover placement codes from an inactive plugin are now removed from the page.
  • Plugin placement codes also leaked as raw text into the RSS, Atom and JSON feeds, because feeds deliberately skip the plugin rendering step. Feeds now clean them out at the source.
v2.66.29

Analytics: the settings on the screen now actually do something

  • Every page of every site ran three table-creation statements and nine setting inserts before rendering, on every single request. That check now happens once and remembers the answer; the admin screens still repair themselves on demand.
  • The analytics master switch did nothing. Turning tracking off left the counting script on every page and the receiving endpoint still wrote every visit to the database, even though the screen said no data would be collected. The endpoint that receives visits now reads the settings before it stores anything, so off means off. The excluded-IP and excluded-path lists were dead in the same way and now work too.
  • The free edition collected visitor data with no way to see it and no way to stop it: the analytics screens are not part of that package, but the counting script and the receiving endpoint were. Neither runs now unless the analytics module is installed.
  • Any other website could post fake visits to the receiving endpoint from a visitor's browser and skew the reports. Requests that identify themselves as coming from somewhere else are now refused.
  • Every comparison figure was biased upward. "7 days" actually measured eight calendar days and compared them against a seven-day span, so the up-and-down badges on the cards flattered the current period on every range. Both windows are now the same length.
  • The same page was counted several times over: an address with "?page=2" or a campaign tag on the end became its own row in the most-viewed list. Addresses are now reduced to the page itself, for existing history as well as new visits, and web-encoded characters in Turkish addresses are decoded so they read normally and match the right article.
  • Daily totals were being lost for good. The receiving endpoint and the housekeeping task both rotate the daily privacy key, and whichever got there first made the other skip that day's summary - one site had summaries for only 42 of its 83 days. Summarising no longer depends on the key, and missing days are recomputed from the raw records that are still within the retention window.
  • Analytics silently collected nothing on installations where the first database file the endpoint found was not the one in use - it gave up instead of trying the next one. It now uses the first connection that actually works.
  • The bounce rate loaded every visit session of the selected period into memory to count them; on ninety days of a busy site that is tens of thousands of rows for a single percentage. The database does the counting now.
  • A malformed address in the browser bar ("?range[]=x") crashed the analytics screen with a server error.
  • Saving the analytics settings and then refreshing the page submitted the form again.
v2.66.28

Advanced SEO panel: tools that had quietly disappeared are back

  • Long tool tables no longer scroll inside their own frame. The panel measures the tool it is showing and grows to fit, so the slug repair and content SEO lists - hundreds of rows - scroll with the page instead of trapping a second scrollbar inside it.
  • The heading hierarchy screen could not be opened from anywhere in the panel. It lists every published article whose headings start at the wrong level and fixes them in one click - on a test site it had findings for two hundred articles - but when the SEO tools were gathered into a single panel, this one screen was left off the menu, and the panel hides each tool's own tabs. It is now a module of its own, under Content.
  • On installations where the Advanced SEO plugin is switched off, eight tools became unreachable: the SEO overview, heading fixer, content optimiser, internal linking, featured images, slug repair, orphan content and the year updater. They were removed from the main menu when the panel took over as their single entry point, so switching the panel off left the files installed and invisible. Five sites were in exactly that state. The menu now falls back to an "SEO Tools" entry whenever the panel is unavailable.
  • The panel listed every tool it knows about, whether or not that screen exists in the installation at hand. A missing screen produced an empty white frame with no explanation, because a page that is not found says nothing inside a frame. The panel now lists only the tools it can actually open.
  • Fixes to the panel screen itself never reached existing sites: the update tool carried the plugin's code but not the page that draws it. It is now on the list.
v2.66.27

Critical: the installer failed on its final step

  • New installations failed at the last step of the wizard. The installer carries its own copy of a small helper for reading PHP size limits, and the core gained a function with the same name on 7 August - so the moment the wizard loaded the core to finish setting up, PHP refused the duplicate and the install stopped with a server error. The installer's copy now has its own name, which also keeps its behaviour independent of the core's version. Anyone who downloaded the package between 7 and 18 August should download it again.
  • The end-to-end install test that would have caught this now runs against the packaged installer, and its error detection no longer trips over the words "server error" appearing inside a script comment - a false alarm that masked whether the page was actually broken.
v2.66.26

Article pages stop being dead ends, and the ad-readiness panel now sees template repetition

  • Shared sidebar modules - categories, topics and recent posts - that any theme can use without carrying its own copy. A theme that ships its own version keeps it; the shared one only fills the gap.
  • Three new checks in the ad-readiness panel, covering what it could not see before: how much of the site shares one title pattern or one section skeleton, how many posts run without a single image in the body, and whether a large batch of posts was published on one day. These are the traits that make a site read as machine-produced regardless of how well each article is written.
  • One theme had its tag list switched off in code. The line dated back to when tag pages returned “gone”, and it was never revisited after those pages started serving again - so a site whose every post carried tags published not a single tag link. The list is back.
  • Three themes never printed tags at all, although most of their posts were tagged. An article that ends without a single onward link is a dead end for the reader and for a crawler alike.
  • The personal theme shipped its category, tag and recent-post modules switched off, so the sidebar of an article carried three links in total. The same article rendered by the theme that did get ad approval carries thirty-nine. The modules are on by default now.
  • The travel theme's article rail held only a table of contents, share buttons and a back-to-top button; the theme's own richer sidebar was never included on article pages. Category, tag and recent-post navigation now sits in the rail.
v2.66.25

Image dimensions everywhere, and archives now list their posts in structured data

  • Category, tag and author archives now publish the list of posts they show as structured data. The page already declared itself a collection, but never said what was in it; the list is built from the same query the theme uses, so it cannot drift from what a visitor sees.
  • Resized image variants never received width and height. The lookup stripped the size suffix from the filename but removed the file extension along with it, so the name it searched for could never match a stored one - a comparison that could not succeed by construction. Every related-post card and listing thumbnail was therefore published without dimensions, and those are the most numerous images on a page: each one shifted the layout while it loaded. Sizes now come from the file itself, so the variant reports its own true dimensions.
  • Author avatars and site logos were skipped entirely. They are not stored in the media library, so no size was ever known for them, and an avatar can appear half a dozen times on a single article. They are measured now - layout treatment for them stays unchanged, only the dimensions are added.
  • The featured image went into the structured data without dimensions on sites whose images predate the media library, even though the in-content images had them. That is the one image search engines look at first.
  • The single post page now declares its author and section to social networks as well. Publication and modification times were already sent; the author was only in the structured data, so shared links carried no author attribution.
v2.66.24

API settings: quotas now apply to content generation, and usage statistics finally count it

  • The API tab now opens with the automation entry points it is named after: a link to the REST API keys used by n8n, Zapier or your own script, and one to the ready-made n8n workflows. Both had moved to other screens with no way back from here.
  • Each AI setting now states what it governs - which calls a quota covers, that the token limit applies to analysis rather than article length, and what the cache window actually caches.
  • The daily and per-account AI quotas were only applied to SEO analysis. Article generation - the path that actually spends most of the tokens - ignored them completely, so a site set to 200 calls a day could make thousands, and on a paid provider that lands straight on the owner's bill. Both quotas now cover every AI call, and the screen shows how much is left.
  • The usage statistics counted the same narrow path, so most sites saw zeros no matter how much they generated. Every generation call is now recorded with its provider, model, token count and duration.
  • The temperature slider did not reach article generation either: that code carried a fixed value and the setting only affected analysis. The configured value now applies everywhere it is accepted.
  • The API key test endpoints now require an administrator account, matching the screen that calls them.
  • The model field accepted an empty value and stored it, which left every later request pointing at no model at all - generation failed with nothing on screen to explain why. Empty and malformed values now fall back to the saved model.
  • The default provider field accepted any text. An unrecognised value made the site report "no AI key connected" while the key sat there saved.
  • Choosing a provider hid the other providers' key fields, and they could not be reached again without reloading - even though keys are stored per provider and several can be filled in. Nothing is hidden now; the default provider is marked instead.
  • With a provider other than Gemini selected, the panel claimed the integration was off and asked for a Gemini key although generation was working. The status now follows the provider actually in use.
v2.66.23

User management: lockout protection, account status and a single password rule

  • Accounts can now be deactivated instead of deleted. The account status was stored and enforced everywhere - an inactive account cannot sign in and is hidden from author pages - but there was no way to set it from the panel, so the only way to stop someone from signing in was to delete their account along with everything attached to it.
  • Locked accounts can be released from the user's edit screen. After five failed sign-in attempts an account locks for fifteen minutes, and the counter only cleared on a successful sign-in - so someone who could not remember their password stayed locked out with no way for an administrator to help. The current lock state and the failed-attempt counter are now shown, with a control to clear both.
  • The user list now marks inactive, banned and locked accounts, so "why can't I sign in?" has a visible answer.
  • The last administrator could lock themselves out of their own site. Changing your own role to subscriber, deactivating your own account or deleting the only administrator was accepted without a word - and afterwards nobody could reach user management again, with no way back except editing the database by hand. All three paths are now refused while no other active administrator remains.
  • The role field accepted any value that was posted. A value outside the four known roles silently emptied the role - leaving an account that could sign in but had no permissions at all - and on databases in strict mode it broke the save outright. Role and status are now checked against their allowed values.
  • Usernames were stored exactly as typed, including spaces and slashes, even though the username is also the author page address. A username can no longer be set to an e-mail address either: the sign-in screen accepts both a username and an e-mail, so the two would collide.
  • Changing a username left the old author page as a dead address; it now redirects to the new one, the same way category addresses already did.
  • The user screen enforced no password rule at all - "123" was accepted. Both the user screen and My Profile now apply one shared rule: at least eight characters with a letter and a digit, and obvious passwords are refused.
  • Changing a password now also ends that account's "remember me" session on both screens, so older browser cookies stop working immediately.
  • With a role filter active, the "All" tab showed the filtered number rather than the total, and paging through search results silently dropped the search.
  • Deleting a user left their avatar file behind on disk.
v2.66.22

Spam Protection screen rebuilt, and its settings now save reliably

  • The Spam Protection screen was built with a layout system the admin panel does not use, so none of its structure applied: the four summary figures stacked into four full-width bands down the page, the settings sat in a single narrow column, and the icons never appeared. The screen is rebuilt with the panel's own components and now reads as one page: summary cards across the top, settings in the main column, quick actions and blocked addresses alongside.
  • A status line at the top now states plainly whether protection is on. Every threshold on the page is meaningless while the master switch is off, and nothing on the old screen said so.
  • Turning protection off was never saved: the screen decided the switch's state from the presence of the field rather than its value, so the setting stayed on no matter what was chosen.
  • Turning the master switch off also erased the thresholds underneath it - link limit, submit time, flood caps all fell back to factory numbers, because disabled fields are not submitted by the browser and the screen treated a missing field as a request to reset. A missing field now keeps the saved value.
  • Out-of-range values were stored as typed; they are now kept within the limits the screen advertises.
  • The minimum submit time was an admin setting the guard did not read: the screen could say five seconds while the server decided at three. The configured value is now the one that applies.
  • Spam catches were being written to a table that some installs never had. The repair routine existed but was never called from anywhere, so on those sites every caught bot vanished without trace and the screen reported nothing. The table is now created on demand and the write is retried.
  • Several English labels on this screen showed placeholder text generated from their internal names; they have been written properly. Two Turkish descriptions described the wrong thing.
v2.66.21

Spam protection: one shared surface for every public form

  • Public forms now share a single anti-spam surface. Comments, the contact form, the newsletter box and the form builder each had their own hand-built protection, and they had drifted apart. One component now renders the hidden protection fields and one function runs the shared checks, so a new form is protected by construction rather than by remembering to repeat the work.
  • Bot catches are now recorded. Honeypot hits, instant submissions and flood blocks were silently discarded on the comment channel, so there was no way to tell working protection from absent protection; they are logged now.
  • The timing check that catches instant bot submissions was inactive on five themes and the newsletter box, because the field it reads was never rendered there; one theme's comment form had no honeypot at all. Every public form now carries all three protection fields.
  • The newsletter box never sent its hidden fields at all: the script assembled its own payload from just the e-mail address, so the honeypot on that form could never trip. The whole form is submitted now.
  • Messages flagged as spam by the contact form were stored with an invalid status, because the column had never been extended with a spam value. They appeared in no folder - including the ones caught by mistake, which is exactly what the spam folder exists to prevent. The column is repaired automatically and previously mis-stored messages are recovered.
  • One theme's comment form posted to an address that does not exist, so signed-in readers' comments went nowhere.
  • Comment length limits counted bytes rather than characters, so Turkish text was measured incorrectly - a long comment could be refused while a single-letter name passed. Both channels now measure the same way.
  • Names and subjects accepted line breaks, which single-line fields should never carry; the value is now cleaned on the way in.
v2.66.20

Tags no longer lead nowhere, and images declare their size

  • Tag links led to a bare “410 Gone” screen. Themes show tags in several places - under the article, in the sidebar cloud, on archive and search pages - but tag pages were only served when tag archives were switched on, which they are not by default. Every tagged article therefore carried several dead internal links, and a reader who clicked one landed on an unstyled error page. Tag pages are now always served with the site's own design; the setting decides only whether search engines may index them. With it off they are shown to readers but marked noindex and left out of the sitemap, exactly as before.
  • Images inside articles were rendered without their dimensions, so the page reflowed as they loaded - the layout shift that Core Web Vitals measures. Both the article's main image and images inside the text now declare their size, taken from the media library, across every theme. In-text images also load lazily while the leading image stays eager, which is what browsers need for the largest element to appear quickly.
v2.66.19

Legal pages: updated details now apply, duplicate date and mangled e-mail fixed

  • Correcting your contact e-mail, address or business name and generating the legal pages again left the pages unchanged, still showing the details from installation. The generator kept any page that was long enough, to avoid overwriting text you had written yourself - but that also protected the untouched pages that shipped with the install. The generator now recognises a page you have never edited and refreshes it with your new details, while a page you edited by hand is still kept, and now says so and points to the overwrite option.
  • Legal pages showed the last-updated line twice, with two different dates: the generator wrote one into the page text while the theme printed its own. The line now comes from the theme only, and pages that were never edited have the leftover line removed automatically when the Pages screen is opened and during maintenance.
  • The last-updated date always showed today, on every theme, even for a page that had not changed in months - a misleading claim on a legal page. It now reflects when the page was actually last saved.
  • Turkish spelling correction in the generated text ran across the whole page, including e-mail addresses and links, so an address such as iletisim@example.com could be rewritten into an invalid one. Addresses and links are now left untouched while the surrounding text is still corrected.
v2.66.18

Media: half-rendered screen on an empty library, and file types

  • The media library stopped rendering half-way down the page whenever the library was empty - which is exactly the state of a brand-new site. The file counters are produced with SQL sums, and a sum over zero rows is empty rather than zero; feeding that empty value into the counter text raised an error that ended the response early, so the page arrived without its grid, upload button or closing markup. The counters are now normalised to zero, and the translation layer no longer lets an empty value end a page.
  • Every uploaded file was recorded as an image, whatever it was: PDFs, documents, spreadsheets, archives and text files all carried the image type in the library records. The type is now derived from the file itself, and existing records are corrected once during routine maintenance.
  • The Video tab listed the entire library instead of videos, because that tab had no filter of its own. Video and audio now filter correctly, the Documents tab no longer mixes media files in, and the item count matches what the tab actually shows.
v2.66.17

Built-in pages: stable dates instead of a false freshness signal

  • Pages served from a theme template rather than a stored record announced the current moment as their publish and modification date, so the structured data changed on every single request - two requests three seconds apart reported two different timestamps. Search engines were told the page had just been edited every time they fetched it. These pages now carry a stable date taken from the template that produces their text, so the date only moves when the text actually changes.
  • The same pages were listed in the sitemap with today's date every day, the same "permanently fresh" signal the homepage and category listings were corrected for earlier. Their sitemap entry now uses the same stable date.
v2.66.16

Pages: duplicate legal URLs, sitemap gaps and SEO visibility

  • The Pages hub now requires the page-editing capability. It previously checked only that someone was signed in, which gave accounts holding lesser roles more reach over published legal text than intended.
  • The legal page status table now shows how each page actually appears to search engines: its canonical address, whether it is indexable, whether it is in the sitemap, and its meta description length - with a plain-language note when something needs attention.
  • Legal pages served from the theme template - the default state of a fresh site - answered on both their Turkish and English addresses with identical content, and each address declared itself canonical. Measured: /privacy and /gizlilik returned the same page byte for byte as two indexable URLs. Every alias now collapses onto one address per document, chosen by the site language, exactly as it already did once a page existed in the CMS.
  • Those same pages were missing from the sitemap: live, indexable, but never submitted, because the sitemap only listed pages stored in the database. Privacy, terms, cookie policy, disclaimer, about and contact are now listed whenever they are served, and a page stored in the CMS replaces the built-in entry instead of being listed twice.
  • Legal, about and contact pages served from a theme template carried the site-wide meta description - the same sentence as the homepage - because the route never handed the page's identity to the theme. Each now carries its own description; verified across every theme.
  • The legal page editor screen answered with a server error on every install: it queried a table that belongs to the jekcms.com marketing site and does not exist in the CMS. The address now redirects to the page it was meant to open.
  • Generated legal pages calculated reading time with a counter that splits Turkish words, inflating the estimate by roughly 40%.
v2.66.15

Menus: second menu could not be created, plus icon support

  • Menu items can carry an icon (emoji), set next to the title in the menu editor and shown in every theme's navigation.
  • Menu items whose parent was removed used to vanish from the navigation; they are now shown at the top level instead of being silently dropped.
  • Menu links are now restricted to safe schemes: a `javascript:` or `data:` link saved into a menu is stored and rendered as an inert "#".
  • Creating a second menu failed with a server error. Menus carry a unique slug, but the create/update code never wrote one: the first new menu was stored with an empty slug and every menu after it collided with it. Menus now get a unique slug derived from their name, and existing rows with an empty slug are repaired automatically. Renaming a menu keeps its slug, so nothing that points at it breaks.
  • The Tech theme ignored the menu module completely - its header always printed the first five categories, so nothing configured under Menus ever appeared. It now publishes the assigned menu and falls back to categories only when no menu exists.
  • A menu assigned to the "Main" location was invisible on every theme, because themes read the "Header" location. "Main" is now treated as an alias of the header location, so existing menus start working without being touched, and the location list only offers what themes actually render.
  • When two menus shared one location, which of them appeared was left to chance. The site now consistently shows the older one, and the Menus screen warns that the others stay hidden.
v2.66.14

SERP site name: save defect fixed, end-to-end identity checks

  • SERP Identity Check now verifies the whole live chain Google reads for the site name - homepage reachability and indexability, the title, og:site_name, the WebSite schema name/url/alternateName, the canonical, the favicon, and whether the www variant consolidates onto one host - so a broken link in the chain shows up without waiting for a re-crawl.
  • Settings → General now flags a site name that is empty, generic, or a literal copy of the domain right next to the field, since Google falls back to showing the domain in those cases, plus a direct link to the identity check.
  • The identity check no longer reports internal state rows (plugin schema markers, heal flags, cached audit payloads) as autoload defects - they are excluded by design, so the check can now actually report a clean install and a real defect stands out.
  • A setting could fail to save entirely when its stored row lived under a different group label: the settings table keeps `key` globally unique, but the shared save helper looked the row up by group plus key, found nothing, and then tried to insert - hitting a duplicate-key error. The value silently never applied, which for the site name meant search results kept showing the domain. The save path now resolves by key (as the read path already did) and moves the row to the requested group.
  • Breadcrumbs on Turkish sites announced the root as "Home" even though the site declared itself Turkish. Google shows breadcrumbs in search results, so the trail now uses the site's own language ("Ana Sayfa").
v2.66.13

SEO audit: pagination signals and robots consistency

  • rel=prev/next pagination links are now emitted centrally for every theme - including the four themes whose headers never passed pagination context.
  • Page 2+ of the home/blog feed now carries the page number in its title instead of duplicating page 1's title.
  • Out-of-range pagination URLs (?page=N beyond the last page) returned an empty archive with HTTP 200 and a self-referencing canonical - an infinite, indexable space of thin duplicate pages. Every paginated list (home feeds, category/tag archives, author pages, every theme) now returns a real 404.
  • The personal theme stamped paginated archive pages with an extra "noindex, follow" robots tag next to the core's "index, follow" - conflicting directives, and search engines pick the restrictive one, silently dropping page 2+ from the index. Paginated archive pages are all indexable again with a single robots tag.
  • A per-post robots value saved as plain "index, follow" wiped the core defaults' max-image-preview:large directive, costing those posts large-thumbnail eligibility in Google Discover. Indexable robots values without max-* directives now get the default set appended.
  • URLs of non-paginated pages (a single post, a fixed homepage) with a stray ?page=999 served identical content that declared itself canonical - the canonical now keeps ?page only on genuinely paginated templates and consolidates everything else onto the clean URL.
v2.66.12

AdSense readiness: aligned with current approval criteria

  • New audit check: the privacy policy is now scanned for Google's "Required content" disclosures - cookie use, the third-party (Google) advertising-cookie statement and the personalized-ads opt-out link. If you rewrote the generated legal pages and dropped these sections, the audit catches it.
  • New audit group: ad-click encouragement phrases ("click the ads", "reklamlara tıklayın") are now scanned in titles, slugs and bodies - the clearest program-policy violation there is.
  • New sidebar card: applicant requirements (18+ age rule, the 6-month site-ownership rule that applies in some countries, HTML source access).
  • The consent-banner check now explains the certified-CMP rule accurately: since January 2024, serving ads to EEA/UK/Switzerland visitors requires a Google-certified CMP (IAB TCF) - the built-in banner covers the GDPR baseline but does not replace it; enabling Google's own consent message under AdSense → Privacy & messaging after approval satisfies the rule. The application-day checklist gained the same step.
  • The policy-scan pass message now states its honest scope: Google's prohibited-content list is broader (hate speech, misleading health/election claims, deceptive practices) than what pattern scanning can detect.
  • Policy patterns containing the Turkish dotless "ı" (e.g. "şifre kırma", "sızma testi") were silently missed in ALL-CAPS titles because uppercase "I" lowercases to "i", not "ı". The scanner now folds both the text and the patterns to a shared canonical form, so case no longer hides a match.
v2.66.11

Settings audit: SVG hardening in the branding preview

  • The generated-logo and favicon SVG fields are now sanitized before they are stored and before they are rendered in the branding preview. These are hidden form fields, so a tampered value could previously carry an event handler (e.g. onload) or script into the admin branding screen; the old check only rejected literal <script> tags and the preview printed the markup raw. Legitimate generated logos are unaffected.
v2.66.10

License & update audit: free-tier update channel repaired

  • Update availability queries without a license key are now treated as the lowest tier and only see the core release, matching the existing rule for unknown keys.
  • The license heartbeat endpoint no longer includes internal error details in its 500 responses outside debug mode.
  • The tripwire reporting endpoint now has an IP rate limit, closing an unbounded-log disk-fill vector.
  • Expired one-time download tokens are now swept opportunistically instead of accumulating forever.
  • Free-tier installations could not install core updates: the server correctly serves the free package, but the signed update manifest only listed the full package's checksum, so the client's tamper check rejected the legitimate free download as a mismatch. The manifest now carries a signed entry for the free package too, and the client accepts either signed checksum - the tamper protection itself is unchanged.
  • The update manifest no longer embeds full internal catalog rows (IDs, file paths, changelog text); it now carries exactly the fields clients verify, which also makes the signed payload much smaller.
v2.66.9

Redirect manager overhaul: 404 suggestion engine revived, URL matching fixed

  • Pasting a full URL of your own site as the redirect source now works - the domain is stripped and the path is stored canonically; foreign-domain sources are rejected with a clear message.
  • Static-asset 404s (missing images, fonts, bot .env scans) are excluded from the suggestion log so real page URLs aren't buried in noise.
  • The redirects table is now self-healing on older installations where it never existed - adding a redirect no longer fails with a generic error, and automatic 301s on slug changes work there too.
  • The "Orphan 404s" suggestion engine never received any data: the 404 logger existed but nothing ever called it, so the tab read from a table nothing wrote to. 404s (including theme-rendered ones) are now logged centrally, so the one-click "create 301" suggestions finally appear.
  • Redirects with Turkish or other non-ASCII characters in the slug never fired: the browser sends the URL percent-encoded while the redirect was stored decoded, and the two were compared as raw strings. Requests are now normalized exactly like the router normalizes them (decoding, trailing slash, subfolder base path), so /eski-yazı style redirects work.
  • Redirects were completely dead on subfolder installations (e.g. example.com/blog): the incoming path carried the folder prefix while the rule was stored without it, and relative targets redirected to the domain root instead of the subfolder.
  • Saving a redirect whose target equals its source is now rejected - previously it created an infinite redirect loop in the browser.
  • Form resubmission on refresh is gone: actions now follow the POST→redirect→GET pattern, so pressing F5 after toggling a redirect no longer silently toggles it back.
  • The "Hits (30 days)" stat actually showed the lifetime hit total of recently-hit rules; it is now split into an honest "Total hits" and "rules hit in the last 30 days".
v2.66.8

SEO tab: archive indexing controls and Pinterest verification

  • Archive Indexing panel in Settings → SEO: the thin-content engine that decides whether author and category archives are indexable was always running, but its knobs were hidden. You can now turn author-archive indexing on/off and tune the minimum-post thresholds for author and category archives - meta robots and the sitemap follow the same values, so Google never gets conflicting signals.
  • Pinterest site verification field: the meta tag output has supported Pinterest verification all along, but the form only offered Google, Bing and Yandex. The fourth field is now there.
  • The “AI bot access” shortcut in the SEO checklist pointed at an anchor that didn't exist on the page, so the click landed at the top instead of the AI bot panel. The anchor now exists and the link scrolls to the right place.
  • Archive threshold values are clamped to a sane 1–50 range on save; previously a 0 or negative value silently fell back to a different number than the one shown in the form.
v2.66.7

Security hardening: 2FA replay protection, backup codes, secret handling

  • Backup recovery codes: enabling 2FA now generates ten single-use codes shown once. If you lose your authenticator device you can still sign in - no more lockout requiring server access. Codes can be regenerated with a current code.
  • Mandatory 2FA policy: a new toggle can require every administrator to use two-factor authentication; admins without it are guided to set it up at login and can't disable it while the policy is on.
  • The File Integrity Monitor now shows a distinct “monitoring inactive” state when no manifest has been created yet, instead of falsely reporting “clean”.
  • Two-factor codes can no longer be reused: each 6-digit code is now single-use within its time window (a captured code can't be replayed on another session).
  • The reCAPTCHA secret key is now encrypted at rest and is no longer written back into the settings form's HTML.
  • Two-factor secrets are now stored encrypted (same protection as mail/API secrets).
  • reCAPTCHA on the admin login now fails closed: if Google's verification service is unreachable, login is blocked (comment/contact forms still fail open so real visitors aren't blocked; this is configurable).
  • Re-keying an already-enabled 2FA now requires the current code.
v2.66.6

Mail overhaul: honest delivery status, diagnostic errors, deliverability tools

  • Every core e-mail (sent or failed) is now logged, and the Mail tab shows a “Recent Sends” panel with per-message errors - failures are finally visible instead of dying silently.
  • One-click Deliverability (DNS) check on the Mail tab: verifies the sender domain's MX, SPF and DMARC records - the three most common reasons mail lands in spam.
  • A clear warning appears when the sender address and the SMTP account are on different domains (the classic setup that providers treat as spoofing).
  • The core SMTP client never checked the server's replies - a rejected recipient (550) or rejected message (554) was still reported as “sent”, so failed contact-form, comment and download-delivery e-mails vanished without a trace. Every SMTP step is now verified and failures carry the server's exact response.
  • The “Send test” button used a different mail engine than real notifications - a passing test could hide a broken production path. The test now exercises the same engine your notifications use (and no longer depends on the newsletter plugin being present).
  • The admin's PHP mail() / SMTP method choice was ignored by core notifications; it is now honored everywhere, and authless SMTP relays (no username) work.
  • Scheduled-task e-mails were sent raw with an empty From header due to a settings-lookup bug; they now go through the same configured engine.
  • E-mails now include Date and Message-ID headers, a plain-text alternative part and base64 body encoding (all common spam-score factors), attachments finally work over SMTP, and connections have proper timeouts.
v2.66.5

Ad manager overhaul: every slot now works, new revenue placements, premium controls

  • New “End of Article” slot - the ideal spot for an AdSense Multiplex unit, monetizing readers who finish a post. Works in every theme automatically.
  • Four previously dead slots now work in every theme with zero theme edits: mobile bottom anchor (with a dismiss button), mobile top banner, sidebar top and sticky sidebar - the core injects them universally.
  • Revenue Settings panel: in-content ad interval (every N paragraphs, following the 300–500 word rule) with a per-page cap, lazy loading for below-fold ads (protects Core Web Vitals), a GDPR consent gate that holds custom ad codes until the visitor accepts cookies, and an editor for extra ads.txt lines (non-Google networks/resellers).
  • The Banner Manager's [banner id=N] shortcode finally renders on the site - it previously appeared as plain text because no frontend handler existed.
  • Slots in the admin are now ordered and badged by earning power (in-article and above-the-fold first), and slots the active theme can't print are labeled clearly.
  • In-article ads no longer appear in 3-paragraph posts (a counting quirk made the threshold more aggressive than documented) and never land right before the article-end ads (no stacking).
  • The Pets theme printed the in-article ad at the very end of the post, stacked on top of the bottom ad - it now flows between paragraphs like every other theme.
  • Ad styles were emitted up to three times per page; now exactly once.
  • List ads (in-feed) filled their gaps: Travel archives, search results in five themes and homepages in seven themes now show the between-posts slot.
  • Post descriptions in structured data no longer leak raw shortcodes like [banner id=3].
  • Deleting a banner now uses a POST request (the CSRF token no longer travels in the URL).
  • Side discovery: the spam settings save path called a function that did not exist anywhere - saving spam settings or the auto-blacklist would have crashed. Defined properly.

Get your site live

The setup wizard gets a site live in about 30 minutes. See the prices and the free edition.

View Pricing
  • Setup and live in 30 minutes
  • 15 ready-made themes
  • AVIF/WebP image optimization
  • Automatic SEO - Sitemap, Schema.org
  • Cookieless built-in analytics (ZeroTrack)

Be the first to know

New features, release notes and CMS guides. We send a couple of emails a month.