Skip to content

Several enhancements & new features#5

Open
soullessxo wants to merge 25 commits intowintercms:mainfrom
soullessxo:main
Open

Several enhancements & new features#5
soullessxo wants to merge 25 commits intowintercms:mainfrom
soullessxo:main

Conversation

@soullessxo
Copy link

@soullessxo soullessxo commented Apr 10, 2023

  • Global settings tab added, can be enabled/disabled, if enabled empty page or model meta_title and meta_description will be substituted by one specified in global settings, meta_title prefix/suffix with separator optional.
  • Optional favicon.ico support
  • Optional HTML minification
  • Optional robots.txt (enable/disable switch in settings)
  • Optional humans.txt (enable/disable switch in settings)
  • Optional security.txt (enable/disable switch in settings)
  • Added support for using external models and output form to controllers that using this model by
    public $metadata_from = 'column_name';, stupid and simple.
    Model's metadata can be set from page controller by $this->seoTags->useMetadataModel($modelEntity);

@LukeTowers
Copy link
Member

LukeTowers commented Apr 11, 2023

@8blvck thanks for the contribution! Couple of notes:

  • Please change the references to 8blvck back to Winter and remove the extra steps required just for your fork
  • Indentation should be four spaces and please undo any other formatting only changes. Also every file must end with a newline for better git diffs
  • Anything that is controlled by a database setting should also be controllable through a config file setting using the approach that the database setting takes precedent over the config file but will fall back to loading from the config file if no DB value for a given setting is present.

Does your adjustment to the metadata storage allow for it to be stored inside of already existing JSON blob columns alongside pre-existing data?

@soullessxo
Copy link
Author

soullessxo commented Apr 11, 2023

Does your adjustment to the metadata storage allow for it to be stored inside of already existing JSON blob columns alongside pre-existing data?

Are you talking about prefixing properties in JSON with "meta_"? Then I believe so, since it stored in seo property.
Real life example:

{
    "seo": {
        "meta_image":"",
        "meta_title":"Winter Blog Post Title",
        "meta_description":"Winter Blog Post Description",
        "meta_nofollow":"1"
    }
}

UPD:
Good that you pointed that out tho, i'll stick with your solution and just prefix fields in extendExternalPlugins() for now.

Plugin.php Outdated
],
\Winter\Blog\Controllers\Categories::class => [
\Winter\Blog\Models\Category::class,
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to make this configurable in the config file so that attaching SEO fields to custom models would be as easy as adding them to the config?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something similar to https://github.com/LukeTowers/wn-easyaudit-plugin/blob/main/config/config.php#L68 & https://github.com/LukeTowers/wn-easyaudit-plugin/blob/main/Plugin.php#L225.

If we added a model behaviour (Seoable or something) that also provided helper methods for getting / setting the SEO values then we could use that example pretty much verbatim which would simplify the below logic a lot.

}
win.ready = ready;
win.counter = counter;
win.ready('[data-counter]', (el) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to look at rewriting this as a Snowboard.js plugin, see https://github.com/wintercms/winter/blob/develop/modules/backend/formwidgets/iconpicker/assets/js/src/iconpicker.js as an example, specifically the last two lines which enable the use of data-control="iconpicker" to automatically attach the JS to the relevant elements.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, on second thought with the goal of attaching this to fields using the attributes property on fields this is probably fine as it is, although the indentation still needs to be fixed here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda feel like that would still be useful as a plugin, unless we have specific fields in core that have limits on length.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any objections to writing it as a Snowboard plugin that's available in the core (with initial support for the text / textarea / maybe Froala fields)? That way we can use it in this plugin without having to have it only included in this plugin.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll write it as a first party plugin, as I would like to create an example of a plugin that provides Snowboard assets. If you feel afterwards that it should be in core, we can move it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me. Are you going to do it in this plugin?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, I'll do it as its own plugin, and just add it as a requirement for this plugin. You never know - there may be other plugins that could use the same feature down the line.

Comment on lines +27 to +63
global_app_name:
tab: 'Global'
label: 'App name'
span: auto
placeholder: ''
type: text
default: ''
comment: 'App name can be visible in the title meta tag'
global_separator:
tab: 'Global'
label: 'App name separator'
span: auto
placeholder: ''
type: text
default: '|'
comment: 'Sybmol to separate title from app name: {app name} {sepratator} {title}'
global_app_name_pos:
tab: 'Global'
label: 'Select how the app name should appear in the title'
options:
hide: 'Hide'
prefix: 'Prefix'
suffix: 'Suffix'
span: auto
type: balloon-selector
global_app_title:
tab: 'Global'
label: 'App title'
size: tiny
span: full
placeholder: 'Your app global title'
type: text
comment: '[data-counter]'
attributes:
data-counter: 1
data-min: 50
data-max: 60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could all be simplified down into a single field that supports string replacements with a default value of {page_title} | {app_name}; with that string being parsed by the SEOTags component before rendering using the current title of the page object as {page_title} and the current app.name as the {app_name} text; and only doing this if there is not already an explicit title meta tag setup.

That way in a single field they can do any format, positioning, separator that they could possibly want without requiring all of these extra fields.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally this field should probably be called "Default Meta Title". Comment: "Meta title that is used for the page when one isn't set already. Use {page_title} to reference the page's title and {app_name} to reference this website's name".

Comment on lines +117 to +128
enable_favicon:
tab: 'Favicon'
label: 'Enable icons'
span: full
type: switch
default: 0
favicon:
tab: 'Favicon'
commentAbove: 'Global favicon'
type: mediafinder
mode: image
span: left
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to have two separate settings for this, if a favicon has been uploaded or configured in the settings then it's enabled and if it's not present then it's disabled.

On a side note; it would be better to use a fileupload field here instead since you wouldn't want the favicon to be accidentally moved, removed, or used elsewhere on the site so it would be better to have the one to one relationship.

Additionally is the .ico format anything special that we need to be converting automatically beyond just resizing to 16x16 and hoping for the best?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something else that I've been considering for a while as well is adding support for favicons to the Winter core itself in the backend branding settings area. Ideally I'd like it to handle as much of what https://realfavicongenerator.net/ handles automatically from just uploading a single image and then what this plugin could do is pull the generated meta tags into the frontend (since they would otherwise only be injected into the backend).

That way the site's favicon management stays where it makes logical sense for it to be (with the rest of the branding settings) and it simplifies the logic that would have to be in this plugin.

Any thoughts on that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LukeTowers I completely agree with you.

What I always get from RealFavicon when I make a generation:

Easy to resize:

  • favicon.ico (32 X 32px)
  • favicon-16x16.png
  • favicon-32x32.png
  • apple-touch-icon.png (180 X 180px)
  • android-chrome-192x192.png
  • android-chrome-384x384.png
  • android-chrome-512x512.png

More complicated (?):

  • mstile-150x150.png (but 270 X 270px with a 150px square image centered)
  • safari-pinned-tab.svg - silhouette image

Other non images:

  • browserconfig.xml (contains references to one color and to the mstile-150x150.png file)
  • site.webmanifest (contains references to android images, names and colors)

It can be difficult to manage the conversion of different formats and may require the installation of a graphics library.

One possible solution is to use the Favicon API, in this case it require an extra step for the end user: getting an API key.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to use the API! @damsfx is that something you'd be willing to play around with?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!
But I'm going to wait and see how this PR evolves before I make any changes, as it modifies the plugin in a number of ways.
It might have perhaps been worth splitting it up into different functionalities.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@damsfx honestly you could probably just create a new PR just for that functionality branching from the current main branch; I'm not sure this PR will be merged as one piece in its current state.

Comment on lines +3 to +7
{% if tagName == 'title' %}
<title>{{ tagContent }}</title>
{% else %}
<meta name="{{ tagName }}" property="{{ tagName }}" content="{{ tagContent }}" />
{% endif %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not always desirable to have the same <title> and , see https://stackoverflow.com/a/21076311.

It's usually the responsibility of the theme to handle the title tag (see https://github.com/wintercms/wn-workshop-theme/blob/main/partials/html/head.htm#L7). While it would be nice to make the Tab Title configurable with this plugin that wouldn't work across the board on all themes unless the theme was using <title>{{ this.page.title }}</title> in which case we could modify that immediately before rendering it after parsing it through our setting, but most themes will not be doing that.

@LukeTowers
Copy link
Member

Looking good @8blvck, you've got me excited to see this finished :) I've added a bunch of thoughts and guidance; let me know what you think or if you have any questions!

@soullessxo
Copy link
Author

Hey @LukeTowers, I'm pretty curious about having Seoable behavior. Currently testing plugin. everything works as expected on php 8.1. About HTML minification you absolutely right, even tho it sucks, i'd rather have this option, than not :)
Going to work around your thoughts in nearest future, thanks.

@bennothommo bennothommo requested a review from LukeTowers May 5, 2023 00:28
@damsfx
Copy link
Contributor

damsfx commented Feb 3, 2024

@LukeTowers @VadBe What remains to be done about this PR?

@LukeTowers
Copy link
Member

There's still some pending comments of mine that haven't been responded to. @VadBe is this still something you'd like to push across the finish line?

@LukeTowers LukeTowers changed the title Minor improvements Several enhancements & new features Jun 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants