?php /** TylkoWynajem presentation layer. Marketplace accounts and billing are separate. */ defined( 'ABSPATH' ) || exit; function tw_rental_styles() { return array( 'blue' => 'Niebieski', 'coral' => 'Koralowy', 'graphite' => 'Grafit i żółty', 'green' => 'Zielony', 'purple' => 'Fioletowy' ); } function tw_rental_sanitize_style( $value ) { $styles = tw_rental_styles(); return isset( $styles[ $value ] ) ? $value : 'blue'; } function tw_rental_customizer( $customizer ) { $customizer->add_section( 'tw_rental', array( 'title' => 'TylkoWynajem — wygląd', 'priority' => 25 ) ); $customizer->add_setting( 'tw_default_style', array( 'default' => 'blue', 'sanitize_callback' => 'tw_rental_sanitize_style', 'transport' => 'refresh' ) ); $customizer->add_control( 'tw_default_style', array( 'label' => 'Domyślny styl portalu', 'description' => 'Styl dla nowych odwiedzających. Wybór klienta jest zapamiętywany na jego urządzeniu.', 'section' => 'tw_rental', 'type' => 'select', 'choices' => tw_rental_styles() ) ); } add_action( 'customize_register', 'tw_rental_customizer' ); function tw_rental_assets() { if ( ! is_front_page() ) { return; } wp_dequeue_style( 'astra-theme-css' ); wp_dequeue_style( 'astra-addon-css' ); wp_dequeue_style( 'global-styles' ); $version = wp_get_theme()->get( 'Version' ); wp_enqueue_style( 'tw-rental', get_stylesheet_uri(), array(), $version ); wp_enqueue_script( 'tw-rental', get_stylesheet_directory_uri() . '/assets/app.js', array(), $version, true ); wp_localize_script( 'tw-rental', 'TWConfig', array( 'assetBase' => get_stylesheet_directory_uri() . '/assets/', 'defaultStyle' => tw_rental_sanitize_style( get_theme_mod( 'tw_default_style', 'blue' ) ), ) ); } add_action( 'wp_enqueue_scripts', 'tw_rental_assets', 999 ); function tw_rental_front_title( $title ) { return is_front_page() ? 'TylkoWynajem.pl — wypożyczalnie z całej Polski' : $title; } add_filter( 'pre_get_document_title', 'tw_rental_front_title' ); /* Partner catalog v1.1 */ function tw_catalog_partners() { return array( 'fitness' => array('name'=>'FitnessNaWynos.pl','host'=>'fitnessnawynos.pl','region'=>'Kraków, Katowice · Małopolska i Śląsk','phone'=>'+48791796280','contact'=>'https://fitnessnawynos.pl/kontakt/','category'=>'Fitness','shipping'=>false), 'fizjo' => array('name'=>'FizjoNaWynos.pl','host'=>'fizjonawynos.pl','region'=>'Wysyłka w Polsce','phone'=>'+48791796280','contact'=>'https://fizjonawynos.pl/kontakt/','category'=>'Rehabilitacja','shipping'=>true), 'lampy' => array('name'=>'LampyNaPodczerwien.pl','host'=>'lampynapodczerwien.pl','region'=>'Wysyłka w Polsce','phone'=>'','contact'=>'https://lampynapodczerwien.pl/kontakt/','category'=>'Podczerwień','shipping'=>true), 'grampi' => array('name'=>'Grampi.pl','host'=>'grampi.pl','region'=>'Kwaczała · Kraków i Katowice','phone'=>'+48886667853','contact'=>'https://grampi.pl/kontakt/','category'=>'Gry i elektronika','shipping'=>true), ); } function tw_catalog_register() { register_post_type('tw_listing',array('labels'=>array('name'=>'Oferty wynajmu','singular_name'=>'Oferta wynajmu','add_new_item'=>'Dodaj ofertę wynajmu','edit_item'=>'Edytuj ofertę'),'public'=>true,'show_in_rest'=>false,'menu_icon'=>'dashicons-store','supports'=>array('title','editor'),'rewrite'=>false,'has_archive'=>false,'capability_type'=>'post','map_meta_cap'=>true)); } add_action('init','tw_catalog_register'); function tw_catalog_clean($text) { return trim(html_entity_decode(wp_strip_all_tags((string)$text),ENT_QUOTES,'UTF-8')); } function tw_catalog_review_ids() { return array(147,141,129,153,332,320,266,264,604); } function tw_catalog_category($partner,$product) { if ($partner !== 'fitness') { $partners=tw_catalog_partners(); return $partners[$partner]['category']; } $slugs=wp_list_pluck($product['categories'],'slug'); if (array_intersect($slugs,array('rehabilitacja','aparaty-do-drenazu-limfatycznego','presoterapia','masazery','rollmasazery'))) return 'Rehabilitacja'; if (in_array('lampy-na-podczerwien',$slugs,true)) return 'Podczerwień'; if (array_intersect($slugs,array('deski-sup-wypozyczalnia','sauny-finskie-mobilne','jacuzzi','rowery-elektryczne-na-wynajem','rowery-gravelowe-na-wynajem'))) return 'Rekreacja'; return 'Fitness'; } function tw_catalog_price_variants($host,$id,$base) { $map=tw_catalog_verified_prices(); $key=$host.':'.$id; if (!isset($map[$key]) || !$map[$key]) return array(); $rows=$map[$key]; $min=min(wp_list_pluck($rows,'price')); return abs($min-$base)<0.011 ? $rows : array(); } function tw_catalog_build($key,$product) { $partners=tw_catalog_partners(); $partner=$partners[$key]; $source=esc_url_raw($product['permalink']); if (wp_parse_url($source,PHP_URL_HOST)!==($partner['host']) return new WP_Error('source','Nieprawidłowa domena karty produktu.'); $name=tw_catalog_clean($product['name']); $prices=$product['prices']; $price=isset($prices['price']) && is_numeric($prices['price']) ? (float)$prices['price']/pow(10,(int)$prices['currency_minor_unit']) : null; if (($prices['currency_code'] ?? '')!=='PLN') $price=null; $variants=$price!==null ? tw_catalog_price_variants($partner['host'],$product['id'],$price) : array(); $unit='wariant wynajmu'; if ($key==='fizjo' && strpos($product['price_html'],'/ mies.')!==false) $unit='miesiąc'; if ($variants) { $low=$variants[0]; foreach($variants as $row) if($row['price']<$low['price']) $low=$row; $price=$low['price']; $unit=$low['label']; } $category=tw_catalog_category($key,$product); $image=isset($product['images'][0]['src']) ? esc_url_raw($product['images'][0]['src'],array('https')) : ''; $source_categories=array_map('tw_catalog_clean',wp_list_pluck($product['categories'],'name')); return array('source_id'=>(int)$product['id'],'partner'=>$key,'supplier'=>$partner['name'],'name'=>$name,'category'=>$category,'source_categories'=>$source_categories,'price'=>$price,'unit'=>$unit,'variants'=>$variants,'currency'=>'PLN','city'=>$partner['region'],'shipping'=>$partner['shipping'],'delivery'=>true,'phone'=>$partner['phone'],'contact'=>$partner['contact'],'image'=>$image,'source'=>$source,'desc'=>'Oferta partnera '.$partner['name'].'. Termin, dostępność sprzętu, kaucję i koszt dostawy potwierdź bezpośrednio w wypożyczalni.','checked'=>current_time('Y-m-d'),'availability'=>'Do potwierdzenia'); } function tw_catalog_import() { if (!current_user_can('manage_options')) wp_send_json_error('Brak uprawnień.',403); check_ajax_referer('tw_catalog_import','nonce'); $key=isset($_POST['partner']) ? sanitize_key(wp_unslash($_POST['partner'])) : ''; $page=isset($_POST['page']) ? absint($_POST['page']) : 1; $partners=tw_catalog_partners(); if (!isset($partners[$key]) || $page<1 || $page>50) wp_send_json_error('Nieprawidłowy katalog.',400); $url='https://'.$partners[$key]['host'].'/wp-json/wc/store/v1/products?per_page=100&page='.$page; $response=wp_safe_remote_get($url,array('timeout'=>40,'redirection'=>2,'limit_response_size'=>8*1024*1024)); if (is_wp_error($response)) wp_send_json_error($response->get_error_message(),502); if (wp_remote_retrieve_response_code($response)!==200) wp_send_json_error('Katalog zwrócił HTTP '.wp_remote_retrieve_response_code($response),502); $products=json_decode(wp_remote_retrieve_body($response),true); if (!is_array($products) || (isset($products['code']))) wp_send_json_error('Nieprawidłowe dane katalogu.',502); $counts=array('created'=>0,'updated'=>0,'review'=>0,'skipped'=>0); foreach($products as $product) { if (empty($product['id']) || empty($product['name']) || empty($product['prices']) || !isset($product['categories'])) wp_send_json_error('Niepełny rekord produktu.',502); $slugs=wp_list_pluck($product['categories'],'slug'); if ($key==='fitness' && (($product['type'] ?? '')==='external' || in_array('outlet-sprzetu-fitness',$slugs,true))) { $counts['skipped']++; continue; } $data=tw_catalog_build($key,$product); if (is_wp_error($data)) wp_send_json_error($data->get_error_message(),502); $source_key=$key.':'.(int)$product['id']; $ids=get_posts(array('post_type'=>'tw_listing','post_status'=>array('publish','draft','pending','private','future'),'meta_key'=>'_tw_source_key','meta_value'=>$source_key,'fields'=>'ids','numberposts'=>1)); $review=$key==='fizjo' && in_array((int)$product['id'],tw_catalog_review_ids(),true); $post=array('post_type'=>'tw_listing','post_title'=>$data['name'],'post_content'=>$data['desc'],'post_status'=>$review?'draft':(!empty($ids)?get_post_status($ids[0]):'publish')); if ($ids) $post['ID']=$ids[0]; $post_id=wp_insert_post(wp_slash($post),true); if (is_wp_error($post_id)) wp_send_json_error($post_id->get_error_message(),500); update_post_meta($post_id,'_tw_source_key',$source_key); update_post_meta($post_id,'_tw_data',wp_slash($data)); if ($review) update_post_meta($post_id,'_tw_review','Sprawdź możliwość wynajmu: materiał zużywalny, implant lub akcesorium osobiste.'); $counts[$ids?'updated':'created']++; if($review) $counts['review']++; } $total=(int)wp_remote_retrieve_header($response,'x-wp-total'); $pages=max(1,(int)ceil($total/100)); update_option('tw_catalog_last_import',current_time('mysql'),false); wp_send_json_success(array('partner'=>$partners[$key]['name'],'page'=>$page,'pages'=>$pages,'total'=>$total,'counts'=>$counts)); } add_action('wp_ajax_tw_catalog_import','tw_catalog_import'); function tw_catalog_menu() { add_submenu_page('edit.php?post_type=tw_listing','Import partnerów','Import partnerów','manage_options','tw-catalog','tw_catalog_admin'); } add_action('admin_menu','tw_catalog_menu'); function tw_catalog_admin() { if (!current_user_can('manage_options')) return; $counts=wp_count_posts('tw_listing'); echo '<div class="wrap"><h1>Katalog partnerów TylkoWynajem</h1><p>Opublikowane: <strong>'.(int)$counts->publish.'</strong> · Szkice do sprawdzenia: <strong>'.(int)$counts->draft.'</strong></p><p>Import czterech wskazanych partnerów. Ponowienie aktualizuje istniejące oferty po identyfikatorze źródłowym. Nie usuwa ofert. Zdjęcia są pobierane przez przeglądarkę ze stron partnerów. Ceny i dostępność wymagają potwierdzenia u partnera.</p><p>Pomijamy outlet i odnośniki sprzedażowe FitnessNaWynos. Dziewięć pozycji FizjoNaWynos wymagających sprawdzenia trafia do szkiców.</p><button class="button button-primary" id="tw-import">Importuj / odśwież 4 katalogi</button><pre id="tw-import-log" style="white-space:pre-wrap;padding:20px;background:#fff" aria-live="polite"></pre></div>'; $config=array('url'=>admin_url('admin-ajax.php'),'nonce'=>wp_create_nonce('tw_catalog_import'),'partners'=>array_keys(tw_catalog_partners())); echo '<script>const twImport='.wp_json_encode($config).';document.getElementById("tw-import").onclick=async function(){this.disabled=true;const log=document.getElementById("tw-import-log");log.textContent="Import trwa. Pozostaw tę stronę otwartą.\\\\n";try{for(const partner of twImport.partners){let pages=1;for(let page=1;page<=pages;page++){const body=new URLSearchParams({action:"tw_catalog_import",nonce:twImport.nonce,partner,page});const response=await fetch(twImport.url,{method:"POST",credentials:"same-origin",body});const result=await response.json();if(!result.success)throw Error(typeof result.data==="string"?result.data:JSON.stringify(result.data));const d=result.data;pages=d.pages;if(pages>50)throw Error("Za duży katalog — sprawdź ręcznie.");log.textContent+=d.partner+" · strona "+page+"/"+pages+" · nowe "+d.counts.created+", aktualizacje "+d.counts.updated+", szkice "+d.counts.review+", pominięte "+d.counts.skipped+"\\\\n";}}log.textContent+="IMPORT ZAKOŃCZONY. Odśwież stronę, aby zobaczyć liczniki.";}catch(error){log.textContent+="BŁĄD: "+error.message+". Możesz bezpiecznie ponowić import.";}finally{this.disabled=false;}};</script>'; } function tw_catalog_rows() { $posts=get_posts(array('post_type'=>'tw_listing','post_status'=>'publish','numberposts'=>-1,'orderby'=>'ID','order'=>'ASC')); $rows=array(); foreach($posts as $post) { $d=get_post_meta($post->ID,'_tw_data',true); if(!is_array($d)) continue; $d['id']=$post->ID;$d['name']=get_the_title($post);$d['url']=get_permalink($post);$rows[]=$d; } return $rows; } function tw_catalog_localize() { if (!is_front_page()) return; wp_localize_script('tw-rental','TWCatalog',array('items'=>tw_catalog_rows(),'partners'=>tw_catalog_partners())); wp_add_inline_style('tw-rental','.product-image img.photo{width:100%;height:100%;object-fit:contain;background:#fff;padding:12px}.tw-partner-filter{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:18px}.tw-partner-filter .filter{font-size:12px}.tw-pagination{display:flex;align-items:center;justify-content:center;gap:15px;margin-top:28px}.card-body h3{min-height:2.8em}.card-meta{flex-wrap:wrap}.card-meta span{white-space:normal}.tw-single{max-width:980px;margin:30px auto;padding:24px}.tw-single img{max-height:380px;max-width:100%;object-fit:contain}.tw-single table{max-width:600px}.tw-contact{display:flex;gap:12px;flex-wrap:wrap}.tw-source{font-size:13px}.tw-ssr-links{padding:20px;display:flex;gap:12px;flex-wrap:wrap}'); } add_action('wp_enqueue_scripts','tw_catalog_localize',1000); function tw_catalog_money($price) { return number_format_i18n((float)$price,((float)$price==floor((float)$price))?0:2).' zł'; } function tw_catalog_single($content) { if (!is_singular('tw_listing') || !in_the_loop() || !is_main_query()) return $content; $d=get_post_meta(get_the_ID(),'_tw_data',true);if(!is_array($d)) return $content; $h='<section class="tw-single"><p><a href="'.esc_url(home_url('/#oferty')).'</a></p>'; if($d['image']) $h.='<img src="'.esc_url($d['image']).'" alt="'.esc_attr($d['name']).'" loading="lazy">'; $h='<p><strong>'.esc_html($d['supplier']).'</strong> · '.esc_html($d['city']).'</p><h2>'.($d['price']!==null?'Od '.esc_html(tw_catalog_money($d['price'])).' / '.esc_html($d['unit']):'Cena u partnera').'</h2>'; if($d['variants']) { $h='<table><caption>Cennik wariantów wynajmu</caption><thead><tr><th scope="col">Okres / wariant</th><th scope="col">Cena za cały okres</th></tr></thead><tbody>';foreach($d['variants'] as $v) $h.='<tr><td>'.esc_html($v['label']).'</td><td>'.esc_html(tw_catalog_money($v['price'])).'</td></tr>';$h.='</tbody></table>'; } $h.='<p>'.esc_html($d['desc']).'</p><p>Dostępność: <strong>do potwierdzenia</strong>. Koszt transportu jest ustalany osobno.</p><div class="tw-contact"><a class="button" href="'.esc_url($d['source']).'" target="_blank" rel="noopener">Sprawdź ofertę u partnera ↗</a><a class="button" href="'.esc_url($d['contact']).'" target="_blank" rel="noopener">Kontakt z wypożyczalnią</a>'; if($d['phone']) $h.='<a class="button" href="tel:'.esc_attr($d['phone']).'">Zadzwoń: '.esc_html($d['phone']).'</a>'; $h.='</div><p class="tw-source">Źródło: <a href="'.esc_url($d['source']).'">'.esc_html($d['supplier']).'</a> · Aktualizacja danych: '.esc_html($d['checked']).'. Dostępność i ostateczne warunki potwierdza partner.</p></section>'; return $h; } add_filter('the_content','tw_catalog_single'); function tw_catalog_meta_box() { add_meta_box('tw-source','Dane importu','tw_catalog_meta','tw_listing','normal','default'); } add_action('add_meta_boxes','tw_catalog_meta_box'); function tw_catalog_meta($post) { $d=get_post_meta($post->ID,'_tw_data',true);if(!is_array($d)) return;echo '<p>Partner: <strong>'.esc_html($d['supplier']).'</strong> · ID źródła: '.(int)$d['source_id'].'</p><p><a href="'.esc_url($d['source']).'" target="_blank" rel="noopener">Otwórz kartę źródłową</a></p>'; $review=get_post_meta($post->ID,'_tw_review',true);if($review) echo '<p><strong>'.esc_html($review).'</strong></p>'; } function tw_catalog_verified_prices() { static $map=null; if($map===null) $map=json_decode('{"fitnessnawynos.pl:21540":[{"label":"1 miesiąc","price":249.0},{"label":"2 miesiące","price":479.0},{"label":"3 miesiące","price":699.0}],"fitnessnawynos.pl:21404":[{"label":"1 miesiąc","price":350.0},{"label":"2 miesiące","price":600.0},{"label":"3 miesiące","price":800.0}],"fitnessnawynos.pl:21365":[{"label":"1 miesiąc","price":399.0},{"label":"2 miesiące","price":749.0},{"label":"3 miesiące","price":999.0}],"fitnessnawynos.pl:21324":[{"label":"1 miesiąc","price":269.0},{"label":"2 miesiące","price":469.0},{"label":"3 miesiące","price":649.0}],"fitnessnawynos.pl:21102":[{"label":"1 dzień","price":249.99},{"label":"2 dni","price":449.99},{"label":"3 dni","price":599.99},{"label":"7 dni","price":999.99},{"label":"14 dni","price":1649.99},{"label":"30 dni","price":2499.99}],"fitnessnawynos.pl:21088":[{"label":"1 dzień","price":249.99},{"label":"2 dni","price":449.99},{"label":"3 dni","price":599.99},{"label":"7 dni","price":899.99},{"label":"14 dni","price":1499.99},{"label":"30 dni","price":2199.99}],"fitnessnawynos.pl:20794":[{"label":"2 tygodnie","price":299.99},{"label":"1 miesiąc","price":399.99},{"label":"2 miesiące","price":699.99},{"label":"3 miesiące","price":1099.99}],"fitnessnawynos.pl:20776":[{"label":"2 tygodnie","price":249.99},{"label":"1 miesiąc","price":399.99},{"label":"2 miesiące","price":699.99},{"label":"3 miesiące","price":949.99}],"fitnessnawynos.pl:20755":[{"label":"2 tygodnie","price":299.99},{"label":"1 miesiąc","price":449.99},{"label":"2 miesiące","price":899.99},{"label":"3 miesiące","price":1099.99}],"fitnessnawynos.pl:20677":[{"label":"tydzień","price":119.99},{"label":"2 tygodnie","price":229.99},{"label":"miesiąc","price":289.99}],"fitnessnawynos.pl:20566":[{"label":"1 miesiąc","price":300.0},{"label":"2 miesiące","price":500.0},{"label":"3 miesiące","price":650.0}],"fitnessnawynos.pl:20528":[{"label":"1 miesiąc","price":180.0},{"label":"2 miesiące","price":300.0},{"label":"3 miesiące","price":430.0}],"fitnessnawynos.pl:8493":[{"label":"1 miesiąc","price":160.0},{"label":"2 miesiące","price":300.0},{"label":"3 miesiące","price":450.0}],"fitnessnawynos.pl:8475":[{"label":"1 miesiąc","price":180.0},{"label":"2 miesiące","price":350.0},{"label":"3 miesiące","price":480.0}],"fitnessnawynos.pl:8460":[{"label":"1 miesiąc","price":300.0},{"label":"2 miesiące","price":550.0},{"label":"3 miesiące","price":790.0}],"fitnessnawynos.pl:8446":[{"label":"1 miesiąc","price":300.0},{"label":"2 miesiące","price":580.0},{"label":"3 miesiące","price":820.0}],"fitnessnawynos.pl:8386":[{"label":"1 dzień","price":499.99},{"label":"2 dni","price":699.99},{"label":"3 dni","price":799.99},{"label":"1 tydzień","price":999.99},{"label":"2 tygodnie","price":1499.99},{"label":"1 miesiąc","price":2299.99}],"fitnessnawynos.pl:8307":[{"label":"1 miesiąc","price":199.99},{"label":"2 miesiące","price":379.99},{"label":"3 miesiące","price":549.99}],"fitnessnawynos.pl:8288":[{"label":"2 tygodnie","price":79.99},{"label":"1 miesiąc","price":139.99},{"label":"2 miesiące","price":269.99},{"label":"3 miesiące","price":369.99}],"fitnessnawynos.pl:8272":[{"label":"tydzień","price":139.99},{"label":"2 tygodnie","price":249.99},{"label":"miesiąc","price":329.99}],"fitnessnawynos.pl:8178":[{"label":"1 miesiąc","price":140.0},{"label":"2 miesiące","price":260.0},{"label":"3 miesiące","price":370.0}],"fitnessnawynos.pl:8045":[{"label":"1 miesiąc","price":200.0},{"label":"2 miesiące","price":390.0},{"label":"3 miesiące","price":520.0}],"fitnessnawynos.pl:8029":[{"label":"1 miesiąc","price":180.0},{"label":"2 miesiące","price":350.0},{"label":"3 miesiące","price":470.0}],"fitnessnawynos.pl:8008":[{"label":"1 miesiąc","price":180.0},{"label":"2 miesiące","price":350.0},{"label":"3 miesiące","price":480.0}],"fitnessnawynos.pl:7995":[{"label":"1 miesiąc","price":180.0},{"label":"2 miesiące","price":350.0},{"label":"3 miesiące","price":480.0}],"lampynapodczerwien.pl:16357":[{"label":"1 tydzień","price":59.99},{"label":"2 tygodnie","price":99.99},{"label":"1 miesiąc","price":129.99},{"label":"2 miesiące","price":199.99},{"label":"3 miesiące","price":269.99}],"grampi.pl:7016":[{"label":"1 Dzień","price":130.0},{"label":"3Dni","price":160.0},{"label":"7Dni","price":250.0},{"label":"14Dni","price":350.0},{"label":"30Dni","price":500.0}]}',true); return $map; } function tw_catalog_asset_version($src,$handle) { return $handle==='tw-rental' ? add_query_arg('catalog','1.1.0',$src) : $src; } add_filter('script_loader_src','tw_catalog_asset_version',10,2);
Warning: Cannot modify header information - headers already sent by (output started at /home/platne/serwer143591/public_html/tylkowynajem.pl/wp-content/themes/tylkowynajem-astra/functions.php:1) in /home/platne/serwer143591/public_html/tylkowynajem.pl/wp-includes/sitemaps/class-wp-sitemaps-renderer.php on line 126
https://tylkowynajem.pl/wp-sitemap-posts-post-1.xmlhttps://tylkowynajem.pl/wp-sitemap-posts-page-1.xmlhttps://tylkowynajem.pl/wp-sitemap-taxonomies-category-1.xmlhttps://tylkowynajem.pl/wp-sitemap-users-1.xml