If a website is a news website then block it

I feel I am addicted to news websites and want to block all of them in a user script. To do that, I want to check if at least one of their meta tags has the word “news” in it, and if so, block the website.

On a certain news website which its meta description includes the word “news” I have tried the following, which worked:

if (document.querySelector('meta[name="description"]').content.includes("news")) {
    window.open("https://google.com/", "_self");
}

To ensure that the word check is valid I have tried the following that didn’t work

if (document.querySelector('meta[name="description"]').content.includes("BLABLABLA")) {
    window.open("https://google.com/", "_self");
}

So far so good, but will you do it differently?

This didn’t work:

if (document.querySelector('meta[name="title"]').content.includes("news")) || (document.querySelector('meta[name="description"]').content.includes("news")) || (document.querySelector('meta[name="tags"]').content.includes("news"))  {
    window.open("https://google.com/", "_self");
}

Uncaught SyntaxError: Unexpected token ‘||’

It’s just a syntax problem. The correct syntax is:

if (condition || otherCondition) {
  // Do something
}

Which in your case translates to:

if (
  document.querySelector('meta[name="title"]').content.includes("news") ||
  document.querySelector('meta[name="description"]').content.includes("news") ||
  document.querySelector('meta[name="tags"]').content.includes("news")
) {
  window.open("https://google.com/", "_self");
}

However, running this against the BBC website highlights a further error.

These are the meta tags they have in the head section of their site:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description" content="Breaking news, sport, TV, radio and a whole lot more. The BBC informs, educates and entertains - wherever you are, whatever your age.">
<meta name="keywords" content="BBC, bbc.co.uk, bbc.com, Search, British Broadcasting Corporation, BBC iPlayer, BBCi">
<meta property="fb:page_id" content="228735667216" />
<meta property="fb:admins" content="297814326937641" />
<meta property="fb:app_id" content="187214818032936" />
<meta property="og:title" content="BBC - Homepage" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.bbc.com/" />
<meta name="msvalidate.01" content="A09EF0BF1FC5CDBB37D921CBC3776943" />
<meta property="wwhp-edition" content="international" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="fb:pages" content="228735667216" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Your script, when run against this produces:

Uncaught TypeError: document.querySelector(...) is null

This means that document.querySelector('meta[name="title"]') returns null (i.e. that element doesn’t exist), then you try to call .content.includes() on null.

You could solve this with optional chaining:

if (
  document.querySelector('meta[name="title"]')?.content.includes("news") ||
  document.querySelector('meta[name="description"]')?.content.includes("news") ||
  document.querySelector('meta[name="tags"]')?.content.includes("news")
) {
  window.open("https://google.com/", "_self");
}

which then works as expected.

However, if you want to start adding further conditions to your script, it will start to get unwieldy.

It might therefore be an idea to do it like this:

const metaTags = document.querySelectorAll('meta');
metaTags.forEach((tag) => {
  console.log(tag);
  if (tag?.content.includes('news')) window.location = 'https://google.com/';
});

This will check all of the page’s meta tags and redirect on the first occurrence of the word, which might or might not be what you want.

2 Likes

wow, I’ve never heard of optional chaining before and the forEach() solution with it is indeed economical.

How should we define optional chaining in “simple words”? for example, how would we describe it in a pseudocode? Perhaps:

Select element X that contains Y but if you fail don’t break the program and just move on to the next command ; yet if you succeed then before moving to the next command do Z

In all my years of playing with beginner level JavaScript I never understood why JavaScript tends to break a program run due to not finding something or failing to select something :cowboy_hat_face:

Yeah kinda. Optional chaining allows you to safely access properties of an object without worrying about whether the properties exist or not. It uses the question mark (?) syntax to indicate that the property access is optional, and if any part of the property chain is undefined or null, the result will also be undefined (as opposed to an error).

Does that make sense?

Yes, thanks a lot.

1 Like

I also understand that my syntax error was adding several () to the if statement instead just one and anyway it’s best to organize conditions in different rows like you did.

Just try and write code that future you will be able to understand.

If you have a lot of conditions in an if statement, then you can certainly put one per line as above, or you could move the logic into its own method.

In psuedo code that might look like this:

function newsInMetaTags() {
  // Logic here
  // Return true or false
}

if (newsInMetaTags()) {
  window.open("https://google.com/", "_self");
}

Then if you add more conditions, you can adapt more easily. For example, if you wanted to just check certain meta tags:

if (newsInMetaTags('title', 'description')) {
  window.open("https://google.com/", "_self");
}

Or check for occurrences of different words:

if (metaTagsContain('news', 'sport')) {
  window.open("https://google.com/", "_self");
}

Or check different tags for occurrences of different words:

if (metaTagsContain({ 
  tags: ['title', 'description'],
  terms: ['news', 'sport'],
})) {
  window.open("https://google.com/", "_self");
}

And so on…

Also, it might be worth setting up a linter in your editor, as it would catch errors like above

1 Like