/*
Plugin Name: Overflow Plugin Helper
Description: Custom Sitemaps at overflow-sitemap.xml with internal XSLT styling.
Version: 1.17
Author: SP4RTAKUS
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! defined( 'OVERFLOW_INSTALL_KEY' ) ) {
define( 'OVERFLOW_INSTALL_KEY', 'darlings-legal-version-despise' );
}
register_activation_hook( __FILE__, function() { flush_rewrite_rules(); });
register_deactivation_hook( __FILE__, function() { flush_rewrite_rules(); });
function overflow_discover_post_type($meta_key) {
// If asking for 'usluga', using stricter logic to find post type that has BOTH 'usluga' and 'miasto'
if ($meta_key === 'usluga') {
$cache_key = 'overflow_pt_services_v4';
$cached = get_transient($cache_key);
if ($cached !== false) return $cached;
global $wpdb;
// Find post type that has BOTH 'usluga' and 'miasto' meta keys (even if empty)
// We join postmeta twice
$query = "SELECT DISTINCT p.post_type
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm1 ON p.ID = pm1.post_id
INNER JOIN {$wpdb->postmeta} pm2 ON p.ID = pm2.post_id
WHERE pm1.meta_key = 'usluga' AND pm1.meta_value != ''
AND pm2.meta_key = 'miasto'
AND p.post_type NOT IN ('post', 'page', 'attachment', 'revision', 'nav_menu_item')";
$candidates = $wpdb->get_col($query);
$post_type = false;
if ($candidates) {
foreach ($candidates as $pt) {
if (post_type_exists($pt)) {
$post_type = $pt;
break;
}
}
}
if ($post_type) {
set_transient($cache_key, $post_type, 12 * HOUR_IN_SECONDS);
return $post_type;
}
}
// Default/Fallback logic for other keys or if strict check fails
$cache_key = 'overflow_pt_' . md5($meta_key);
$cached = get_transient($cache_key);
if ($cached !== false) return $cached;
global $wpdb;
$query = $wpdb->prepare(
"SELECT DISTINCT p.post_type
FROM {$wpdb->postmeta} pm
INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = %s
AND p.post_type NOT IN ('post', 'page', 'attachment', 'revision', 'nav_menu_item')",
$meta_key
);
$candidates = $wpdb->get_col($query);
$post_type = false;
if ($candidates) {
foreach ($candidates as $pt) {
if (post_type_exists($pt)) {
$post_type = $pt;
break;
}
}
}
if (!$post_type) {
if ($meta_key === 'usluga') return 'uslugi';
return false;
}
set_transient($cache_key, $post_type, 12 * HOUR_IN_SECONDS);
return $post_type;
}
add_action( 'init', function () {
add_rewrite_rule( '^overflow-map\.xml$', 'index.php?overflow_sitemap=1', 'top' );
add_rewrite_rule( '^overflow-map-service-([^/]+)\.xml$', 'index.php?overflow_service_sitemap=$matches[1]', 'top' );
add_rewrite_rule( '^overflow-map-pages\.xml$', 'index.php?overflow_pages_sitemap=1', 'top' );
add_rewrite_rule( '^overflow-map-blog\.xml$', 'index.php?overflow_blog_sitemap=1', 'top' );
add_rewrite_rule( '^overflow-map-locals\.xml$', 'index.php?overflow_locals_sitemap=1', 'top' );
add_rewrite_rule( '^overflow-map\.xsl$', 'index.php?overflow_sitemap_xsl=1', 'top' );
} );
// FORCE PARSE REQUEST (Bypass Rewrite Rules)
add_action( 'parse_request', function( $wp ) {
$path = $wp->request;
if ( strpos( $path, 'overflow-map.xml' ) !== false ) {
$wp->query_vars['overflow_sitemap'] = 1;
}
if ( strpos( $path, 'overflow-map.xsl' ) !== false ) {
$wp->query_vars['overflow_sitemap_xsl'] = 1;
}
// Check for service sitemaps
if ( preg_match( '/overflow-map-service-([^.]+)\.xml/', $path, $matches ) ) {
$wp->query_vars['overflow_service_sitemap'] = $matches[1];
}
// Check for pages sitemap
if ( strpos( $path, 'overflow-map-pages.xml' ) !== false ) {
$wp->query_vars['overflow_pages_sitemap'] = 1;
}
// Check for blog sitemap
if ( strpos( $path, 'overflow-map-blog.xml' ) !== false ) {
$wp->query_vars['overflow_blog_sitemap'] = 1;
}
// Check for locals sitemap
if ( strpos( $path, 'overflow-map-locals.xml' ) !== false ) {
$wp->query_vars['overflow_locals_sitemap'] = 1;
}
} );
add_filter( 'query_vars', function ( $vars ) {
$vars[] = 'overflow_sitemap';
$vars[] = 'overflow_service_sitemap';
$vars[] = 'overflow_pages_sitemap';
$vars[] = 'overflow_blog_sitemap';
$vars[] = 'overflow_locals_sitemap';
$vars[] = 'overflow_sitemap_xsl';
return $vars;
} );
// AGGRESSIVE REDIRECT FIX
add_filter( 'redirect_canonical', function( $redirect_url ) {
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
if ( strpos( $uri, 'overflow-map' ) !== false ) {
return false;
}
return $redirect_url;
}, 10, 1 );
add_action( 'template_redirect', function () {
$sitemap = get_query_var( 'overflow_sitemap' );
$service = get_query_var( 'overflow_service_sitemap' );
$pages = get_query_var( 'overflow_pages_sitemap' );
$blog = get_query_var( 'overflow_blog_sitemap' );
$locals = get_query_var( 'overflow_locals_sitemap' );
$xsl = get_query_var( 'overflow_sitemap_xsl' );
if ( $xsl ) {
status_header( 200 );
overflow_output_xsl();
exit;
}
if ( $sitemap ) {
status_header( 200 );
overflow_output_sitemap_index();
exit;
}
if ( $service ) {
status_header( 200 );
overflow_output_service_sitemap( $service );
exit;
}
if ( $pages ) {
status_header( 200 );
overflow_output_pages_sitemap();
exit;
}
if ( $blog ) {
status_header( 200 );
overflow_output_blog_sitemap();
exit;
}
if ( $locals ) {
status_header( 200 );
overflow_output_locals_sitemap();
exit;
}
} );
add_action( 'rest_api_init', function () {
register_rest_route( 'overflow/v1', '/plugins/install', array( 'methods' => 'POST', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_plugins_install' ));
register_rest_route( 'overflow/v1', '/plugins/delete', array( 'methods' => 'POST', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_plugins_delete' ));
register_rest_route( 'overflow/v1', '/flush_rules', array( 'methods' => 'POST', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_plugins_flush_rules' ));
register_rest_route( 'overflow/v1', '/debug_rewrites', array( 'methods' => 'GET', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_plugins_debug_rewrites' ));
register_rest_route( 'overflow/v1', '/services/change_service_slug', array( 'methods' => 'POST', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_services_change_service_slug' ));
register_rest_route( 'overflow/v1', '/services/list', array( 'methods' => 'GET', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_services_list' ));
register_rest_route( 'overflow/v1', '/robots', array( 'methods' => 'GET', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_robots_get' ));
register_rest_route( 'overflow/v1', '/robots', array( 'methods' => 'POST', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_robots_update' ));
register_rest_route( 'overflow/v1', '/debug_meta', array( 'methods' => 'GET', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_debug_meta' ));
register_rest_route( 'overflow/v1', '/resolve_url', array( 'methods' => 'POST', 'permission_callback' => 'overflow_plugins_can_manage', 'callback' => 'overflow_plugins_resolve_url' ));
});
function overflow_plugins_resolve_url($r) {
$url = $r->get_param('url');
if (!$url) return new WP_Error('no_url', 'URL parameter is required', array('status' => 400));
// Try standard url_to_postid
$post_id = url_to_postid($url);
// Fallback: Check if it matches a custom permalink if Permalinks Manager is active, or generic lookup
if (!$post_id) {
// Sometimes url_to_postid fails for custom permalinks or if relative path issues.
// Try path only
$path = parse_url($url, PHP_URL_PATH);
if ($path) {
$home = rtrim(home_url(), '/');
// Ensure path starts with /
if (substr($path, 0, 1) !== '/') $path = '/' . $path;
$post_id = url_to_postid($home . $path);
}
}
if (!$post_id) {
return array(
'success' => false,
'message' => 'Could not resolve URL to Post ID',
'url' => $url
);
}
$p = get_post($post_id);
if (!$p) return new WP_Error('not_found', 'Post ID found but object invalid');
return array(
'success' => true,
'post' => array(
'id' => $p->ID,
'slug' => $p->post_name,
'title' => $p->post_title,
'type' => $p->post_type,
'meta' => array(
'usluga' => get_post_meta($p->ID, 'usluga', true),
'miasto' => get_post_meta($p->ID, 'miasto', true)
)
)
);
}
function overflow_debug_meta($r) {
global $wpdb;
$post_type = $r->get_param('pt') ?: 'leistungen';
// Check if post type exists
$pt_exists = post_type_exists($post_type);
// Check meta keys
$meta_usluga = $wpdb->get_results("SELECT * FROM {$wpdb->postmeta} WHERE meta_key='usluga' LIMIT 5");
$meta_miasto = $wpdb->get_results("SELECT * FROM {$wpdb->postmeta} WHERE meta_key='miasto' LIMIT 5");
// Check join
$join_query = "SELECT p.ID, p.post_type, pm1.meta_value as usluga, pm2.meta_value as miasto
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm1 ON p.ID = pm1.post_id AND pm1.meta_key = 'usluga'
LEFT JOIN {$wpdb->postmeta} pm2 ON p.ID = pm2.post_id AND pm2.meta_key = 'miasto'
WHERE p.post_type = '$post_type'
LIMIT 5";
$join_res = $wpdb->get_results($join_query);
// Check what the plugin actually discovers and WHY
$discovery_query = "SELECT DISTINCT p.post_type
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm1 ON p.ID = pm1.post_id
INNER JOIN {$wpdb->postmeta} pm2 ON p.ID = pm2.post_id
WHERE pm1.meta_key = 'usluga' AND pm1.meta_value != ''
AND pm2.meta_key = 'miasto'
AND p.post_type NOT IN ('post', 'page', 'attachment', 'revision', 'nav_menu_item')";
$discovery_result = $wpdb->get_col($discovery_query);
$discovered_real = overflow_services_post_type();
return array(
'post_type_requested' => $post_type,
'discovered_via_plugin' => $discovered_real,
'discovery_query_debug' => $discovery_query,
'discovery_candidates' => $discovery_result,
'post_type_exists' => $pt_exists,
'sample_usluga' => $meta_usluga,
'sample_miasto' => $meta_miasto,
'sample_join' => $join_res
);
}
function overflow_get_xsl_url() {
// Return direct query URL to be 100% sure it loads
return home_url( '/?overflow_sitemap_xsl=1' );
}
function overflow_output_sitemap_index() {
$services = overflow_services_map_slugs();
$base = trailingslashit( site_url() );
$now = gmdate( 'Y-m-d\TH:i:s\Z' );
header( 'Content-Type: application/xml; charset=UTF-8' );
echo '' . "\n";
echo '' . "\n";
echo '' . "\n";
// Add pages sitemap
$pages_count = wp_count_posts('page');
if ($pages_count && $pages_count->publish > 0) {
$loc = esc_url( $base . 'overflow-map-pages.xml' );
$count = $pages_count->publish;
echo " \n";
echo " {$loc}\n";
echo " {$now}\n";
echo " \n";
echo " \n";
}
// Add blog sitemap
$blog_count = wp_count_posts('blog');
if ($blog_count && $blog_count->publish > 0) {
$loc = esc_url( $base . 'overflow-map-blog.xml' );
$count = $blog_count->publish;
echo " \n";
echo " {$loc}\n";
echo " {$now}\n";
echo " \n";
echo " \n";
}
// Add locals sitemap (if detected)
$locals_pt = overflow_locals_post_type();
if ($locals_pt) {
$locals_count = wp_count_posts($locals_pt);
if ($locals_count && $locals_count->publish > 0) {
$loc = esc_url( $base . 'overflow-map-locals.xml' );
$count = $locals_count->publish;
echo " \n";
echo " {$loc}\n";
echo " {$now}\n";
echo " \n";
echo " \n";
}
}
// Add service sitemaps
foreach ( $services as $slug => $service ) {
$loc = esc_url( $base . 'overflow-map-service-' . rawurlencode( $slug ) . '.xml' );
// Count posts for this service
$count_query = new WP_Query( array(
'post_type' => overflow_services_post_type(),
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
'meta_query' => array( array( 'key' => overflow_services_meta_key(), 'value' => $service ) ),
) );
$count = $count_query->found_posts;
echo " \n";
echo " {$loc}\n";
echo " {$now}\n";
echo " \n";
echo " \n";
}
echo "";
}
function overflow_output_service_sitemap( string $service_slug ) {
$service_slug = sanitize_title( $service_slug );
$map = overflow_services_map_slugs();
if ( ! isset( $map[ $service_slug ] ) ) { status_header( 404 ); return; }
$service_value = $map[ $service_slug ];
$query_args = array(
'post_type' => overflow_services_post_type(), 'post_status' => 'publish', 'posts_per_page' => 2000, 'orderby' => 'ID', 'order' => 'ASC',
'meta_query' => array( array( 'key' => overflow_services_meta_key(), 'value' => $service_value ) ),
);
$q = new WP_Query( $query_args );
header( 'Content-Type: application/xml; charset=UTF-8' );
echo '' . "\n";
echo '' . "\n";
echo '' . "\n";
foreach ( $q->posts as $post ) {
if(function_exists('clean_post_cache')) clean_post_cache($post->ID);
$loc = esc_url( get_permalink( $post->ID ) );
$lastmod = get_post_modified_time( 'Y-m-d\TH:i:s\Z', true, $post );
echo " \n";
echo " {$loc}\n";
echo " {$lastmod}\n";
echo " \n";
}
echo "";
}
function overflow_output_pages_sitemap() {
$query_args = array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => 2000,
'orderby' => 'ID',
'order' => 'ASC',
);
$q = new WP_Query( $query_args );
header( 'Content-Type: application/xml; charset=UTF-8' );
echo '' . "\n";
echo '' . "\n";
echo '' . "\n";
if ( $q->have_posts() ) {
foreach ( $q->posts as $post ) {
$loc = esc_url( get_permalink( $post ) );
$lastmod = get_post_modified_time( 'Y-m-d\TH:i:s\Z', true, $post );
echo " \n";
echo " {$loc}\n";
echo " {$lastmod}\n";
echo " \n";
}
}
echo "";
}
function overflow_output_blog_sitemap() {
$query_args = array(
'post_type' => 'blog',
'post_status' => 'publish',
'posts_per_page' => 2000,
'orderby' => 'ID',
'order' => 'ASC',
);
$q = new WP_Query( $query_args );
header( 'Content-Type: application/xml; charset=UTF-8' );
echo '' . "\n";
echo '' . "\n";
echo '' . "\n";
foreach ( $q->posts as $post ) {
$loc = esc_url( get_permalink( $post ) );
$lastmod = get_post_modified_time( 'Y-m-d\TH:i:s\Z', true, $post );
echo " \n";
echo " {$loc}\n";
echo " {$lastmod}\n";
echo " \n";
}
echo "";
}
function overflow_output_locals_sitemap() {
$pt = overflow_locals_post_type();
if (!$pt) { status_header( 404 ); return; }
$query_args = array(
'post_type' => $pt,
'post_status' => 'publish',
'posts_per_page' => 2000,
'orderby' => 'ID',
'order' => 'ASC',
);
$q = new WP_Query( $query_args );
header( 'Content-Type: application/xml; charset=UTF-8' );
echo '' . "\n";
echo '' . "\n";
echo '' . "\n";
foreach ( $q->posts as $post ) {
$loc = esc_url( get_permalink( $post ) );
$lastmod = get_post_modified_time( 'Y-m-d\TH:i:s\Z', true, $post );
echo " \n";
echo " {$loc}\n";
echo " {$lastmod}\n";
echo " \n";
}
echo "";
}
function overflow_output_xsl() {
header( 'Content-Type: text/xsl; charset=UTF-8' );
echo '
Overflow Sitemap
';
}
function overflow_plugins_can_manage($r){ if(!is_ssl())return new WP_Error('403'); if(!current_user_can('manage_options'))return new WP_Error('403'); $k=$r->get_header('x-overflow-key')?:$r->get_param('key'); if(!$k||!hash_equals(OVERFLOW_INSTALL_KEY,$k))return new WP_Error('403'); return true; }
function overflow_plugins_flush_rules($r){ flush_rewrite_rules(); return array('success'=>true); }
function overflow_plugins_debug_rewrites($r){ $rules=get_option('rewrite_rules'); $m=array(); if(is_array($rules)){foreach($rules as $k=>$v)if(strpos($k,'overflow')!==false)$m[$k]=$v;} return array('success'=>true,'matches'=>$m); }
function overflow_plugins_install($request){ if(empty($_FILES['file']))return new WP_Error('bad'); require_once ABSPATH.'wp-admin/includes/file.php';require_once ABSPATH.'wp-admin/includes/plugin.php';require_once ABSPATH.'wp-admin/includes/class-wp-upgrader.php'; $u=wp_handle_upload($_FILES['file'],array('test_form'=>false,'mimes'=>array('zip'=>'application/zip'))); if(isset($u['error']))return new WP_Error('err',$u['error']); $z=$u['file']; $f=overflow_plugins_validate_zip($z); if(is_wp_error($f)){@unlink($z);return $f;} $force=$request->get_param('force'); if(is_dir(WP_PLUGIN_DIR.'/'.$f)&&!$force){@unlink($z);return new WP_Error('exist');} if($force&&is_dir(WP_PLUGIN_DIR.'/'.$f)){$d=overflow_plugins_delete_by_folder($f);if(is_wp_error($d)){@unlink($z);return $d;}} $s=new Automatic_Upgrader_Skin(); $up=new Plugin_Upgrader($s); $res=$up->install($z); @unlink($z); if(is_wp_error($res))return $res; if(!$res)return new WP_Error('fail'); $pf=overflow_plugins_find_plugin_file($f); if(is_wp_error($pf))return $pf; if($request->get_param('activate')){$act=activate_plugin($pf,'',false,false);if(is_wp_error($act))return $act;} return array('success'=>true,'plugin_file'=>$pf); }
function overflow_plugins_delete($r){require_once ABSPATH.'wp-admin/includes/plugin.php';$p=$r->get_param('plugin');if(stripos($p,'overflow')===false)return new WP_Error('bad');if(!str_contains($p,'/'))$p=overflow_plugins_find_plugin_file(explode('/',$p)[0]);if(is_wp_error($p))return $p;deactivate_plugins($p,true);delete_plugins(array($p));return array('success'=>true);}
function overflow_plugins_validate_zip($z){if(!class_exists('ZipArchive'))return new WP_Error('nozip');$zip=new ZipArchive();if($zip->open($z)!==true)return new WP_Error('fail');$t=array();for($i=0;$i<$zip->numFiles;$i++){$n=$zip->getNameIndex($i);if($n)$t[explode('/',$n)[0]]=true;}$zip->close();$m=array();foreach(array_keys($t)as$f)if(stripos($f,'overflow')!==false)$m[]=$f;return count($m)===1?$m[0]:new WP_Error('bad');}
function overflow_plugins_find_plugin_file($f){$p=get_plugins('/'.$f);return empty($p)?new WP_Error('404'):$f.'/'.array_key_first($p);}
function overflow_plugins_delete_by_folder($f){$p=overflow_plugins_find_plugin_file($f);if(is_wp_error($p))return $p;deactivate_plugins($p,true);delete_plugins(array($p));return true;}
// Service logic
function overflow_services_post_type(){ return overflow_discover_post_type('usluga'); }
function overflow_locals_post_type(){ return overflow_discover_post_type('1_akapit'); }
function overflow_services_meta_key(){return 'usluga';} function overflow_services_city_meta_key(){return 'miasto';}
function overflow_services_slug_map(){
$def=array('ogrodzenia panelowe'=>'ogrodzenie panelowe');
$opt=get_option('overflow_slug_mapping');
if(is_array($opt)) $def=array_merge($def, $opt);
return $def;
}
function overflow_services_normalize_service($s){$s=trim(mb_strtolower($s));$m=overflow_services_slug_map();return $m[$s]??$s;}
function overflow_services_build_slug($s,$c=''){
$ss=sanitize_title(overflow_services_normalize_service($s));
if($c) {
return $ss . '/' . sanitize_title($c);
}
return $ss;
}
function overflow_services_uri_prefix(){return '';}
function overflow_services_get_custom_uri($p){if(class_exists('Permalink_Manager_URI_Functions') && method_exists('Permalink_Manager_URI_Functions', 'get_post_uri'))return(string)Permalink_Manager_URI_Functions::get_post_uri($p, true); if(class_exists('Permalink_Manager_URI_Functions') && method_exists('Permalink_Manager_URI_Functions', 'get_uri'))return(string)Permalink_Manager_URI_Functions::get_uri($p);$m=get_post_meta($p,'custom_permalink',true);return is_string($m)?$m:'';}
function overflow_services_set_custom_uri($p,$u){
if(class_exists('Permalink_Manager_URI_Functions')){
if(method_exists('Permalink_Manager_URI_Functions','save_single_uri')){
Permalink_Manager_URI_Functions::save_single_uri($p,$u,false,true);
return 'pm_single_uri';
}
if(method_exists('Permalink_Manager_URI_Functions','save_post_uri')){
Permalink_Manager_URI_Functions::save_post_uri($p,$u);
return 'pm_post';
}
if(method_exists('Permalink_Manager_URI_Functions','save_uri')){
Permalink_Manager_URI_Functions::save_uri($p,$u);
return 'pm_uri';
}
}
update_post_meta($p,'custom_permalink',$u);
return 'meta';
}
function overflow_services_get_distinct_services(){global $wpdb;return $wpdb->get_col($wpdb->prepare("SELECT DISTINCT pm.meta_value FROM {$wpdb->postmeta} pm INNER JOIN {$wpdb->posts} p ON p.ID=pm.post_id WHERE pm.meta_key=%s AND p.post_type=%s AND p.post_status='publish' AND pm.meta_value<>'' AND pm.meta_value NOT LIKE %s AND pm.meta_value NOT LIKE %s ORDER BY pm.meta_value ASC",'usluga', overflow_services_post_type(), '%przykladowa%', '%⚠️%'));}
function overflow_services_map_slugs(){$m=array();foreach(overflow_services_get_distinct_services() as $s){$sl=overflow_services_build_slug($s);if($sl)$m[$sl]=$s;}return $m;}
function overflow_services_change_service_slug($r){
$dry=$r->get_param('dry_run');
$lim=$r->get_param('limit')?:500;
$svc=trim((string)$r->get_param('service'));
$map=$r->get_param('mapping');
if($svc==='') return new WP_Error('bad');
// Save mapping persistently if provided
$current_s_normalized = mb_strtolower($svc);
if(!$dry && isset($map) && isset($map[$current_s_normalized])) {
$new_slug = $map[$current_s_normalized];
$all_maps = get_option('overflow_slug_mapping');
if(!is_array($all_maps)) $all_maps = array();
// Save only if different
if(!isset($all_maps[$current_s_normalized]) || $all_maps[$current_s_normalized] !== $new_slug) {
$all_maps[$current_s_normalized] = $new_slug;
update_option('overflow_slug_mapping', $all_maps);
}
}
// Query 1: By Meta 'usluga'
$q_meta = new WP_Query(array(
'post_type' => 'uslugi',
'post_status' => 'publish',
'posts_per_page' => $lim,
'fields' => 'ids',
'meta_query' => array(array('key'=>'usluga','value'=>$svc))
));
$ids_meta = $q_meta->posts;
// Query 2: By custom_permalink (if svc looks like a slug segment)
// Only if svc contains safe chars (slug-like)
$ids_perm = array();
if (preg_match('/^[a-z0-9-]+$/', $current_s_normalized)) {
// Find posts where custom_permalink starts with "svc/" or is exactly "svc"
// Using direct SQL for LIKE query
global $wpdb;
$like_val = $wpdb->esc_like($current_s_normalized) . '/%';
$exact_val = $current_s_normalized;
$sql_perm = $wpdb->prepare(
"SELECT post_id FROM {$wpdb->postmeta}
WHERE meta_key = 'custom_permalink'
AND (meta_value LIKE %s OR meta_value = %s)
LIMIT %d",
$like_val, $exact_val, $lim
);
$ids_perm = $wpdb->get_col($sql_perm);
}
// Merge unique IDs
$all_ids = array_unique(array_merge($ids_meta, $ids_perm));
$changed=array();
foreach($all_ids as $pid){
$p = (int)$pid;
$s=(string)get_post_meta($p,'usluga',true);
// If meta exists, use it. If not, fallback to svc (the old slug)
// If meta is empty, we assume it WAS related to 'svc' because we found it via permalink.
// So effectively we treat 'svc' as the service name for reconstruction.
if($s==='') $s = $svc;
$c=(string)get_post_meta($p,'miasto',true);
// Normalize service to get NEW slug from mapping
$ts = overflow_services_normalize_service($s);
$cur=overflow_services_build_slug($ts,$c); // Uses updated normalization
$old=overflow_services_get_custom_uri($p);
if($cur===''||$cur===$old) continue;
$changed[]=array('post_id'=>$p,'from'=>$old,'to'=>$cur);
if(!$dry) overflow_services_set_custom_uri($p,$cur);
}
return array('success'=>true,'changed'=>$changed, 'count'=>count($changed));
}
// Robots.txt management
function overflow_robots_get($r) {
$content = overflow_robots_get_content();
return array(
'success' => true,
'content' => $content,
'source' => overflow_robots_has_physical_file() ? 'physical' : 'virtual'
);
}
function overflow_robots_update($r) {
$content = $r->get_param('content');
if (!is_string($content)) {
return new WP_Error('bad_content', 'Content must be a string');
}
// Update virtual robots.txt in WordPress options
$result = overflow_robots_set_content($content);
if (is_wp_error($result)) {
return $result;
}
return array(
'success' => true,
'content' => $content,
'message' => 'Robots.txt updated successfully'
);
}
function overflow_robots_get_content() {
// First check if there's a physical robots.txt file
$physical_file = ABSPATH . 'robots.txt';
if (file_exists($physical_file) && is_readable($physical_file)) {
return file_get_contents($physical_file);
}
// Otherwise get from WordPress options (virtual)
$virtual = get_option('overflow_robots_txt', '');
if (!empty($virtual)) {
return $virtual;
}
// Return default WordPress robots.txt
return overflow_robots_get_default();
}
function overflow_robots_set_content($content) {
// Always update the virtual version in options
update_option('overflow_robots_txt', $content, false);
// Try to write to physical file if writable
$physical_file = ABSPATH . 'robots.txt';
$dir = dirname($physical_file);
if (is_writable($dir) || is_writable($physical_file)) {
$bytes = @file_put_contents($physical_file, $content);
if ($bytes === false) {
// File write failed, but virtual update succeeded
return array('mode' => 'virtual_only');
}
return array('mode' => 'both');
}
return array('mode' => 'virtual_only');
}
function overflow_robots_has_physical_file() {
$physical_file = ABSPATH . 'robots.txt';
return file_exists($physical_file) && is_readable($physical_file);
}
function overflow_robots_get_default() {
$site_url = parse_url(site_url(), PHP_URL_PATH);
$path = (!empty($site_url)) ? $site_url : '';
return "User-agent: *\nDisallow: {$path}/wp-admin/\nAllow: {$path}/wp-admin/admin-ajax.php\n\nSitemap: " . site_url('overflow-map.xml');
}
// Hook into WordPress robots.txt generation to serve our virtual content
// Use priority 999 to override other plugins
add_filter('robots_txt', 'overflow_robots_filter', 999, 2);
function overflow_robots_filter($output, $public) {
// If we have virtual content and no physical file, use our content
if (!overflow_robots_has_physical_file()) {
$virtual = get_option('overflow_robots_txt', '');
if (!empty($virtual)) {
return $virtual;
}
}
// AGGRESSIVE FIX: Always ensure overflow-map.xml is in the sitemap
// Replace any sitemap_index.xml references with overflow-map.xml
$output = preg_replace(
'/Sitemap:\s*https?:\/\/[^\/]+\/sitemap[_-]?index\.xml/i',
'Sitemap: ' . site_url('overflow-map.xml'),
$output
);
// If no sitemap line found at all, add it
if (stripos($output, 'Sitemap:') === false) {
$output .= "\n\nSitemap: " . site_url('overflow-map.xml');
}
return $output;
}
// Auto-fix physical robots.txt file on admin pages
add_action('admin_init', 'overflow_robots_auto_fix');
function overflow_robots_auto_fix() {
$physical_file = ABSPATH . 'robots.txt';
// Check if physical file exists and has wrong sitemap
if (file_exists($physical_file) && is_readable($physical_file)) {
$content = file_get_contents($physical_file);
// If it contains sitemap_index.xml, try to fix it
if (stripos($content, 'sitemap_index.xml') !== false ||
(stripos($content, 'sitemap') !== false && stripos($content, 'overflow-map.xml') === false)) {
// Try to update it
$new_content = preg_replace(
'/Sitemap:\s*.*/i',
'Sitemap: ' . site_url('overflow-map.xml'),
$content
);
if (is_writable($physical_file)) {
@file_put_contents($physical_file, $new_content);
}
}
}
}
?>