PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / trunk
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO vtrunk
2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 1.11.0 All 47 releases
thinkrank / includes / frontend / template-functions.php

template-functions.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO trunk, at includes/frontend/template-functions.php

306 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Template Functions for ThinkRank SEO
4 *
5 * Helper functions for themes to display ThinkRank SEO elements
6 *
7 * @package ThinkRank\Frontend
8 * @since 1.0.0
9 */
10
11 // Prevent direct access
12 if (!defined('ABSPATH')) {
13 exit;
14 }
15
16 /**
17 * Display ThinkRank breadcrumbs
18 *
19 * Usage in theme templates:
20 * <?php thinkrank_breadcrumbs(); ?>
21 *
22 * @since 1.0.0
23 *
24 * @param array $args Optional. Arguments to customize breadcrumb display
25 * @return void
26 */
27 function thinkrank_breadcrumbs($args = []) {
28 /**
29 * Fires to display ThinkRank breadcrumbs
30 *
31 * @since 1.0.0
32 *
33 * @param array $args Breadcrumb display arguments
34 */
35 do_action('thinkrank_breadcrumbs', $args);
36 }
37
38 /**
39 * Get ThinkRank breadcrumbs data without displaying
40 *
41 * @since 1.0.0
42 *
43 * @return array|null Breadcrumb data or null if not available
44 */
45 function thinkrank_get_breadcrumbs() {
46 // Check if ThinkRank is loaded
47 if (!function_exists('thinkrank')) {
48 return null;
49 }
50
51 $plugin = thinkrank();
52 if (!$plugin) {
53 return null;
54 }
55
56 $seo_manager = $plugin->get_component('frontend_seo');
57
58 if (!$seo_manager || !method_exists($seo_manager, 'get_current_breadcrumbs')) {
59 return null;
60 }
61
62 return $seo_manager->get_current_breadcrumbs();
63 }
64
65 /**
66 * Display the ThinkRank hero section (Site Identity → Hero & Branding)
67 *
68 * Usage in theme templates:
69 * <?php thinkrank_hero(); ?>
70 *
71 * Also available as the [thinkrank_hero] shortcode for use in content.
72 *
73 * @since 1.19.0
74 *
75 * @param array $args Optional. Reserved for future display arguments.
76 * @return void
77 */
78 function thinkrank_hero($args = []) {
79 /**
80 * Fires to display the ThinkRank hero section.
81 *
82 * @since 1.19.0
83 *
84 * @param array $args Hero display arguments.
85 */
86 do_action('thinkrank_hero', $args);
87 }
88
89 /**
90 * Get the ThinkRank hero section data without displaying it
91 *
92 * @since 1.19.0
93 *
94 * @return array|null Hero data (title, subtitle, cta_text, cta_url,
95 * background_image, html) or null if not available
96 */
97 function thinkrank_get_hero() {
98 // Check if ThinkRank is loaded
99 if (!function_exists('thinkrank')) {
100 return null;
101 }
102
103 $plugin = thinkrank();
104 if (!$plugin) {
105 return null;
106 }
107
108 $seo_manager = $plugin->get_component('frontend_seo');
109
110 if (!$seo_manager || !method_exists($seo_manager, 'get_current_hero')) {
111 return null;
112 }
113
114 return $seo_manager->get_current_hero();
115 }
116
117 /**
118 * Check if ThinkRank SEO is handling the current page
119 *
120 * @since 1.0.0
121 *
122 * @return bool True if ThinkRank is handling SEO for current page
123 */
124 function thinkrank_is_seo_active() {
125 // Check if ThinkRank is loaded
126 if (!function_exists('thinkrank')) {
127 return false;
128 }
129
130 $plugin = thinkrank();
131 if (!$plugin) {
132 return false;
133 }
134
135 $seo_manager = $plugin->get_component('frontend_seo');
136
137 if (!$seo_manager || !method_exists($seo_manager, 'has_seo_data')) {
138 return false;
139 }
140
141 return $seo_manager->has_seo_data();
142 }
143
144 /**
145 * Get current page SEO metadata
146 *
147 * @since 1.0.0
148 *
149 * @return array Current SEO metadata
150 */
151 function thinkrank_get_seo_metadata() {
152 // Check if ThinkRank is loaded
153 if (!function_exists('thinkrank')) {
154 return [];
155 }
156
157 $plugin = thinkrank();
158 if (!$plugin) {
159 return [];
160 }
161
162 $seo_manager = $plugin->get_component('frontend_seo');
163
164 if (!$seo_manager || !method_exists($seo_manager, 'get_current_metadata')) {
165 return [];
166 }
167
168 return $seo_manager->get_current_metadata();
169 }
170
171 /**
172 * Get breadcrumb inline CSS
173 *
174 * @since 1.0.0
175 *
176 * @return string CSS styles for breadcrumbs
177 */
178 function thinkrank_get_breadcrumb_css(): string {
179 return '
180 .thinkrank-breadcrumbs {
181 margin: 1rem 0;
182 font-size: 0.9rem;
183 }
184 .thinkrank-breadcrumbs .breadcrumb-prefix {
185 font-weight: 600;
186 margin-right: 0.5rem;
187 }
188 .thinkrank-breadcrumbs .breadcrumb-list {
189 list-style: none;
190 margin: 0;
191 padding: 0;
192 display: flex;
193 flex-wrap: wrap;
194 align-items: center;
195 }
196 .thinkrank-breadcrumbs .breadcrumb-item {
197 margin: 0;
198 padding: 0;
199 display: flex;
200 align-items: center;
201 }
202 .thinkrank-breadcrumbs .breadcrumb-item a {
203 color: #0073aa;
204 text-decoration: none;
205 }
206 .thinkrank-breadcrumbs .breadcrumb-item a:hover {
207 text-decoration: underline;
208 }
209 .thinkrank-breadcrumbs .breadcrumb-item.current span {
210 color: #666;
211 font-weight: 500;
212 }
213 .thinkrank-breadcrumbs .breadcrumb-separator {
214 margin: 0 0.5rem;
215 color: #999;
216 }';
217 }
218
219 // Enqueue breadcrumb styles properly if breadcrumbs are enabled
220 add_action('wp_enqueue_scripts', function() {
221 // Check if ThinkRank is loaded
222 if (!function_exists('thinkrank')) {
223 return;
224 }
225
226 $plugin = thinkrank();
227 if (!$plugin) {
228 return;
229 }
230
231 $seo_manager = $plugin->get_component('frontend_seo');
232 if (!$seo_manager) {
233 return;
234 }
235
236 // Both checks below read the site_identity settings category. Loading the
237 // full Site_Identity_Manager (115KB) on every front-end page to get them
238 // would be worse, but the two ad-hoc queries that replaced it did not share
239 // the object cache the manager populates on `wp` — so the category was
240 // fetched twice per request, uncached, on top of the manager's own read
241 // (#402).
242 //
243 // Read that cache entry directly. Abstract_SEO_Manager caches the merged
244 // settings under this key on every get_settings('site') call, and `wp` runs
245 // before wp_enqueue_scripts, so on a normal front-end render this is a hit
246 // and costs nothing. The fallback is one query for the whole category
247 // rather than two for parts of it.
248 $identity = wp_cache_get('seo_settings_site_identity_site_0', 'thinkrank_seo');
249
250 if (!is_array($identity)) {
251 global $wpdb;
252 $table = $wpdb->prefix . 'thinkrank_seo_settings';
253
254 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Lightweight frontend check avoids loading heavy manager class
255 $rows = $wpdb->get_results(
256 $wpdb->prepare(
257 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name uses WordPress prefix, safe to interpolate
258 "SELECT setting_key, setting_value FROM `{$table}` WHERE context_type = %s AND context_id = %d AND setting_category = %s AND is_active = 1",
259 'site',
260 0,
261 'site_identity'
262 ),
263 ARRAY_A
264 );
265
266 $identity = [];
267 foreach ((array) $rows as $row) {
268 $identity[$row['setting_key']] = $row['setting_value'];
269 }
270
271 // Deliberately not written back to the object cache: the manager caches
272 // the values *merged with its defaults* under this key, and seeding it
273 // with raw rows would hand every later reader a partial record.
274 }
275
276 $identity_value = static function (string $key) use ($identity): string {
277 return isset($identity[$key]) ? trim((string) $identity[$key]) : '';
278 };
279
280 if (!empty($identity['breadcrumbs_enabled'])) {
281 wp_enqueue_style(
282 'thinkrank-breadcrumbs',
283 THINKRANK_PLUGIN_URL . 'static/css/breadcrumbs.css',
284 [],
285 THINKRANK_VERSION
286 );
287 }
288
289 // Hero check — only load hero CSS when the hero will actually render.
290 // Mirrors the render gate in SEO_Manager::generate_hero_html(): a title, a
291 // subtitle, or a COMPLETE CTA (both text and URL). A CTA with text but no
292 // URL renders nothing, so it must not pull in the stylesheet.
293 $hero_renders = '' !== $identity_value('hero_title')
294 || '' !== $identity_value('hero_subtitle')
295 || ('' !== $identity_value('hero_cta_text') && '' !== $identity_value('hero_cta_url'));
296
297 if ($hero_renders) {
298 wp_enqueue_style(
299 'thinkrank-hero',
300 THINKRANK_PLUGIN_URL . 'static/css/hero.css',
301 [],
302 THINKRANK_VERSION
303 );
304 }
305 });
306