It is our choices, Harry, that show what we truly are, far more than our abilities. – J.K. Rowling
Foreword
We wrote a foreword on 4.0. It’s a story on our efforts making this update, and why we’re exhilarated bringing you this update… finally.
Release highlights
- We completely refactored the plugin without losing features. This is the fastest full-featured SEO plugin for WordPress… by far.
- You can now use quick & bulk editing options. They blend perfectly into the interface of WordPress.
- Now, there are more term options, including redirects and canonical URLs.
- Want to enable indexing for just one page? Now you can, with qubit robots options.
- The SEO Bar is completely rewritten. It now lists the issues found so you can easily see what requires attention.
- The sitemap is also new. It lists your pages more intelligently, making it easier for search engines to find your latest updates.
- There’s a new and improved API for all the JavaScript, SEO Bar, sitemaps, tooltips, term-and post meta, and more!
- The character and pixel guidelines can now change depending on your site language.
- Full keyboard navigation support is now possible for tooltips. The tooltips now also adjust their size intelligently, so they won’t ever fall out of your browser window.
- …and more than 1000 other noteworthy changes, found below in the detailed log.
Environment upgrade notes
- PHP 5.4 and PHP 5.5 support has been dropped. Here’s why:
- PHP 5.5 hasn’t received updates for over 3 years and using it brings a significant security risk to your website.
- Using PHP 5.6 lowers our time spent on maintenance, and it increases our productivity; so, we can focus on faster, better, and more useful solutions.
- WordPress no longer supports PHP versions lower than 5.6 since WordPress 5.2. They, too, finally realize we need to move on.
- Learn more about Upgrading PHP.
- WordPress 4.6 through 4.8 support has been dropped. Here’s why:
- More than 75% of all WordPress sites are using version 4.9 or later.
- The API changes between WordPress versions are massive. We can’t support older versions reliably.
- Although we wanted to move to WordPress 5.0 or later, many users have opted out because of conflicting interests–to put it lightly. Keep your site updated, and use the Classic Editor plugin if you really can’t stand the block editor.
If, for any reason, you still wish to use PHP 5.4/5.5 and/or WordPress 4.6/4.7/4.8, The SEO Framework 3.2.4 still supports them.
Share your love!
We hope you’ll love this update as much as we do. Please consider sharing it with the world, by giving us an awesome review! We read every one of them. Thanks!
Detailed log
Let’s go the extra mile; or 1,609.347 meters.
For everyone: automatic upgrading
- Upgrading happens automatically after you update the plugin, on any page but the SEO settings page. It can’t occur during an AJAX request.
- The upgrading process can be initiated by anyone, even by your visitors.
- Upgrade requests shouldn’t occur concurrently. Only one visitor can initiate this at a time.
- The upgrade should complete in the background within 300 seconds. When the upgrader is running, you can’t access the SEO Settings page.
- When the upgrade fails, it tries to restart itself in the first following server request. This is unlikely to happen.
- If you are unable to access the SEO settings page after updating (and 300 seconds have passed), you may encounter a caching plugin issue. If you’re using a caching plugin, flush your site’s cache, and The SEO Framework should finalize the upgrade.
- The upgrade initiator is independent of WordPress’ “updating” action callback. This adds support for WordPress Multisites, and it allows you to update the plugin via FTP.
- The upgrading process can be initiated by anyone, even by your visitors.
For everyone: settings upgrades
- For all current and new users, the database version will be set to
4000
. - Current users might find their options being altered.
- The old sitemap endpoints are removed from the WordPress rewrite rules, and the rewrite rules are flushed for one last time at PHP shutdown.
- The title separator
dash
will be converted tondash
, because that was already the case. - The cronjob-pinging option is set to enabled (default); this will improve post-saving performance by offloading the sitemap pinging requests to a later time.
- The homepage’s “Meta Title Additions Location” was not in line with the global title location option. So, we rectified that. This means that “left” is now “right,” and vice versa.
- This is a downgrade-compatibility breaking change! If you must downgrade, you must reverse this option manually.
For everyone: API changes
- The plugin’s API has been overhauled almost completely.
- If you have no coding experience – but you have still implemented filters/snippets acquired from our support forums – please check out the debug logs on your server.
- If you’re getting deprecation or “doing it wrong” notices on the website or in your logs after updating, don’t be alarmed. Copy the error or notice and paste it in our support forums in a code block. Our support team (Sybre…) will forge new snippets for you, or point you to newly available options.
- Note that you should never set
WP_DEBUG
totrue
(inwp-config.php
) on a production website. Set this tofalse
; live sites shouldn’t be constantly debugged.
For developers: About the quantum options
- To put it simply, the individual robots options can now be set to
1
,0
, or-1
. - The
-1
value is new, but it PHP can see it as true-esque. But, instead, you should treat the value as an enforced0
(false-esque). - Use the updated robots-meta API (
the_seo_framework()->robots_meta()
) to get the real value.
For developers: About the sitemap
- We removed our dependency on the WordPress Rewrite API. Many developers don’t know how this works, and we took it on ourselves to fix their issues.
- Some hosting companies misconfigured the Rewrite system as well on NGINX-powered websites.
- No longer are these our issues, as we now have our own rewrite-API implemented via this plugin. It’s straightforward and shouldn’t conflict with the WordPress Rewrite API. It’s based on Automattic’s sitemap integration in Jetpack.
- Our new API automatically injects the sitemap after WordPress rewrite system has had a go, and is the only sitemap integration that’s compatible with all translation plugins.
- Now, you can even add your own sitemaps! In just 15 minutes, we wrote an example sitemap extension plugin that achieves this. The hardest part was coming up with names for the functions.
For developers: About the post meta API
- Parts of the post meta API is deprecated, in favor of a more robust solution.
- Now, when fetching a single post meta item, we get all of it, and filter out what The SEO Framework (might have) inserted.
- We now also prefill the values that aren’t set with the default options. You can filter these.
- In conclusion, it’s faster and more reliable. You can now obtain the real value, always, asserted via
the_seo_framework()->get_post_meta_item()
.
Super detailed log
> View code changes.
> View closed tickets.
If you think the economy is more important than the environment, try holding your breath while counting your money. – Guy McPherson
For everyone
- Added:
- New term settings:
- Blog name removal.
- Open Graph title and description inputs.
- Twitter title and description inputs.
- Social image input.
- 301 Redirect input.
- Canonical URL input.
- New quantum robot options:
- For all public posts, pages, and terms, you can now flip states of overlapping robot directives. Forcing an indexing or noindexing state, for example.
- New automated robot directives:
- Search engines no longer have to guess your intent for indexing, as we now deindex the following endpoints:
- Feeds, via an
X-Robots-Tag
header. - Comment pagination, via a forced
noindex
robots’ meta tag. - robots.txt, via an
X-Robots-Tag
header.- Only when outputted via PHP. Web servers don’t launch WordPress otherwise.
- Feeds, via an
- Search engines no longer have to guess your intent for indexing, as we now deindex the following endpoints:
- New ways to edit in bulk:
- Using the WordPress native bulk-editor, you can now change the following SEO settings for all public posts, pages, and terms:
- Indexing
- Link following
- Archiving
- Tip: Leave the values as
— No Change —
to keep the value unchanged. - Note: We can’t assert the expected value of
Default
, because no two pages are alike.
- Using the WordPress native bulk-editor, you can now change the following SEO settings for all public posts, pages, and terms:
- New ways to edit quickly:
- Using the WordPress native quick-editor, you can now change the following SEO settings for all public posts, pages, and terms:
- Canonical URL
- Indexing
- Link following
- Archiving
- Redirecting
- Using the WordPress native quick-editor, you can now change the following SEO settings for all public posts, pages, and terms:
- New accessibility features:
- Tooltips can now be accessed using your keyboard.
- For the SEO Bar, you can now highlight warnings with symbols, so to discern issues more quickly.
- We’re not completely satisfied on this integration, but we’ll revisit that after we get enough feedback.
- Image fields now have an image icon nearby. Hover over it (or tap it, or use keyboard navigation) to preview the image.
- The term meta inputs now have the “are you sure you want to leave this page?”-listener attached.
- New installation notifications:
- For new users, after installing The SEO Framework, users who have
update_plugins
capabilities may now see a confirmation that the plugin’s set up, and that there are installation instructions available. - For older users, after upgrading The SEO Framework’s database, users who have
update_plugins
capabilities may now see a confirmation notice that the site has been upgraded.
- For new users, after installing The SEO Framework, users who have
- New sitemap pinging features:
- Search engine pinging for the sitemap can now be offloaded to the WordPress cron-scheduler; this feature is enabled by default.
- New HTML comments:
- The estimated plugin-boot time is added to the closing HTML comment; which adds the bulk of the page-loading time of this plugin. In this update, we decreased that time, substantially–and we’re proudly showing it.
- New social sharing features:
- An option to have multiple social images to be outputted. How this affects sharing depends on the social network.
- We disabled multiple images for Twitter Cards because Twitter doesn’t handle this well: They grab the final (less favorable) image found by default, they don’t allow you to select an image, etc.
- Sites that upgraded from TSF v3.2.4 or below have this option disabled by default. New installations have this enabled.
- Fallback images are now always appended; you can no longer overwrite them.
- Social images may now be obtained from your post or page’s content.
- Alt-tags are now provided with social images, which help with accessibility when sharing your page.
- For WooCommerce, the Product Category Thumbnail is now considered for social images.
- An option to have multiple social images to be outputted. How this affects sharing depends on the social network.
- New editing experience:
- When using the Block Editor, AKA WordPress 5.0+’s Gutenberg, on post update (and for unpublished posts, also on preview and autosave):
- A new SEO Bar is inserted (when enabled).
- All description placeholders will refresh.
- The social image placeholder will refresh.
- When using the Block Editor, AKA WordPress 5.0+’s Gutenberg, on post update (and for unpublished posts, also on preview and autosave):
- New term settings:
- Improved:
- Accessibility:
- The homepage settings may now reveal more information on where this data can be altered.
- Screen-reader support has been reimplemented for the SEO Bar; it’s now completely written out and accurate.
- You can now, again, navigate to the SEO Bar with your keyboard. This was disabled previously as it messed with the browser cache due to a wrong implementation.
- When clicking the title prefix, like “Category: ” or “Private: “, the text selection now goes to the beginning, instead of the end.
- When double-clicking on the title prefix, you’ll select the first word (or piece of whitespace).
- When triple-clicking on the title prefix, you’ll select the whole input.
- When clicking the title addition, like “- My Site”, the text selection no longer just goes to the end regardless of its position, but now goes to the beginning if it’s prefixed.
- When double-clicking on the title addition, you’ll now select the last word (or first, if prefixed) (or piece of whitespace).
- When triple-clicking on the title addition, you’ll select the whole input.
- When updating the SEO settings, but when no settings have been changed, you now get a proper notification.
- The SEO Settings update notifications now also state that caches are flushed.
- HTML entities are now converted from your input to the examples and placeholders. Like in the Homepage SEO Settings’ title-additions examples, and in the Open Graph and Twitter placeholders.
- Various sentences have been updated to be more easily interpretable.
- Informational links to Google pages no longer predict your language; Google does this for you automatically based on your locations or preferences.
- AJAX failures are now handled gracefully.
- AI Generators:
- Descriptions:
- They now work better with RTL languages, like Arabic and Hebrew; however, due to ambiguity in language construction, it will read from top to bottom (like the web is built), instead of bottom to top (like books are).
- It no longer accidentally slices the last sentence off when they’re a full sentence.
- The excerpt-clause trimming is now at least twice (to infinitely) as fast, by utilizing simpler algorithms for text lengths.
- They now work better with non-Roman languages, by using updated string length guidelines.
- See the Guidelines (character) section below for details.
- This only works when your site-language is set to these, not via translation plugins.
- Translation plugins are capable of supporting these during loops; this has been supported since WordPress version 4.7 (2016) thanks to the new user-locale functionality.
- For instance, in the admin term-view loop, they could dynamically change the WordPress locale, without affecting the interface.
- And, for instance, when loading the post or term editor, they could set the locale, also without affecting the interface.
- We preemptively added support for these situations by relying on WordPress. I implore them to address this because until then, it’ll be an irregular experience.
- They now account for German’s extra capitalization width.
- Canonical URL:
- The automatic scheme determination now uses the “Site Address” scheme in “General Settings” to fall back on.
- With that, we also updated the settings’ documentation.
- The automatic scheme determination now uses the “Site Address” scheme in “General Settings” to fall back on.
- Descriptions:
- Guidelines:
- Titles/Descriptions:
- The character guidelines have been updated for these languages (annotation: Language (language) @ adjusted/Roman):
- Assamese (অসমীয়া) @ 148/160
- Austrian German (Österreichisch Deutsch) @ 158/160
- Swiss German (Schweiz Deutsch) @ 158/160
- German (Deutsch) @ 158/160
- Gujarati (ગુજરાતી) @ 148/160
- Malayalam (മലയാളം) @ 100/160
- Japanese (日本語) @ 70/160
- Korean (한국어) @ 82/160
- Talim (தமிழ்) @ 120/160
- Taiwanese Mandarin (Traditional Chinese) (繁體中文) @ 70/160
- Hong Kong (Chinese version) (香港中文版) @ 70/160
- Mandarin (Simplified Chinese) (简体中文) @ 70/160
- The pixel guidelines have been updated for these languages (annotation: Language (language) @ adjusted/Roman):
- Arabic (العربية) @ 760/910
- Moroccan Arabic (العربية المغربية) @ 760/910
- South Azerbaijani (گؤنئی آذربایجان) @ 760/910
- Iran Farsi (فارسی) @ 760/910
- Hazaragi (هزاره گی) @ 760/910
- Central Kurdish (كوردی) @ 760/910
- The pixel and character counters now parse your input as HTML, giving you a more accurate rating. For example, HTML entities are now decoded on-the-fly.
- The character guidelines have been updated for these languages (annotation: Language (language) @ adjusted/Roman):
- Titles/Descriptions:
- Internationalization:
- Sites set to the Assamese, German, Gujarati, Malayalam, Japanese, Korean, Talim, Traditional Chinese, or Simplified Chinese languages now have adjusted character guidelines.
- Sites set to the Arabic, Azerbaijani, Farsi, Hazaragi, or Kurdish languages now have adjusted pixel guidelines.
- UI strings that were hard to translate in other locales have been rewritten. Yes, this takes some time to get used to.
- Layout:
- Reordered the Homepage Settings meta box tabs to be more in line with the Post Meta Settings meta box.
- Some option headers are now better aligned to the center.
- We now thoroughly exclaim what the sitemap is and isn’t for.
- Google+ is deceased, so we added an icon indicating that, cleared the placeholder, and removed the assumed profile redirection link.
- We didn’t remove the option, because you may practically add a link to a non-Google+ profile. We’ll transform these options into an array of inputs when anything goes for Google’s Knowledge Graph.
- Performance:
- The SEO Bar now loads quicker, as redundant checks have been removed.
- Moving your mouse over a tooltip item now requires less processing by removing inefficient jQuery dependencies, reducing the restyling time by 32% (based on a single test).
- Tooltip creation also no longer uses inefficient jQuery dependencies anymore, reducing the generation time by 50% (based on a single test).
- We offloaded a large portion of the admin-sided PHP scripts to different objects, freeing up RAM and lowering plugin boot-time.
- The admin helper-scripts have been optimized to execute no unnecessary paint-jobs, lowering browser-CPU usage.
- The SEO Settings notifications no longer get dragged around your page on-load and instead are preemptively placed. This prevents painting the whole page three times.
- We now mostly use WordPress’ built-in window-resize debounce-handler, which reduces some processing required.
- We now default all URL escaping to check for HTTPS first, instead of HTTP. If you’re not on the TLS protocol already… do it! It’s free and also good for SEO.
- We split the main JavaScript and CSS files into multiple, dedicated files. Improving performance and lowering power consumption on all pages where TSF is active.
- HTTP/2: To take full advantage of this change, multiplexing support (like in HTTP/2) is advised.
- CSS: This significantly lowers class and ID lookups on every page load and DOM update, which drastically lowers processing time.
- JS: The main advantage of splitting these files is that if one script fails, the other may still continue. The performance should remain roughly the same; however, further optimizations have been implemented.
- PR: Love using WordPress on the go? Now you can use it for longer! Also, lower power consumption is great for the environment, times 100,000 sites.
- Sitemap:
- The blog page (not as homepage) now chooses a better
lastmod
value; based on whether the blog page was edited, or a new post was recently published.- Before it was only when a post was most recently published.
- The blog page (not as homepage) now chooses a better
- SEO Bar:
- Other states are now shown when “noindex” is set, regardless.
- However, now, when the post is redirected, you’ll now only see that.
- Assessments are now listed, instead of written out.
- Perfect screen-reader support has been implemented.
- When a part of the SEO Bar is red, it’ll now halt and clear assessment, and it’ll tell you what to fix first.
- Now, you may need to fix multiple things, but you’ll be guided through what needs immediate attention until it’s blue, yellow, or green.
- The SEO Bar may now be altered and extended by other plugins and themes.
- The SEO Bar is now regenerated in full when performing a quick or bulk edit.
- Changed the assessments:
- Title:
- Added absent title checks.
- Added absent branding checks.
- Added page protective state prefix checks.
- Added term prefix checks.
- Added a disclaimer to the title length calculation, as it’s not using pixels.
- Improved duplicated branding checks:
- It now always asserts–even if the branding has been disabled.
- It now supports Unicode and ignoring capitalization thereof.
- Description:
- Added page excerpt generation checks.
- Added page builder state checks.
- Added page protective state empty checks.
- Added a disclaimer to the description length calculation, as it’s not using pixels.
- Tweaked the duplicated-word checks, by bothering you less often on shorter words.
- Indexing:
- Added meta override checks.
- Added literal exclaiming when WordPress overrules the SEO settings.
- Added term multiple post type checks.
- Added term zero post count checks.
- Added for non-standard robots.txt file checks.
- Added externally-pointing canonical URL tests.
- Following:
- Added indexing conflict checks.
- Added meta override checks.
- Added literal exclaiming when WordPress overrules the SEO settings.
- Added term multiple post type checks.
- Added for non-standard robots.txt file checks.
- Archiving:
- Added indexing conflict checks.
- Added meta override checks.
- Added literal exclaiming when WordPress overrules the SEO settings.
- Added term multiple post type checks.
- Added for non-standard robots.txt file checks.
- Redirect:
- This test has been added to terms.
- Title:
- Other states are now shown when “noindex” is set, regardless.
- Spam control:
- Added more
index.php
files which prevent nasty backlinks and crawlers to index this plugin’s files whenIndexes
option isn’t disabled in Apache.- Add
Options -Indexes
to your.htaccess
file to prevent this for all plugins that do not honor this behavior.
- Add
- Added more
- Tooltips:
- Their text is no longer bolded by default, so you may now see different bolding in the tooltip.
- They now intelligently determines the position of themselves, much like a self-driving car.
- They now intelligently makes themselves wider or slimmer based on their contents and surrounding.
- When you make text wider or slimmer, it becomes taller. So, it also calculates whether it will overflow to the top or bottom of its container.
- Using Gutenberg with the Post SEO settings meta box in the sidebar, tooltips will no longer overflow.
- Accessibility:
- Changed:
- We now support WordPress v4.9 and later, instead of WordPress v4.6 and later.
- We now support PHP v5.6 and later, instead of PHP v5.4 and later.
- Backslashes (back-solidus) are no longer stripped from post and term meta. Slash away!
- This also resolves an issue where the number of slashes is halved every time you update the post.
- Note that the site settings don’t support this functionality, because WordPress implements PHP 4.x compatibility on options that strip them (this is explained as “not fixed” below).
- We switched the homepage title option name from left to right, and right to left.
- This doesn’t affect your titles, it’s only semantics.
- Schema.org logos may now be of any proportion, instead of just square, and cropping them must exceed 112px squared.
- We removed the “recommended” title separator highlighting, RSS parsers are great at rendering HTML entities, so this shouldn’t be an issue.
- We no longer automatically resize images when they’re deemed too large.
- Although this worked as intended, we highly doubt users will be uploading images over 4096x4096px, and it’s a waste of resources to test each image.
- Moreover, these resized images weren’t registered with WordPress.
- When images are found to be over 4096 pixels in width or height, they’ll be discarded.
- SEO meta generation no longer occurs when using Customizer.
- Redirects may now be set and performed on protocols other than
http
andhttps
. - Term meta:
- When a term is disabled via the post type settings, saving it won’t erase the custom SEO term meta.
- The same behavior already applied to singular post items.
- When a term is disabled via the post type settings, saving it won’t erase the custom SEO term meta.
- Redirects: When a post is redirected, it will no longer be included in the sitemap. So, you no longer have to fiddle with the “index” setting to get the expected result.
- Sitemap:
- The sitemap post limit now counts all posts, pages, and custom post types; instead of them separately.
- Note: Because we can’t guess your intent when you set the option (or left it unchanged), we aren’t updating this.
- New users will have this setting set to 3000 posts, from 1200 previously.
- The post query has changed:
- First, we find the blog and front-page ID. We add these on top of the sitemap.
- Then, we query all public hierarchical post types (pages). The sitemap query limit is used here, and we query-sort the items by published date, ascending.
- Then, we query all public non-hierarchical post types (posts), but no attachments–the sitemap query limit is used again, and we query-sort the items by last updated, descending.
- Finally, we combine the pages and posts and add them to the file.
- Note that, at most, 50000 items will be displayed, or 49998 if the homepage is a blog.
- The blog page’s priority is now
1.0
, from0.9
. Note, however, that this feature is disabled by default and deprecated by some search engines. - The page and post priorities now deduce based on item’s position from
0.9
, instead of that pages always has a priority of0.9
.
- The sitemap post limit now counts all posts, pages, and custom post types; instead of them separately.
- Removed:
- DOWNGRADE COMPATIBILITY! – Global options.
- When you upgrade to this version or later, you can’t downgrade to v3.0.6 or lower without running into issues.
- Downgrading to v3.1.x and v3.2.x is still supported.
- Upgrading from v2.7.0 and higher to this version is still supported.
- Upgrading from all the way below v2.7.0 (December 2016!) is untested and might cause issues. Double-check your settings!
- When you upgrade to this version or later, you can’t downgrade to v3.0.6 or lower without running into issues.
- DOWNGRADE COMPATIBILITY! – Post, Page, Term meta options.
- We added multi-dimensional options in the form of qubits: -1, 0, 1.
- When you upgrade to this version, robots meta-settings for posts, pages, and terms may have a new, previously unknown value entered:
-1
.- This value means “override and disable the default robots-setting”.
- For example, if you set
noindex
to all tags, but set-1
to a specific tag, the tag may be indexed.
- For example, if you set
- Because the options were simpler before,
-1
will be treated as1
. So, when you downgrade, this setting will yield the opposite effect.
- This value means “override and disable the default robots-setting”.
- DOWNGRADE COMPATIBILITY! – Homepage title options.
- The title additions locations (left and right) are now switched.
- This was necessary to flatten and simplify the title-API, so home-specific checks no longer need to be reversed.
- Webkit flexbox vendor prefixes in all CSS files. All browsers that relied on these have been updated to the latest spec since.
- Image support for breadcrumbs has been removed, search engines don’t seem to use these, and documentation for it disappeared.
- DOWNGRADE COMPATIBILITY! – Global options.
- Fixed:
- Accessibility:
- Global:
- Our input-select elements no longer overflow to the right (or left, on RTL) of your screen. Most notably, with our Focus extension‘s homonymous example selector.
- Dismissible notices can now be dismissed using keyboard navigation on all browsers.
- You can now focus the SEO Bar items. Screen readers will exclaim what’s written.
- In extent, tooltips are now displayed when focusing an element that has one.
- And, in extent to that, you can now focus on
[?]
marks that aren’t hyperlinks, and the pixel counter. - Fixed an inexplicable text rendering issue for tooltips on iOS.
- Added extra padding to the notifications, so that the dismiss-button won’t overlap the text.
- Post edit:
- When using the Block Editor, after saving the page, setting changes are registered consistently again to the “Are you sure you wish to leave with unsaved changes?” notification handler.
- When you’re editing the homepage via the post settings, the disabled “Remove the blog name?” option’s tooltip now states it’s handled elsewhere.
- Settings page:
- When pasting a webmaster code tag in the respective settings field, no change listener was invoked, and you didn’t get an “Are you sure?”-message when navigating from the settings page with unchanged settings.
- When you clear a sitemap color input field, the default color is now displayed correctly.
- Trailing, leading, and double spaces are now trimmed from the homepage title examples.
- We moved the Meta Title Additions for the Homepage Settings to the Additions tab. This way, users are less prone to fill these in the wrong order.
- Global:
- Meta tags:
- We now correctly strip HTML tags from the “Biographical Info” section for the description-generator on author archives.
- Usability:
- Settings:
- The global site-wide
noindex
option no longer setsnofollow
automatically, too. Albeit, that’s implied. - The global site-wide
nofollow
option now has an effect. - The global category and tag
noarchive
options now have an effect. - The global category and tag
noindex
options no longer setnoarchive
automatically, too. Albeit, that’s implied. - The post type robots-meta and disable-SEO settings now only apply to taxonomies and terms that have all their shared post types set, instead of just the post type of the most recent post published.
- The settings screens’ contextual information reflect this change.
- When setting merely space-characters in any Twitter Profile fields, no longer a lone
@
will be set.
- The global site-wide
- Meta:
- When you re-save a pre-escaped HTML input in the title or meta-fields, they will no longer be reparsed.
- Before:
—
->—
->—
- Now:
—
->—
->—
-> to infinity and beyond.
- Before:
- The dash
-
separator selection has been removed, because it was converted to–
via WordPress’ texturization.- All sites using this separator will be upgraded to use the
ndash
option now. - We couldn’t leave this separator in as it was obstructing a security feature. To secure the title’s output, without losing any information you put it, we relied on WordPress texturization options.
- We could extrude that from WordPress’ texturization, but that’d cause discrepancy, and, as such, it wouldn’t be sustainable.
- All sites using this separator will be upgraded to use the
- The post status is now correctly refreshed after using quick-edit.
- The primary term ID is now correctly visually preassigned for posts that have been created when this plugin wasn’t active.
- When you re-save a pre-escaped HTML input in the title or meta-fields, they will no longer be reparsed.
- Settings:
- Nitpicking:
- The sitemap’s XSL stylesheet no longer uses the latest post ID to determine the title generation; instead, it always adds your blog name to the right.
- The sitemap now can’t exceed the imposed 50,000 entry-limit; unless you use custom filters to extend the sitemap beyond that.
- The plugin is no longer booted again when a compatibility file is loaded.
- This issue couldn’t propagate thanks to “Just In Time” checks, but since we now emit warnings, it’s been discovered.
- If the homepage is a page, and it’s private or protected, the homepage Meta Title field on the SEO Settings page now reflects that.
- Our upgrader is fast. However, just in case, we increased the PHP execution-timeout to 300 seconds, instead of the standard 30~60 seconds.
- This may not yield useful on every site, depending on the PHP configuration.
- Upgrading can no longer incur race conditions, where upgrades run simultaneously.
- Redirects no longer occur when using the Customizer.
- WordPress already has protection against this by bouncing you back; but, you can now preview the page.
- The notice-dismiss button color is now the same as WordPress’ default.
- Compatibility:
- We took our hands off the WordPress Rewrite system. All plugin conflicts related to this are no longer our problem–albeit, it never was our fault.
- Now, we can implement Polylang’s broken system for the sitemap finally. As such, all sitemaps now work with Polylang.
- Keep in mind, however, that you may wish to enable the “Hide URL language information for default language” option to remove the base language requirement to output the main language’s sitemap.
- Thanks to Yoast’s broken and misrepresenting NGINX rules, we received too many support inquiries and negative responses as it’s not interchangeable; so, we went out of our way to make them compatible.
- Now, we can implement Polylang’s broken system for the sitemap finally. As such, all sitemaps now work with Polylang.
- When using Jetpack’s Publicize, their Twitter Card and Open Graph tags are now outputted only when TSF’s are disabled.
- When using TSF’s Open Graph tags, Jetpack’s Twitter Card meta tags are removed as well. As for why; see this issue comment.
- We took our hands off the WordPress Rewrite system. All plugin conflicts related to this are no longer our problem–albeit, it never was our fault.
- Accessibility:
- Not fixed:
- Note: These bugs are edge-cases that were found during “breaking sessions.” The overhead required to fix these is currently too high for further consideration.
- Titles:
- When you empty your site name in the general settings (which you should never do), title examples in the settings area may fail to process correctly.
- Some WordPress character texturizations aren’t converted in the title inputs, only conditionally in the placeholders, and always in the tags. For example,
--
should become—
(—
).- WordPress is becoming more JavaScript-powered every release, we may see compatibility forwarded in the future.
- Back-solidi (
\
) are not stripped from the autogenerated titles and descriptions.- Because WordPress applies PHP 4 compatibility on some settings by stripping back-solidi, and then not on others, this leads to inconsistent behavior we’d have to fix independently for each case.
- Takeaway: Don’t use backward solidi in WordPress, use
\
if you must instead.
- The “Remove the blog name?” option is not hidden when doing so globally.
- We highly discourage using the global option to achieve the implied behavior. We left this option visible to let users recognize there is an alternative since.
- Interface:
- When navigating away from the settings page, after changing the “category prefix” setting, the related example no longer reflects the adjusted setting.
- This bug is introduced in this version. Using EdgeHTML, when hovering (without moving) or focusing (either via keyboard navigation or via touching) an object with a tooltip, both our tooltip as the browser-native tooltip is shown.
- This is something we can’t fix. See https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6793560/.
- Bootstrap has the same issue and denied a fix for it. See https://github.com/twbs/bootstrap/issues/18692 & https://github.com/twbs/bootstrap/pull/19434.
- This will be fixed when EdgeHTML phases out in favor for Chromium (Blink). This will be sooner than later.
- Workaround: Refocus the element or move your mouse, and the browser-tooltip should be gone.
- This bug is introduced in this version. When loading in the new image-preview tooltip in the sidebar of Gutenberg for the first time, the browser needs to paint the image in the GPU memory. This takes too long (yes, anything above 15ms is too long), and causes our calculations to fail.
- For us to account for this, we need to know when the image finishes painting, and then show (or readjust) the tooltip. This is a janky experience.
- We already preload the image in your browser-cache (either disk or RAM), but we don’t paint it preemptively.
- The workaround for this issue is to load in the tooltip once, remove your pointer, and then reload it.
- The horrendously small working area in the Gutenberg sidebar is unwelcomed by many among us. We still are not confident in moving our meta box there permanently.
- For us to account for this, we need to know when the image finishes painting, and then show (or readjust) the tooltip. This is a janky experience.
- Terms:
- When all posts attached to a term have been excluded from being shown in archives, the term may be empty, and
noindex
will be set. The SEO Bar isn’t aware of this, because it doesn’t run such a query.- Making it aware may slow your admin queries down significantly. We haven’t found the time to see if this can be integrated via available queries.
- When all posts attached to a term have been excluded from being shown in archives, the term may be empty, and
- Settings:
- Back-solidi (
\
) are not parsed correctly for the SEO Settings. This is because WordPress handles our sanitization for those settings, and they process slashes before sending the data to us.- So, input this:
\\z
, and you get this:\z
. Save again, and you get this:z
. In other words, try using\
, instead.
- So, input this:
- Back-solidi (
- Images:
- When default social images are found to be too large, they’ll be discarded, and no fallbacks will be used instead.
- Your input images must either be intentionally malformed, or the images are far too large (over 4096 pixels in width or height).
- When default social images are found to be too large, they’ll be discarded, and no fallbacks will be used instead.
- Filters:
- When using custom meta title or meta description filters, they may not be processed for the meta input fields.
- Fixing this requires restructuring the custom title and description methods with flags.
- When using custom meta title or meta description filters, they may not be processed for the meta input fields.
- Block editor:
- When you edit the homepage via the block editor, and add or remove any of the homepage social descriptions via the SEO Settings page, and then hit “Update” in the block editor, the social-locks won’t be altered.
- Fixing this would require us to send out new locks.
- This is such an edge-case that would be “fun” if we made that seamless, but “practical” is another word that stops us here. If we didn’t mention it, we’d dare to bet none of our 100,000 users would’ve ever noticed in a million years.
- Moreover, WordPress is far from ready when it comes to a REST-driven admin interface. Ignoring Calypso, Gutenberg is the only first-party WP interface that is JS driven. There are still no tools available for us that would allow us to integrate this easily.
- When you edit the homepage via the block editor, and add or remove any of the homepage social descriptions via the SEO Settings page, and then hit “Update” in the block editor, the social-locks won’t be altered.
- Redirects:
- We’re not detecting whether a redirect will loop back to the current page.
- To do this accurately, we need to predict whether the endpoint leads to any of the plausible endpoints WordPress supports. This is expensive on your CPU.
- WordPress’ rewrite system also has autocompletion, among other features, that will force us to follow the redirect internally before sending it out.
- And last but not least, we can’t detect whether a query parameter is handled further by other systems embedded, like translation plugins.
- To resolve all of the above, we could send a custom “Redirect by” and “Redirecting to” headers, and test for that to prevent a loop. Unfortunately, these headers are volatile when WordPress or other plugins take over (multiple endpoints, autocompletion, etc.), nullifying this effort.
- To conclude, just make sure you don’t point the redirect URL to the page itself.
- We’re not detecting whether redirects are initiated on post-as-archive pages, like the blog page, or the WooCommerce product page.
- Redirecting such pages may cause unexpected behavior on subsequent endpoints that rely on these pages as their base points.
- This also accounts for many other pages, like those, which are based on a custom field or shortcode.
- We’re not detecting whether a redirect will loop back to the current page.
For translators
- Added:
- Many, many sentences. Sorry!
- Changed:
- For the nth time: everything.
- Notable changes:
- Fewer
%s
, more Markdown. This means that you’ll see fewer fragmented sentences, but do mind the Markdown markup! home page
is now consistentlyhomepage
.- Removed and replaced (most) instances of grammatical gender-(in)sensitive pronouns which would make it impossible to translate correctly, like
this %s
,that %s
, andthe %s
.
- Fewer
- Updated:
- Translation object; POT file.
For developers
Note: Only public changes are listed; internal functionality changes are listed as global “improvements.”
- General changes:
- Improved:
- The class autoloader now considers folder structure automatically, based on the namespace used.
- The script loader now discerns between posts and taxonomies, and can now prevent loading scripts when SEO is disabled for the post type or taxonomy.
- In the debug interface, the JSON+LD scripts are now more readable.
- The script loader now accepts and concatenates inline JS.
- Changed:
- Custom setting tabs and their content-callbacks should no longer have their output be returned, but always be printed instead.
- The helper tooltip item for primary-term selection using the classic editor may now be repositioned differently, to account for the new keyboard-navigation-supported tooltips, making the positioning more natural.
- Removed:
- PHP 5.4 and 5.5 support. The plugin now requires PHP 5.6 and higher.
- With that, we no longer require using
wp_json_encode()
,wp_parse_url()
, and other backward-compatible functionality. - You’ll also find that our API has changed. For example, we now use generators to yield images.
- With that, we no longer require using
- PHP 5.4 and 5.5 support. The plugin now requires PHP 5.6 and higher.
- Fixed:
- Registering inline scripts now correctly converts
{{$rel_color}}
.
- Registering inline scripts now correctly converts
- Improved:
- Option notes:
- Added:
- Under
THE_SEO_FRAMEWORK_SITE_OPTIONS
:seo_bar_symbols
- Values: either
1
or0
. - Default:
0
, for all sites. - Location: General Settings -> Layout -> SEO Bar Settings.
- Use: Converts SEO Bar item symbols based on their state.
- Values: either
multi_og_image
- Values: either
1
or0
. - Default:
1
for new sites.0
for upgraded sites. - Location: Social Meta Settings -> General -> Social Image Settings.
- Use: Allows TSF to output multiple OG image tags. This does NOT affect the image parser.
- Values: either
ping_use_cron
- Values: either
1
or0
. - Default:
0
, for all sites. - Location: Sitemap Settings -> Ping -> Ping Settings.
- Use: Enables pinging via cron-jobs.
- Values: either
- Under
THE_SEO_FRAMEWORK_SITE_CACHE
:settings_notice
- Values: Any simple string.
- Default:
''
(empty string). - Use: Holds the last-update action resolution state, so proper notifications can be send.
- Under
- Changed:
- Under
THE_SEO_FRAMEWORK_SITE_OPTIONS
:home_title_location
- Values: either
left
orright
, as before. - Default:
left
when RTL (Arabic, Hebrew, etc.),right
when LTR (Roman, Latin, etc.). - Location: Homepage Settings -> Additions -> Meta Title Additions Location.
- Use: Sets the location of the Home Page Title and the Additions.
- What’s changed: When upgrading, left becomes right, and vice versa. This simplifies the API.
- Values: either
- Under
- Removed:
attachment_noindex
and sanitization thereof, since 3.1 it’s changed tonoindex_post_types['attachment']
.attachment_nofollow
and sanitization thereof, since 3.1 it’s changed tonofollow_post_types['attachment']
.attachment_noarchive
and sanitization thereof, since 3.1 it’s changed tonoarchive_post_types['attachment']
.title_seperator
, since 3.1 it’s changed totitle_separator
(note the previous typo).
- Changed:
add_option()
is no longer called every admin request, only when the options aren’t registered yet.
- Added:
- Term meta notes:
- Added:
title_no_blog_name
, int, one or zero.redirect
, URL string.canonical
, URL string.og_title
, URL string.og_description
, URL string.tw_title
, URL string.tw_description
, URL string.social_image_url
, URL string.social_image_id
, int.
- Changed:
noindex
, it can now be set to-1
.nofollow
, it can now be set to-1
.noarchive
, it can now be set to-1
.
- Removed:
saved_flag
, it’s no longer necessary. If the term is saved with The SEO Framework enabled, the term meta will be auto-filled; whether something’s adjusted or not.
- Other:
- Arbitrary keys may no longer be stored. Use the new API instead.
- Added:
- Post meta notes:
- Changed:
_genesis_noindex
, it can now be set to-1
._genesis_nofollow
, it can now be set to-1
._genesis_noarchive
, it can now be set to-1
.- Throughout the plugin, the scalar input types are no longer converted to strings via
the_seo_framework()->get_custom_field()
.
- Other:
- Arbitrary keys may no longer be stored. Use the new API instead.
- Changed:
- Function notes:
- Removed:
- These are non-API functions, and were marked private:
_activation_setup_sitemap()
_deactivation_unset_sitemap()
- These are non-API functions, and were marked private:
- Removed:
- Class notes:
- Noted:
- Methods that you shouldn’t use–marked private or aren’t visible–aren’t listed here, unless specifically annotated.
- Added classes:
\The_SEO_Framework\Bridges\
family:\The_SEO_Framework\Bridges\ListEdit
, this class extends\The_SEO_framework\Bridges\ListTable
.\The_SEO_Framework\Bridges\ListTable
, holds basic caller functionality for WordPress list tables.- Abstract class. Must be extended.
- Public methods:
__construct()
, initializes the callbacks, always.
- Abstract methods:
_add_column()
_output_column_contents_for_post()
_output_column_contents_for_term()
- Note that this function must be created and return its first parameter as it’s a filter callback.
- Shared properties:
$post_type
$taxonomy
$doing_ajax
\The_SEO_Framework\Bridges\Ping
, holds callback functionality for search engine sitemap-pinging and cron-engaging thereof.- This class can’t be instantiated.
- Public static methods:
engage_pinging_cron()
ping_search_engines()
ping_google()
ping_bing()
\The_SEO_Framework\Bridges\PostSettings
- This class can’t be instantiated.
- This class is marked protected, only for internal use.
\The_SEO_Framework\Bridges\Scripts
, this file bridges The SEO Framework to the script loaders for WordPress. It registers all scripts based on the query; by default, it is only loaded on the admin screens.- Relies on
\The_SEO_Framework\Builders\Scripts
for registering and enqueuing the scripts. - Public static methods:
decode_entities()
decode_all_entities()
prepare_media_scripts()
prepare_metabox_scripts()
get_tsf_scripts()
get_tt_scripts()
get_ays_scripts()
get_list_edit_scripts()
get_seo_settings_scripts()
get_post_edit_scripts()
get_term_edit_scripts()
get_gutenberg_compat_scripts()
get_media_scripts()
get_title_scripts()
get_description_scripts()
get_social_scripts()
get_primaryterm_scripts()
get_counter_scripts()
- Relies on
\The_SEO_framework\Bridges\SeoBar
, this file bridges The SEO Framework to the SEO Bar loaders for WordPress. It prepares the list table columns and checks for post type and taxonomy compatibility.- Relies on
\The_SEO_Framework\Builders\SeoBar
package for building the SEO Bar via interpreters.- This package relies on
\The_SEO_framework\InterPreters\SeoBar
for interpreting the SEO Bar from PHP to HTML.
- This package relies on
- This is a private class, and should not be called externally.
- Relies on
\The_SEO_Framework\Bridges\SeoSettings
- This class can’t be instantiated.
- This class is marked protected, only for internal use.
\The_SEO_Framework\Bridges\Sitemap
, this file initializes the sitemap query, and it’s loaded when the sitemap functionality is enabled.- Public methods:
get_expected_sitemap_endpoint_url()
get_sitemap_endpoint_list()
output_base_sitemap()
output_stylesheet()
output_sitemap_header()
output_sitemap_urlset_open_tag()
output_sitemap_urlset_close_tag()
- Public static methods:
get_instance()
prepare()
- Public methods:
\The_SEO_Framework\Bridges\TermSettings
- This class can’t be instantiated.
- This class is marked protected, only for internal use.
\The_SEO_Framework\Builders\
family:\The_SEO_Framework\Builders\Images
, this file holds generators for images.- Example usage:
- Get one URL:
-
$url = \The_SEO_Framework\Builders\Images::get_featured_image_details()->current()['url'];
-
- Get multiple URLs, if any:
-
foreach ( \The_SEO_Framework\Builders\Images::get_featured_image_details() as $details ) { $url = $details['url']; }
-
- Get one URL:
- Public static methods, all generators:
get_attachment_image_details
get_featured_image_details
get_content_image_details
get_fallback_image_details
get_theme_header_image_details
get_site_logo_image_details
get_site_icon_image_details
- Example usage:
\The_SEO_framework\Builders\SeoBar
- Abstract class. Must be extended.
- This class can’t be instantiated, nor can any extending classes.
- Public static variables:
tests
, for all registered tests, there must be a correspondingtest_%s
function created.
- Public methods:
_run_test()
- Abstract methods: These must be created.
has_blocking_redirect()
prime_cache()
prime_query_cache()
- Shared variables: All extending classes can modify these variables, and all those classes will be affected once they are.
tsf
query
cache
(private)
\The_SEO_framework\Builders\SeoBar_Page
, this class extends\The_SEO_framework\Builders\SeoBar
.- Use
the_seo_framework()->get_generated_seo_bar()
to generate a bar.
- Use
\The_SEO_framework\Builders\SeoBar_Term
, this class extends\The_SEO_framework\Builders\SeoBar
.- Use
the_seo_framework()->get_generated_seo_bar()
to generate a bar.
- Use
\The_SEO_Framework\Builders\Sitemap
, this file builds the sitemap, and it’s only loaded on sitemap endpoints.- You can extend this class to add your own sitemap interpreters.
- Public methods:
__construct()
__destruct()
prepare_generation()
shutdown_generation()
build_sitemap()
, abstract.is_post_included_in_sitemap()
is_term_included_in_sitemap()
\The_SEO_Framework\Builders\Sitemap_Base
, extends\The_SEO_Framework\Builders\Sitemap
.- Public methods:
build_sitemap()
, abstractly defined.
- Public methods:
\The_SEO_Framework\InterPreters\
family:\The_SEO_framework\InterPreters\SeoBar
, this file interprets the SEO Bar from PHP to HTML.- This class can’t be instantiated.
- Public constants:
STATE_UNKNOWN
, bitwise 1.STATE_BAD
, bitwise 2.STATE_OKAY
, bitwise 4.STATE_GOOD
, bitwise 8.
- Public static variables:
query
, the current SEO Bar query.
- Public static methods:
generate_bar()
&collect_seo_bar_items()
register_seo_bar_item()
&edit_seo_bar_item()
- Removed classes:
\The_SEO_Framework\Compat
- Loading fewer PHP files is faster, ~0.00001s is saved.
- The two methods therein were moved to
\The_SEO_Framework\Load
:load_early_compat_files()
, protected._include_compat()
, marked private.
\The_SEO_Framework\Metaboxes
- All but one of the methods therein were moved to
\The_SEO_Framework\Bridges\SeoSettings
. - Method
nav_tab_wrapper()
was moved to\The_SEO_Framework\Admin_Pages
.
- All but one of the methods therein were moved to
\The_SEO_Framework\Inpost
- This is part of the facade object
the_seo_framework()
, so this class shouldn’t be called externally.
- This is part of the facade object
\The_SEO_Framework\Sitemap
- This file has been split over multiple files, to the new
Sitemap
class family:\The_SEO_framework\Bridges\Sitemap
\The_SEO_framework\Builders\Sitemap
, extended by:\The_SEO_framework\Builders\Sitemap_Base
- This file has been split over multiple files, to the new
\The_SEO_Framework\Doing_It_Right
- Some methods therein have been moved to the new
SeoBar
class family:\The_SEO_framework\InterPreters\SeoBar
\The_SEO_framework\Bridges\SeoBar
\The_SEO_framework\Builders\SeoBar
, extended by:\The_SEO_framework\Builders\SeoBar_Page
\The_SEO_framework\Builders\SeoBar_Term
- Some methods therein have been moved to the new
- Rmeoved interfaces:
\The_SEO_Framework\Debug_Interface
- Implementors:
\The_SEO_Framework\Load
\The_SEO_Framework\Debug
- Was redundant, added to load time. Removed.
- Implementors:
- Noted:
- Method notes:
- For object
the_seo_framework()
:- Added:
get_filtered_raw_custom_field_title()
get_filtered_raw_generated_title()
s_qubit()
, note: this method is not registered as an option filter!s_bsol_raw()
, note: this method is not registered as an option filter!make_data_attributes()
, internal use only.make_single_select_form()
get_post_types_from_taxonomy()
get_generated_seo_bar()
is_robots_meta_noindex_set_by_args()
init_term_meta()
save_term_meta()
update_single_term_meta_item()
save_post_meta()
update_single_post_meta_item()
s_term_meta()
s_post_meta()
detect_page_builder()
is_blog_page_by_id()
query_supports_seo()
is_taxonomy_supported()
get_post_meta_defaults()
get_taxonomical_canonical_url()
, note: this method was calledget_taxonomial_canonical_url()
get_taxonomical_custom_canonical_url()
get_term_meta_item()
use_taxonomical_title_branding()
is_attachment_admin()
is_wc_product_admin()
is_customize_preview()
get_safe_schema_image()
s_image_details()
s_image_details_deep()
s_field_id()
esc_attr_preserve_amp()
get_hierarchical_post_types()
get_nonhierarchical_post_types()
convert_to_url_if_path()
detect_site_url_scheme()
- Changed:
__construct()
now emits warnings when instantiated twice or more.html_output()
is now marked as private.init_admin_scripts()
removed deprecated parameter and its notice.set_url_scheme()
removed deprecated parameter and its notice.is_preview()
now checks the user capabilities, because WordPress blindly agrees with this state.can_do_sitemap_robots()
now useshas_robots_txt()
andget_robots_txt_url()
to determine validity.get_robots_txt_url()
now returns the robots.txt URL, even if one’s physically set.sanitize_field_id()
now no longer strips square brackets.robots_meta()
now has two new parameters.add_option_filter()
no longer registers its filter more than once for an option key.register_settings()
no longer usesadd_option()
when the options are already registered.inpost_seo_save()
- Renamed to
_update_post_meta()
. - Now coverts
_genesis_noindex
,_genesis_nofollow
, and_genesis_noarchive
to qubits. - Now allows updating during
WP_CRON
, this was to protect against bulk-and quick-edit; which we now handle. - Now allows updating during
WP_AJAX
, this was to protect against bulk-and quick-edit; which we now handle.
- Renamed to
_update_term_meta()
- Renamed from
update_term_meta
- noindex, nofollow, noarchive are now converted to qubits.
- Added new keys to sanitize.
- Now marked as private.
- Added more sanity protection. Superfluous: “Does the term exist? Is the user allowed to do this?”
- No longer runs when no
autodescription-meta
POST data is sent. - Now uses the current term meta to set new values.
- No longer deletes meta from abstracting plugins on save when they’re deactivated.
- Now allows updating during
WP_AJAX
, this was to protect against bulk-and quick-edit; which we now handle.
- Renamed from
get_term_meta()
- Removed deprecated filter
the_seo_framework_get_term_meta
. - Now fills in defaults if older term meta isn’t set.
- Removed deprecated filter
get_term_meta_defaults()
now returns more values.is_single_admin()
now usesis_singular_admin()
to check for the correct base; so categories and tags no longer falsely returntrue
.get_generated_single_term_title()
no longer redundantly tests the query, but now only uses the term input or queried object.is_taxonomy_disabled()
now only returns true if all post types in the taxonomy are disabled, and it usesis_post_type_supported()
instead ofis_post_type_disabled()
to do so.create_canonical_url()
andget_canonical_url()
can now fetch custom canonical URLs for terms; this is implied via trickling down methods.create_canonical_url()
now fixes input args preemptively to be in line with other getters. So you could enter an integer, although you shouldn’t.get_post_type_archive_canonical_url()
- Now only accepts strings or null as the first parameter.
- Forwarded post type object calling to WordPress’ URL function.
_save_inpost_primary_term()
now works as intended; and it no longer accidentally falls back on the other post meta handlers.get_separator_list()
no longer returns thedash
index.get_home_title_seplocation()
return value, left is now right, and vice versa.- In extent,
get_title_seplocation( true )
also yields this behavior.
- In extent,
s_twitter_name()
- Now returns empty on lone
@
entries. - Now returns empty when using only spaces and tabs.
- Now returns empty on lone
s_facebook_profile()
- No longer returns a plain Facebook URL when the entry path is sanitized to become empty.
- Now returns empty when using only spaces and tabs.
s_relative_url()
no longer trims the prepending/
.s_redirect_url()
- Removed rudimentary relative URL testing.
- Removed input transformation filters, and with that, removed redundant multisite spam protection.
- Now allows all protocols. Enjoy!
- Now no longer lets through double-absolute URLs (e.g.
https://google.com/https://google.com/path/to/file/
) when filterthe_seo_framework_allow_external_redirect
is set to false.- This isn’t a security issue,
do_redirect()
always prepended (and still does prepend) the local host for sanity.
- This isn’t a security issue,
has_robots_txt()
, now tries to loadwp-admin/includes/file.php
to prevent a fatal error.has_sitemap_xml()
, now tries to loadwp-admin/includes/file.php
to prevent a fatal error.is_term_meta_capable()
no longer incorrectly determines post type archives as capable; they aren’t considered term taxonomies, because they don’t yield taxonomies, but solely post types.is_category_admin()
removed memoization.is_page()
, now tests for hierarchical post types, which is more reliable.is_single()
now tests for nonhierarchical post types, which is more reliable.is_singular()
now no longer processes integers as input.is_singular_admin()
removed first parameter.is_tag_admin()
removed memoization.is_wc_product()
- Added admin support.
- Added a parameter for the Post ID or post to test.
delete_object_cache()
now actually does something: flushes the object cache.get_available_twitter_cards()
- Now only asserts the social titles as required.
- Now always returns an array, instead of a boolean (false) on failure.
nav_tab_wrapper()
, deprecated third parameter, silently.get_word_count()
- Now expects PCRE UTF-8 encoding support.
- Moved filter outside of this function.
- Short length now works as intended, instead of comparing as less, it compares as less or equal to.
get_social_image_uploader_form()
now adds a media preview dispenser.get_logo_uploader_form()
now adds a media preview dispenser.strip_tags_cs()
now allows emptying the indexesspace
andclear
.generate_dismissible_notice()
now adds a tabindex to the dismiss-dashicon, so keyboard naviation is possible.get_home_page_tagline()
added memoization.can_run_sitemap()
no longer memoizes the return value.
- Removed:
- Deprecated methods, these were marked deprecated since 3.1.0 (September 13, 2018):
get_meta_output_cache_key()
get_prefered_scheme()
description_from_cache()
title()
build_title()
generate_home_title()
get_the_real_archive_title()
use_archive_prefix()
untitled()
add_title_pagination()
process_title_additions()
title_from_cache()
single_term_title()
post_title_from_ID()
title_from_custom_field()
get_tax_labels()
get_supported_post_type()
get_paged_post_url()
is_checked()
is_option_checked()
generate_description()
description_from_custom_field()
generate_description_from_id()
- Public methods, these were marked private:
set_js_nonces()
get_js_nonces()
inattachment_seo_save()
inpost_seo_save()
save_custom_fields()
- Public methods, these were obstructing:
is_post_included_in_sitemap()
, usenew \The_SEO_Framework\Builders\Sitemap()->is_post_included_in_sitemap()
instead.load_assets()
, this was an internal function that only loaded a few scripts on our admin page.settings_init()
, this was an internal function that handles the update state automatically. Is now_settings_init()
.get_sitemap_xsl_stylesheet_tag()
, this is now part of\The_SEO_Framework\Builders\Sitemap::get_instance()->output_sitemap_header()
.get_sitemap_urlset_open_tag()
, we now output it directly.get_sitemap_urlset_close_tag()
, we now output it directly.
- Public methods, these were meant to only be used internally:
add_inpost_seo_box_init()
add_taxonomy_seo_box_init()
general_metabox()
title_metabox()
description_metabox()
robots_metabox()
homepage_metabox()
social_metabox()
webmaster_metabox()
sitemaps_metabox()
feed_metabox()
schema_metabox()
add_post_state()
post_state()
- Public methods, are now rendered ineffective:
post_type_supports_inpost()
enqueue_page_defaults()
add_removable_query_args()
register_image_dimension()
parse_image_args()
parse_og_image()
rewrite_rule_sitemap()
enqueue_sitemap_query_vars()
reinitialize_rewrite()
enqueue_rewrite_activate()
enqueue_rewrite_deactivate()
maybe_flush_rewrite()
flush_rewrite_rules_activation()
flush_rewrite_rules_deactivation()
maybe_output_sitemap_stylesheet()
seo_bar()
seo_bar_ajax()
get_seo_bar_ajax()
get_taxonomy_seo_bar_ajax()
get_taxonomy_seo_bar()
get_the_seo_bar_classes()
get_the_seo_bar_i18n()
- Many more public methods were removed:
- See the “class notes” above.
- Deprecated methods, these were marked deprecated since 3.1.0 (September 13, 2018):
- Deprecated:
- With alternatives, refer to the source (search for your old method) for a relayed alternative:
get_default_scripts()
,enqueue_gutenberg_compat_scripts()
enqueue_media_scripts()
enqueue_primaryterm_scripts()
get_seo_bar()
post_status()
metabox_scripts()
Scripts()
doing_ajax()
initialize_term_meta()
ping_searchengines()
ping_google()
ping_bing()
get_sitemap_xsl_url()
get_sitemap_xml_url()
output_sitemap_xsl_stylesheet()
post_type_supports_custom_seo()
taxonomy_supports_custom_seo()
get_taxonomial_canonical_url()
get_custom_field()
get_schema_image()
get_social_image()
get_social_image_url_from_home_meta()
get_social_image_url_from_post_meta()
get_social_image_url_from_seo_settings()
get_social_image_url_from_post_thumbnail()
get_social_image_url_from_attachment()
get_image_from_woocommerce_gallery()
get_header_image()
get_site_icon()
get_site_logo()
sanitize_field_id()
- Without alternatives, go make your own:
check_wp_locale()
maybe_lowercase_noun()
fetch_the_term()
current_theme_supports_title_tag()
can_use_logo()
- With alternatives, refer to the source (search for your old method) for a relayed alternative:
- Added:
- For object
- Property notes:
- For object
the_seo_framework()
:- Removed:
profile_settings
page_defaults
- Removed:
- For object
- Constant notes:
- Namespace
\The_SEO_Framework\
:ROBOTS_IGNORE_PROTECTION
, used for thethe_seo_framework()->robots_meta()
method family, ignores post’s password/privacy settings.ROBOTS_IGNORE_SETTINGS
, used for thethe_seo_framework()->robots_meta()
method family, ignores current post/term’s SEO settings.
- Namespace
- Action notes:
- Added:
the_seo_framework_sitemap_header
, runs in the sitemap HTTP header.the_seo_framework_setting_notices
, runs below the settings header.
- Added:
- Filter notes:
- Added:
the_seo_framework_query_supports_seo
, boolean.the_seo_framework_sitemap_path_prefix
, string.the_seo_framework_sitemap_endpoint_list
, array.the_seo_framework_sitemap_supported_post_types
, array.the_seo_framework_sitemap_hpt_query_args
, array. hpt = Hierarchical post types.the_seo_framework_sitemap_nhpt_query_args
, array. nhpt = Non-hierarchical post types.the_seo_framework_sitemap_exclude_term_ids
, array. Not used internally.
- Improved:
the_seo_framework_robots_meta_array
, now has two new parameters,$args
and$ignore
.the_seo_framework_sitemap_post_limit
, now has a new parameter,$hierarchical
.the_seo_framework_sitemap_additional_urls
, now has a new parameter:$args
.the_seo_framework_sitemap_extend
, now has a new parameter:$args
.the_seo_framework_term_meta_defaults
, now has a new parameter:$term_id
.
- Changed:
the_seo_framework_scripts
:- Now contains all registered scripts.
- Now has a new parameter:
$bridge
.
the_seo_framework_term_meta_defaults
now holds more values in the first parameter.the_seo_framework_separator_list
no longer yields thedash
index.the_seo_framework_{$type}_settings_tabs
, the callback indexes have been changed for these filters, as the class structure changed:the_seo_framework_inpost_settings_tabs
the_seo_framework_general_settings_tabs
the_seo_framework_homepage_settings_tabs
the_seo_framework_robots_settings_tabs
the_seo_framework_schema_settings_tabs
the_seo_framework_sitemaps_settings_tabs
the_seo_framework_social_settings_tabs
the_seo_framework_title_settings_tabs
the_seo_framework_inpost_settings_tabs
, the second parameter is deprecated, and henceforth yieldsnull
.the_seo_framework_bother_me_desc_length
- Now moved to the SEO Bar callers, and now only runs once per session.
- The entered and default length is now counted as a minimum, instead of a minimum minus one.
the_seo_framework_fetched_description_excerpt
- Deprecated second parameter.
- Added third paramter:
$args
.
- Fixed:
the_seo_framework_title_from_generation
, now works for:- the homepage title in the admin screens.
- the homepage title example in the admin screens.
- the latest post title example in the admin screens.
- singular breadcrumb generation.
- blog page’s automated description.
the_seo_framework_title_from_custom_field
, now works for:- the homepage title example in the admin screens.
- all breadcrumb generation.
- term title placeholders.
the_seo_framework_use_title_branding
now works for the homepage title in the admin screens.the_seo_framework_title_separator
now works in the admin screens.
- Deprecated:
the_seo_framework_save_custom_fields
, usethe_seo_framework_save_post_meta
instead. Same syntax, same effect, better name.the_seo_framework_current_term_meta
, useget_term_metadata
instead. See WordPress functionget_metadata()
for details.- We know, the
get_term_metadata
filter is inconvenient, but so is maintaining and explaining the filter we deprecated. - This filter was largely only in place because we didn’t have bulk-editing systems in place. But now we do.
- Moreover, there are many more hooks through which you can influence this, like when updating the term meta. Those hooks are vastly more reliable, because the term meta may be obtained elsewhere, without using our API.
- We know, the
- Removed:
the_seo_framework_js_l10n
, overhauled.the_seo_framework_get_term_meta
, this was deprecated since 3.1.0.- Use
the_seo_framework_term_meta_defaults
instead.
- Use
the_seo_framework_show_seo_column
, this is unreliable. Use the options API instead.the_seo_framework_custom_post_type_support
, this is unreliable. Use the options API instead orthe_seo_framework_supported_post_type
.the_seo_framework_sitemap_pages_count
, use the options API orthe_seo_framework_sitemap_post_limit
instead.the_seo_framework_sitemap_posts_count
, use the options API orthe_seo_framework_sitemap_post_limit
instead.the_seo_framework_sitemap_custom_posts_count
, use the options API orthe_seo_framework_sitemap_post_limit
instead.the_seo_framework_sitemap_exclude_cpt
, usethe_seo_framework_sitemap_supported_post_types
instead.the_seo_framework_sitemap_pages_query_args
.the_seo_framework_sitemap_posts_query_args
.the_seo_framework_sitemap_cpt_query_args
.the_seo_framework_admin_page_defaults
, we trust our defaults are right.the_seo_framework_metabox_id
, this never worked reliably.the_seo_framework_allow_states
, use the action handler instead.the_seo_framework_ogimage_output
, use the new image generator, instead.the_seo_framework_twitterimage_output
, use the new image generator, instead.the_seo_framework_sanitize_redirect_args
, this was obstructing sanity.
- Added:
- Rewrite notes:
- Removed:
- All WordPress rewrite manipulation.
- Changed:
- The following query variables have changed, in the format:
from -> to
the_seo_framework_sitemap=xml -> tsf-sitemap=base
the_seo_framework_sitemap=xsl -> tsf-sitemap=xsl-stylesheet
- Note: Since these endpoints are interpreted outside of the WordPress rewrite system, these endpoints may no longer work based on your permalink settings.
- The following query variables have changed, in the format:
- Removed:
- Compatibility notes:
- Unloaded:
- The
mbstring
compatibility file (/inc/compat/php-mbstring.php
) is no longer loaded automatically because we no longer need the compatibility functionmb_strpos()
.
- The
- Unloaded:
- Browser notes:
- We’ve now officially abandoned support for Internet Explorer. Goodbye, old, annoying friend.
- To enhance support for other deprecated browsers along the way, we now use a body class we control:
tsf-js
andtsf-no-js
. Now, this body class changes fromtsf-no-js
totsf-js
only when the browser supports ES2015.
- To enhance support for other deprecated browsers along the way, we now use a body class we control:
- With our most excellent users moving to HTTP/2 and beyond, we’re going to take full advantage of multiplexing by sending out more scripting files.
- More files is good; because, we can selectively send out the files; so there’s less code to parse in your browser on most requests.
- This also alleviates some strain on your server, as we don’t have to blindly fill states and values for all requests every time.
- And, most importantly, maintaining the code will be much easier; so, we can deploy faster with fewer errors.
- Last but not least, WordPress is moving from plain HTML and PHP to JS. We need to get ourselves well prepared for this shift.
- We cleaned up the RTL-specific scripts, and embedded an RTL body-class check instead in the LTR scripts. This is slightly slower, but decreases the heft of the plugin package significantly.
- Affected files, both
.css
and.js
(and their*.min.*
equivalents):ays
– meaning “Are you sure?”, these files handle on-navigation alerts, so to prevent loss of data.- Namespaces:
window.tsfAys
andwindow.tsfAysL10n
- Script ID:
tsf-ays
- Namespaces:
c
, these files handle the character and pixel counters.- Namespaces:
window.tsfC
andwindow.tsfCL10n
. - Script ID:
tsf-c
- Fun fact: The proposed name was
counter.js
, but uBlock blocks this script name by default. - Note that this file is loaded conditionally, based on the user’s settings.
- Namespaces:
post
, these files handle post SEO settings pages, mostly.- Namespaces:
window.tsfPost
andwindow.tsfPostL10n
. - Script ID:
tsf-post
- Namespaces:
term
, these files handle term SEO settings pages, mostly.- Namespaces:
window.tsfTerm
andwindow.tsfTermL10n
. - Script ID:
tsf-term
- Namespaces:
tsf
, these main files are now trimmed down to the most basic of forms per dependency requirements.- JS:
- Before: 27.7KB minified, 2782 SLOC
- After: 2.4KB minified, 488 SLOC
- CSS:
- Before: 16.0KB minified, 1006 SLOC
- After: 7.1KB minfified, 480 SLOC
- JS:
settings
, these files handle the SEO Settings page, mostly.- Namespaces:
window.tsfSettings
andwindow.tsfSettingsL10n
. - Script ID:
tsf-settings
- Namespaces:
le
– meaning “List Edit”, these files handle list edit page actions.- Namespaces:
window.tsfLe
andwindow.tsfLeL10n
- Script ID:
tsf-le
- Namespaces:
- Affected files, only
.js
(and their*.min.*
equivalents):description
, these files handle meta description inputs.- Namespaces:
window.tsfDescription
andwindow.tsfDescriptionL10n
. - Script ID:
tsf-description
- Namespaces:
title
, these files handle meta title inputs.- Namespaces:
window.tsfTitle
andwindow.tsfTitleL10n
. - Script ID:
tsf-title
- Namespaces:
social
, these files handle social meta inputs.- Namespaces:
window.tsfSocial
andwindow.tsfSocialL10n
. - Script ID:
tsf-social
- Namespaces:
- JS notes:
- Announcement: There’s finally a reliable JS API for The SEO Framework. Enjoy!
- Note: We added a plethora of events, and some now have added parameters. These are only documented in the code.
- Added:
- Object
tsfAys
:- Properties:
l10n
- Methods:
reset
getChangedState
registerChange
deregisterChange
registerChangeListener
registerResetListener
registerUnloadListener
reloadDefaultListeners
- Related localization & attribution object:
tsfAysL10n
.
- Properties:
- Object
tsfDescription
:- Properties:
l10n
- Methods:
setInputElement
getState
updateState
triggerCounter
triggerInput
enqueueTriggerInput
triggerUnregisteredInput
enqueueUnregisteredInputTrigger
- Related localization & attribution object:
tsfDescriptionL10n
.
- Properties:
- Object
tsfLe
:- Properties:
l10n
- Related localization & attribution object:
tsfLeL10n
.
- Properties:
- Object
tsfPost
:- Properties:
l10n
- Related localization & attribution object:
tsfPostL10n
.
- Properties:
- Object
tsfSettings
:- Properties:
l10n
- Related localization & attribution object:
tsfSettingsL10n
- Properties:
- Object
tsfSocial
:- Properties:
l10n
- Methods:
initTitleInputs
initDescriptionInputs
getState
updateState
- Related localization & attribution object:
tsfSettingsL10n
- Properties:
- Object
tsfTerm
:- Properties:
l10n
- Related localization & attribution object:
tsfTermL10n
.
- Properties:
- Object
tsfTitle
:- Properties:
l10n
untitledTitle
- Methods:
setInputElement
getState
updateState
triggerCounter
triggerInput
enqueueTriggerInput
triggerUnregisteredInput
enqueueUnregisteredInputTrigger
- Related localization & attribution object:
tsfTitleL10n
.
- Properties:
- Object
tsfC
, including:- Properties:
counterType
counterClasses
l10n
- Methods:
updatePixelCounter
updateCharacterCounter
triggerCounterUpdate
resetCounterListener
- Related localization & attribution object:
tsfCL10n
.
- Properties:
- Global:
- After tsfAys registers or resets its listeners, this jQuery event is triggered:
$( document.body ).trigger( 'tsf-registered-ays-listeners' );
- After the sidebar is closed in Gutenberg:
$( document.body ).trigger( 'tsf-gutenberg-sidebar-closed' );
- After the sidebar is opened in Gutenberg:
$( document.body ).trigger( 'tsf-gutenberg-sidebar-opened' );
- After a list item is updated in a WordPress list overview table:
document.dispatchEvent( new Event( 'tsfLeUpdated' ) );
- After tsfAys registers or resets its listeners, this jQuery event is triggered:
- Object
- Changed:
- Object
tsf
, overhauled:- Properties:
l10n
- Methods:
stripTags
decodeEntities
escapeString
ampHTMLtoText
sDoubleSpace
getStringLength
selectByValue
convertJSONResponse
setAjaxLoader
unsetAjaxLoader
resetAjaxLoader
- Related localization & attribution object:
tsfL10n
.
- Properties:
- Object
tsfGBC
now resides ingbc.{.min}.js
, instead oftsf-gbc{.min}.js
- Object
tsfTT
:- We now add the default tooltip boundary (
.tsf-tooltip-boundary
) to#wpwrap
, instead of#wpcontent
.
- We now add the default tooltip boundary (
- Object
- Removed:
tsf.[...]
:tsf.counterType
, usetsfC.counterType
instead.tsf.counterClasses
, usetsfC.counterClasses
instead.tsf._initCounters
, was marked private.tsf._initWebmastersInput
, was marked private.tsf._initCanonicalInput
, was marked private.tsf.flexTabToggle
.tsf.addNoFocusClass
.tsf.setTabsOnload
.tsf.tabToggle
.tsf._doFlexResizeListener
, was marked private.tsf.taglineToggleOnload
.tsf.confirmedReset
.tsf.setColorOnload
.tsf.onLoadUnregisterChange
tsf.attachUnsavedChangesListener
, usetsfAys.registerListeners
instead.tsf.registerChange
, usetsfAys.registerChange
instead.
tsfL10n.[...]
:tsfL10n.states.isHome
.tsfL10n.states.hasInput
.tsfL10n.states.counterType
.tsfL10n.states.useTagline
.tsfL10n.states.taglineLocked
.tsfL10n.states.useTermPrefix
.tsfL10n.states.isSettingsPage
.tsfL10n.states.isPostEdit
.tsfL10n.states.isTermEdit
.tsfL10n.states.postType
.tsfL10n.states.isPrivate
.tsfL10n.states.isPasswordProtected
.tsfL10n.states.homeLocks
.tsfL10n.states.stripTitleTags
.tsfL10n.states.isGutenbergPage
.tsfL10n.i18n.saveAlert
, usetsfAysL10n.i18n.saveAlert
instead.tsfL10n.i18n.confirmReset
, usetsfSettingsL10n.i18n.confirmReset
instead.tsfL10n.i18n.privateTitle
.tsfL10n.i18n.protectedTitle
.tsfL10n.i18n.pixelsUsed
, usetsfCL10n.i18n.pixelsUsed
instead.tsfL10n.i18n.inputGuidelines
, usetsfCL10n.i18n.guidelines
instead.tsfL10n.params
, all all indexes therein.
- We’ve now officially abandoned support for Internet Explorer. Goodbye, old, annoying friend.
- Other:
- Updated
composer.json
, now includes developer scripts. - Updated
phpcs.xml
, now uses the newer, non-WordPress.com VIP-exclusive standards. - Cleaned up code, removed redundant calls, finished my homework, took a hike, fed the birds.
- Updated