Following Error: DeclarationError: Undeclared identifier. contracts/GorillaNFT.sol:98:5: | 98 | _setTokenURI(tokenId, tokenURI); CAN ANYONE HELP PLZ?

Hi Folks! I'm trying to compile the following code, but I got the following error:
DeclarationError: Undeclared identifier. contracts/GorillaNFT.sol:98:5: | 98 | _setTokenURI(tokenId, tokenURI);
Can anyone check this and helps out? Here's the code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

contract GorillaNFT is ERC721Enumerable {
    uint256 public constant MAX_NFT_SUPPLY = 16;
    mapping(address => uint256) private _balances;

    address private admin;
    uint256 private goldEditionCount;
    uint256 private silverEditionCount;
    uint256 private bronzeEditionCount;
    uint256 private specialEditionCount;

    mapping(uint256 => string) private _tokenNames; // Mapping for Token-Name

    mapping(address => bool) private presaleParticipants;

    // URL-path for the PICS
    string private constant baseURI = "";
    string private constant goldBasePath = "phase1/goldpic";
    string private constant silverBasePath = "phase2/silverpic";
    string private constant bronzeBasePath = "phase3/bronzepic";
    string private constant specialBasePath = "phase4/specialpic";    

    constructor() ERC721("GorillaNFT", "GNFT") {
        admin = msg.sender;

    modifier onlyAdmin() {
        require(msg.sender == admin, "Only admin can perform this action");

    modifier presaleParticipant() {
        require(presaleParticipants[msg.sender], "Address is not a presale participant");

    function addToPresaleParticipants(address participant) external onlyAdmin {
        presaleParticipants[participant] = true;

    function mintGoldEdition(address to, string memory name) external presaleParticipant {
        require(goldEditionCount < 4, "Gold edition limit reached");
        _mintNFT(to, name);

    function mintSilverEdition(address to, string memory name) external presaleParticipant {
        require(silverEditionCount < 4, "Silver edition limit reached");
        _mintNFT(to, name);

    function mintBronzeEdition(address to, string memory name) external presaleParticipant {
        require(bronzeEditionCount < 4, "Bronze edition limit reached");
        _mintNFT(to, name);

    function mintSpecialEdition(address to, string memory name) external presaleParticipant {
        require(specialEditionCount < 4, "Special edition limit reached");
        _mintNFT(to, name);

    function _mintNFT(address to, string memory name, uint256 editionType) private {
        require(totalSupply() < MAX_NFT_SUPPLY, "All NFTs have been minted");
        uint256 tokenId = totalSupply() + 1;
        _safeMint(to, tokenId);
        _tokenNames[tokenId] = name; // Saves the name for the token

        // Set token metadata, including image URLs, based on the edition
        _setTokenMetadata(tokenId, editionType);

    function _setTokenMetadata(uint256 tokenId, uint256 editionType) private {
        require(tokenId > 0 && tokenId <= MAX_NFT_SUPPLY, "Invalid token ID");

            string memory tokenURI;

            if (editionType == 1) {
                tokenURI = string(abi.encodePacked(baseURI, goldBasePath, uintToString(tokenId), ".jpg"));
            } else if (editionType == 2) {
                tokenURI = string(abi.encodePacked(baseURI, silverBasePath, uintToString(tokenId), ".jpg"));
            } else if (editionType == 3) {
                tokenURI = string(abi.encodePacked(baseURI, bronzeBasePath, uintToString(tokenId), ".jpg"));
            } else if (editionType == 4) {
                tokenURI = string(abi.encodePacked(baseURI, specialBasePath, uintToString(tokenId), ".jpg"));
            } else {
                revert("Invalid edition type");

    // Set the token URI for the NFT token
    _setTokenURI(tokenId, tokenURI);

    // Help function for uint to string conversion
    function uintToString(uint256 value) private pure returns (string memory) {
        if (value == 0) {
        return "0";
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
        temp /= 10;
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
        digits -= 1;
        buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
        value /= 10;
        return string(buffer);

    // Overriding the _increaseBalance function from ERC721Enumerable
    function _increaseBalance(address account, uint128 value) internal virtual override(ERC721Enumerable) {
        require(value > 0, "Value must be greater than zero");
        require(account != address(0), "Invalid account address");
        _balances[account] += value;

        // Call the _increaseBalance function from the parent class to increase the balance
        super._increaseBalance(account, value);

If I'm correct in my assumption, then the import of ERC721URIStorage is necessary for _setTokenURI, but how do I implement this without subsequently receiving an error for the totalsupply()? Tanks!

Well, the error-message tells you that one of the identifiers in this expression is not declared anywhere in your code (_setTokenURI or tokenId or tokenURI).

Indeed, you attempt to use the undeclared identifier _setTokenURI as a function-call in your code.
So you either need to implement this function in your contract, or inherit it from another contract.

Thanks bro for ya help.

I think you might be missing the ERC721 declaration.

contract GorillaNFT is ERC721, ERC721Enumerable {

Actually, _setTokenURI is part of the ERC721URIStorage extension.

When you inherit ERC721Enumerable you automatically get ERC721. What is missing here is the URIStorage part:

contract GorillaNFT is ERC721Enumerable, ERC721URIStorage {