ok so im having issues searching the many levels of my json file, it needs to be able search not only the title but also content, but each content is array that can be a string, but also have another level that has a title and content. here is the code im using to search the json. once i post this code, next ill post the working json file. please do not write anything until you see this and the json file.

controller:

	public function actionSearch()
	{
		$model = new SearchForm();
		$request = \Yii::$app->request;
		if (($request->isAjax) && ($request->isPost)) {
			
			$model->load($request->post());
			if ($model->validate()) {
				
				/**
				* Debugging - Log the search query.
				*/
				\Yii::info("Search Query: " . $model->query . " | Type: " . $model->type, __METHOD__);//*/
				
				// Determine the file based on the content type.
				$filePath = Yii::getAlias('@app/web/data/');
				$fileToRead = null;
				
				// Default values for variables.
				$type = null;
				$placeholder = null;
				
				// Use the content type from the model (make sure to set this in your form).
				switch ($model->type) {
					case 'faq' :
						$fileToRead = 'faq.json';
						break;
					case 'terms' :
						$fileToRead = 'terms.json';
						break;
					case 'cookie' :
						$fileToRead = 'cookie.json';
						break;
					case 'privacy' :
						$fileToRead = 'privacy.json';
						break;
				}
				
				if ($fileToRead) {
					
					$content = file_get_contents($filePath . $fileToRead);
					$data = json_decode($content, true);
					
					 /**
					 * Debugging - Log to check structure of the data.
					 */
					 \Yii::info("Data Loaded: " . json_encode($data), __METHOD__);//*/
					 
					if (!empty($model->query)) {
					 	
					 	// Use the search function from the ContentRenderer.
					 	$results = JsonRender::search($data['top_level'], $model->query);
					}
					 
					/**
					* Debugging - Count the results.
					*/
					\Yii::info("Number of Results Found: " . count($results), __METHOD__);//*/	
				}
				
				/**
				* Debugging - Log results to check what has been found.
				*/
				\Yii::info("Found Results: " . json_encode($results), __METHOD__);//*/
				
				// Render the search results.
				return $this->renderPartial('_search', [
					'model' => $model,
					'type' => $model->type,
					'placeholder' => $placeholder,
					'results' => $results,
				]);
			}
			else {
				/**
				* Debugging - Log validation errors if needed.
				*/
				\Yii::info("Validation Failed: " . json_encode($model->getErrors()), __METHOD__);//*/
			
				// If validation fails or more checks, render partial view with search query
				return $this->renderPartial('_search', [
					'model' => $model,
					'results' => [],
				]);
			}
		}
		
		// Default behavior for non-AJAX requests.
		return $this->goHome();
	}
	

Comonpent file:

public static function search($content, $query)
{
    $results = [];

    // If the search query is empty
    if (empty($query)) {
        \Yii::info("Empty search query.", __METHOD__);
        return $results; // Early return if query is empty.
    }

    $query = trim($query); // Clean the query
    \Yii::info("Starting search for query: " . $query, __METHOD__);

    if (is_array($content)) {
        foreach ($content as $item) {
            // Check Level 1
            if (isset($item['level_one'])) {
                $levelOne = $item['level_one'];
                $levelOneTitle = trim($levelOne['title']); // Clean title
                \Yii::info("Checking level_one title: " . $levelOneTitle, __METHOD__);

                // Check if level_one title matches
                if (stripos($levelOneTitle, $query) !== false) {
                    $results[] = [
                        'title' => $levelOneTitle,
                        'content' => 'Content found in level_one title.'
                    ];
                    \Yii::info("Match found in level_one title: " . json_encode($levelOne), __METHOD__);
                }

                // Check Level 1 content for matches
                if (isset($levelOne['content']) && is_array($levelOne['content'])) {
                    foreach ($levelOne['content'] as $contentItem) {
                        // Check direct string content
                        if (is_string($contentItem) && stripos($contentItem, $query) !== false) {
                            $results[] = [
                                'title' => $levelOneTitle,
                                'content' => $contentItem
                            ];
                            \Yii::info("Match found in level_one content: " . json_encode($contentItem), __METHOD__);
                        }
                        // Check for level_two if content item is an array
                        if (is_array($contentItem) && isset($contentItem['level_two'])) {
                            self::checkLevelTwo($contentItem['level_two'], $query, $results);
                        }
                    }
                }
            }
        }
    }

    \Yii::info("Number of results found: " . count($results), __METHOD__);
    return $results; // Return collected results
}


class JsonRender
{

/**
 * Check Level Two items for matches.
 */
private static function checkLevelTwo($levelTwoItems, $query, &$results)
{
    foreach ($levelTwoItems as $levelTwo) {
        // Check for Level 2
        if (isset($levelTwo['level_two'])) {
            $levelTwoData = $levelTwo['level_two'];
            $levelTwoTitle = trim($levelTwoData['title']); // Clean title
            \Yii::info("Checking level_two title: " . $levelTwoTitle, __METHOD__);

            // Check if level_two title matches
            if (stripos($levelTwoTitle, $query) !== false) {
                $results[] = $levelTwoData; // Collect sanitized level_two
                \Yii::info("Match found in level_two title: " . json_encode($levelTwoData), __METHOD__);
            }

            // Check level_two content for matches
            if (isset($levelTwoData['content']) && is_array($levelTwoData['content'])) {
                foreach ($levelTwoData['content'] as $contentItem) {
                    // Check if this content item is a string
                    if (is_string($contentItem) && stripos($contentItem, $query) !== false) {
                        $match = [
                            'title' => $levelTwoTitle,
                            'content' => $contentItem
                        ];
                        $results[] = $match; // Collect match from level_two content
                        \Yii::info("Match found in level_two content: " . json_encode($match), __METHOD__);
                    }
                    // Check for level_three if content item is an array
                    if (is_array($contentItem) && isset($contentItem['level_three'])) {
                        self::checkLevelThree($contentItem['level_three'], $query, $results);
                    }
                }
            }
        }
    }
}

/**
 * Check Level Three items for matches.
 */
private static function checkLevelThree($levelThreeItems, $query, &$results)
{
    foreach ($levelThreeItems as $levelThree) {
        if (isset($levelThree['level_three'])) {
            $levelThreeData = $levelThree['level_three'];
            $levelThreeTitle = trim($levelThreeData['title']); // Clean title
            \Yii::info("Checking level_three title: " . $levelThreeTitle, __METHOD__);

            // Check if level_three title matches
            if (stripos($levelThreeTitle, $query) !== false) {
                $results[] = $levelThreeData; // Collect sanitized level_three
                \Yii::info("Match found in level_three title: " . json_encode($levelThreeData), __METHOD__);
            }

            // Check level_three content for matches
            if (isset($levelThreeData['content']) && is_array($levelThreeData['content'])) {
                foreach ($levelThreeData['content'] as $contentItem) {
                    if (is_string($contentItem) && stripos($contentItem, $query) !== false) {
                        $match = [
                            'title' => $levelThreeTitle,
                            'content' => $contentItem
                        ];
                        $results[] = $match; // Collect match from level_three content
                        \Yii::info("Match found in level_three content: " . json_encode($match), __METHOD__);
                    }
                }
            }
        }
    }
}

    /**
     * Sanitizes HTML by allowing specified tags and attributes.
     * @param string $html The HTML to sanitize.
     * @return string The sanitized HTML.
     */
    private static function sanitizeHtml($html)
    {
        $allowedTags = '<a>,<b>,<i>,<br>,<p>,<ul>,<ol>,<li>,<img>';
        return strip_tags($html, $allowedTags);
    }
}


view:

<div class="col-12">
    <div class="search-results mt-3 mb-5"> 
        <?php if (!empty($results)): ?>
            <ul class="list-group"> 
                <?php foreach ($results as $result): ?>
                    <li class="list-group-item"> 
                        <h5><?= Html::encode($result['title'] ?? ''); ?></h5>
                        <p>
                        	<?= Html::encode(is_array($result['content']) ? implode(', ', array_map('strip_tags', $result['content'])) : $result['content']); ?>
                            <?php //Html::encode(is_array($result['content']) ? implode(', ', $result['content']) : $result['content']); ?>
                        </p>
                    </li><!-- .list-group-item -->
                <?php endforeach; ?>
            </ul><!-- .list-group -->
        <?php else: ?>
            <?php if (!empty($model->query)): // Only show if the search query is not empty ?>
                <div class="alert alert-warning" role="alert">
                    No results found for "<strong><?= Html::encode($model->query); ?></strong>".
                </div>
            <?php endif; ?>
        <?php endif; ?>
    </div><!-- .search-results .mt-3 .mb-5 -->
</div><!-- .col-12 -->