Our full article archive from over 25 years.
Our full article archive from over 25 years.
Showing 15,408 results (page 34 of 617)
March 06, 2025 | Mark Morse
The interviews are the most important aspect of the NFL Draft Combine. Head Coach Mike Vrabel and EVP of Player Personnel Eliot Wolf were busy every night they were in Indianapolis conducting those interviews.
March 05, 2025 | Mark Morse
Free Agency starts in a few days with legal tampering allowed starting March 10th at 12 noon. Teams had to designate players as Franchise tagged by 4PM on March 4th.
March 04, 2025 | Ian Logue
It's no secret that offensive tackle was a significant problem for the New England Patriots, and it sounds like they may already have a plan in place to address it ahead of free agency.
March 02, 2025 | Steve Balestrieri
I have been able to do that and moved Ben [McAdoo] over to defense to help Terrell and his staff just look at it from an offensive perspective
February 28, 2025 | Ian Logue
We didn't see much of Trace McSorley here in New England, and it appears that after a couple of stints elsewhere, he's heading back to where he started.
February 28, 2025 | Ian Logue
For a team that's in the middle of a significant rebuild, it looks like one key Patriots personnel executive may not be a part of things moving forward.
February 27, 2025 | Ian Logue
Former New England Patriots running back Stevan Ridley apparently got off on the wrong foot with the clubduring his rookie year after arriving to the facility above the playing weight Bill Belichick had in mind for him, and one mistake he later made apparently nearly saw him let go from the team.
February 27, 2025 | Ian Logue
Former New England Patriots running back Stevan Ridley recently appeared on the Games With Names podcast with Julian Edelman, with Ridley recounting a story from when he first arrived in Foxboro after he was drafted in the third round during the 2011 Patriots Draft.
February 27, 2025 | Ian Logue
According to NFL reporter Ian Rapoport, defensive tackle Davon Godchaux has been given permission by the team to seek a trade. This news comes after Godchaux signed an extension last offseason, signing a two-year deal back on July 31, 2024.
February 27, 2025 | Ian Logue
While the D- owner Robert Kraft received in the Patriots 2025 NFLPA Report Card was a big point of discussion on Wednesday, what's going down in New Jersey should make all of that pale in comparison.
February 26, 2025 | Ian Logue
One of the biggest questions being asked since Mike Vrabel was hired last month has been where things will stand when it comes to personnel for the New England Patriots.
February 26, 2025 | Ian Logue
It's been a while since Eliot Wolf spoke to the media, and the Patriots personnel man took a long look back at last season and came pointing the finger at himself after a tough finish.
February 26, 2025 | Ian Logue
Here's what New England Patriots Executive Vice President of Player Personnel Eliot Wolf had to say during his press conference on Wednesday down at the NFL Scouting Combine in Indianapolis.
February 26, 2025 | Ian Logue
The NFLPA released its report card for 2025, and once again, the Patriots found themselves at the bottom of the rankings compared to their peers.
February 26, 2025 | Ian Logue
Mike Vrabel is taking charge of the New England Patriots' roster decisions heading into the 2025 offseason. With a clear vision for free agency and the draft, Vrabel is working alongside Eliot Wolf and Ryan Cowden to reshape the team. Find out how the new power structure is influencing the Patriots’ offseason strategy, potential free-agent targets, and Vrabel’s approach to building a competitive roster.
February 25, 2025 | Ian Logue
Mike Vrabel held his press conference earlier this morning, and he sat down for another Q&A session with the local media later in the day. Here's a full transcript from that session.
February 25, 2025 | Ian Logue
With NFL Free Agency just weeks away, the big question is going to be just how much of a splash the Patriots are able to make coming off of two straight 4-13 seasons.
February 25, 2025 | Ian Logue
Here's the full transcript from New England Patriots head coach, Mike Vrabel's press conference on Tuesday down in Indianapolis.
February 25, 2025 | Mark Morse
The NFL Combine is held at Lucas Oil Stadium In Indianapolis and is an opportunity for the top NFL draft prospects in this year’s class to go through measurements, medical physicals, and various on-field drills, some of which are specific to their position group, others measure the player’s overall athleticism.
February 24, 2025 | Steve Balestrieri
Matt Miller said on “X”: “For me, it's Abdul Carter 1st overall and then there's a gap to every other prospect in this class.”
February 23, 2025 | Ian Logue
This is certainly a big week coming up for the New England Patriots, with the NFL Scouting Combine set to begin on February 27th, allowing for a first glimpse of some of the candidates that will be available in this year's upcoming NFL Draft. In this morning's Patriots' news article, we look at what's ahead for Mike Vrabel, along with potential Patriots trade rumors that could see Rhamondre Stevenson's future in question heading into 2025.
February 21, 2025 | Ian Logue
Drake Maye hasn't been in New England very long, but he seems to have one thing in common with the fans here locally. He's a big fan of the red old-school throwback uniforms.
February 21, 2025 | Ian Logue
Patriots quarterback Drake Maye appeared with Chris Long on the "Green Light" podcast recently, and was asked about which players he expected to potentially step up in 2025.
February 21, 2025 | Ian Logue
Rookie quarterback Drake Maye talked about what life was like for him in his first season with the New England Patriots during a recent appearance with Chris Long on the Green Light podcast.
February 21, 2025 | Ian Logue
New England Patriots quarterback Drake Maye recently appeared on the Green Light podcast with Chris Long, with Maye talking about his rookie season along with giving some good insight on some other stuff as well.
Error: ' + self.escapeHtml(json.message) + '
'; } }).catch(function(e) { self.setLoading(false); console.error(e); }); }, renderSocialPack: function(data) { var self = this; this.socialEl.innerHTML = 'Error: ' + self.escapeHtml(json.message) + '
'; } }).catch(function(e) { self.setLoading(false); console.error(e); }); }, runTitles: function(editor, forceRefresh) { var self = this; var contentHtml = this.getSafeContent(editor); var title = (document.getElementById('title') || {}).value || ''; this.showResults('titles'); this.setLoading(true); fetch(PFEAI.rest_url + 'seo-titles?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ content: contentHtml, title: title, post_id: PFEAI.post_id, provider: this.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}).then(function(json){ self.setLoading(false); if(json.titles) { self.renderTitles(json); var timestamp = json.generated_at || Date.now()/1000; self.setCachedState('btn-titles', 'View Titles', 'titles', timestamp, json.from_cache); self.startCacheWindow(json.from_cache); } else if (json.code) { self.titlesEl.innerHTML = 'Error: ' + self.escapeHtml(json.message) + '
'; } }); }, runTranscriptScan: function(editor, forceRefresh) { var self = this; var contentText = this.getSafeText(editor); if (contentText.length < 50) { alert('Please paste transcript.'); return; } this.showResults('transcript'); this.setLoading(true); fetch(PFEAI.rest_url + 'transcript-scan?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ content: contentText, post_id: PFEAI.post_id, provider: this.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}) .then(function(json){ self.setLoading(false); console.log('Transcript scan response:', json); // Handle the response - could be {suggestions: [...]} or a single object or bad cache var suggestions = null; if (json.suggestions && Array.isArray(json.suggestions)) { // Correct format: {suggestions: [{...}, {...}]} suggestions = json.suggestions; } else if (json.title && json.context) { // Bad format: single object at root (legacy cache issue) // Wrap it in an array suggestions = [json]; console.warn('Transcript response was single object, wrapped in array. Consider clearing cache.'); } if (suggestions && suggestions.length > 0) { self.renderTranscriptSuggestions(suggestions, contentText); var timestamp = json.generated_at || Date.now()/1000; self.setCachedState('btn-transcript', 'View Transcript Results', 'transcript', timestamp, json.from_cache); self.startCacheWindow(json.from_cache); } else if (json.code) { self.transcriptEl.innerHTML = 'Error: ' + self.escapeHtml(json.message) + '
'; } else { console.error('Unexpected transcript response:', json); self.transcriptEl.innerHTML = 'Unexpected response format. Please click "Rescan" to refresh.
'; } }) .catch(function(err) { self.setLoading(false); console.error('Transcript scan error:', err); self.transcriptEl.innerHTML = 'Request failed: ' + self.escapeHtml(err.message) + '
'; }); }, /** * IMPROVED: Added better error handling and timeout management for transcript outline */ runTranscriptOutline: function(title, content, clickedCard) { var self = this; var resDiv = document.getElementById('pfeai-transcript-result'); // Show loading state with timeout warning resDiv.innerHTML = 'Generating outline...
This may take up to 30 seconds for longer transcripts.
'; // Validate inputs if (!title) { resDiv.innerHTML = 'Error: No headline selected. Please click a headline above.
'; return; } if (!content || content.length < 50) { resDiv.innerHTML = 'Error: Transcript content is too short or missing.
'; return; } // Create abort controller for timeout var controller = new AbortController(); var timeoutId = setTimeout(function() { controller.abort(); }, 180000); // 3 minute timeout (matching server timeout) fetch(PFEAI.rest_url + 'transcript-outline?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ selected_title: title, content: content, provider: this.getProvider() }), signal: controller.signal }) .then(function(r) { clearTimeout(timeoutId); if (!r.ok) { throw new Error('Server returned status ' + r.status); } return r.json(); }) .then(function(json) { console.log('Transcript outline response:', json); // Check for error response if (json.code) { resDiv.innerHTML = 'Error: ' + self.escapeHtml(json.message) + '
Try selecting a different headline or click Rescan.
'; return; } // Check for required field (blurb) if (json.blurb) { self.renderTranscriptOutlineResult(json, title); } else { console.error('Missing blurb in response:', json); resDiv.innerHTML = 'AI response was incomplete. Please try again.
Response received but missing required content.
'; } }) .catch(function(err) { clearTimeout(timeoutId); console.error('Transcript outline error:', err); var errorMsg = 'Error generating outline.'; if (err.name === 'AbortError') { errorMsg = 'Request timed out. The transcript may be too long.'; } else if (err.message) { errorMsg = err.message; } resDiv.innerHTML = '' + self.escapeHtml(errorMsg) + '
Try again or select a different headline.
'; }); }, runArticleIdeas: function(editor, forceRefresh) { var self = this; var title = (document.getElementById('title') || {}).value || ''; var contentText = this.getSafeText(editor).trim(); // Only block if not forcing refresh AND there's content if (!forceRefresh && (title.length > 0 || contentText.length > 5)) { alert('To generate fresh Topic Inspiration, please clear the Title and Content editor first.'); return; } this.showResults('ideas'); this.setLoading(true); // Function to fetch new ideas var fetchIdeas = function() { fetch(PFEAI.rest_url + 'article-ideas?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ title: '', post_id: PFEAI.post_id, provider: self.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}).then(function(json){ self.setLoading(false); if(json.ideas) { self.renderIdeasInteractive(json); self.setCachedState('btn-ideas', 'View Topics', 'ideas', Date.now()/1000); } else if (json.code) { self.ideasEl.innerHTML = 'Error: ' + self.escapeHtml(json.message) + '
'; } }).catch(function(e) { self.setLoading(false); console.error(e); }); }; // If forcing refresh, clear cache first, then fetch new ideas if (forceRefresh) { fetch(PFEAI.rest_url + 'clear-ideas-cache?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ post_id: PFEAI.post_id }) }) .then(function() { fetchIdeas(); }) .catch(function() { fetchIdeas(); }); // Still try to fetch even if clear fails } else { fetchIdeas(); } }, /** * IMPROVED: Added better error handling for idea outline */ runIdeaOutline: function(title, context) { var self = this; var resDiv = document.getElementById('pfeai-idea-result'); if(!resDiv) return; resDiv.innerHTML = 'Drafting outline...
This may take up to 30 seconds.
'; // Create abort controller for timeout var controller = new AbortController(); var timeoutId = setTimeout(function() { controller.abort(); }, 180000); // 3 minute timeout fetch(PFEAI.rest_url + 'idea-outline?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ idea_title: title, context: context, provider: this.getProvider() }), signal: controller.signal }) .then(function(r) { clearTimeout(timeoutId); if (!r.ok) { throw new Error('Server returned status ' + r.status); } return r.json(); }) .then(function(json) { console.log('Idea outline response:', json); if (json.code) { resDiv.innerHTML = 'Error: ' + self.escapeHtml(json.message) + '
'; return; } if(json.blurb) { self.renderIdeaOutlineResult(json, title); } else { resDiv.innerHTML = 'AI response was incomplete. Please try again.
'; } }) .catch(function(err) { clearTimeout(timeoutId); console.error('Idea outline error:', err); var errorMsg = 'Error generating outline.'; if (err.name === 'AbortError') { errorMsg = 'Request timed out. Please try again.'; } else if (err.message) { errorMsg = err.message; } resDiv.innerHTML = '' + self.escapeHtml(errorMsg) + '
'; }); }, runTagline: function(editor) { var self = this; var c = this.getSafeContent(editor); var t = (document.getElementById('title') || {}).value || ''; if (!t) { alert('Enter title first'); return; } // Debug logging console.log('PFEAI Tagline: Content length = ' + c.length); // Show loading state on button var btn = this.panelEl.querySelector('.pfeai-tagline-btn'); var originalText = btn ? btn.textContent : ''; if (btn) { btn.disabled = true; btn.innerHTML = ' Thinking...'; } fetch(PFEAI.rest_url + 'generate-tagline?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body:JSON.stringify({content:c, title:t, provider: this.getProvider()}) }) .then(function(r){ console.log('PFEAI Tagline: Response status = ' + r.status); return r.json(); }) .then(function(j){ console.log('PFEAI Tagline: Response = ', j); // Restore button state if (btn) { btn.disabled = false; btn.textContent = originalText; } if(j.tagline) { document.getElementById('pftwt_tagline').value = j.tagline; self.startCacheWindow(false); // API call was made } else if (j.code) { alert('Error: ' + j.message); } else { console.warn('PFEAI Tagline: No tagline in response', j); alert('No tagline was generated. Please try again.'); } }) .catch(function(e) { console.error('PFEAI Tagline: Error = ', e); // Restore button state on error if (btn) { btn.disabled = false; btn.textContent = originalText; } alert('Error: ' + e.message); }); }, runTagSuggestions: function(editor) { var self = this; var c = this.getSafeContent(editor); var t = (document.getElementById('title') || {}).value || ''; // Debug: log content length console.log('PFEAI Tags: Content length = ' + c.length + ', Title = ' + t); if (!c || c.length < 50) { alert('Please add more content before generating tags.'); return; } // Show loading state on button var btn = this.panelEl.querySelector('.pfeai-tags-btn'); var originalText = btn ? btn.textContent : ''; if (btn) { btn.disabled = true; btn.innerHTML = ' Thinking...'; } fetch(PFEAI.rest_url + 'suggest-tags?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body:JSON.stringify({content:c, title:t, provider: this.getProvider()}) }) .then(function(r){ console.log('PFEAI Tags: Response status = ' + r.status); return r.json(); }) .then(function(j){ console.log('PFEAI Tags: Response = ', j); // Restore button state if (btn) { btn.disabled = false; btn.textContent = originalText; } // Check for error response if (j.code) { alert('Error generating tags: ' + (j.message || j.code)); return; } if(j.tags && j.tags.length > 0 && jQuery) { var $ = jQuery; var tagsAdded = 0; var tagBox = $('#post_tag'); // Method 1: Use WordPress tagBox API if available if (window.tagBox && typeof window.tagBox.flushTags === 'function') { var $input = $('#new-tag-post_tag'); j.tags.forEach(function(tag) { $input.val(tag); // Trigger the tag addition window.tagBox.flushTags(tagBox, false, 1); tagsAdded++; }); } else { // Method 2: Manually add tags and trigger events var $input = $('#new-tag-post_tag'); var $addBtn = $('#post_tag .tagadd'); j.tags.forEach(function(tag, index) { // Small delay between additions to let WordPress process each one setTimeout(function() { $input.val(tag); $addBtn.trigger('click'); // Also try triggering the keypress enter event as backup var e = $.Event('keypress'); e.which = 13; // Enter key $input.trigger(e); tagsAdded++; // On last tag, show success message if (index === j.tags.length - 1) { setTimeout(function() { // Force refresh the tag cloud display if (window.tagBox && typeof window.tagBox.get === 'function') { window.tagBox.get('post_tag'); } console.log('PFEAI Tags: Added ' + j.tags.length + ' tags'); }, 100); } }, index * 50); // 50ms delay between each tag }); } self.startCacheWindow(false); // API call was made // Show feedback to user if (btn) { btn.textContent = 'Added ' + j.tags.length + ' tags!'; setTimeout(function() { btn.textContent = originalText; }, 2000); } console.log('PFEAI Tags: Added ' + j.tags.length + ' tags'); } else { console.warn('PFEAI Tags: No tags returned or empty array', j); alert('No tags were generated. Please try again.'); } }) .catch(function(e) { console.error('PFEAI Tags: Error = ', e); // Restore button state on error if (btn) { btn.disabled = false; btn.textContent = originalText; } alert('Error: ' + e.message); }); }, /** * Run Meta Description from the main menu button * Shows loading on the menu button and navigates to SEO tab with result */ runMetaDescFromMenu: function(editor) { var self = this; var title = (document.getElementById('title') || {}).value || ''; var content = this.getSafeContent(editor); if (!title && !content) { alert('Please add a title or content first.'); return; } // Show loading state on the menu button var btn = this.panelEl.querySelector('.pfeai-meta-btn'); var originalText = btn ? btn.textContent : ''; if (btn) { btn.disabled = true; btn.innerHTML = ' Thinking...'; } fetch(PFEAI.rest_url + 'generate-meta-desc?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body: JSON.stringify({content: content, title: title, provider: this.getProvider()}) }) .then(function(r){return r.json()}) .then(function(j){ // Restore button state if (btn) { btn.disabled = false; btn.textContent = originalText; } if(j.meta_description) { // Navigate to SEO tab and show result self.showResults('seo'); // Fill in the meta description textarea var textarea = document.getElementById('pfeai-meta-description'); if (textarea) { textarea.value = j.meta_description; self.updateSerpPreview(); } self.startCacheWindow(false); // API call was made // Show success feedback on button briefly if (btn) { btn.textContent = 'Generated!'; setTimeout(function() { btn.textContent = originalText; }, 2000); } } else if (j.code) { alert('Error: ' + j.message); } else { alert('No meta description was generated. Please try again.'); } }) .catch(function(e) { // Restore button state on error if (btn) { btn.disabled = false; btn.textContent = originalText; } console.error('PFEAI Meta Desc: Error = ', e); alert('Error: ' + e.message); }); }, runMetaDescription: function() { var self = this; var title = (document.getElementById('title') || {}).value || ''; var content = this.getSafeContent(tinymce.activeEditor); if (!title && !content) { alert('Please add a title or content first.'); return; } var btn = document.getElementById('pfeai-generate-meta-btn'); if (btn) { btn.textContent = 'Generating...'; btn.disabled = true; } fetch(PFEAI.rest_url + 'generate-meta-desc?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body: JSON.stringify({content: content, title: title, provider: this.getProvider()}) }) .then(function(r){return r.json()}) .then(function(j){ if (btn) { btn.innerHTML = '✨ Generate New Meta Description'; btn.disabled = false; } if(j.meta_description) { var textarea = document.getElementById('pfeai-meta-description'); if (textarea) { textarea.value = j.meta_description; self.updateSerpPreview(); } self.startCacheWindow(false); // API call was made } else if (j.code) { alert('Error: ' + j.message); } }) .catch(function(e) { if (btn) { btn.innerHTML = '✨ Generate New Meta Description'; btn.disabled = false; } console.error(e); }); }, runFAQ: function(editor) { var self = this; var c = this.getSafeContent(editor); var t = (document.getElementById('title') || {}).value || ''; if (!c || c.length < 100) { alert('Please write or paste the article content first so the AI can generate accurate FAQs.'); return; } this.showResults('faq'); this.setLoading(true); fetch(PFEAI.rest_url + 'generate-faq?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body: JSON.stringify({content: c, title: t, provider: this.getProvider()}) }) .then(function(r){ return r.json(); }) .then(function(j){ self.setLoading(false); if(j.faq && j.faq.length > 0) { self.renderFAQ(j.faq, editor); self.startCacheWindow(false); } else if (j.code) { self.faqEl.innerHTML = 'Error: ' + self.escapeHtml(j.message) + '
'; } else { self.faqEl.innerHTML = 'Failed to generate FAQ. Please try again.
'; } }) .catch(function(e) { self.setLoading(false); self.faqEl.innerHTML = 'Error: ' + self.escapeHtml(e.message) + '
'; }); }, renderFAQ: function(faqData, editor) { var self = this; if (!this.faqEl) return; this.faqEl.innerHTML = ''; var header = document.createElement('h4'); header.style.margin = '0 0 10px 0'; header.textContent = 'Review & Edit FAQ'; this.faqEl.appendChild(header); var instruction = document.createElement('p'); instruction.style.fontSize = '11px'; instruction.style.color = '#666'; instruction.textContent = 'Review your FAQs below. Clicking the button will send them down to the "Article FAQ & Schema" box at the bottom of your post screen. Remember to click the WordPress Update/Publish button to save them!'; this.faqEl.appendChild(instruction); var faqContainer = document.createElement('div'); faqContainer.id = 'pfeai-faq-inputs-container'; // Build editable inputs for each Q&A in the sidebar faqData.forEach(function(item, index) { var box = document.createElement('div'); box.style.background = '#fff'; box.style.padding = '10px'; box.style.marginBottom = '10px'; box.style.border = '1px solid #ddd'; box.style.borderRadius = '4px'; var qLabel = document.createElement('strong'); qLabel.style.fontSize = '11px'; qLabel.textContent = 'Question ' + (index + 1); box.appendChild(qLabel); var qInput = document.createElement('input'); qInput.type = 'text'; qInput.className = 'pfeai-faq-q'; qInput.style.width = '100%'; qInput.style.marginBottom = '8px'; qInput.value = item.question || ''; box.appendChild(qInput); var aLabel = document.createElement('strong'); aLabel.style.fontSize = '11px'; aLabel.textContent = 'Answer ' + (index + 1); box.appendChild(aLabel); var aInput = document.createElement('textarea'); aInput.className = 'pfeai-faq-a'; aInput.style.width = '100%'; aInput.style.height = '50px'; aInput.style.fontSize = '12px'; aInput.value = item.answer || ''; box.appendChild(aInput); faqContainer.appendChild(box); }); this.faqEl.appendChild(faqContainer); // The Button to transfer text to the Meta Box var insertBtn = document.createElement('button'); insertBtn.type = 'button'; insertBtn.className = 'button button-primary'; insertBtn.style.width = '100%'; insertBtn.innerHTML = '↓ Send to FAQ Meta Box'; insertBtn.onclick = function() { var qInputs = faqContainer.querySelectorAll('.pfeai-faq-q'); var aInputs = faqContainer.querySelectorAll('.pfeai-faq-a'); var transferCount = 0; for (var i = 0; i < qInputs.length; i++) { var qText = qInputs[i].value.trim(); var aText = aInputs[i].value.trim(); // Locate the PHP Meta Box inputs on the main post screen var metaQ = document.getElementById('pfeai_meta_q_' + i); var metaA = document.getElementById('pfeai_meta_a_' + i); if (metaQ && metaA) { metaQ.value = qText; metaA.value = aText; if (qText && aText) transferCount++; } } if (transferCount === 0) { alert('Could not locate the FAQ Meta Box on the screen. Please ensure "Article FAQ & Schema" is checked in your Screen Options at the top right.'); return; } insertBtn.innerHTML = '✓ Sent to Meta Box!'; setTimeout(function() { insertBtn.innerHTML = '↓ Send to FAQ Meta Box'; }, 2000); }; this.faqEl.appendChild(insertBtn); }, updateSerpPreview: function(selectedTitle) { var titleEl = document.getElementById('pfeai-serp-title'); var descEl = document.getElementById('pfeai-serp-desc'); var charCount = document.getElementById('pfeai-meta-char-count'); var titleCharNote = document.getElementById('pfeai-title-char-note'); var metaTextarea = document.getElementById('pfeai-meta-description'); // Update title if provided if (selectedTitle && titleEl) { titleEl.textContent = selectedTitle; // Truncate if too long (Google truncates around 60 chars) if (selectedTitle.length > 60) { titleEl.textContent = selectedTitle.substring(0, 57) + '...'; } } // Update title character count if (titleCharNote && titleEl) { var currentTitle = selectedTitle || titleEl.textContent; if (currentTitle === '(Select a title above)') currentTitle = ''; var titleLen = currentTitle.length; var titleColor = titleLen <= 60 ? '#2e7d32' : '#c62828'; titleCharNote.innerHTML = 'Title: ' + titleLen + '/60 chars ' + (titleLen <= 60 ? '✓' : '(may be truncated)'); } // Update description if (metaTextarea && descEl) { var desc = metaTextarea.value; if (desc) { descEl.textContent = desc.length > 155 ? desc.substring(0, 152) + '...' : desc; } else { descEl.textContent = '(Enter a meta description above)'; } } // Update character count with color coding if (metaTextarea && charCount) { var len = metaTextarea.value.length; var color = '#666'; var status = ''; if (len === 0) { color = '#666'; } else if (len < 120) { color = '#e65100'; // Orange - too short status = ' (too short)'; } else if (len >= 120 && len <= 155) { color = '#2e7d32'; // Green - optimal status = ' ✓ optimal'; } else if (len > 155 && len <= 160) { color = '#e65100'; // Orange - slightly long status = ' (slightly long)'; } else { color = '#c62828'; // Red - too long status = ' (will be truncated)'; } charCount.innerHTML = '' + len + ' / 155 characters' + status + ''; } }, saveToClipboard: function(title, html, redirectToNew) { fetch(PFEAI.rest_url + 'save-clipboard?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ title: title, content: html }) }) .then(function(){ if (redirectToNew) { // Redirect to new post page window.open('/patriots/blog/wp-admin/post-new.php', '_blank'); } else { alert('Saved! You can now access this draft in the "Saved" tab on any new post.'); location.reload(); } }); }, clearClipboard: function() { fetch(PFEAI.rest_url + 'clear-clipboard?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce } }) .then(function(r) { return r.json(); }) .then(function(json) { if (json.success) { alert('Saved draft cleared.'); location.reload(); } }) .catch(function(e) { console.error(e); }); }, clearIdeasCache: function() { fetch(PFEAI.rest_url + 'clear-ideas-cache?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ post_id: PFEAI.post_id }) }) .then(function(r) { return r.json(); }) .then(function(json) { if (json.success) { alert('Topics cache cleared.'); location.reload(); } }) .catch(function(e) { console.error(e); }); }, togglePanel: function(forceState) { if (!this.panelEl) return; var open = this.panelEl.classList.contains('pfeai-open'); var shouldOpen = (typeof forceState === 'boolean') ? forceState : !open; if (shouldOpen) { this.panelEl.classList.add('pfeai-open'); document.body.classList.add('pfeai-panel-open'); this.updateTranscriptVisibility(); if (this.isMinimized) document.body.classList.add('pfeai-panel-minimized'); else document.body.classList.remove('pfeai-panel-minimized'); } else { this.panelEl.classList.remove('pfeai-open'); document.body.classList.remove('pfeai-panel-open'); } }, showMenu: function() { this.panelEl.classList.remove('pfeai-show-results'); }, showResults: function(activeTab) { this.panelEl.classList.add('pfeai-show-results'); if (activeTab) this.switchTab(activeTab); }, updateTranscriptVisibility: function() { var isTranscript = false; var labels = document.querySelectorAll('.categorychecklist label'); for (var i = 0; i < labels.length; i++) { if (labels[i].innerText.indexOf('Patriots Transcripts') !== -1) { var input = labels[i].querySelector('input[type="checkbox"]'); if (input && input.checked) isTranscript = true; } } var btn = document.getElementById('btn-transcript'); var tab = document.getElementById('tab-transcript'); if (isTranscript) { if (btn) btn.style.display = 'block'; if (tab) tab.style.display = 'inline-block'; } else { if (btn) btn.style.display = 'none'; if (tab) tab.style.display = 'none'; } }, preloadSavedData: function() { if (!PFEAI.saved_data) return; if (PFEAI.saved_data.transcript && PFEAI.saved_data.transcript.suggestions) { this.renderTranscriptSuggestions(PFEAI.saved_data.transcript.suggestions, ''); this.setCachedState('btn-transcript', 'View Transcript Results', 'transcript', PFEAI.saved_data.transcript.generated_at); } if (PFEAI.saved_data.analysis && PFEAI.saved_data.analysis.highlights) { this.renderAnalysis(PFEAI.saved_data.analysis); this.setCachedState('btn-scan', 'View Analysis Results', 'highlights', PFEAI.saved_data.analysis.generated_at); } if (PFEAI.saved_data.titles && PFEAI.saved_data.titles.titles) { this.renderTitles(PFEAI.saved_data.titles); this.setCachedState('btn-titles', 'View Titles', 'titles', PFEAI.saved_data.titles.generated_at); } if (PFEAI.saved_data.ideas && PFEAI.saved_data.ideas.ideas) { this.renderIdeasInteractive(PFEAI.saved_data.ideas); this.setCachedState('btn-ideas', 'View Topics', 'ideas', PFEAI.saved_data.ideas.generated_at); } if (PFEAI.saved_data.social && PFEAI.saved_data.social.tweets) { this.renderSocialPack(PFEAI.saved_data.social); this.setCachedState('btn-social', 'View Social Posts', 'social', PFEAI.saved_data.social.generated_at); } if (PFEAI.saved_data.clipboard && this.savedEl) { this.renderSavedDraft(PFEAI.saved_data.clipboard); } if (PFEAI.saved_data.fact_check && PFEAI.saved_data.fact_check.factChecks) { this.renderFacts(PFEAI.saved_data.fact_check.factChecks); this.setCachedState('btn-fact-check', 'View Fact Check', 'facts', PFEAI.saved_data.fact_check.generated_at); } if (PFEAI.saved_data.links && PFEAI.saved_data.links.links) { this.renderInternalLinks(PFEAI.saved_data.links, null); this.setCachedState('btn-internal-links', '\uD83D\uDD17 View Links', 'links', PFEAI.saved_data.links.generated_at); } // Always render the SEO tab this.renderSeoTab(); // Render the Search Insights data this.renderGSCPanel(); }, setCachedState: function(btnId, newText, tabName, timestamp) { var btn = document.getElementById(btnId); if (btn) { if (btnId === 'btn-transcript' || btnId === 'btn-ideas' || btnId === 'btn-social') { btn.innerHTML = '' + this.escapeHtml(newText) + '' + self.escapeHtml(p) + '
'; }).join('\n'); tinymce.activeEditor.insertContent(html); insertDraftsBtn.textContent = 'Inserted!'; setTimeout(function() { insertDraftsBtn.textContent = 'Insert All Drafts into Editor'; }, 1500); } }; draftsDiv.appendChild(insertDraftsBtn); // Copy all drafts button var copyDraftsBtn = document.createElement('button'); copyDraftsBtn.type = 'button'; copyDraftsBtn.className = 'button button-small'; copyDraftsBtn.style.marginTop = '8px'; copyDraftsBtn.textContent = 'Copy All Drafts'; copyDraftsBtn.onclick = function() { var allDrafts = (data.draft_paragraphs || []).join('\n\n'); navigator.clipboard.writeText(allDrafts); copyDraftsBtn.textContent = 'Copied!'; setTimeout(function() { copyDraftsBtn.textContent = 'Copy All Drafts'; }, 1500); }; draftsDiv.appendChild(copyDraftsBtn); container.appendChild(draftsDiv); } var kpLabel = document.createElement('strong'); kpLabel.textContent = 'Key Points:'; container.appendChild(kpLabel); var kpList = document.createElement('ul'); kpList.className = 'pfeai-list'; (data.key_points || []).forEach(function(pt) { var li = document.createElement('li'); li.textContent = pt; // SECURITY: textContent escapes HTML kpList.appendChild(li); }); container.appendChild(kpList); var sparkDiv = document.createElement('div'); sparkDiv.style.marginTop = '10px'; sparkDiv.style.borderTop = '1px solid #eee'; sparkDiv.style.paddingTop = '10px'; var sparkLabel = document.createElement('strong'); sparkLabel.textContent = 'Spark Sentences:'; sparkDiv.appendChild(sparkLabel); var sparkText = (data.spark_sentences || []).join('\n\n'); var textarea = document.createElement('textarea'); textarea.id = 'pfeai-spark-text'; textarea.style.width = '100%'; textarea.style.height = '100px'; textarea.style.fontSize = '12px'; textarea.style.marginTop = '5px'; textarea.value = sparkText; // SECURITY: .value doesn't execute HTML sparkDiv.appendChild(textarea); var btnDiv = document.createElement('div'); btnDiv.style.marginTop = '8px'; btnDiv.style.display = 'flex'; btnDiv.style.gap = '10px'; var insertBtn = document.createElement('button'); insertBtn.type = 'button'; insertBtn.className = 'button button-small button-primary'; insertBtn.id = 'pfeai-insert-spark'; insertBtn.textContent = 'Insert into Editor'; btnDiv.appendChild(insertBtn); var saveBtn = document.createElement('button'); saveBtn.type = 'button'; saveBtn.className = 'button button-small'; saveBtn.style.background = '#e8f5e9'; saveBtn.style.color = '#2e7d32'; saveBtn.style.borderColor = '#66bb6a'; saveBtn.id = 'pfeai-save-clipboard'; saveBtn.innerHTML = '📝 Start New Post →'; btnDiv.appendChild(saveBtn); sparkDiv.appendChild(btnDiv); container.appendChild(sparkDiv); resDiv.innerHTML = ''; resDiv.appendChild(container); resDiv.scrollIntoView({behavior:'smooth'}); // Bind events insertBtn.onclick = function(){ var wt = document.getElementById('title'); if(wt) { wt.value = title; wt.focus(); var pt = document.getElementById('title-prompt-text'); if(pt) pt.classList.add('screen-reader-text'); } if(typeof tinymce !== 'undefined' && tinymce.activeEditor) { var t = document.getElementById('pfeai-spark-text').value; tinymce.activeEditor.insertContent('' + self.escapeHtml(t).replace(/\n\n/g, '
') + '
'); } }; saveBtn.onclick = function(){ var fullHTML = ''; if(data.blurb) fullHTML += 'Blurb: ' + self.escapeHtml(data.blurb) + '
'; // Include key quotes in saved draft if(data.key_quotes && data.key_quotes.length) { fullHTML += 'Key Quotes:
Draft Paragraphs:
'; data.draft_paragraphs.forEach(function(p){ fullHTML += '' + self.escapeHtml(p) + '
'; }); } if(data.key_points && data.key_points.length) { fullHTML += 'Key Points:
' + self.escapeHtml(sparkVal).replace(/\n\n/g, '
') + '
'; // Save and redirect to new post self.saveToClipboard(title, fullHTML, true); }; }, /** * SECURITY FIX: renderIdeasInteractive now uses proper escaping */ renderIdeasInteractive: function(data) { var self = this; this.ideasEl.innerHTML = ''; var h3 = document.createElement('h3'); h3.textContent = 'Topic Inspiration'; this.ideasEl.appendChild(h3); var p = document.createElement('p'); p.style.fontSize = '11px'; p.style.marginBottom = '10px'; p.textContent = 'Click a topic to generate an outline.'; this.ideasEl.appendChild(p); (data.ideas || []).forEach(function(i) { var c = document.createElement('div'); c.className = 'pfeai-card pfeai-clickable'; c.style.cursor = 'pointer'; c.style.borderLeftColor = '#8e44ad'; var h = document.createElement('h4'); h.style.margin = '0 0 4px 0'; h.style.color = '#8e44ad'; h.textContent = i.title; // SECURITY: textContent escapes HTML c.appendChild(h); var pEl = document.createElement('p'); pEl.style.fontSize = '12px'; pEl.textContent = i.context || i.angle || ''; // SECURITY: textContent escapes HTML c.appendChild(pEl); var sr = document.createElement('div'); sr.className = 'pfeai-score-row'; sr.style.marginTop = '6px'; sr.style.borderTop = '1px solid #eee'; sr.style.paddingTop = '4px'; sr.innerHTML = 'Trend: ' + parseInt(i.trend_score || i.ctr_score || 0, 10) + 'Disc: ' + parseInt(i.discover_score || 0, 10) + ''; c.appendChild(sr); (function(title, context) { c.addEventListener('click', function() { self.runIdeaOutline(title, context); }); })(i.title, i.context); self.ideasEl.appendChild(c); }); var rd = document.createElement('div'); rd.id = 'pfeai-idea-result'; rd.style.marginTop = '15px'; rd.style.borderTop = '1px solid #ccc'; rd.style.paddingTop = '10px'; this.ideasEl.appendChild(rd); }, /** * SECURITY FIX: renderIdeaOutlineResult now uses proper escaping */ renderIdeaOutlineResult: function(data, title) { var self = this; var resDiv = document.getElementById('pfeai-idea-result'); // Build DOM elements instead of innerHTML for safety var container = document.createElement('div'); container.style.background = '#fff'; container.style.padding = '10px'; container.style.border = '1px solid #ddd'; container.style.marginTop = '10px'; var h3 = document.createElement('h3'); h3.style.marginTop = '0'; h3.style.color = '#8e44ad'; h3.textContent = title; // SECURITY: textContent escapes HTML container.appendChild(h3); var blurbLabel = document.createElement('strong'); blurbLabel.textContent = 'Blurb:'; container.appendChild(blurbLabel); var blurbP = document.createElement('p'); blurbP.textContent = data.blurb || ''; // SECURITY: textContent escapes HTML container.appendChild(blurbP); // DRAFT PARAGRAPHS SECTION if (data.draft_paragraphs && data.draft_paragraphs.length > 0) { var draftsDiv = document.createElement('div'); draftsDiv.style.marginTop = '12px'; draftsDiv.style.marginBottom = '12px'; draftsDiv.style.padding = '10px'; draftsDiv.style.background = '#f3e5f5'; draftsDiv.style.borderLeft = '4px solid #9c27b0'; draftsDiv.style.borderRadius = '4px'; var draftsLabel = document.createElement('strong'); draftsLabel.style.display = 'block'; draftsLabel.style.marginBottom = '8px'; draftsLabel.style.color = '#7b1fa2'; draftsLabel.innerHTML = '✍ Draft Paragraphs:'; draftsDiv.appendChild(draftsLabel); var paragraphLabels = ['Opening', 'Middle/Analysis', 'Context/Closing']; (data.draft_paragraphs || []).forEach(function(para, idx) { var paraContainer = document.createElement('div'); paraContainer.style.marginBottom = '12px'; paraContainer.style.padding = '8px'; paraContainer.style.background = '#fff'; paraContainer.style.borderRadius = '4px'; paraContainer.style.border = '1px solid #e1bee7'; var paraLabel = document.createElement('div'); paraLabel.style.fontSize = '10px'; paraLabel.style.color = '#8e44ad'; paraLabel.style.marginBottom = '4px'; paraLabel.style.fontWeight = 'bold'; paraLabel.textContent = (paragraphLabels[idx] || 'Paragraph ' + (idx + 1)) + ':'; paraContainer.appendChild(paraLabel); var paraText = document.createElement('p'); paraText.style.margin = '0'; paraText.style.fontSize = '12px'; paraText.style.lineHeight = '1.5'; paraText.style.color = '#333'; paraText.textContent = para; paraContainer.appendChild(paraText); // Copy button for individual paragraph var copyParaBtn = document.createElement('button'); copyParaBtn.type = 'button'; copyParaBtn.className = 'button button-small'; copyParaBtn.style.marginTop = '6px'; copyParaBtn.style.fontSize = '10px'; copyParaBtn.textContent = 'Copy'; (function(text, btn) { btn.onclick = function() { navigator.clipboard.writeText(text); btn.textContent = 'Copied!'; setTimeout(function() { btn.textContent = 'Copy'; }, 1500); }; })(para, copyParaBtn); paraContainer.appendChild(copyParaBtn); draftsDiv.appendChild(paraContainer); }); // Insert all drafts button var insertDraftsBtn = document.createElement('button'); insertDraftsBtn.type = 'button'; insertDraftsBtn.className = 'button button-small button-primary'; insertDraftsBtn.style.marginTop = '8px'; insertDraftsBtn.style.marginRight = '8px'; insertDraftsBtn.textContent = 'Insert All Drafts into Editor'; insertDraftsBtn.onclick = function() { if(typeof tinymce !== 'undefined' && tinymce.activeEditor) { var html = (data.draft_paragraphs || []).map(function(p) { return '' + self.escapeHtml(p) + '
'; }).join('\n'); tinymce.activeEditor.insertContent(html); insertDraftsBtn.textContent = 'Inserted!'; setTimeout(function() { insertDraftsBtn.textContent = 'Insert All Drafts into Editor'; }, 1500); } }; draftsDiv.appendChild(insertDraftsBtn); // Copy all drafts button var copyDraftsBtn = document.createElement('button'); copyDraftsBtn.type = 'button'; copyDraftsBtn.className = 'button button-small'; copyDraftsBtn.style.marginTop = '8px'; copyDraftsBtn.textContent = 'Copy All Drafts'; copyDraftsBtn.onclick = function() { var allDrafts = (data.draft_paragraphs || []).join('\n\n'); navigator.clipboard.writeText(allDrafts); copyDraftsBtn.textContent = 'Copied!'; setTimeout(function() { copyDraftsBtn.textContent = 'Copy All Drafts'; }, 1500); }; draftsDiv.appendChild(copyDraftsBtn); container.appendChild(draftsDiv); } var kpLabel = document.createElement('strong'); kpLabel.textContent = 'Key Points:'; container.appendChild(kpLabel); var kpList = document.createElement('ul'); kpList.className = 'pfeai-list'; (data.key_points || []).forEach(function(pt) { var li = document.createElement('li'); li.textContent = pt; // SECURITY: textContent escapes HTML kpList.appendChild(li); }); container.appendChild(kpList); var sparkDiv = document.createElement('div'); sparkDiv.style.marginTop = '10px'; sparkDiv.style.borderTop = '1px solid #eee'; sparkDiv.style.paddingTop = '10px'; var sparkLabel = document.createElement('strong'); sparkLabel.textContent = 'Spark Sentences:'; sparkDiv.appendChild(sparkLabel); var sparkText = (data.spark_sentences || []).join('\n\n'); var textarea = document.createElement('textarea'); textarea.id = 'pfeai-idea-spark-text'; textarea.style.width = '100%'; textarea.style.height = '100px'; textarea.style.fontSize = '12px'; textarea.style.marginTop = '5px'; textarea.value = sparkText; // SECURITY: .value doesn't execute HTML sparkDiv.appendChild(textarea); var btnDiv = document.createElement('div'); btnDiv.style.marginTop = '8px'; btnDiv.style.display = 'flex'; btnDiv.style.gap = '10px'; var insertBtn = document.createElement('button'); insertBtn.type = 'button'; insertBtn.className = 'button button-small button-primary'; insertBtn.id = 'pfeai-insert-idea-spark'; insertBtn.textContent = 'Insert into Editor'; btnDiv.appendChild(insertBtn); var saveBtn = document.createElement('button'); saveBtn.type = 'button'; saveBtn.className = 'button button-small'; saveBtn.style.background = '#e8f5e9'; saveBtn.style.color = '#2e7d32'; saveBtn.style.borderColor = '#66bb6a'; saveBtn.id = 'pfeai-save-idea-clipboard'; saveBtn.innerHTML = '📝 Start New Post →'; btnDiv.appendChild(saveBtn); sparkDiv.appendChild(btnDiv); container.appendChild(sparkDiv); resDiv.innerHTML = ''; resDiv.appendChild(container); resDiv.scrollIntoView({behavior:'smooth'}); // Bind events insertBtn.onclick = function(){ var wt = document.getElementById('title'); if(wt) { wt.value = title; wt.focus(); var pt = document.getElementById('title-prompt-text'); if(pt) pt.classList.add('screen-reader-text'); } if(typeof tinymce !== 'undefined' && tinymce.activeEditor) { var t = document.getElementById('pfeai-idea-spark-text').value; tinymce.activeEditor.insertContent('' + self.escapeHtml(t).replace(/\n\n/g, '
') + '
'); } }; saveBtn.onclick = function(){ var fullHTML = ''; if(data.blurb) fullHTML += 'Blurb: ' + self.escapeHtml(data.blurb) + '
'; // Include draft paragraphs in saved draft if(data.draft_paragraphs && data.draft_paragraphs.length) { fullHTML += 'Draft Paragraphs:
'; data.draft_paragraphs.forEach(function(p){ fullHTML += '' + self.escapeHtml(p) + '
'; }); } if(data.key_points && data.key_points.length) { fullHTML += 'Key Points:
' + self.escapeHtml(sparkVal).replace(/\n\n/g, '
') + '
'; // Save and redirect to new post self.saveToClipboard(title, fullHTML, true); }; }, /** * SECURITY FIX: renderSavedDraft now uses proper escaping */ renderSavedDraft: function(clip) { var self = this; if(!this.savedEl) return; var cleanText = (clip.content || '') .replace(//g, '').replace(/<\/p>/g, '\n\n')
.replace(//g, '').replace(/<\/strong>/g, '')
.trim();
// Build DOM elements instead of innerHTML
var container = document.createElement('div');
container.style.background = '#e8f5e9';
container.style.padding = '10px';
container.style.border = '1px solid #c8e6c9';
var h3 = document.createElement('h3');
h3.style.marginTop = '0';
h3.style.color = '#2e7d32';
h3.textContent = 'Saved Draft';
container.appendChild(h3);
// Content first
var contentDiv = document.createElement('div');
var contentLabel = document.createElement('strong');
contentLabel.textContent = 'Content:';
contentDiv.appendChild(contentLabel);
contentDiv.appendChild(document.createElement('br'));
var contentTextarea = document.createElement('textarea');
contentTextarea.id = 'pfeai-saved-content';
contentTextarea.style.width = '100%';
contentTextarea.style.height = '300px';
contentTextarea.style.fontSize = '12px';
contentTextarea.value = cleanText; // SECURITY: .value doesn't execute HTML
contentDiv.appendChild(contentTextarea);
container.appendChild(contentDiv);
// Title second
var titleDiv = document.createElement('div');
titleDiv.style.marginTop = '10px';
titleDiv.style.marginBottom = '10px';
var titleLabel = document.createElement('strong');
titleLabel.textContent = 'Title:';
titleDiv.appendChild(titleLabel);
titleDiv.appendChild(document.createElement('br'));
var titleInput = document.createElement('input');
titleInput.type = 'text';
titleInput.id = 'pfeai-saved-title';
titleInput.value = clip.title || ''; // SECURITY: .value doesn't execute HTML
titleInput.style.width = '100%';
titleInput.style.fontSize = '12px';
titleDiv.appendChild(titleInput);
container.appendChild(titleDiv);
// Button container
var btnContainer = document.createElement('div');
btnContainer.style.marginTop = '10px';
btnContainer.style.display = 'flex';
btnContainer.style.gap = '10px';
var insertBtn = document.createElement('button');
insertBtn.type = 'button';
insertBtn.className = 'button button-primary';
insertBtn.id = 'pfeai-insert-saved';
insertBtn.textContent = 'Insert into Editor';
btnContainer.appendChild(insertBtn);
var clearBtn = document.createElement('button');
clearBtn.type = 'button';
clearBtn.className = 'button';
clearBtn.style.background = '#ffebee';
clearBtn.style.color = '#c62828';
clearBtn.style.borderColor = '#ef9a9a';
clearBtn.textContent = 'Clear Saved Draft';
btnContainer.appendChild(clearBtn);
container.appendChild(btnContainer);
this.savedEl.innerHTML = '';
this.savedEl.appendChild(container);
insertBtn.onclick = function() {
var t = document.getElementById('pfeai-saved-title').value;
var c = clip.content; // Use original HTML content (already sanitized by server)
var wt = document.getElementById('title');
if(wt) {
wt.value = t;
wt.focus();
var pt = document.getElementById('title-prompt-text');
if(pt) pt.classList.add('screen-reader-text');
}
if(typeof tinymce !== 'undefined' && tinymce.activeEditor){
tinymce.activeEditor.setContent(c);
}
};
clearBtn.onclick = function() {
if (confirm('Are you sure you want to clear your saved draft? This cannot be undone.')) {
self.clearClipboard();
}
};
},
toggleMinimize: function() {
if (!this.panelEl) return;
this.isMinimized = !this.isMinimized;
this.panelEl.classList.toggle('pfeai-minimized', this.isMinimized);
document.body.classList.toggle('pfeai-panel-minimized', this.isMinimized);
},
setLoading: function(isLoading) { if(this.loadingEl) this.loadingEl.style.display = isLoading ? 'block' : 'none'; },
switchTab: function(tabName) {
if (!this.panelEl) return;
this.panelEl.querySelectorAll('.pfeai-tab').forEach(function(b) {
b.classList.toggle('pfeai-tab-active', b.getAttribute('data-tab') === tabName);
});
this.panelEl.querySelectorAll('.pfeai-tab-content').forEach(function(c) {
c.style.display = (c.getAttribute('data-tab') === tabName) ? 'block' : 'none';
});
// Refresh SEO tab to get current title when switching to it
if (tabName === 'seo') {
this.renderSeoTab();
}
},
/**
* Internal Link Suggester
* Fetches candidate posts from WP via the REST endpoint, sends to LLM for ranking,
* then renders cards with one-click TinyMCE link insertion.
*/
runInternalLinks: function(editor, forceRefresh) {
var self = this;
var title = (document.getElementById('title') || {}).value || '';
var contentHtml = this.getSafeContent(editor);
if (!contentHtml || contentHtml.length < 100) {
alert('Please write or paste article content first.');
return;
}
if (!PFEAI.post_id) {
alert('Please save the post as a draft first. WordPress needs a Post ID to match categories and tags for link candidates.');
return;
}
this.showResults('links');
this.setLoading(true);
fetch(PFEAI.rest_url + 'internal-links?_t=' + Date.now(), {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce },
body: JSON.stringify({
content: contentHtml,
title: title,
post_id: PFEAI.post_id,
provider: this.getProvider(),
force_refresh: forceRefresh || false
})
})
.then(function(r) { return r.json(); })
.then(function(json) {
self.setLoading(false);
if (json.links && json.links.length > 0) {
self.renderInternalLinks(json, editor);
var timestamp = json.generated_at || Date.now()/1000;
self.setCachedState('btn-internal-links', '\uD83D\uDD17 View Links', 'links', timestamp, json.from_cache);
self.startCacheWindow(json.from_cache);
} else if (json.code) {
self.linksEl.innerHTML = ' Error: ' + self.escapeHtml(json.message) + ' No strong internal link opportunities found for this article. Error: ' + self.escapeHtml(e.message) + ' No "striking distance" keywords found for this URL yet. Keywords ranking #7-#20. Push these to Page 1! ' + self.escapeHtml(json.suggestion) + ' ' + self.escapeHtml(json.suggestion) + ' Join 2,000+ fans getting exclusive stats, analysis, and insights delivered straight to their inbox every week. Never miss a play.
(Google data usually lags by 48 hours). Striking Distance
';
html += '
';
html += 'Suggested Addition:BE THE FIRST TO KNOW