Documentation

M SEO Editor

M SEO Editor gives a WordPress site the search and social output it needs and nothing more: meta titles and descriptions, Open Graph and Twitter Cards, an XML sitemap, and a single Schema.org graph per page, with WooCommerce products handled properly. It works from the moment it is activated, so the settings page is for refining the defaults rather than switching features on. One thing to know before anything else: the sitemap selection and the WooCommerce brand source are frozen at activation, so the order in which you install your plugins matters. This manual covers version 1.0.0 and is written for an administrator who has just installed it.

Written for version 1.1.2. WordPress 6.5+ PHP 7.4+

Installing and activating

The plugin needs WordPress 6.5 or newer and PHP 7.4 or newer. It has no build step, no license key and no account.

  1. Install WooCommerce and any plugin that registers its own content types first. Read the warning below before you activate M SEO Editor.
  2. Download the ZIP, or copy the m-seo-editor folder into /wp-content/plugins/.
  3. In wp-admin go to Plugins, then Add New, then Upload, pick the ZIP and install it.
  4. Activate the plugin on the Plugins screen.
  5. In the admin menu click M SEO. The Plugins screen also gains a Settings link that goes straight there.
Careful

Activation writes the list of content types and taxonomies to include in the sitemap into the database once, and never updates it again. Anything registered later, WooCommerce products above all, is missing from that list until you tick it by hand on the Sitemap tab.

What is live the moment you activate it

Activation writes the default settings into the mse_settings option, records the sitemap state in the mse_rewrite_state option, registers the sitemap routes and flushes the rewrite rules once, so /sitemap.xml answers straight away. An existing mse_settings option is never overwritten, so deactivating and reactivating keeps your configuration. Everything below is already producing output before you open the settings page.

  • Titles from the built-in templates: %%title%% %%sep%% %%sitename%% for content, %%sitename%% %%sep%% %%tagline%% for a front page that lists the latest posts.
  • Meta descriptions taken from the manual excerpt, or generated from the content and trimmed to roughly 160 characters.
  • A canonical tag chosen per request context, replacing the one WordPress prints itself.
  • Open Graph and Twitter Card tags (og_enabled is 1), card type summary_large_image.
  • One JSON-LD graph per page: WebSite, Organization, WebPage, BreadcrumbList and, on posts, Article.
  • The XML sitemap (sitemap_enabled is 1), covering the public post types and taxonomies that existed at the moment of activation: every public type except attachments, plus categories and tags. Featured images are included. The core wp-sitemap.xml is switched off, and a Sitemap: line is added to the robots.txt WordPress generates.
  • With WooCommerce active: product structured data and product Open Graph price tags, both on. Neither of the two depends on when WooCommerce was installed.
  • Title separator: the en dash. Knowledge graph type: an organisation, named after the site title.

What stays empty until you fill it in

These are the shipped blanks. None of them breaks anything while empty, but the first four are worth setting on day one.

  • Homepage title and homepage meta description.
  • Organisation or person name, and the logo (kg_name, kg_logo_id).
  • Default social image (default_og_image_id).
  • X (Twitter) site username and the social profile URL list.
  • Title template and the noindex checkbox for every content type.
  • The sitemap exclusion list (sitemap_exclude_ids).

Where the plugin lives in wp-admin

The plugin adds one top-level menu item, M SEO, with a magnifier icon near the bottom of the admin menu. Its page is headed M SEO Editor and lives at admin.php?page=m-seo-editor. Access requires the manage_options capability, which in practice means an administrator. A user without it never reaches the page: WordPress hides the menu entry and answers a direct visit with its own message, "Sorry, you are not allowed to access this page." The plugin repeats the check inside the page as a second line of defence, so its own wording is not what anyone sees. The page has the tabs General, Social and Sitemap, plus WooCommerce while WooCommerce is active. Each tab has its own Save Changes button, and saving one tab never resets the values of another. On the edit screen of any post, page, product or custom post type the plugin adds a box headed SEO followed by the plugin name, placed high in the main column below the editor. It renders identically in the block editor, the classic editor and on WooCommerce product screens.

General tab

Three sections: Titles & descriptions, Content types, and Knowledge graph. The homepage fields apply only when the front page shows the latest posts. If the front page is a static page, its title and description come from that page's own SEO box and the two homepage fields are ignored.

  • Title separator: eight choices (hyphen, en dash, em dash, middle dot, bullet, vertical bar, right angle quote, tilde). Default: the en dash. An unrecognised value is replaced by the en dash.
  • Homepage title: default empty, which produces %%sitename%% %%sep%% %%tagline%%.
  • Homepage meta description: default empty, which falls back to the site tagline.
  • Content types: one row per public post type (attachments are deliberately excluded), each with a title template (default empty, meaning %%title%% %%sep%% %%sitename%%) and a checkbox "Hide from search results (noindex)", default off.
  • Template variables: %%title%%, %%sitename%%, %%tagline%%, %%sep%%, %%excerpt%%, %%category%%, plus %%price%% and %%sku%% when WooCommerce is active. An unknown variable written in lowercase letters and underscores resolves to nothing. Anything else between the %% markers, a capital letter or a digit for instance, is printed into the title exactly as typed, so %%Title%% and %%price2%% end up visible in search results. Separators left orphaned by an empty variable are collapsed, and stray ones are trimmed from the start and end of the title.
  • This site represents: "An organisation" (default) or "A person".
  • Organisation or person name: default empty, falls back to the site title.
  • Logo: default none. Used as the publisher image in structured data; square, at least 112 by 112 px.

Social tab

Open Graph and Twitter Card output, and the profile list that feeds sameAs in the structured data. The image used for a share is resolved in three steps: the post's own social image, then its featured image, then the default social image set here. If none of the three exists, the image tags are omitted and the Twitter card type is switched from the large image to a plain summary automatically.

  • Social meta tags: "Output Open Graph and Twitter Card tags", default on. Turned off, the plugin prints no og: and no twitter: tags at all, and social networks fall back to guessing.
  • Default social image: default none. Recommended 1200 by 630 px.
  • Card type: "Summary with large image" (default) or "Summary".
  • Site username: default empty. Stored without the @, one to fifteen letters, digits or underscores. An invalid entry is refused, the previous value is kept and a notice explains why. The handle is also published as https://x.com/username in the sameAs list.
  • Profile URLs: default empty, one URL per line. A line WordPress can repair is repaired rather than rejected: type facebook.com/mypage and it is stored, and published in sameAs, as http://facebook.com/mypage on insecure http. Only a line that cannot be salvaged at all is dropped, and only those are counted in the notice. Type the full https:// address yourself and check the field after saving.

Sitemap tab

While the sitemap is on, the tab shows a link to the live index at the top. The index is at /sitemap.xml, child sitemaps at /sitemap-{type}.xml, page two onwards at /sitemap-{type}-2.xml, and the browser-readable stylesheet at /sitemap.xsl. On a site still using plain permalinks the same documents are served at /?mse_sitemap=index, and robots.txt points there. Sitemaps are sent with the headers X-Robots-Tag: noindex and Cache-Control: public, max-age=3600.

  • Sitemap: "Generate an XML sitemap", default on. It replaces the built-in WordPress sitemap; when it is off, the WordPress default returns.
  • Include content types: the boxes ticked at activation, which were every public post type except attachments as they existed at that moment. This is a stored list, not a live one.
  • Include taxonomies: the boxes ticked at activation, which were categories and tags, plus product categories only if WooCommerce was already active then. Also a stored list.
  • Images: "Include featured and product gallery images", default on.
  • Exclude content: comma-separated post or page IDs, default empty.
  • Each sitemap page holds up to 1000 URLs. Paging is counted from published posts before noindex and exclusions are applied, so the last page of a large type can be short or even empty. That is deliberate and still valid XML.
  • Left out automatically: anything not published, password-protected posts, content marked noindex, whole content types marked noindex, excluded IDs, WooCommerce products whose catalogue visibility is Hidden, and terms with no posts. No author or user sitemap is generated at all.
  • Taxonomy entries carry no lastmod date. Only post type entries do.

WooCommerce tab

This tab exists only while WooCommerce is active. The Product node covers simple and variable products: name, description, image, sku, gtin (from the WooCommerce global unique id field, 9.2 and newer), brand, and an Offer, or an AggregateOffer with lowPrice, highPrice and offerCount for variable products. priceValidUntil is added only on a simple product that is on sale with an end date; the AggregateOffer of a variable product never carries it. aggregateRating is added only when reviews are enabled site-wide and the product has at least one review. The Shop page's own SEO box governs the product archive.

  • Product structured data: "Replace WooCommerce structured data with the richer M SEO version", default on. It unhooks WooCommerce's own Product, WebSite and BreadcrumbList generators so a page never carries two Product entities. The structured data in WooCommerce order emails is left alone.
  • Product Open Graph: adds product:price:amount, product:price:currency and product:availability for Facebook catalogues and Pinterest Rich Pins. Default on.
  • Brand source: the value stored at activation, which is "Brands (WooCommerce)" only if the product_brand taxonomy already existed then, and "None" otherwise. The dropdown lists Brands and every global product attribute, but the stored value never updates itself. Install WooCommerce after this plugin and the setting stays "None", so no brand reaches the Product schema until you pick one and save.

The SEO box on a post, page or product

The box has three tabs. Search engine shows a Google-style snippet preview above an SEO title field (up to 200 characters) and a Meta description field (up to 400 characters). Both placeholders show what would be used if you leave the field empty, and both are live: the gauge under each field reports the character count and the actual pixel width, warning past 580 px and marking the excess past 620 px for the title, while for the description the limits are 920 px and 990 px. Social holds the share-card preview, Social title, Social description, Social image and og:type. Advanced holds Canonical URL, noindex and nofollow. Clearing a field deletes the stored value rather than saving an empty one. Saving requires edit rights on the post, and that check is all there is: the nine meta keys are not exposed to the REST API, and a WP-CLI write with wp post meta goes straight to the database without passing it.

Careful

The Automatic option under og:type names a value the box guesses as if the post were an ordinary singular page. It reads Automatic (article) for posts and pages and Automatic (product) for products, and it is right there. On a static front page, on the posts page and on the WooCommerce Shop page the live output is website while the box still says article. The output is correct; only the label is not.

First run, in order

Nothing here is compulsory, but this is the shortest path from a fresh activation to a correctly configured site. Leave every noindex checkbox alone at this stage.

  1. Open M SEO, General. Pick the separator you want in browser tabs and search results.
  2. If your front page lists the latest posts, write the homepage title and meta description. If it is a static page, skip both fields and edit that page's SEO box instead.
  3. Under Content types, set a title template only where the default %%title%% %%sep%% %%sitename%% does not fit. Whatever you write, keep %%title%% in it.
  4. Under Knowledge graph, choose organisation or person, enter the name and select a square logo. Save.
  5. Go to Social. Leave the tags switched on, upload a 1200 by 630 default social image, confirm the card type, add the X username without the @, and paste one full https:// profile URL per line. Save, then read the field back to check nothing was rewritten to http.
  6. Go to Sitemap. Tick every content type and taxonomy that belongs in search, especially anything installed after this plugin. Untick what does not belong there. Save.
  7. Follow the link at the top of the Sitemap tab and check the index renders and lists what you expect.
  8. If WooCommerce is active, open the WooCommerce tab, leave both options on and pick the brand source that matches your catalogue, even if it looks already chosen. Save.
  9. Open one post and one page, look at the snippet preview, and adjust the title and description where the automatic version reads badly.
  10. Submit /sitemap.xml in Google Search Console and Bing Webmaster Tools.

The shape of the risk

Be clear about what can go wrong. M SEO Editor has no login, firewall, redirect or mail features: it cannot lock you out of wp-admin and it does not touch email delivery. What it can do is remove your site or part of it from search results, quietly leave content out of the sitemap, and permanently delete every SEO field you have ever typed. It can also make one ordinary page answer 404 to a visitor who follows a crafted link, which has its own section below. Every setting can be put back by hand, but nothing puts it back for you, and two of them erase a stored choice without your touching it. Only deleting the plugin destroys data.

Dangerous: noindex on a single post

The same directive is available per post, in the Advanced tab of the SEO box. It is the right tool for a thank-you page, and the wrong tool everywhere else. A noindexed post is removed from the sitemap, is served without a canonical tag, and gets no structured data at all. On a WooCommerce product that last point bites twice: because the plugin has already unhooked WooCommerce's own Product markup, a noindexed product page ends up with no product structured data from either plugin, and quietly loses its rich results. Any canonical URL you typed on that post is also ignored while noindex is on.

  1. List every post currently carrying the flag with the first command below.
  2. Untick the box in the SEO box, Advanced tab, and update the post. Alternatively delete the meta row directly with the second command, replacing 123 with the post ID.
  3. Reload the front-end URL and confirm the canonical tag and the JSON-LD script are back.
  4. Wait for the next crawl, or request indexing in Search Console.
wp post list --post_type=any --meta_key=_mse_noindex --meta_value=1 --fields=ID,post_title
wp post meta delete 123 _mse_noindex

Dangerous: the canonical URL override

The Canonical URL field in the Advanced tab replaces the page's own address with whatever you type. Pointing it at another URL tells every search engine that this page is a duplicate and should not rank; done by accident, or copied into several posts from a template, it removes those pages from results while they still return 200 and look perfectly healthy to a visitor. Nothing on screen flags the mistake. Worse, what you type is put through the WordPress URL cleaner, which repairs rather than rejects: a value with no scheme, example.com or a fat-fingered exmaple.com, is stored as http://exmaple.com and printed as a live canonical pointing off site. The field is not left empty and that state is not safe. Only a string that cannot be salvaged at all, javascript: for instance, is dropped.

  1. List every post that carries a stored canonical with the first command below, and read the actual value of a suspect one with the second.
  2. Open the affected post, go to the SEO box, Advanced tab, and clear the Canonical URL field completely. The placeholder shows the correct default permalink.
  3. Update the post, then run the second command again. It must return nothing. If the row is still there, delete it with the third command.
  4. View the page source and confirm the canonical link now points at the page itself.
  5. Repeat for every post that received the same wrong value, then request indexing for the most important of them.
wp post list --post_type=any --meta_key=_mse_canonical --fields=ID,post_title
wp post meta get 123 _mse_canonical
wp post meta delete 123 _mse_canonical
Careful

A canonical pointing somewhere else is the quietest way to lose rankings with this plugin. The page keeps working, the traffic does not. Because a scheme-less typo is silently completed to http://, always read the stored value back rather than trusting the screen.

Dangerous: noindex or a canonical on the posts page or the Shop page

Two ordinary-looking pages govern a whole archive. The page assigned as the Posts page under Settings, Reading governs the blog archive, and the WooCommerce Shop page governs the product archive: the plugin resolves each of those archives back to its governing page and reads the SEO box saved on it. Tick noindex there and the entire archive is served with a noindex directive, loses its canonical tag and loses its structured data, the same blast radius as hiding the whole content type from the General tab. Type an address into Canonical URL there and the entire archive is re-canonicalised to it. Nothing on either edit screen says the page is special, and the audit commands in the previous sections list it among ordinary content, so it has to be checked by name.

  1. Find the two page IDs with the first two commands below. An empty page_for_posts means the front page lists the posts itself and there is no separate posts page.
  2. Open each page in the editor, go to the SEO box, Advanced tab, and confirm noindex is unticked and Canonical URL is empty unless you set it deliberately. Update the page.
  3. Or read and clear the two meta values from the command line, replacing 123 with the page ID.
  4. Load the blog archive and /shop/ and view the source: the robots meta tag must carry no noindex, the canonical link must point at the archive itself, and the JSON-LD script must be back.
wp option get page_for_posts
wp option get woocommerce_shop_page_id
wp post meta get 123 _mse_noindex
wp post meta get 123 _mse_canonical
wp post meta delete 123 _mse_noindex
wp post meta delete 123 _mse_canonical
Careful

One checkbox on the Posts page or the Shop page deindexes an entire archive, and the setting that normally does that lives somewhere else entirely. When a whole blog or a whole shop archive disappears from search and the General tab looks clean, these two pages are the next place to look.

Dangerous: noindex and canonical are not administrator-only

The SEO box appears on every managed post type for anyone who can edit that post, and its save handler asks for exactly one thing: edit rights on the post. That means an Editor can noindex any page on the site or point its canonical somewhere else, and an Author or Contributor can do the same to their own content. Nobody needs manage_options and nobody has to visit the settings page. The three previous sections describe damage an administrator never has to cause personally, so audit for it rather than assuming it did not happen.

  1. Run both commands below periodically, or after handing editing rights to someone new.
  2. Anything unexpected in the first list is a page currently hidden from search. Anything in the second list has a stored canonical override; read it with wp post meta get before deciding.
  3. Fix what is wrong exactly as described in the two previous sections: untick the box, or clear the field, or delete the meta row.
  4. There is no per-role switch for this. If it must not happen, keep the roles that can edit published content small.
wp post list --post_type=any --meta_key=_mse_noindex --meta_value=1 --fields=ID,post_title,post_author
wp post list --post_type=any --meta_key=_mse_canonical --fields=ID,post_title,post_author

Dangerous: install order freezes the sitemap selection

Activation writes the list of content types and taxonomies to include in the sitemap into mse_settings once and never revisits it. Settings are read by merging the stored option over the defaults, and a merge only fills in keys that are missing, so the stored lists always win. Install WooCommerce, a custom post type plugin or a theme that registers a post type after M SEO Editor, and that type is simply not in the list. Nothing on screen says so: the sitemap looks healthy, the index renders, and a whole catalogue is missing from it. The same freeze applies to Brand source on the WooCommerce tab, which stays None and leaves the brand out of every Product schema. Recovery is one save on each tab; the cost of not knowing is months of uncrawled products.

  1. After installing anything that adds a content type or a taxonomy, open M SEO, Sitemap.
  2. Tick the new content types under Include content types and the new taxonomies under Include taxonomies. Save.
  3. Open the WooCommerce tab, pick Brand source again even if it looks already chosen, and save. A stored None does not change by itself.
  4. Follow the link at the top of the Sitemap tab and confirm the new child sitemap is listed in the index.
  5. To see what is actually stored rather than what the checkboxes suggest, read the option with the command below and look at sitemap_post_types, sitemap_taxonomies and wc_brand_source.
wp option get mse_settings --format=json
Careful

A shop that activated M SEO Editor before installing WooCommerce has no products in its sitemap at all and no brand in its Product schema, and nothing anywhere reports it. Check the Sitemap and WooCommerce tabs after every plugin installation.

Dangerous: saving the Sitemap tab while another plugin is off

When the Sitemap tab is saved, the submitted selection is intersected with the content types and taxonomies that exist at that moment. A type whose plugin is deactivated does not exist, so it is not drawn as a checkbox and is stripped out of the stored list. Reactivating the other plugin does not bring it back: the entry is gone from the option and the box comes back unticked. This bites during ordinary plugin-conflict debugging, where deactivating things one at a time is the whole method. It is silent, it survives the reactivation, and it removes an entire content type from the sitemap.

  1. Do not save the Sitemap tab while any plugin is temporarily deactivated. If you must, note which types are missing from the list first.
  2. After reactivating the other plugin, go back to M SEO, Sitemap, re-tick the content types and taxonomies that returned, and save.
  3. Follow the link at the top of the tab and confirm the child sitemap for that type is listed again.
  4. If you are not sure what was lost, compare the stored list with the types you actually have.
wp option get mse_settings --format=json
wp post-type list --public=1 --field=name

Dangerous: switching the sitemap off or emptying it

Two settings on the Sitemap tab can silently empty what you submitted to the search engines. Unticking "Generate an XML sitemap" makes /sitemap.xml start returning 404, drops the Sitemap: line from robots.txt and hands the job back to the WordPress default at /wp-sitemap.xml, which no longer matches the URL you registered in Search Console. Separately, unticking every box under "Include content types" is accepted without complaint and strips every post URL out of the sitemap. The index does not look empty afterwards, because the taxonomy sitemaps are listed from their own separate setting: with categories and tags still ticked, /sitemap-category.xml and /sitemap-post_tag.xml keep appearing while your posts, pages and products are gone. Untick the taxonomies too and only then is the index genuinely empty. Neither destroys data, and both are undone by re-ticking the boxes and saving.

  1. Open M SEO, Sitemap, and tick "Generate an XML sitemap" again.
  2. Tick the content types and taxonomies that belong in search. Save.
  3. Follow the link at the top of the tab and confirm the index lists your child sitemaps.
  4. Open /robots.txt and confirm the Sitemap: line is back. If it is not, read the next section before assuming the plugin is broken.
Careful

A sitemap that renders but lists nothing you care about is worse than one that 404s, because monitoring sees a healthy document. After any change on this tab, open the index and count what is in it.

When the Sitemap line never appears in robots.txt

The plugin adds the Sitemap: line to the robots.txt that WordPress generates on the fly. Two things stop it, and neither is a plugin fault. First, a real robots.txt file sitting in the web root: WordPress never generates anything in that case, so the line can only be added to the file by hand. Second, Settings, Reading, "Discourage search engines from indexing this site": while that box is ticked the line is withheld, and WordPress itself adds a site-wide noindex to every page. That checkbox is the single fastest way to remove a WordPress site from search, it has nothing to do with this plugin, and it is the first thing to check when a site vanishes from Google after a launch. A reader following the previous section's verification step will otherwise wait for a line that is never coming.

  1. Open Settings, Reading, and untick "Discourage search engines from indexing this site". Save.
  2. Open Settings, Permalinks and press Save once, which regenerates the rewrite rules.
  3. Open /robots.txt in a browser. The Sitemap: line must be there.
  4. If it is not, check the web root over FTP or the file manager for a physical robots.txt. If one exists, add the Sitemap: line to it by hand; WordPress cannot.
  5. View the source of any public page and confirm there is no noindex left in the robots meta tag.
Careful

"Discourage search engines from indexing this site" is normal on a staging site and fatal on a live one. It is set outside this plugin, so nothing in M SEO reports it, and its effect looks exactly like a plugin failure.

When the canonical tag disappears on its own

On every front-end request the plugin removes the canonical tag WordPress prints and puts its own in place. That substitution is unconditional, but the replacement is not always produced. There is no canonical on a noindexed page, which is deliberate. There is also none on a request the plugin cannot classify, on a term whose archive link cannot be resolved, and on anything a custom mse_canonical filter empties. What the page loses differs by case. A request the plugin cannot classify gets no JSON-LD script at all, not a shortened one; the other two leave the structured data shrunk to the WebSite and publisher nodes. Only on a singular view does the missing tag cost you a canonical that stock WordPress would have printed, because core prints one on singular content and nowhere else, so on an archive there is nothing to lose against core. Such requests are rare, but they are worth recognising instead of hunting for a theme bug.

  1. View the page source. If the canonical link is missing, first check whether the page is noindexed, at post level or at content type level. If it is, that is the explanation and the fix is in the earlier sections.
  2. If it is not noindexed, look for a custom mse_canonical or mse_context filter in the theme or a companion plugin.
  3. As a stopgap on a single important page, type the correct address into the Canonical URL field of that post's SEO box.
  4. On a term archive, confirm the taxonomy is registered with a working archive link. A term whose link cannot be built gets no canonical.

The mse_sitemap parameter on ordinary URLs

The sitemap is reached through a public query parameter, which is what makes it work on sites with plain permalinks. The side effect is that the parameter works on every front-end URL, not only on /sitemap.xml. Appending ?mse_sitemap=index to any page address returns the sitemap index with HTTP 200 at that address. Appending ?mse_sitemap= followed by any value the plugin does not recognise turns that page into a 404 for whoever opened the link, and that happens on a perfectly healthy site with the sitemap switched on. With the sitemap switched off, or while another SEO plugin has taken over, every value does it, index included. The 200 responses carry X-Robots-Tag: noindex, so search engines are not going to index the duplicates; the 404 carries no such header, and nothing is stored or changed either way. There is no setting to turn this off and no recovery to perform. It is here so that a support ticket about "a page that 404s only for one visitor" is not diagnosed as an attack.

A title template without %%title%%

The title template field on the General tab accepts any text at all and is used exactly as written. A template such as "Buy at %%sitename%%" contains no page-specific variable, so every single page of that content type is served the identical title tag. Google treats a site full of identical titles as duplicate content and the whole type loses visibility. Nothing warns you, and the snippet preview on a post looks correct because it renders that same identical title. The rule is simple: any template you write for a content type must contain %%title%%, or a variable that differs per item such as %%sku%%.

  1. Open M SEO, General, Content types, and read the template of every type where you wrote one.
  2. If a template has no %%title%% and no other per-item variable, either add %%title%% to it or clear the field completely.
  3. A cleared field falls back to %%title%% %%sep%% %%sitename%%, which is always safe.
  4. Save, then open two different items of that type on the front end and confirm the title tags differ.

Dangerous: deleting the plugin erases every SEO field

Deactivating the plugin removes nothing. Deleting it runs uninstall.php, which deletes the options mse_settings and mse_rewrite_state and then deletes the nine post meta keys _mse_title, _mse_description, _mse_canonical, _mse_noindex, _mse_nofollow, _mse_og_title, _mse_og_description, _mse_og_image_id and _mse_og_type from every post on the site. On a multisite installation it loops over every site in the network and does the same to each. This happens whether you press Delete on the Plugins screen or run wp plugin delete from the command line: the CLI is not a file removal, it runs the same uninstall routine. Every hand-written SEO title and description you have ever entered is gone in one step, with no export and no undo. There is no recovery path inside WordPress: the only way back is a database restore.

  1. Before deleting anything, take a database dump with the command below and keep it somewhere off the server. This applies to the command line exactly as much as to the Plugins screen.
  2. If you only want the plugin to stop working, deactivate it instead of deleting it. Deactivation keeps every setting and every field.
  3. If you are switching to another SEO plugin, install and configure the new one first, migrate the fields it can import, then delete M SEO Editor last.
  4. If the deletion has already happened, restore wp_options and wp_postmeta from the most recent backup. Nothing else recovers those rows.
wp db export mse-seo-backup.sql
Careful

Delete is irreversible and network-wide, from the Plugins screen and from wp plugin delete alike. It wipes the plugin's post meta from every post of every site in a multisite network, not just the one you are looking at.

When another SEO plugin is active

If Yoast SEO, Rank Math, All in One SEO, SEOPress or The SEO Framework is active, M SEO Editor stands down completely: no meta tags, no structured data, no sitemap, and the sitemap routes are not claimed, so /sitemap.xml returns 404 rather than the homepage. A warning appears in wp-admin for administrators, reading "M SEO Editor is paused." The settings page and the SEO box stay fully usable and nothing is deleted, so your data waits for you. Deactivate the other plugin and everything resumes on the next admin page load, including a single automatic rewrite flush that hands /sitemap.xml back. If you genuinely want both, a filter forces output, at the price of duplicate tags on every page.

add_filter( 'mse_seo_conflict', '__return_empty_string' );
Careful

Forcing output while another SEO plugin runs puts two titles, two canonicals and two schema graphs on every page. Search engines treat that as a broken site. Use it only to test, never as a permanent state.

Troubleshooting

The plugin wraps its head output in HTML comments that name the version, so viewing the page source tells you immediately whether it is running at all. If the sitemap returns 404 on a site that used to serve it, the rewrite rules are usually stale: save the permalinks once under Settings, Permalinks, or run the command below.

  • No M SEO tags in the page source: another SEO plugin is active and the plugin has stood down. Check wp-admin for the paused notice.
  • A whole content type is missing from the sitemap: it was registered after M SEO Editor was activated, or it was stripped when the Sitemap tab was saved while its plugin was off. Tick it on the Sitemap tab and save.
  • No brand in the Product schema: Brand source is still None because WooCommerce arrived after the plugin. Pick it again on the WooCommerce tab and save.
  • The homepage title and description are ignored: the front page is a static page. Those two fields apply only when the front page lists the latest posts. Edit the page's own SEO box instead.
  • /sitemap.xml returns 404: flush the rewrite rules; check for a physical sitemap.xml file in the web root or a server rewrite rule intercepting the URL before WordPress; confirm the sitemap is switched on; on plain permalinks use /?mse_sitemap=index. A site move or a domain change needs one manual permalink save.
  • No Sitemap: line in robots.txt: a physical robots.txt file exists in the web root, or Settings, Reading, "Discourage search engines from indexing this site" is ticked.
  • A page is missing from the sitemap: it is not published, it is password-protected, it or its whole content type is marked noindex, its ID is in the exclusion list, or, for a product, its catalogue visibility is Hidden.
  • The last page of a sitemap is short or has no entries: expected. Paging is calculated before noindexed and excluded content is filtered out.
  • Every page of one content type has the same title: its title template contains no %%title%%.
  • A variable such as %%Title%% shows up in search results: only lowercase names are recognised. Rewrite it in lowercase.
  • The Twitter card shows a small image: no image could be resolved, so the card type was changed to summary. Set a featured image or a default social image.
  • The theme's own title still wins: the plugin works through the WordPress title API, so a theme that prints its own hardcoded title tag bypasses it.
  • A saved value reverted: the X username was rejected as invalid, or profile URL lines that could not be salvaged were dropped. The reason is in the notice at the top of the settings page. A line that was silently repaired to http produces no notice.
  • A change is not visible on the front end: sitemaps are sent with a one hour cache header, and a page cache or CDN may hold the old head output.
wp rewrite flush

Privacy and data

Nothing leaves the site. The plugin makes no outbound HTTP requests of any kind, sets no cookies, registers no cron events, creates no database tables, sends no email and does not ping search engines. There is no account, no license key and no telemetry. Everything it stores lives in the tables WordPress already has: one option, mse_settings, holding the whole configuration; one option, mse_rewrite_state, holding the word active or standdown so the sitemap routes can be handed over cleanly; and nine post meta keys, all prefixed _mse_, written only on posts where a field was filled in, since empty fields are deleted rather than stored. Choosing a logo or a social image stores the media library ID only, never a copy. No personal data of visitors is read, stored or transmitted at any point, and no author or user sitemap is generated.

Uninstalling

Deactivating and deleting are two very different operations, and the difference is worth stating plainly one more time. Deactivation flushes the rewrite rules and stops the output: the meta tags, the structured data and the sitemap disappear, the WordPress core sitemap at /wp-sitemap.xml returns, the Sitemap: line leaves robots.txt, and WooCommerce resumes printing its own structured data. Every setting and every field you typed survives untouched and comes back the moment you activate the plugin again, including the frozen sitemap selection. Deletion additionally runs the uninstall routine described above and removes both options and all nine meta keys from every post, on every site of a multisite network. Nothing else is left behind either way: your posts, pages, products, excerpts, featured images and media library are never touched, and there are no tables, cron events, transients or files outside the plugin folder to clean up. The rewrite rules regenerate by themselves on the next flush, so no sitemap URL is left hanging.

Filters for developers

Every value the plugin outputs can be changed from a theme or a small companion plugin, with no edits to the plugin itself. The most useful ones: mse_settings filters the whole configuration at read time, which is how you give WPML or Polylang per-language values, and also how you can override the frozen sitemap lists in code; mse_title, mse_description and mse_canonical adjust the final values per request; mse_og_tags, mse_twitter_tags, mse_og_type and mse_og_image cover the social set; mse_robots_flags decides noindex and nofollow; mse_template_vars registers your own %%variables%%; mse_schema_graph, mse_schema_product, mse_schema_article_types, mse_schema_search_action and mse_breadcrumb_trail shape the structured data before it is printed; mse_sitemap_post_types, mse_sitemap_taxonomies, mse_sitemap_entry, mse_sitemap_term_entry, mse_sitemap_index, mse_sitemap_query_args and mse_sitemap_max_urls shape the sitemap, and returning an empty entry drops a URL; mse_post_types, mse_metabox_post_types and mse_register_meta_args decide where the SEO box appears; mse_context exposes the resolved request context that every other decision keys off; mse_seo_conflict controls the stand-down; mse_output_comment and mse_sitemap_taxonomy_choices are cosmetic.

Automatic updates

The plugin checks majevski.com for new releases and offers them through the normal WordPress update screen — the same prompt, changelog popup and one-click install as any other plugin. Checks are cached, never slow a page down, and fail open: if majevski.com cannot be reached, the site simply carries on and tries again later. An update package is only ever accepted from majevski.com over HTTPS, and an older version is never offered. Versions before 1.1.0 predate the update channel, so they cannot see new releases — install 1.1.0 or newer manually once, and every later release arrives on its own.

Want something like this built?

Everything on this page was designed, built and is run by one person. If you need the same for your business, tell me what you have in mind.

Book a call opens in a new tab