Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace current SEO-features by universal SEO-Module #1218

Open
phorward opened this issue Jul 18, 2024 · 1 comment
Open

Replace current SEO-features by universal SEO-Module #1218

phorward opened this issue Jul 18, 2024 · 1 comment
Assignees
Labels
feature New feature or request Priority: High After critical issues are fixed, these should be dealt with before any further issues. proposal

Comments

@phorward
Copy link
Member

phorward commented Jul 18, 2024

The current SEO-stuff in ViUR-core which was integrated with version 3.0 is not really good and usable.

The disadvantages are:

  • bad to configure, including bad naming
    • Skeleton.getCurrentSEOKeys()... fills viurCurrentSeoKeys, viurActiveSeoKeys, viurLastRequestedSeoKeys
    • Module.seo_language_map ...
  • sticks to the existing render/module schema

In a test-project, we found that is would be easier to have a SEO-module which does a SEO-routing. The current implementation looks like this:

skeletons/seo.py

from viur.core.bones import *
from viur.core.skeleton import Skeleton


class SeoSkel(Skeleton):

    target = KeyBone(
        descr="Target key",
        required=True,
    )

    seo_path = BaseBone(
        descr="SEO-Path",
        required=True,
    )

    redirect_path = BaseBone(
        descr="Redirect-Path",
        required=True,
    )

modules/seo.py

import re
import typing as t
from viur.core.prototypes.list import List
from viur.core import db, errors, current, skeleton, tasks


UMLAUT_TO_SEO = str.maketrans({
    "ä": "ae",
    "ö": "oe",
    "ü": "ue",
    "Ä": "Ae",
    "Ö": "Oe",
    "Ü": "Ue",
    "ß": "ss",
    " ": "-",
})


class Seo(List):

    def seo_path(self, name: str | t.Iterable) -> str:
        if isinstance(name, str):
            name = name.translate(UMLAUT_TO_SEO)
            name = re.sub(r"[^a-zA-Z0-9-/]", "-", name)
            return name.lower()

        return "/".join(self.seo_path(part) for part in name if name)

    def skel_path(
        self,
        skel: skeleton.SkeletonInstance,
        *,
        module_prefix=None,
        module=None,
        module_postfix=None,
        action="view",
        key=None
    ) -> str:
        key = key or skel["key"]
        if not key:
            raise ValueError("A key is required to construct a path")

        return "/".join(
            str(part) for part in (
                module_prefix,
                module or skel.kindName,
                module_postfix,
                action,
                key.id_or_name
            ) if part
        )

    @tasks.CallDeferred
    def create(self, target: db.Key, seo_path: str, redirect_path: str):
        """
        Creates a new SEO entry for a given target, seo_path and redirect_path.
        """
        skel = self.addSkel()
        skel["key"] = db.Key(skel.kindName, target.id_or_name)
        skel["seo_path"] = seo_path
        skel["redirect_path"] = redirect_path
        skel.toDB()

    @tasks.CallDeferred
    def delete(self, target: db.Key):
        """
        Drops SEO entry for a given target.
        """
        skel = self.editSkel()
        if skel.fromDB(target.id_or_name):
            skel.delete()

    def route(self, path):
        """
        Routes a SEO-path into a redirected path
        """
        if skel := self.viewSkel().all().filter("seo_path", path).getSkel():
            return current.request.get()._route(skel["redirect_path"])

        raise errors.NotFound()

... and is currently used in modules/index.py as follows:

from viur.core import conf, errors, exposed
from viur.core.prototypes.skelmodule import SkelModule


class Index(SkelModule):

    @exposed
    def index(self, *args, **kwargs):
        # Try to perform SEO-routing
        if len(args) > 0:
            return conf.main_app.vi.seo.route("/".join(args))

        template = self.render.getEnv().get_template("index.html")
        return template.render(start=True)

An entry currently is manually added from a skeleton this way:

class ExampleSkel(Skeleton):
    name = StringBone(
        descr="Name",
        required=True,
        searchable=True
    )

    seo_path = RawBone(
        descr="SEO-Pfad",
        readOnly=True,
        visible=False,
    )

    @classmethod
    def toDB(cls, skel, **kwargs):
        skel["seo_path"] = conf.main_app.vi.seo.seo_path(skel["name"])

        if ret := super().toDB(skel, **kwargs):
            if skel["seo_path"]:
                conf.main_app.vi.seo.create(
                    ret,
                    skel["seo_path"],
                    conf.main_app.vi.seo.skel_path(skel)
                )
            else:
                conf.main_app.vi.seo.delete(ret)

        return ret

    @classmethod
    def delete(cls, skel, **kwargs):
        conf.main_app.vi.seo.delete(skel["key"])
        return super(cls, skel, **kwargs)

Requirements for a final SEO module:

  1. The SEO-lookup must be part of the ViUR module routing
  2. There must be an easier/default method to update SEO entries, maybe similar to a hook-function as before, and the handling must be done in the Module, not in the Skeleton.
  3. Maybe this is also part of the ActionSkel paradigm.

The old SEO-stuff should be removed (breaking change, but it's really nowhere used in current projects!).

@phorward phorward added feature New feature or request help wanted Extra attention is needed proposal Priority: Medium This issue may be useful, and needs some attention. labels Jul 18, 2024
@phorward phorward added this to the ViUR-core v3.7 milestone Jul 18, 2024
@phorward
Copy link
Member Author

Relates to #803

@phorward phorward added Priority: High After critical issues are fixed, these should be dealt with before any further issues. and removed help wanted Extra attention is needed Priority: Medium This issue may be useful, and needs some attention. labels Oct 7, 2024
@phorward phorward self-assigned this Oct 7, 2024
@phorward phorward added viur-meeting Issues to discuss in the next ViUR meeting and removed viur-meeting Issues to discuss in the next ViUR meeting labels Oct 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request Priority: High After critical issues are fixed, these should be dealt with before any further issues. proposal
Projects
None yet
Development

No branches or pull requests

1 participant