1,'noindex_date'=>1,'noindex_author'=>0,'clean_tracking'=>1,'product_cat_index'=>1,'product_tag_index'=>0];} static function get(){return wp_parse_args(get_option(self::OPT,[]),self::defaults());} static function menu(){add_submenu_page('mpseo-dashboard',__('Advanced technical SEO', 'multipify-seo-boost'),__('Technical SEO', 'multipify-seo-boost'),'manage_options','mpseo-technical',[__CLASS__,'page']);} static function save(){if ('POST' !== (isset($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) : '') || !isset($_POST['mpseo_v31_save']) || !is_scalar($_POST['mpseo_v31_save'])) return; if (!current_user_can('manage_options')) return; check_admin_referer('mpseo_v31_save');$keys=array_keys(self::defaults());$v=[];foreach($keys as $k)$v[$k]=isset($_POST[$k]) && is_scalar($_POST[$k]) && '1'===sanitize_text_field(wp_unslash($_POST[$k]))?1:0;update_option(self::OPT,$v);add_settings_error('mpseo_v31','saved',__('Settings saved.', 'multipify-seo-boost'),'updated');} static function page(){$o=self::get();echo ('

' . esc_html__('Advanced technical SEO', 'multipify-seo-boost') . '

' . esc_html__('Indexing control for archives, tracking URL cleanup and a dedicated image sitemap.', 'multipify-seo-boost') . '

');settings_errors('mpseo_v31');echo '
';wp_nonce_field('mpseo_v31_save');foreach(['noindex_search'=>__('Noindex internal search results', 'multipify-seo-boost'),'noindex_date'=>__('Noindex date archives', 'multipify-seo-boost'),'noindex_author'=>__('Noindex author archives', 'multipify-seo-boost'),'clean_tracking'=>__('Canonical without tracking parameters (utm_*, gclid, fbclid)', 'multipify-seo-boost'),'product_cat_index'=>__('Index WooCommerce categories', 'multipify-seo-boost'),'product_tag_index'=>__('Index WooCommerce product tags', 'multipify-seo-boost')] as $k=>$l)echo '

';echo ('

' . esc_html__('Open the image sitemap', 'multipify-seo-boost') . '

';} static function rewrite(){add_rewrite_rule('^seo-images\.xml$','index.php?mpseo_images=1&mpseo_images_page=1','top');add_rewrite_rule('^seo-images-([0-9]+)\.xml$','index.php?mpseo_images=1&mpseo_images_page=$matches[1]','top');} static function vars($v){$v[]='mpseo_images';$v[]='mpseo_images_page';return $v;} static function image_sitemap(){ if(!get_query_var('mpseo_images'))return; $config=MPSEO_Sitemaps::config(); if(!MPSEO_Sitemaps::enabled()||empty($config['images'])){status_header(404);nocache_headers();exit;} $raw_page=get_query_var('mpseo_images_page'); if(!is_scalar($raw_page)){status_header(404);nocache_headers();exit;} $page=min(100000,max(1,absint($raw_page))); if ((string)$raw_page !== (string)$page && (string)$raw_page !== '') {status_header(404);nocache_headers();exit;} $types=array_keys(MPSEO_Sitemaps::public_types()); if(!$types){status_header(404);nocache_headers();exit;} // Use the same indexability rules as the primary sitemap, including overrides. // Iterate through bounded batches rather than loading all products in memory. $remaining=MPSEO_Sitemaps::PER_PAGE; $skip=($page-1)*MPSEO_Sitemaps::PER_PAGE; $entries=[]; foreach($types as $type){ $count=MPSEO_Sitemaps::count_indexable($type); if($skip >= $count){$skip-=$count;continue;} $type_page=(int)floor($skip/MPSEO_Sitemaps::PER_PAGE)+1; $type_offset=$skip%MPSEO_Sitemaps::PER_PAGE; while($remaining>0){ $ids=MPSEO_Sitemaps::post_ids_page($type,$type_page,MPSEO_Sitemaps::PER_PAGE); if(!$ids)break; foreach(array_slice($ids,$type_offset) as $id){$entries[]=(int)$id;if(--$remaining===0)break;} if($remaining===0||count($ids)'; echo ''; foreach($entries as $id){ $p=get_post($id);if(!$p||!MPSEO_Sitemaps::post_indexable($id))continue; $images=[]; if(has_post_thumbnail($id))$images[]=get_post_thumbnail_id($id); if(preg_match_all('/wp-image-([0-9]+)/',$p->post_content,$matches))$images=array_merge($images,array_map('intval',$matches[1])); $images=array_slice(array_values(array_unique(array_filter($images))),0,50); if(!$images)continue; $nodes=''; foreach($images as $image_id){ $src=wp_get_attachment_image_url($image_id,'full');if(!$src)continue; $nodes.=''.esc_xml($src).''; $alt=get_post_meta($image_id,'_wp_attachment_image_alt',true); if($alt)$nodes.=''.esc_xml($alt).''; $nodes.=''; } if($nodes){ $permalink=get_permalink($id); if($permalink) echo ''.esc_xml($permalink).''.wp_kses($nodes,['image:image'=>[],'image:loc'=>[],'image:title'=>[],'image:caption'=>[],'image:geo_location'=>[],'image:license'=>[]]).''; } } echo '';exit; } static function robots($r){$o=self::get();if(is_search()&&!empty($o['noindex_search']))$r['noindex']=true;if(is_date()&&!empty($o['noindex_date']))$r['noindex']=true;if(is_author()&&!empty($o['noindex_author']))$r['noindex']=true;if(function_exists('is_product_category')&&is_product_category()&&empty($o['product_cat_index']))$r['noindex']=true;if(function_exists('is_product_tag')&&is_product_tag()&&empty($o['product_tag_index']))$r['noindex']=true;if(!empty($r['noindex']))unset($r['index']);return $r;} static function canonical($url,$post){$o=self::get();if(empty($o['clean_tracking']))return $url;return remove_query_arg(['gclid','fbclid','msclkid','utm_source','utm_medium','utm_campaign','utm_term','utm_content'],$url);} static function archive_meta(){if(!is_archive()&&!is_search())return;global $wp; $title=wp_get_document_title(); if(function_exists('is_product_category')&&is_product_category()){$term=get_queried_object();if($term instanceof WP_Term){$custom=get_term_meta($term->term_id,'mpseo_title',true);if($custom)$title=$custom;}} echo "\n\n";} }