Next.js Discord

Discord Forum

html-react-parser stripping Imgix signed parameter

Unanswered
American Sable posted this in #help-forum
Open in Discord
American SableOP
I don't know what is causing it, but the browser back button works every time unless the previous page you went to is the home page. The URL updates, but the page does not.

If someone would be willing to help, that'd be awesome.

254 Replies

American SableOP
Also, nav-forward to home also doesn't work.
we'd need to see how you set up your navigation in a repo that we can access
preferably deployed to vercel so that we know what you precisely meant
American SableOP
It's even worse on Vercel. On nav-back to home, the browser tab freezes.
https://site-three-vert.vercel.app/
I can't help but notice my REST API is loaded in the client. Any way to do that on the server?
American SableOP
Why is it not surprising that nobody will help me
it crashes my browser lmao
American SableOP
I was having that issue too. Only when going back to the home page.
Oddly enough, it seems to be going home properly at the moment, but for how long?
very likely has something to do with the animations on the homepage
try removing them and test
American SableOP
Ok
Didn't fix it on my local setup
you may have to share your code. are you doing some async stuff in your client components?
American SableOP
Unnortunately yes. It was the only way I could fix my previous problem with toggling elements.
Just know, the site relies on WordPress with a specific setup.
https://github.com/davidmatthewcoleman/site
you just have to keep removing stuff to debug. but go through this thread, you may find something that helps

https://github.com/vercel/next.js/issues/50382
American SableOP
So I need to remove async.
Can we reopen the previous issue with toggling my navbar? The only thing that fixed it was async.
Should I just consider downgrading the project to NextJS 12?
American SableOP
Previously I was unable to toggle the navigation unless I removed the menu itself and the logo. Both of those made server-side API calls to WordPress.
Or at least I believe they were server-side.
how about fetching the data in a client component with sth like react-query. then import your component in the server page
American SableOP
I'm still very new to all of this. Please remember, I was exclusively WordPress and PHP for 8 years. I'm not very good when learning something new.
This is my API file. If I'm doing something wrong, please let me know.
https://github.com/davidmatthewcoleman/site/blob/main/src/app/api.tsx
I will need to leave pretty soon though.
It would be extremely helpful if someone out there were willing to look into my repo and tell me everything I'm doing wrong and how to fix them.

I've even tried ChatGPT and it wasn't much help.
Again, I'm a total noob at this, and being autistic and bipolar at the same time as having anxiety problems has made this a very stressful project.

So stressful, I'm honestly starting to consider bailing and just going back to a WordPress front-end.
American SableOP
Ok, thanks.
@American Sable Ok, thanks.
https://codesandbox.io/p/sandbox/festive-surf-sg5r95?welcome=true

what i've done is rather than make the page async i moved the data fetching inside a client component and then imported that component into my page. let me know if you have any questions
American SableOP
I'm restructuring my project.
But I get this error in my page.tsx
My lib/api.tsx file

import { Site, menuID } from "./info";

interface QueryParams {
  [key: string]: string | number | boolean;
}

function buildQueryString(params: QueryParams): string {
  const query = Object.keys(params)
    .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
    .join("&");
  return query ? `?${query}` : "";
}

async function fetchData(url: string, params?: QueryParams) {
  const query = params ? buildQueryString(params) : "";
  const response = await fetch(`${url}${query}`);
  const data = await response.json();
  const totalPages = Number(response.headers.get("X-WP-TotalPages"));

  return { data, totalPages };
}

export async function fetchLogo() {
  const url = `${Site}/wp-json/`;
  return fetchData(url);
}

export async function fetchImage(imageId: number) {
  const params: QueryParams = {};

  const url = `${Site}/wp-json/wp/v2/media/${imageId}`;
  return fetchData(url, params);
}

export async function fetchMenu() {
  const url = `${Site}/wp-json/options/menu/${menuID}`;
  return fetchData(url);
}

export async function fetchPosts(limit: number, page: number, tag?: string) {
  const params: QueryParams = {
    per_page: limit.toString(),
    page: page.toString(),
    ...(tag && { "filter[tag]": tag }),
  };

  const url = `${Site}/wp-json/wp/v2/posts`;
  return fetchData(url, params);
}

export async function fetchPost(slug: string) {
  const params: QueryParams = {
    slug,
    per_page: "1",
    _embed: true,
  };

  const url = `${Site}/wp-json/wp/v2/posts`;
  return fetchData(url, params);
}

export async function fetchPage(slug: string) {
  const params: QueryParams = {
    slug,
    per_page: "1",
    _embed: true,
  };

  const url = `${Site}/wp-json/wp/v2/pages`;
  return fetchData(url, params);
}

export async function fetchTags(searchTerm: string) {
  const params: QueryParams = {
    search: searchTerm,
  };

  const url = `${Site}/wp-json/wp/v2/tags`;
  return fetchData(url, params);
}
I really want to use environment variables in place of lib/info though.
By the way ChatGPT was actually a little helpful with creating this file.
Maybe something is wrong with it though, and I'm just too dumb to notice.
@American Sable But I get this error in my page.tsx
one more thing here. move the data fetching to a client component like i did, then label it 'use client'. then import the component in your Home
American SableOP
That would mean no environment variables though, right?
Oh well.
no you can use environment variables. doesn't affect it
or do you mean exposing it to the client?
American SableOP
If I use environment variables, Site and menuID become undefined
looks like you already exposed it to the client. you need to add NEXT_PUBLIC_ prefix
American SableOP
Prefix to what?
Oh, the variable?
yes
like NEXT_PUBLIC_API_KEY=1245845
American SableOP
Ok
Moving to .env causes fetch to fail
But I think I'm getting a little off-topic with the environment variables.
American SableOP
I know. That's what I have. Just was lazy and didn't want to type the entire thing.
do you get something in your terminal/console when you log the environment varialbe?
American SableOP
Yep. fetch fails.
Of course the site is a solid white page
But I suspect the blank page has something to do with the screenshotted error above
Oh, wait log the variable itself? Let me try that.
The log prints nothing at all. Just that the fetch fails.
I can live without environment variables for now. I want to try and fix the issue with the API.
alright then. what's the issue with the fetch?
for the react query, did you follow the way i initialized it? you have to use a client side provider and import into your layout
American SableOP
I did.
Is anything wrong with my api file? That could be causing something.
It was made with the help of ChatGPT afterall. lol.
can't really say. the fetchData fn looks okay to me
American SableOP
ok
what error are you getting
American SableOP
The error I get is on my fetchPosts function within app/page.tsx
Though I've never been good at reading errors
let me see the component where you're using useQuery
American SableOP
"use client";

import { useQuery } from "@tanstack/react-query";
import Hero from '../../components/hero';
import Post from '../../components/post';
import { fetchPosts } from '../../lib/api';

async function Home() {
  const { data: posts, status } = useQuery(['posts'], fetchPosts(3, 1));

  return (
    <>
      <Hero />
      <h2 className='relative flex pb-6 text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-100 sm:text-3xl md:text-5xl z-20'>
        Latest
      </h2>
      <hr className='relative border-gray-200 dark:border-gray-700 z-20' />
      <div className='relative z-50'>
        {
          posts.map((post: any) => {
            return (
              <Post id={post.id} key={post.id} />
            );
          })
        }
      </div>
    </>
  );
}

export default Home;
make your fetch inside the Post component
such that the only thing you're importing inside the Home is <Post/>
American SableOP
Let me try that real quick.
ah. wait. i think it's because you're not returning the fetchPosts fn

do it like this

const { data: posts, status } = useQuery(['posts'], () => fetchPosts(3, 1));
American SableOP
Already moved posts into a postLoop.tsx component.
import { useQuery } from '@tanstack/react-query';
import { fetchPosts } from '../lib/api';
import Post from './post';

function PostLoop({ limit, perPage, tag }: { limit: number, perPage: number, tag: string | undefined }) {
    const { data: posts, status } = useQuery(['posts'], () => fetchPosts( limit, perPage, tag ));

    return (
        posts.map((post: any) => {
            return (
              <Post id={post.id} key={post.id} />
            );
        })
    )
}

export default PostLoop;

Still getting the same error.
Wait, no.
Still getting a white page though.
add 'use client' to the top of this component
American SableOP
Ok
Didn't fix it.
Something is wrong here:
posts.map((post: any) => {
  return (
    <Post id={post.id} key={post.id} />
  );
})
comment this part and console.log posts
American SableOP
Ok
It's definitely fetching
should be post?.data?.map
American SableOP
Isn't that what the data in const { data: posts, status } is for?
So I tried that, but the posts aren't loading.
console.log posts.data what do you get
American SableOP
Undefined. Looks like it's undefined unless I put data: posts
Something about my fetching within api.tsx
Thanks ChatGPT
is it working now?
American SableOP
No. The following code also has a fetch loop somehow.
'use client'

import { useQuery } from '@tanstack/react-query';
import { fetchPosts } from '../lib/api';
import Post from './post';

function PostLoop({ limit, perPage, tag }: { limit: number, perPage: number, tag: string | undefined }) {
    const { data: posts, status } = useQuery([], () => fetchPosts( limit, perPage, tag ));

    console.log(posts);

    return (
        posts?.data.map((post: any) => {
            return (
              <Post id={post?.data?.id} key={post?.data?.id} />
            );
        })
    )
}

export default PostLoop;
The URL I get within the fetch loop is concerning though.
Somehow my tag variable might be causing it.
i don't think you have to do post?.data?.id here

console.log posts again
this is the same component as before nvm
try adding a loading state. that may be the issue, that we're trying to access the data before it's fully loaded
American SableOP
Ok
sth like status === 'loading' ? 'Loading...' : ...rest of your code
American SableOP
Still getting a fetch loop, and posts don't load.
Though the log shows my data as it should
add a query key to the useQuery - useQuery(['posts']...)
@American Sable Still getting a fetch loop, and posts don't load.
wdym? like the page keeps loading and loading?
where's your Post component
American SableOP
Apparently an issue with fetching in NextJS 13 I heard
probably an issue with your fetch fn then. replace your fetch fn with this and see if you still get this problem

export const fetchPosts = async () => {
  const response = await fetch(
    "https://jsonplaceholder.typicode.com/posts?limit=20"
  );
  const data = await response.json();
  const limitedData = data.slice(0, 10);
  return limitedData;
};
American SableOP
Yep, still getting the fetch loop
And undefined is post?.id not getting passed properly.
@American Sable And undefined is post?.id not getting passed properly.
this function is a bit different so you may not have to do posts.data.map
console.log posts to give you an idea
@American Sable Yep, still getting the fetch loop
are you sure you don't have any redundant asyncs in your code?
what does your Home page look like?
American SableOP
Not that I'm aware of.
even your Home file?
American SableOP
No async in home
import Hero from '../../components/hero';
import PostLoop from '../../components/postLoop';

function Home() {
  return (
    <>
      <Hero />
      <h2 className='relative flex pb-6 text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-100 sm:text-3xl md:text-5xl z-20'>
        Latest
      </h2>
      <hr className='relative border-gray-200 dark:border-gray-700 z-20' />
      <div className='relative z-50'>
        <PostLoop limit={3} perPage={1} tag="" />
      </div>
    </>
  );
}

export default Home;
Here's the branch for the changes we've made...
https://github.com/davidmatthewcoleman/site/tree/fixing
are you getting any errors now? or it's just the infinite loop?
American SableOP
The loop with the undefined part in posts/undefined which causes a 404 error on the REST API
Somehow react-query is causeing my fetchData function to not properly build with query parameters. Or so I'm guessing.
i have to go now, i'll take a look in a couple of hours
American SableOP
Ok, thanks for your help.
in the meantime, you can try some other fetching method to rule out potential suspects. you can try fetching directly inside the component
there's an example of that in the docs
American SableOP
Ok, thanks again.
American SableOP
I'm gonna try and see if I can get the changes, but tbh, I've pretty much given up on this endeavor and have begun porting it as a WordPress native theme.
Sorry, I know you worked to fix the fetch loop, but I think this project just can't be salvaged.
Thank you so, so much for your help and advice. I guess I'm just not skilled enough of a developer to make a proper NextJS site.
Just got an email from Vercel saying the merge failed deployment.
No surprise there. My code's just too broken to fix.

If you think there's a way of porting it to use Colby Fayock's starter, let me know. I tried but had problems getting my data from WPGraphQL to work. Any added fields didn't show up.
no worries man. Next released a new version pretty recently and it's quite tricky to work with. not your fault at all, most of us are still coming to terms with the new updates and stuff
American SableOP
If you'd be willing to help me with Colby's starter, I'm ball. Just know, if it fails to work out, I'm jumping ship.
Oh, sorry, I already merged.
See I don't have any clue what I'm doing.
And CORS was because I shut off the live server. Didn't want to waste unnecessary bandwidth.
I don't know how to manage a git repository properly.
Heck, all my commits just say "Init"
do you have a url to Colby's starter so i can check it out
American SableOP
It uses WordPress with WPGraphQL, has support for YoastSEO.
Even uses WordPress menus apparenty.
Only thing it's missing is TailwindCSS and that was easy enough to install.
If you don't have WordPress (this is the Next Discord, so I won't assume you do), I'd recommend getting localwp.
https://localwp.com/
i've never done wordpress in my life
American SableOP
Yeah. The good thing is the dashboard is pretty straight forward.
You'd need to grab the WPGraphQL plugin.
In the dashboard, you go to the plugins tab, click add plugin.
Search in the top right of the plugin repository for WPGraphQL.
Once it shows up, click install. Once finished, click activate. Then you're done with WordPress.
For env.local
WORDPRESS_GRAPHQL_ENDPOINT=[wordpress_url]/graphql
WORDPRESS_MENU_LOCATION_NAVIGATION=menu_location_id
seems like a lot of work and i'm lazy 😅

are you still encountering any issues with this one?
American SableOP
Yes, unfortunately.
In my core wordpress plugin I added fields to graphql.
They definitely show up in the graphql IDE, so I added them to the getAllPosts function within plugins/util.js in Colby's starter.
/**
 * getAllPosts
 */

async function getAllPosts(apolloClient, process, verbose = false) {
  const query = gql`
    {
      posts(first: 10000) {
        edges {
          node {
            title
            excerpt
            databaseId
            slug
            date
            modified
            isSticky
            views
            readingTime
            words
            author {
              node {
                name
              }
            }
            tags {
              edges {
                node {
                  name
                }
              }
            }
          }
        }
      }
    }
  `;

  let posts = [];

  try {
    const data = await apolloClient.query({ query });
    const nodes = [...data.data.posts.edges.map(({ node = {} }) => node)];

    posts = nodes.map((post) => {
      const data = { ...post };

      if (data.author) {
        data.author = data.author.node.name;
      }

      if (data.tags) {
        data.tags = data.tags.edges.map(({ node }) => node.name);
      }

      if (data.excerpt) {
        //Sanitize the excerpt by removing all HTML tags
        const regExHtmlTags = /(<([^>]+)>)/g;
        data.excerpt = data.excerpt.replace(regExHtmlTags, '');
      }

      return data;
    });

    verbose && console.log(`[${process}] Successfully fetched posts from ${apolloClient.link.options.uri}`);
    return {
      posts,
    };
  } catch (e) {
    throw new Error(`[${process}] Failed to fetch posts from ${apolloClient.link.options.uri}: ${e.message}`);
  }
}
When I do that, I get this error in my terminal.
looks like you're trying to access properties that don't exist on the data
American SableOP
You were right though. I had my core plugin disabled, as I didn't need it while developing a WordPress theme.
Reenabling gets rid of the errors, but the data still isn't fetched.
Of course for whatever reason, CSS is not loading in Firefox, so I have to use Chrome.
Notice that views is 0? It shouldn't be...
American SableOP
Yes
Or I assume so, given I can't console.log it given the structure of this project
the stuff on the right is your own data, yeah?
American SableOP
Yes
so, you're doing data?.posts?.nodes.map(...) yeah?
American SableOP
At least it's the fields I added.
No, that was part of the starter.
All I did was added to this.
const query = gql`
    {
      posts(first: 10000) {
        edges {
          node {
            title
            excerpt
            databaseId
            slug
            date
            modified
            isSticky
            views
            readingTime
            words
            author {
              node {
                name
              }
            }
            tags {
              edges {
                node {
                  name
                }
              }
            }
          }
        }
      }
    }
  `;
isSticky wasn't originally there, but as you saw in my screenshot, it shows up.
isSticky being pinned
This is determined by the isSticky value I added.
It works, but none of the other fields do. isSticky is a core wordpress feature though, which makes me wonder.
Yet, using the graphql IDE shows my added fields.
The fact I can't console.log anything in the plugins directory is upsetting.
@Dayo so, you're doing `data?.posts?.nodes.map(...)` yeah?
American SableOP
I totally misread that
is the date hard coded?
American SableOP
That's what I was thinking, but it doesn't appear to be.
Somehow his starter is filtering out non-wordpress fields when fetching from graphql.
Not sure if it's a security measure, or what.
Haha!
See the line databaseId?
I tried searching the project for title and excerpt to no luck.
So I search for databaseId and I find this!
export const POST_FIELDS = gql`
  fragment PostFields on Post {
    id
    categories {
      edges {
        node {
          databaseId
          id
          name
          slug
        }
      }
    }
    databaseId
    date
    isSticky
    postId
    slug
    title
  }
`;
When changing it to this, my fields work.
export const POST_FIELDS = gql`
  fragment PostFields on Post {
    id
    categories {
      edges {
        node {
          databaseId
          id
          name
          slug
        }
      }
    }
    databaseId
    date
    isSticky
    postId
    slug
    title
    views
    readingTime
    words
  }
`;
I do want to keep this thread open just in case I run into further problems though. I most certainly will.
American SableOP
So I do have a problem now.
In Nav.js under my components, I can't seem to get getSiteMetadata() to work.
It's just stuck on promise in console.log
are you awaiting the response?
American SableOP
Won't let me.
I get a bunch of errors if I async the Nav function
Somehow, metadata is being stored in package.json, though I fail to see where.
Was so distracted I just took a bite of moldy bread. Yuck!
American SableOP
Using async on Nav just isn't gonna work. Breaks too many things.
I think Colby is storing data into package.json. I don't see where it is, nor how he's doing it. But if you watch my recording above, you'll see it leads to that.
import config from '../../package.json';
That's within...
import { useContext, createContext } from 'react';

import config from '../../package.json';

import { removeLastTrailingSlash } from 'lib/util';

export const SiteContext = createContext();

/**
 * useSiteContext
 */

export function useSiteContext(data) {
  let { homepage = '' } = config;

  // Trim the trailing slash from the end of homepage to avoid
  // double // issues throughout the metadata

  homepage = removeLastTrailingSlash(homepage);

  return {
    ...data,
    homepage,
  };
}

/**
 * useSite
 */

export default function useSite() {
  const site = useContext(SiteContext);
  return site;
}
Which is used in Nav.js with the following line.
const { metadata = {}, menus } = useSite();
The problem is, none of that makes any sense.
But somehow, he's getting the site name from within lib/site.js which is the above file.
The only other thing I can think of would be SiteContext, which I can't find where it leads to.
I really don't want to hardcode my photo...
this is so complicated
American SableOP
Colby Fayock is insane
But apparently it's the best WordPress/NextJS starter out there.
WebDevStudios had a good one, but it had a hard requirement for an expensive subscription based form plugin for WordPress.
That and it's old and broken.
Is it worth using his starter, or trying to fix my old project?
tbh, i think you can fix the old one. just check those files i modified
American SableOP
Ok.
American SableOP
So I started a new NextJS 13 project, just with the pages directory instead.
I seem to have an issue though. I'm getting this error when trying to render wordpress editor blocks on the page. Somehow the data is an object, not an array?
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
I could just render the post/page content, but then I wouldn't be able to use next/image on any images.
American SableOP
It specifically has to do with the rendering of blocks, as this works just fine.
<div
  className="prose prose-xl prose-p:m-0 prose-p:mb-4 prose-invert prose-img:rounded-md"
  dangerouslySetInnerHTML={{ __html: post[0].content.rendered }}
>
  {/* <Blocks data={post[0].blocks} /> */}
 </div>
American SableOP
Sorry was afk. I fixed it. Apparently my WpImage component was the issue. I simply modified my REST API output, and used the base next/image component and it works.
American SableOP
So I've pretty much fixed all but one problem.
I use Imgix for rendering remote images, and Imgix requires each URL to be signed. I do this in WordPress.
The problem is simple, but I imagine figuring out the cause may be complicated.
On my localhost, the "s" parameter is left intact, but when deployed to Vercel, that parameter is stripped from every image which causes Imgix to give a 403 error. I need that parameter left intact.
American SableOP
Apparently the issue is with html-react-parser
If someone could help me figure out a solution, that'd be awesome.
American SableOP
I really don't want to have to use dangerouslySetInnerHtml...
not sure i understand your issue
American SableOP
Sorry. I'm using html-react-parser as an alternative to dangerouslySetInnerHtml.
The problem is, on a live site it strips the "s" parameter from image URLs
This is a problem because that parameter is required for Imgix to serve images.
Imgix being an image CDN.
are you getting any errors?
American SableOP
Not from NextJS.
I get a 403 error from Imgix.
Because the image is not signed
can you share your code
American SableOP
For some reason Discord won't let me paste it.
I have a Bookmark block I built in WordPress.
That uses Imgix
The line for that is 67
And no, WordPress isn't the issue.
so what line is your issue on
American SableOP
67
Scratch that. Just signed into WordPress. The issue might be WordPress...
Somehow my local WP isn't doing that.
American SableOP
Welp, it's doing that again (stripping the signature) and it's definitely not WordPress.
The images load fine initially with the signature intact, however after just a few milliseconds the signature is stripped and the images reload without it, causing them each a 403 error.
American SableOP
Please, I've been at this for hours.
American SableOP
Here's the relevant component.
https://pastebin.com/wBJ7CGp3
I'd also like to mention that this issue only happens when JavaScript is enabled in the browser.