diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index bbacee3..df3c72b 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -431,8 +431,8 @@ }, "index.php": { "type": "-", - "size": 4267, - "lmtime": 1772117836613, + "size": 4599, + "lmtime": 1772382133382, "modified": false }, "install.php": { diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..9ef8f8f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,9 @@ +# AGENTS.md + +## Sposób pracy +- Pisz do mnie po polsku, zwięźle i krótko, ale merytorycznie + +## Wprowadzanie zmian +- Przeanalizuj wprowadzone zadanie +- Przedstaw plan +- Po akceptacji wdróź plan \ No newline at end of file diff --git a/autoload/controls/class.Products.php b/autoload/controls/class.Products.php index a12c4dc..de79c64 100644 --- a/autoload/controls/class.Products.php +++ b/autoload/controls/class.Products.php @@ -621,12 +621,14 @@ class Products static public function get_product_data() { $product_id = \S::get( 'product_id' ); + $product_name = \factory\Products::get_product_name( $product_id ); $product_title = \factory\Products::get_product_data( $product_id, 'title' ); $product_description = \factory\Products::get_product_data( $product_id, 'description' ); $google_product_category = \factory\Products::get_product_data( $product_id, 'google_product_category' ); $product_url = \factory\Products::get_product_data( $product_id, 'product_url' ); echo json_encode( [ 'status' => 'ok', 'product_details' => [ + 'name' => $product_name, 'title' => $product_title, 'description' => $product_description, 'google_product_category' => $google_product_category, diff --git a/autoload/factory/class.Products.php b/autoload/factory/class.Products.php index 345a487..08d3f22 100644 --- a/autoload/factory/class.Products.php +++ b/autoload/factory/class.Products.php @@ -519,6 +519,19 @@ class Products return $mdb -> get( 'products', $field, [ 'id' => $product_id ] ); } + static public function get_product_name( $product_id ) + { + global $mdb; + + $product_id = (int) $product_id; + if ( $product_id <= 0 ) + { + return null; + } + + return $mdb -> get( 'products', 'name', [ 'id' => $product_id ] ); + } + static public function get_product_merchant_context( $product_id ) { global $mdb; diff --git a/autoload/services/class.SupplementalFeed.php b/autoload/services/class.SupplementalFeed.php index 7210769..d28bb87 100644 --- a/autoload/services/class.SupplementalFeed.php +++ b/autoload/services/class.SupplementalFeed.php @@ -43,17 +43,18 @@ class SupplementalFeed $written = 0; foreach ( $products as $row ) { + $offer_id = self::normalize_feed_offer_id( $row['offer_id'] ?? '' ); $title = self::sanitize_for_tsv( $row['title'] ?? '' ); $description = self::sanitize_for_tsv( $row['description'] ?? '' ); $category = trim( (string) ( $row['google_product_category'] ?? '' ) ); - if ( $title === '' && $description === '' && $category === '' ) + if ( $offer_id === '' || ( $title === '' && $description === '' && $category === '' ) ) { continue; } fwrite( $fp, implode( "\t", [ - $row['offer_id'], + $offer_id, $title, $description, $category @@ -116,4 +117,29 @@ class SupplementalFeed return $value; } + + /** + * Normalizuje offer_id do formatu oczekiwanego przez feed supplemental. + * - usuwa ewentualny prefix channel:lang:country: + * - dla Shopify wymusza wielkie litery kodu kraju: shopify_PL_... + */ + static private function normalize_feed_offer_id( $offer_id ) + { + $offer_id = trim( (string) $offer_id ); + if ( $offer_id === '' ) return ''; + + $offer_id = trim( $offer_id, " \t\n\r\0\x0B'\"" ); + + if ( preg_match( '/^[a-z_]+:[a-z]{2,8}:[a-z]{2,8}:(.+)$/i', $offer_id, $matches ) ) + { + $offer_id = trim( (string) ( $matches[1] ?? '' ) ); + } + + if ( preg_match( '/^shopify_([a-z]{2})_(.+)$/i', $offer_id, $matches ) ) + { + $offer_id = 'shopify_' . strtoupper( (string) $matches[1] ) . '_' . (string) $matches[2]; + } + + return $offer_id; + } } diff --git a/feeds/supplemental_10.tsv b/feeds/supplemental_10.tsv index 1daea0f..2d36694 100644 --- a/feeds/supplemental_10.tsv +++ b/feeds/supplemental_10.tsv @@ -1,6 +1,6 @@ id title description google_product_category -shopify_pl_8476788261204_46803770409300 GS żarówka LED E27 7W ciepłobiała zestaw 10 sztuk -shopify_pl_8454714753364_46732986483028 GS żarówka LED 7W E27 barwa ciepła biała -shopify_pl_8454759842132_46733043466580 Kobi Light żarówka LED E27 7W barwa neutralna biała 4000K 600lm 2425 -shopify_pl_8459153473876_46746440270164 Kobi Light żarówka LED świecowa E14 1,5W 150 lm zimnobiała 6000K 2425 -shopify_pl_8476790358356_46803775684948 Kobi Light żarówki LED E27 7W 4000K neutralne białe zestaw 10 sztuk 2425 +shopify_PL_8476788261204_46803770409300 GS żarówka LED E27 7W ciepłobiała zestaw 10 sztuk +shopify_PL_8454714753364_46732986483028 GS żarówka LED 7W E27 barwa ciepła biała +shopify_PL_8454759842132_46733043466580 Kobi Light żarówka LED E27 7W barwa neutralna biała 4000K 600lm 2425 +shopify_PL_8459153473876_46746440270164 Kobi Light żarówka LED świecowa E14 1,5W 150 lm zimnobiała 6000K 2425 +shopify_PL_8476790358356_46803775684948 Kobi Light żarówki LED E27 7W 4000K neutralne białe zestaw 10 sztuk 2425 diff --git a/templates/products/main_view.php b/templates/products/main_view.php index 904d0f9..fa2c39e 100644 --- a/templates/products/main_view.php +++ b/templates/products/main_view.php @@ -1559,7 +1559,13 @@ $( function() ( AI_CLAUDE_ENABLED ? '' : '' ) + ( AI_GEMINI_ENABLED ? '' : '' ) + '' + - '0/150 znaków' + + '
' + + 'Oryginalny tytul:' + + '' + escape_html( current_product_name ) + '' + + '' + + '
' + '' + '' + '
' + @@ -1652,18 +1658,18 @@ $( function() var jc = this; var $form = this.$content.find( 'form' ); var $inputField = this.$content.find( '.name' ); - var $charCount = this.$content.find( '.js-title-char-count' ); + var $originalTitle = this.$content.find( '.js-original-product-title' ); var $description = this.$content.find( '.description' ); var $productUrl = this.$content.find( '.product-url' ); var $googleCategory = this.$content.find( '.google-category' ); var $titleAlternatives = this.$content.find( '.title-ai-alternatives' ); + var originalProductName = current_product_name; var product_id = $inputField.attr( 'product_id' ); function set_title_value( value ) { value = String( value || '' ); $inputField.val( value ); var len = value.length; - $charCount.text( len + '/150 znaków' ); $inputField.toggleClass( 'is-invalid', len > 150 ); } @@ -1713,6 +1719,10 @@ $( function() success: function( response ) { var data = JSON.parse( response ); if ( data.status == 'ok' ) { + if ( data.product_details.name ) { + originalProductName = String( data.product_details.name ); + $originalTitle.text( originalProductName ).attr( 'title', originalProductName ); + } if ( data.product_details.title ) { set_title_value( data.product_details.title ); } @@ -1744,7 +1754,6 @@ $( function() $inputField.on( 'input', function() { var len = $( this ).val().length; - $charCount.text( len + '/150 znaków' ); $( this ).toggleClass( 'is-invalid', len > 150 ); }); @@ -1831,12 +1840,49 @@ $( function() : ' Pokaż alternatywy (' + $list.find( '.js-title-alt-apply' ).length + ')' ); } ); - this.$content.on( 'click', '.js-title-alt-apply', function() { var selectedTitle = $( this ).attr( 'data-title-alt' ) || ''; set_title_value( selectedTitle ); } ); + this.$content.on( 'click', '.js-copy-original-title', function() { + var originalTitle = $.trim( String( originalProductName || '' ) ); + + if ( !originalTitle ) { + show_toast( 'Brak oryginalnego tytulu do skopiowania.', 'error' ); + return; + } + + if ( navigator.clipboard && typeof navigator.clipboard.writeText === 'function' ) { + navigator.clipboard.writeText( originalTitle ) + .then( function() { + show_toast( 'Oryginalny tytul skopiowany.', 'success' ); + } ) + .catch( function() { + show_toast( 'Nie udalo sie skopiowac tytulu.', 'error' ); + } ); + return; + } + + var $tmp = $( '