Jump to content

Calculate SEO inner links (from blog pages)


Leftfield
 Share

Recommended Posts

Posted (edited)

Hi @All, I made the page with only admin access so I can check in frontend visually (a chart) and links - what pages are most linked from blog pages and where I forgot to use this opportunity.  This is important for SEO and removes manual labor. If you have any suggestions, feel free to shoot.

Simple explanation: I got template=post and want to see stats with inner links to the homepage and service pages. Thanks @poljpocketfor helping me out!

<?php namespace ProcessWire;

// Calculate Internal Link Counts and Linked Pages 
$pages = wire('pages');

// Get all relevant pages directly in one query
$relevantPages = $pages->find("template=post|service|home");
$blogPosts = $relevantPages->find("template=post");
$mainPages = $relevantPages->find("template=home|service"); 

// Function to check if a post DOES NOT link to ANY PUBLISHED service OR home page
/** @var PageArray $mainPagesLinks */
$mainPagesLinks = $wire->wire(new PageArray());
foreach ($mainPages as $mainPage) {
    // this will remove duplicates by default
    $mainPagesLinks->append($mainPage->links("template=post"));
}

// Calculate Internal Link Counts and Linked Pages
$linkCounts = [];
$linkedPages = [];  

foreach ($relevantPages as $page) {
    $linkCounts[$page->id] = 0;
    $linkedPages[$page->id] = [];

    if ($page) {
        $items = $page->links();

        if ($items->count()) {
            foreach ($items as $item) {
                if ($item->template != 'admin') {
                    $linkCounts[$page->id]++;
                    $linkedPages[$page->id][] = $item;
                }
            }
        }
    }
}

arsort($linkCounts);

// Prepare data for the circle chart
$chartLabels = [];
$chartValues = [];
foreach ($linkCounts as $pageId => $count) {
    if ($count > 0) {
        $page = $pages->get($pageId);
        $chartLabels[] = $page->title;
        $chartValues[] = $count;
    }
}
?>

<div class="container py-5 mb-5 links">
    <div class="row py-5">
        <div class="col-12 col-md-4 offset-md-4 pb-5">            
            <canvas id="linkCountChart" width="200" height="200"></canvas>
        </div>
        <div class="col-12 col-md-8 offset-md-2">
            <div class="accordion" id="internalLinksAccordion">
            <?php foreach ($linkCounts as $pageId => $count): ?>
                <?php if ($count > 0): ?> 
                    <?php $page = $pages->get($pageId); ?>
                    <div class="accordion-item">
                        <h2 class="accordion-header" id="heading<?= $page->id ?>">
                            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse<?= $page->id ?>" aria-expanded="false" aria-controls="collapse<?= $page->id ?>">
                                <?= $page->title ?> (<?= $count ?>)
                            </button>
                        </h2>
                        <div id="collapse<?= $page->id ?>" class="accordion-collapse collapse" aria-labelledby="heading<?= $page->id ?>" data-bs-parent="#internalLinksAccordion">
                            <div class="accordion-body">
                                <?php if (!empty($linkedPages[$page->id])): ?>
                                    <ul>
                                        <?php foreach ($linkedPages[$page->id] as $linkedPage): ?>
                                            <?php if ($linkedPage->template != 'service'): ?>
                                                <li><a href="<?= $linkedPage->url ?>"><?= $linkedPage->title ?></a></li>
                                            <?php endif; ?> 
                                        <?php endforeach; ?>
                                    </ul>
                                <?php else: ?>
                                    <p>No internal links found for this page.</p>
                                <?php endif; ?>
                            </div>
                        </div>
                    </div>
                <?php endif; ?> 
            <?php endforeach; ?>
            </div>
            <h3 class="pt-5">Posts without Links to Service and Home Pages</h3>
            <table class="table">
                <thead>
                    <tr>
                        <th>Post Title</th>
                        <th>Edit Link</th>
                    </tr>
                </thead>
                <tbody>
                    <?php
                        // echo results
                        foreach ($blogPosts as $post) {
                            if (!$mainPagesLinks->has($post)) {
                                echo "<tr>";
                                echo "<td><a href=\"{$post->url}\">{$post->title}</a></td>";
                                echo "<td><a href=\"{$post->editUrl}\">Edit</a></td>";
                                echo "</tr>";
                            }
                        }
                    ?>
                </tbody>
            </table>
        </div>
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    document.addEventListener('DOMContentLoaded', function () {
        // Chart data is now defined within the JavaScript scope
        const chartData = {
            labels: <?= json_encode($chartLabels); ?>,
            datasets: [{
                data: <?= json_encode($chartValues); ?>,
                backgroundColor: [
                    'rgba(255, 99, 132, 0.8)',
                    'rgba(54, 162, 235, 0.8)',
                    'rgba(255, 206, 86, 0.8)',
                    // Add more colors as needed
                ],
            }]
        };
        const ctx = document.getElementById('linkCountChart').getContext('2d');
        const linkCountChart = new Chart(ctx, {
            type: 'doughnut', 
            data: chartData,
            options: {
                plugins: {
                    legend: {
                        display: true,
                        position: 'bottom', 
                    },
                }
            }
        });
    });
</script>

 

Edited by Leftfield
  • Like 2
Link to comment
Share on other sites

This is pretty cool - thanks for sharing!

For your color assignment, if this might help, I'd used Chart.js for a PHP-based project in the past and didn't want to have to manually assign colors, so I used the data label to dynamically generate colors for the chart. Here's the helper function I came up with. In my case, I found that the haval128,4 hashtype worked well for color differentiation/contrast, but another option may end up being slightly better with different datasets. 🙂

<?php
/**
* Convert a string into RGB array (with alpha transparency option)
*
* @param string $string Any text to be represented as color
* @param string $hashtype Hashing algorithm which supports a 32-character output
* @return array RGBA color set
*/
function string_to_rgba($string, $hashtype = 'md2') {
    // 32-char options: md2, md4, md5, ripemd128, tiger128,3, tiger128,4, haval128,3, haval128,4, haval128,5
    if (!in_array($hashtype, ['md2', 'md4', 'md5', 'ripemd128', 'tiger128,3', 'tiger128,4', 'haval128,3', 'haval128,4', 'haval128,5'])){
        $hashtype = 'md2';
    }
    $fullhash = hash($hashtype, $string);
    $hash     = substr($fullhash, 0, 8);
    $colors   = str_split($hash, 2);
    foreach ($colors as $i => $color) {
        $decimal = hexdec($color);
        if ($decimal > 230) {
            $decimal -= 25;
        } else if ($decimal < 50) {
            $decimal += 50;
        }
        $colors[$i] = $decimal;
    }
    $colors[3] = intval($colors[3] / 255 * 100);
    return $colors;
}

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...