Search Engine Optimisation module for Altis.
Take control of your search engine and social media listings through meta data and integrations with plugins such as AMP and Facebook Instant Articles.
SEO module for Altis
Home Page: https://www.altis-dxp.com/resources/docs/seo/
Search Engine Optimisation module for Altis.
Take control of your search engine and social media listings through meta data and integrations with plugins such as AMP and Facebook Instant Articles.
We want to include Yoast SEO as our de facto SEO solution. By default, we will include WordPress SEO (free) but we will need to support premium versions as well.
Acceptance Criteria:
humanmade/wp-seo
from composer.json
yoast/wordpress-seo
to composer.json
The AMP plugin has a couple of primary settings, notably
We could potentially hide the AMP admin pages however the validated URLs and error pages are potentially useful so this isn't quite as straightforward as hiding everything. The validations page could be made into the primary one.
Analytics could be added via config as it's just an array of JSON objects.
While upgrading to Altis v9, running altis migrate
in a local environment with a recently refreshed database from an Altis project with approximately 19k published posts caused 361,017 post objects to be processed while "Migrating legacy SEO settings" and took almost 2 hours to run to completion. The query within the migrate_wpseo_to_yoast
function is returning every single post object on the site, including revisions and oembed caches.
The site in question has been using Yoast Premium for years, and never relied on the legacy Altis SEO module. If I query the database directly, I see no meta keys matching our target $old
values in the meta_mapping
object. e.g.,
select count(*) from wp_postmeta where meta_key="_meta_title";
+----------+
| count(*) |
+----------+
| 0 |
+----------+
The reason things are taking so long to run is the meta_query
we execute within that migrate_wpseo_to_yoast()
function:
'meta_query' => [
'relation' => 'OR',
[
'meta_key' => '_meta_title',
'meta_compare' => 'EXISTS',
],
[
'meta_key' => '_meta_description',
'meta_compare' => 'EXISTS',
],
[
'meta_key' => '_meta_keywords',
'meta_compare' => 'EXISTS',
],
],
Note that we're using meta_key
and meta_compare
in the nested arrays. If I am reading the wp meta query docs properly, those keys are only accepted in the meta_query
array itself, and nested arrays should be using key
and compare
, e.g.
[
'key' => '_meta_keywords',
'compare' => 'EXISTS',
],
Because of this difference between the expected arguments and what we are providing, I believe the current query is stripping all meta query comparisons and returning every post on every site. This will result in a LOT of unnecessary processing while upgrading to Altis 9, because the migration routine then goes through the entire site and tries to find each of those three keys on every single post object (none of which have them), to no actual benefit.
You can validate that the meta_key
is being ignored and returning all posts by trying this query locally in wp shell
:
// Handle post meta.
$posts_query_args = [
'post_type' => 'post',
'post_status' => 'any',
'posts_per_page' => 0,
'fields' => 'ids',
'suppress_filters' => true,
'meta_query' => [
'relation' => 'OR',
[
'meta_key' => '2014 SUBARU IMPREZA WRX Hatch, Premium trim, 32k miles',
'meta_compare' => 'EXISTS',
],
],
];
$posts = new WP_Query( $posts_query_args );
// Will log however many posts you have.
WP_CLI::log( $posts->found_posts );
Switching these meta parameters to key
and compare
may not fix the issue, because I made those changes locally and started running that query 30 minutes ago and it still hasn't completed. A triple-barrel EXISTS meta_compare
on a medium-to-large site appears to be paralyzingly slow. (In my testing, only querying for a single EXISTS
meta query at a time was any kind of fast.) However, I suspect that if it does complete, it will correctly detect that no posts in the site actually have these keys present.
This is a pretty big issue with the Altis 9 upgrade path.
Acceptance criteria:
Maintaining these dependencies is unnecessary overhead right now and difficult to manage as they are not on packagist.
These can be moved to the pre-approved plugins on the site.
Now that we have the core WP sitemaps we can build on that value by providing custom sitemaps for specific use cases. Depending on the complexity and variation in requirements the outcome of this might be one of:
The docs for how to construct one are here:
https://support.google.com/webmasters/answer/178636?hl=en
We can either parse post content and add image details inline eg:
<url>
<loc>http://example.com/sample.html</loc>
<image:image>
<image:loc>http://example.com/image.jpg</image:loc>
</image:image>
<image:image>
<image:loc>http://example.com/photo.jpg</image:loc>
</image:image>
</url>
Or it can be a pure image sitemap.
Other metadata can be specified such as caption etc which can be read from gutenberg blocks, the HTML structure or the attachment post data.
The Yoast test helper plugin smooths the process of working with Yoast SEO and testing things out locally so will be useful to document. Thanks for the tip @stuartshields
We assume many of our clients are already aware of what Yoast is and don't need to be reminded about upgrading. For those that don't, that can be addressed by AMs/PMs/Sales. For a better user experience and a more native-looking UI, we want to remove the upsell banners.
Acceptance Criteria:
Migrate any existing WP SEO data into Yoast SEO. This includes both global settings and per-post meta.
Acceptance Criteria:
wp altis migrate
(e.g. wp altis migrate seo
)
Dev Notes
how does WP SEO store the custom title, description and keywords for a post? How can those be migrated?
Both WP SEO and Yoast SEO store that information in post meta, and each have comparable meta keys for that data. Yoast uses a formula for the SEO title (e.g. %%title%% %%page%% %%sep%% %%sitename%%
). We could either default to this or migrate existing data in the WP SEO _meta_title
field to _yoast_wpseo_title
, which is the Yoast equivalent and only added if the title was manually changed from the default pattern.
Probably what makes the most sense is to migrate the meta data over if it exists -- WP SEO also has default patterns which would get migrated over as part of the migration process, so the most important information here is the meta descriptions and SEO keywords, which would be unique for each post.
By default all URLs are treated the same, eg. same frequency for updates, priority etc.
This is pretty suboptimal so I think we can make a companion plugin to provide some better defaults out of the box including easier support for news, video and image sitemaps.
SImpleXMLElement
generationThere seems to be cases where the SEO warning still shows on non-production environments.
If you enter a redirect from with a trailing slash, it will never match
Yoast's instructions inform people to use the following commands:
composer config -g http-basic.my.yoast.com token ...
composer config repositories.my-yoast composer https://my.yoast.com/packages/
composer require yoast/wordpress-seo-premium
To create the auth.json file though, you need to run the first command without -g
; additionally, these commands should be run to generate the files, and not just added to the build script.
From #173
We need to document how redirects handle URL parameters (ie passthrough, can't use them in the source (iirc)).
Additionally, it would be good to document how this interacts with analytics; specifically, that redirects are not tracked in analytics (as they're performed server-side), and tracking parameters/data like UTM parameters will be passed through to the destination.
Yoast premium when installed via composer adds the free version of Yoast SEO as a dependency and attempts to load it from the same directory / location.
We need to determine how best to load Yoast SEO Premium alongside our modifications for the installation location and loading for the Yoast SEO free version.
Google has indexed more than 2,500 pages of content on *.altis.cloud sub domains
Other search engines need to be checked. Yep,
bing - https://www.bing.com/search?q=site%3Aaltis.cloud
duckduckgo - https://duckduckgo.com/?q=site%3Aaltis.cloud
Acceptance criteria:
require-login
plugin to allow robots.txt
here.basic-auth
to indicate it only works for PHP files, and that custom nginx rules can be used for anything else.FBIA has a whole page of settings on its wizard that could be defined via the JSON config. We need to look at all the possible forms this data can take, document those here and then implement the necessary filters.
For Altis v8 and moving forward, we will be using Yoast SEO as our SEO solution by default. There are many parts to this integration including UI changes to remove/hide upsell banners and re-theme to Altis branding, migrating settings and data from WP SEO to Yoast SEO and removing/replacing Altis SEO features with their equivalents that are built into Yoast.
Action Items
There are additional admin UI elements that should be removed to simplify the admin.
Acceptance Criteria:
Dev notes
example code:
add_action( 'admin_init', function() {
$options = get_option( 'wpseo' );
// Disable the admin bar menu.
$options['enable_admin_bar_menu'] = false;
if ( in_array( Altis\get_environment_type(), [ 'local', 'development' ], true ) ) {
// Don't display the HUGE SEO issue on local or dev environments.
$options['ignore_search_engines_discouraged_notice'] = true;
}
update_option( 'wpseo', $options );
// Remove Helpscout.
add_filter( 'wpseo_helpscout_show_beacon', '__return_false' );
// Remove the Premium submenu.
$menu = 'wpseo_dashboard';
$submenu = 'wpseo_licenses';
remove_submenu_page( $menu, $submenu );
}, 11 );
Steps to reproduce:
This warning isn't useful for development and staging environments, and hence should not be shown.
We may want to remove this warning entirely, as private sites will likely also receive it.
Acceptance criteria:
When building the index for attachments (and quite possibly in other areas too), Yoast will filter the attachment image sizes (by default full
, large
, medium_large
) by filesize (see https://github.com/Yoast/wordpress-seo/blob/trunk/inc/class-wpseo-image-utils.php#L340) to exclude anything that is over 2MB.
In conjunction with S3 uploads, this makes these functions very slow, as each image has to be pulled from S3 in full to check it's file size.
Rather than using the image sizes at all, in Altis it seems we should just be passing a tachyon image somehow and not going any of those checks etc.
Tracking issue for humanmade/hm-redirects#46
By default, Yoast SEO adds a dashboard widget (which includes custom CSS and JS). We don't need this in the Altis Dashboard so we can remove.
Acceptance Criteria:
Dev Notes
example code:
add_action( 'admin_init', function() {
// Remove the Dashboard widget.
remove_meta_box( 'wpseo-dashboard-overview', 'dashboard', 'normal' );
wp_dequeue_script( 'dashboard-widget' );
wp_dequeue_style( 'wp-dashboard' );
}
Update the Yoast CSS to match Altis branding. This may be easiest by overriding their :root
variables.
:root {
--yoast-border-default: 1px solid rgba(0,0,0,0.2);
--yoast-color-default: #404040;
--yoast-color-default-darker: #303030;
--yoast-color-primary: #a4286a;
--yoast-color-secondary: #f7f7f7;
--yoast-color-white: #fff;
--yoast-color-green: #6ea029;
--yoast-color-primary-darker: #7b1e50;
--yoast-color-primary-lighter: #f5d6e6;
--yoast-color-secondary-darker: #d9d9d9;
--yoast-color-button-upsell: #fec228;
--yoast-color-button-upsell-hover: #f2ae01;
--yoast-color-dark: #303030;
--yoast-color-sale: #fec228;
--yoast-color-sale-darker: #feb601;
--yoast-color-border: rgba(0,0,0,0.2);
--yoast-color-label: #303030;
--yoast-color-label-help: #707070;
--yoast-color-active: #6ea029;
--yoast-color-inactive: #dc3232;
--yoast-color-inactive-text: #707070;
--yoast-color-inactive-grey: #9e9e9e;
--yoast-color-inactive-grey-light: #f1f1f1;
--yoast-color-active-light: #b6cf94;
--yoast-transition-default: all 150ms ease-out;
--yoast-color-link: #006dac;
--yoast-color-border--default: rgba(0,0,0,0.2);
--yoast-color-focus: 0 0 0 2px #007fff,0 0 0 5px #bfdfff;
Acceptance Criteria:
Dev Notes
In https://github.com/humanmade/altis-seo/blob/master/inc/opengraph/class-author-presenter.php we add the og:article:author
tag, however from what I can see, this is not an opengraph tag. Looking at https://stackoverflow.com/questions/29748013/what-is-the-correct-implementation-of-the-open-graph-article-type, this should be just article:author
. Also, check the same when using this tool: https://webcode.tools/generators/open-graph/article
Before diving into integrating Yoast SEO with Altis, we'd like to deep dive into some considerations about the plugin as to:
The outcome of this spike will determine the next steps for this feature.
Timebox: 2 days
More info here https://support.google.com/webmasters/answer/9008080?hl=en
I think the recommended options are the ones that don't rely on PHP running or any other aspect of the system other than the webserver which leaves:
The file name is unique each time so not really something that can be accounted for in config, easier just to let the webserver do it's thing and document where to put it.
This option we could possibly support as part of a build step by provisioning Route53 updates but I have a feeling that'd require the domain to be transferred to and managed by us.
It seems in some cases when upgrading the Yoast SEO version some database migrations are not happening. Need to explore why this can occur in our setup and resolve it.
The humanmade/meta-tags
plugin can be replaced by Yoast entirely. The only thing that the Meta Tags plugin supports that is not supported out of the box in the free version of Yoast is og:article:author
and og:article:section
. To maintain backwards compatibility, these two tags could be added/ported over manually in our integration code. On the other hand, Yoast adds a lot more data including the ability to have unique meta tags for different social networks (twitter vs facebook).
Screenshots
humanmade/meta-tags
yoast/wordpress-seo
Acceptance Criteria:
humanmade/meta-tags
from composer.json
og:article:author
and og:article:section
tags to appropriate post headersWhen the new site is created, we index ES, but we don't index Yoast. The same goes for the migration
command I think. We should at least index yoast
when people are upgrading to an Altis version with Yoast I think?
Reported here: humanmade/meta-tags#4
In addition to setting appropriate image sizes for each platform using tachyon we should filter the default thumbnail size passed down through all contexts to something more reasonable than the full original image size.
To do this use the following filter from the meta-tags
plugin:
https://github.com/humanmade/meta-tags/blob/master/inc/namespace.php#L255
So for each type you would use the filters:
hm.metatags.context.default
hm.metatags.context.opengraph
hm.metatags.context.twitter
Then check for the existence of $meta['image]
and do the following:
TACHYON_URL
constant)
add_query_arg()
to set the resize
(crop) or fit
(no crop) parameter to that listed abovetachyon_url()
and pass the resize
or fit
parameter in the 2nd parameter of that functionAcceptance criteria:
og:image
contains a tachyon URL set to 1200x627 with no croppingtwitter:image
contains a tachyon URL set to 1200x600 with croppingHM\MetaTags\get_meta_for_context()
with no arguments returns an array with a key image
that is a tachyon URL with constraining dimensions of 1200x1200 with no croppingTo test the above upload a large featured image to a post and check the meta tags output in the <head>
on the post page.
Currently the HM Redirects plugin doesn't support URL's with parameters. So when setting up a redirect, the user can only set old-url
to redirect to new-url
.
So when the complete url https://dev.altis.dev/old-url/?utm_content=search
contains a parameter it won't redirect accordingly and it will cause a 404 error.
Ensure that when a url contains a parameter, that the parameters are preserved in the redirect.
EG: https://dev.altis.dev/old-url/?utm_content=search
redirects to https://dev.altis.dev/new-url/?utm_content=search
Current Issue humanmade/hm-redirects#33
Pull request humanmade/hm-redirects#55
Per https://www.altis-dxp.com/resources/docs/getting-started/configuration/ the directory we use for config is .config
.
The path on this line needs correcting https://github.com/humanmade/altis-seo/blob/master/inc/namespace.php#L94
Acceptance criteria:
robots.txt
in the .config
directory causes the contents of that file to be loaded in the browser at https://<site url>/robots.txt
I'm not 100% sure where the best place to raise this issue is. Trying to install altis without a "minimum-stability": "RC"
specified, I get errors when composer tries to install altis/seo:
➜ platform-site git:(upgrade-altis-to-1.0.0) ✗ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Removal request for altis/seo == 1.0.0.0-RC3
- Conclusion: remove humanmade/facebook-instant-articles-wp 4.2.1+hm
- Removal request for altis/altis == 1.0.0.0-RC3
- Installation request for altis/altis ^1.0 -> satisfiable by altis/altis[1.0.0, 1.0.0-rc3].
- altis/altis 1.0.0 requires altis/seo ^1.0.0 -> satisfiable by altis/seo[1.0.0-rc3, 1.0.0, 1.0.1].
- altis/seo 1.0.1 requires humanmade/facebook-instant-articles-wp 4.2.1+hm -> satisfiable by humanmade/facebook-instant-articles-wp[4.2.1+hm].
- altis/seo 1.0.0 requires humanmade/facebook-instant-articles-wp 4.2.1+hm -> satisfiable by humanmade/facebook-instant-articles-wp[4.2.1+hm].
- Conclusion: don't install humanmade/facebook-instant-articles-wp 4.2.1+hm|keep humanmade/facebook-instant-articles-wp 4.2.1+hm
I think this may be a result of the version number "4.2.1+hm" in https://github.com/humanmade/facebook-instant-articles-wp not being considered a stable release. Do you have any ideas how to change this so that we can install Altis 1.0.0 final without the RC stability flag?
If a custom or other built in colour scheme is used in the admin then some CSS colour variables used in our Yoast SEO colour scheme overrides will be missing. We should avoid loading this CSS if the admin colour scheme is not the default Altis one.
If a Yoast license key exists, users can use Yoast SEO redirects instead of our own. We should document this.
Acceptance Criteria:
This ticket addresses the issues raised by the documentation linting
composer dev-tools lintdocs all -l packages/seo
File Issues:
None
Markdown issues:
Linting: 6 file(s)
Summary: 181 error(s)
Style issues:
11 errors, 0 warnings and 0 suggestions in 6 files.
Yoast SEO isn't being completely translated as expected.
While the Yoast SEO plugin isn't 100% translated in Japanese, we should still be seeing these fields translated. Looking up some of the strings in the Locale translation for the plugin, they have been translated already. https://translate.wordpress.org/locale/ja/default/wp-plugins/wordpress-seo/
Current screenshots:
Would expect to see more translations in place:
Acceptance criteria:
Currently Yoast sitemaps does a pretty gnarly query for author sitemaps. This is because the sitemap also has to exclude anyone with the wpseo_noindex_author == on
user-meta; what's more it's also ordering by another meta key value _yoast_wpseo_profile_updated
.
On large sites this query can take more than 160 seconds.
Yoast SEO >= 17.14 isn't compatible with Altis v12, due to WordPress version requirements. Yoast 20.4 was backported to v12 by mistake. We need to revert this change.
Old PR: https://github.com/humanmade/altis-seo/pull/328/files
Yoast authors sitemap generation queries authors, optionally with published posts, so with Authorship activated, the sitemaps do not generate the desired outcome.
We need to detect for activation of both features, and replace the author sitemaps provider with an extended version of the class that accounts for guest authors as well.
XML Sitemaps are provided by Yoast SEO, which overrides our sitemaps. Removing our XML sitemap code works as expected, however the robots.txt
file still links to the old XML sitemap. It needs to link to the sitemap at sitemap_index.xml
Acceptance Criteria
load.php
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.