Changeset 3431938
- Timestamp:
- 01/04/2026 04:35:03 AM (2 weeks ago)
- Location:
- pcrecruiter-extensions
- Files:
-
- 35 added
- 3 edited
-
tags/2.0.6 (added)
-
tags/2.0.6/PCRecruiter-Extensions.php (added)
-
tags/2.0.6/assets (added)
-
tags/2.0.6/assets/css (added)
-
tags/2.0.6/assets/css/pcr-block-bindings-editor.css (added)
-
tags/2.0.6/assets/css/pcr-deactivation-modal.css (added)
-
tags/2.0.6/assets/css/pcr-job-board.css (added)
-
tags/2.0.6/assets/css/pcr-schema-mapper.css (added)
-
tags/2.0.6/assets/css/pcr-settings.css (added)
-
tags/2.0.6/assets/js (added)
-
tags/2.0.6/assets/js/pcr-admin.js (added)
-
tags/2.0.6/assets/js/pcr-block-bindings-editor.js (added)
-
tags/2.0.6/assets/js/pcr-deactivation-handler.js (added)
-
tags/2.0.6/assets/js/pcr-frontend.js (added)
-
tags/2.0.6/assets/js/pcr-schema-mapper.js (added)
-
tags/2.0.6/assets/svg (added)
-
tags/2.0.6/assets/svg/bsky.svg (added)
-
tags/2.0.6/assets/svg/envelope.svg (added)
-
tags/2.0.6/assets/svg/facebook.svg (added)
-
tags/2.0.6/assets/svg/link.svg (added)
-
tags/2.0.6/assets/svg/linkedin.svg (added)
-
tags/2.0.6/assets/svg/x_logo.svg (added)
-
tags/2.0.6/includes (added)
-
tags/2.0.6/includes/class-block-bindings.php (added)
-
tags/2.0.6/includes/class-deactivation-handler.php (added)
-
tags/2.0.6/includes/class-job-manager.php (added)
-
tags/2.0.6/includes/class-optimization-exclusions.php (added)
-
tags/2.0.6/includes/class-schema-frontend.php (added)
-
tags/2.0.6/includes/class-schema-mapper.php (added)
-
tags/2.0.6/includes/class-seo-enhancements.php (added)
-
tags/2.0.6/includes/class-sitemap-integration.php (added)
-
tags/2.0.6/includes/class-social-widget.php (added)
-
tags/2.0.6/phpcs.xml (added)
-
tags/2.0.6/readme.txt (added)
-
trunk/PCRecruiter-Extensions.php (modified) (7 diffs)
-
trunk/includes/class-optimization-exclusions.php (added)
-
trunk/includes/class-seo-enhancements.php (modified) (16 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
pcrecruiter-extensions/trunk/PCRecruiter-Extensions.php
r3431406 r3431938 5 5 * Plugin URI: https://www.pcrecruiter.net 6 6 * Description: Integrates PCRecruiter job boards with WordPress via iframe embed or full job sync with /job/ custom post type. 7 * Version: 2.0. 57 * Version: 2.0.6 8 8 * Requires at least: 5.6 9 9 * Requires PHP: 7.4 … … 79 79 require_once plugin_dir_path(__FILE__) . 'includes/class-social-widget.php'; 80 80 require_once plugin_dir_path(__FILE__) . 'includes/class-deactivation-handler.php'; 81 require_once plugin_dir_path(__FILE__) . 'includes/class-optimization-exclusions.php'; 81 82 82 83 // Load job-specific classes but don't init yet … … 717 718 if ($a['analytics'] != '') { 718 719 $analytics = ' analytics="true" '; 719 }; 720 720 } 721 722 // Handle jobmanager and internaljobmanager (Full Sync mode) 721 723 if ($loadurl == "jobmanager" || $loadurl == "internaljobmanager") { 722 724 $job_manager = new PCR_Job_Manager(); … … 728 730 if (strpos($loadurl, '.asp?') === false && strpos($loadurl, '.exe?') === false && strpos($loadurl, '.aspx?') === false) { 729 731 // Parse URL to extract base UID and any additional parameters 730 // This handles: "pcr demo.pcrdemo", "pcr%20demo.pcrdemo", and "pcr%20demo.pcrdemo&filter=value"731 732 $parts = explode('&', $loadurl, 2); 732 733 $uid = $parts[0]; // Base UID (may have spaces or %20) … … 738 739 } 739 740 741 // Handle custom forms 740 742 if (is_numeric($sid) && $loadurl !== "about:blank") { 741 743 $script_url = 'https://www2.pcrecruiter.net/pcrbin/' . $loadurl . '&action=opencustomform&sid=' . rawurlencode($sid); … … 754 756 return '<script src="' . esc_url($script_url) . '"></script>'; 755 757 } else { 758 // Handle iframe output 756 759 if (substr($loadurl, 0, 4) !== "http" && substr($loadurl, 0, 8) !== "jobboard") { 757 760 $aspurl = 'https://www2.pcrecruiter.net/pcrbin/' . $loadurl; 758 761 $loadurl = $aspurl; 759 } ;762 } 760 763 if (substr($loadurl, 0, 4) !== "http" && substr($loadurl, 0, 8) == "jobboard") { 761 764 $needs_css = false; 762 765 $aspurl = 'https://host.pcrecruiter.net/pcrbin/' . $loadurl; 763 766 $loadurl = $aspurl; 764 } ;767 } 765 768 766 769 if ($needs_css) { … … 768 771 } 769 772 770 // Note: appendSrcToFrame() is now provided by pcr-frontend.js when in Full Sync mode 771 // For iframe/passthrough mode, this function may not be available but is also not needed 773 // Build iframe attributes 774 $iframe_attrs = array( 775 'frameborder' => '0', 776 'host' => $loadurl, 777 'id' => 'pcrframe', 778 'name' => 'pcrframe', 779 'src' => 'about:blank', 780 'style' => "height:{$initialheight}px;width:100%;background-color:{$background};border:0;margin:0;padding:0", 781 'onload' => 'pcrframeurl();', 782 ); 783 784 // Add analytics attribute if present 785 if (!empty($analytics)) { 786 $iframe_attrs['analytics'] = 'true'; 787 } 788 789 // Apply optimization exclusion attributes (filter hook for class to add attributes) 790 $iframe_attrs = apply_filters('pcrecruiter_iframe_attributes', $iframe_attrs); 791 792 // Build attribute string 793 $attr_string = ''; 794 foreach ($iframe_attrs as $key => $value) { 795 $attr_string .= ' ' . $key . '="' . esc_attr($value) . '"'; 796 } 772 797 773 798 $version = pcrecruiter_get_plugin_version(); 774 799 775 return "<!-- Start PCRecruiter WP {$version}--><iframe frameborder=\"0\" host=\"{$loadurl}\" id=\"pcrframe\" name=\"pcrframe\" src=\"about:blank\" style=\"height:{$initialheight}px;width:100%;background-color:{$background};border:0;margin:0;padding:0\" {$analytics} onload=\"pcrframeurl();\"></iframe><!-- End PCRecruiter WP -->";800 return "<!-- Start PCRecruiter WP {$version}--><iframe{$attr_string}></iframe><!-- End PCRecruiter WP -->"; 776 801 } 777 802 } -
pcrecruiter-extensions/trunk/includes/class-seo-enhancements.php
r3431406 r3431938 61 61 $conflicts[] = array( 62 62 'name' => 'Rank Math', 63 'config' => 'Rank Math → Titles & amp;Meta → Job Posts'63 'config' => 'Rank Math → Titles & Meta → Job Posts' 64 64 ); 65 65 } … … 134 134 /** 135 135 * Add comprehensive meta tags and Open Graph for job posts 136 * Only outputs when no SEO plugin is handling meta tags 136 * 137 * NOTE: If Yoast SEO or Rank Math is active, we rely on their systems 138 * to handle meta tag output. For Yoast, we populate fields via populate_yoast_meta(). 139 * This function only outputs tags when no SEO plugin is handling it. 137 140 */ 138 141 public static function add_job_meta_tags() … … 142 145 } 143 146 144 // Skip if Yoast or Rank Math is active - they handle meta tags 145 // and we populate their fields via populate_yoast_meta() 146 if (defined('WPSEO_VERSION') || defined('RANK_MATH_VERSION')) { 147 $job_id = get_the_ID(); 148 149 // If Yoast is active, check if it has data 150 if (defined('WPSEO_VERSION')) { 151 $yoast_title = get_post_meta($job_id, '_yoast_wpseo_title', true); 152 153 // If Yoast fields are empty, populate them now 154 // This handles old jobs created before populate_yoast_meta() existed 155 if (empty($yoast_title)) { 156 self::populate_yoast_meta($job_id); 157 } 158 159 // Let Yoast handle all meta output 147 160 return; 148 161 } 162 163 // If Rank Math is active, let it handle output 164 // (We don't populate Rank Math fields yet, but its filters will work as fallback) 165 if (defined('RANK_MATH_VERSION')) { 166 return; 167 } 168 169 // No SEO plugin active - PCR outputs meta tags directly 149 170 150 171 $job_id = get_the_ID(); … … 182 203 183 204 // Open Graph tags 184 echo '<meta property="og:type" content=" website">' . "\n";205 echo '<meta property="og:type" content="article">' . "\n"; 185 206 echo '<meta property="og:title" content="' . esc_attr($seo_title) . '">' . "\n"; 186 207 echo '<meta property="og:description" content="' . esc_attr($description) . '">' . "\n"; … … 383 404 384 405 /** 406 * Extract content based on HTML comment markers 407 * Simple, fast, and reliable - no complex tag parsing needed 408 * 409 * Supports: 410 * <!-- pcr-description-start -->content<!-- pcr-description-end --> 411 * <!-- pcr-description-start -->content (uses rest of content) 412 * 413 * @param string $content HTML content 414 * @return string Extracted content or original if no markers found 415 */ 416 private static function extract_marked_description($content) 417 { 418 // Check for start/end markers 419 if (preg_match('/<!--\s*pcr-description-start\s*-->(.*?)<!--\s*pcr-description-end\s*-->/is', $content, $matches)) { 420 return $matches[1]; 421 } 422 423 // Check for start marker only (use rest of content) 424 if (preg_match('/<!--\s*pcr-description-start\s*-->(.*)/is', $content, $matches)) { 425 return $matches[1]; 426 } 427 428 // No markers found - return original content 429 return $content; 430 } 431 432 /** 385 433 * Build meta description from job content 386 434 */ … … 397 445 $content = $post->post_content; 398 446 399 // Look for HTML comment or data attribute markers 400 if (preg_match('/<!--\s*pcr-description-start\s*-->(.*)/is', $content, $matches)) { 401 // Found comment marker - use everything after it 402 $content = $matches[1]; 403 } elseif (preg_match("/<div[^>]*data-pcr-description=[\"']start[\"'][^>]*>(.*?)<\/div>/is", $content, $matches)) { 404 // Found data attribute marker - use content inside the element 405 $content = $matches[1]; 406 } 447 // Extract marked description (handles comments and data attributes with balanced tags) 448 $content = self::extract_marked_description($content); 407 449 408 450 // Strip HTML and shortcodes … … 608 650 /** 609 651 * Override Yoast title if not manually configured 652 * 653 * NOTE: This is primarily a FALLBACK for old jobs created before populate_yoast_meta() was added. 654 * For new jobs, populate_yoast_meta() writes directly to the database, making this filter 655 * redundant (it will find the value and return it). However, this filter provides: 656 * - Backward compatibility for old jobs without database values 657 * - Safety net if user manually clears Yoast field 658 * - Graceful degradation if database population fails 610 659 */ 611 660 public static function maybe_override_yoast_title($title) … … 615 664 } 616 665 617 // If Yoast has a custom title set , respect it666 // If Yoast has a custom title set (manually or auto-populated), respect it 618 667 $yoast_title = get_post_meta(get_the_ID(), '_yoast_wpseo_title', true); 619 668 if (!empty($yoast_title)) { … … 621 670 } 622 671 623 // Otherwise use our optimized title672 // FALLBACK: Generate title for old jobs or if field was cleared 624 673 $title_parts = self::filter_job_title(array('title' => '')); 625 674 return $title_parts['title']; … … 628 677 /** 629 678 * Override Yoast description if not manually configured 679 * 680 * NOTE: This is primarily a FALLBACK for old jobs created before populate_yoast_meta() was added. 681 * See maybe_override_yoast_title() for detailed explanation. 630 682 */ 631 683 public static function maybe_override_yoast_description($description) … … 635 687 } 636 688 637 // If Yoast has a custom description set , respect it689 // If Yoast has a custom description set (manually or auto-populated), respect it 638 690 $yoast_desc = get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true); 639 691 if (!empty($yoast_desc)) { … … 641 693 } 642 694 643 // Otherwise use our optimized description695 // FALLBACK: Generate description for old jobs or if field was cleared 644 696 return self::build_meta_description(get_the_ID()); 645 697 } … … 755 807 /** 756 808 * Populate Yoast SEO meta fields for job posts 757 * Called after job creation/update758 * Only populates if fields are empty (preserves manual edits)759 *760 * @param int $job_id The job post ID761 */762 /**763 * Populate Yoast SEO meta fields for job posts764 * Called after job creation/update765 * Only populates if fields are empty (preserves manual edits)766 *767 * @param int $job_id The job post ID768 */769 /**770 * Populate Yoast SEO meta fields for job posts771 809 * Called after job creation/update via save_post_job hook 772 810 * Only populates if fields are empty (preserves manual edits) … … 776 814 public static function populate_yoast_meta($job_id) 777 815 { 816 // Skip if this is an autosave or revision 817 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 818 return; 819 } 820 821 // Skip quick edits (admin only, not sync) 822 if (isset($_POST['_inline_edit'])) { 823 return; 824 } 825 826 // Skip bulk edits (performance optimization) 827 if (isset($_REQUEST['bulk_edit'])) { 828 return; 829 } 830 778 831 // Only for job posts 779 832 if (get_post_type($job_id) !== 'job') { … … 784 837 if (!defined('WPSEO_VERSION')) { 785 838 return; 839 } 840 841 // Skip if Yoast Premium has templates configured for jobs 842 if (defined('WPSEO_PREMIUM_VERSION')) { 843 $yoast_titles = get_option('wpseo_titles', array()); 844 if (!empty($yoast_titles['title-job']) || !empty($yoast_titles['metadesc-job'])) { 845 // Let Yoast templates handle it 846 return; 847 } 786 848 } 787 849 … … 794 856 $seo_title = self::build_seo_title($job_id, $job_title); 795 857 $meta_description = self::build_meta_description($job_id); 858 859 // Fallback if build methods return empty (Issue #5) 860 if (empty($seo_title) && !empty($job_title)) { 861 $seo_title = $job_title; 862 863 // Log for debugging 864 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { 865 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 866 error_log("PCR: build_seo_title returned empty for job {$job_id}, using fallback"); 867 } 868 } 869 870 if (empty($meta_description)) { 871 // Try to build a basic description from title and location 872 $location = get_post_meta($job_id, '[[position.city_state]]', true); 873 if (!empty($location)) { 874 $meta_description = "Join our team as a {$job_title} in {$location}."; 875 } else { 876 $meta_description = "Join our team as a {$job_title}."; 877 } 878 879 // Log for debugging 880 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { 881 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 882 error_log("PCR: build_meta_description returned empty for job {$job_id}, using fallback"); 883 } 884 } 796 885 797 886 // Only populate if Yoast fields are empty (preserves manual edits) -
pcrecruiter-extensions/trunk/readme.txt
r3431406 r3431938 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 2.0. 57 Stable tag: 2.0.6 8 8 License: GPLv3 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 123 123 124 124 == Changelog == 125 = 2.0.6 - 2026-01-03 = 126 * Exempt PCR iframes/js from interference by optimization plugins 127 * Deprecated pcr-start-description data attribute in echange for <!-- pcr-description-start / end --> comments 128 125 129 = 2.0.5 - 2026-01-02 = 126 130 * Improved handling of company and position logos 127 131 * Radius search sort by distance 128 132 * Yoast fields generation 129 * Exempt PCR frames/js from interference by cache and optimization defer/lazyload plugins130 133 * Performance optimizations 131 134
Note: See TracChangeset
for help on using the changeset viewer.