feat: Add product name retrieval and enhance supplemental feed offer ID normalization
This commit is contained in:
4
.vscode/ftp-kr.sync.cache.json
vendored
4
.vscode/ftp-kr.sync.cache.json
vendored
@@ -431,8 +431,8 @@
|
|||||||
},
|
},
|
||||||
"index.php": {
|
"index.php": {
|
||||||
"type": "-",
|
"type": "-",
|
||||||
"size": 4267,
|
"size": 4599,
|
||||||
"lmtime": 1772117836613,
|
"lmtime": 1772382133382,
|
||||||
"modified": false
|
"modified": false
|
||||||
},
|
},
|
||||||
"install.php": {
|
"install.php": {
|
||||||
|
|||||||
9
AGENTS.md
Normal file
9
AGENTS.md
Normal file
@@ -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
|
||||||
@@ -621,12 +621,14 @@ class Products
|
|||||||
static public function get_product_data() {
|
static public function get_product_data() {
|
||||||
$product_id = \S::get( 'product_id' );
|
$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_title = \factory\Products::get_product_data( $product_id, 'title' );
|
||||||
$product_description = \factory\Products::get_product_data( $product_id, 'description' );
|
$product_description = \factory\Products::get_product_data( $product_id, 'description' );
|
||||||
$google_product_category = \factory\Products::get_product_data( $product_id, 'google_product_category' );
|
$google_product_category = \factory\Products::get_product_data( $product_id, 'google_product_category' );
|
||||||
$product_url = \factory\Products::get_product_data( $product_id, 'product_url' );
|
$product_url = \factory\Products::get_product_data( $product_id, 'product_url' );
|
||||||
|
|
||||||
echo json_encode( [ 'status' => 'ok', 'product_details' => [
|
echo json_encode( [ 'status' => 'ok', 'product_details' => [
|
||||||
|
'name' => $product_name,
|
||||||
'title' => $product_title,
|
'title' => $product_title,
|
||||||
'description' => $product_description,
|
'description' => $product_description,
|
||||||
'google_product_category' => $google_product_category,
|
'google_product_category' => $google_product_category,
|
||||||
|
|||||||
@@ -519,6 +519,19 @@ class Products
|
|||||||
return $mdb -> get( 'products', $field, [ 'id' => $product_id ] );
|
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 )
|
static public function get_product_merchant_context( $product_id )
|
||||||
{
|
{
|
||||||
global $mdb;
|
global $mdb;
|
||||||
|
|||||||
@@ -43,17 +43,18 @@ class SupplementalFeed
|
|||||||
$written = 0;
|
$written = 0;
|
||||||
foreach ( $products as $row )
|
foreach ( $products as $row )
|
||||||
{
|
{
|
||||||
|
$offer_id = self::normalize_feed_offer_id( $row['offer_id'] ?? '' );
|
||||||
$title = self::sanitize_for_tsv( $row['title'] ?? '' );
|
$title = self::sanitize_for_tsv( $row['title'] ?? '' );
|
||||||
$description = self::sanitize_for_tsv( $row['description'] ?? '' );
|
$description = self::sanitize_for_tsv( $row['description'] ?? '' );
|
||||||
$category = trim( (string) ( $row['google_product_category'] ?? '' ) );
|
$category = trim( (string) ( $row['google_product_category'] ?? '' ) );
|
||||||
|
|
||||||
if ( $title === '' && $description === '' && $category === '' )
|
if ( $offer_id === '' || ( $title === '' && $description === '' && $category === '' ) )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fwrite( $fp, implode( "\t", [
|
fwrite( $fp, implode( "\t", [
|
||||||
$row['offer_id'],
|
$offer_id,
|
||||||
$title,
|
$title,
|
||||||
$description,
|
$description,
|
||||||
$category
|
$category
|
||||||
@@ -116,4 +117,29 @@ class SupplementalFeed
|
|||||||
|
|
||||||
return $value;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
id title description google_product_category
|
id title description google_product_category
|
||||||
shopify_pl_8476788261204_46803770409300 GS żarówka LED E27 7W ciepłobiała zestaw 10 sztuk
|
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_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_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_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_8476790358356_46803775684948 Kobi Light żarówki LED E27 7W 4000K neutralne białe zestaw 10 sztuk 2425
|
||||||
|
|||||||
|
@@ -1559,7 +1559,13 @@ $( function()
|
|||||||
( AI_CLAUDE_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-claude" data-field="title" data-provider="claude" title="Zaproponuj tytuł przez Claude"><i class="fa-solid fa-brain"></i> Claude</button>' : '' ) +
|
( AI_CLAUDE_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-claude" data-field="title" data-provider="claude" title="Zaproponuj tytuł przez Claude"><i class="fa-solid fa-brain"></i> Claude</button>' : '' ) +
|
||||||
( AI_GEMINI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-gemini" data-field="title" data-provider="gemini" title="Zaproponuj tytuł przez Gemini"><i class="fa-solid fa-diamond"></i> Gemini</button>' : '' ) +
|
( AI_GEMINI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-gemini" data-field="title" data-provider="gemini" title="Zaproponuj tytuł przez Gemini"><i class="fa-solid fa-diamond"></i> Gemini</button>' : '' ) +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<small class="js-title-char-count">0/150 znaków</small>' +
|
'<div class="original-title-row" style="display:flex;align-items:center;gap:8px;margin-top:6px;">' +
|
||||||
|
'<small class="text-muted">Oryginalny tytul:</small>' +
|
||||||
|
'<small class="js-original-product-title" style="flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="' + escape_html( current_product_name ) + '">' + escape_html( current_product_name ) + '</small>' +
|
||||||
|
'<button type="button" class="btn btn-xs btn-default js-copy-original-title" title="Kopiuj oryginalny tytul" aria-label="Kopiuj oryginalny tytul">' +
|
||||||
|
'<i class="fa-regular fa-copy"></i>' +
|
||||||
|
'</button>' +
|
||||||
|
'</div>' +
|
||||||
'<div class="title-ai-alternatives" style="margin-top:8px;display:none;"></div>' +
|
'<div class="title-ai-alternatives" style="margin-top:8px;display:none;"></div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div class="form-group">' +
|
'<div class="form-group">' +
|
||||||
@@ -1652,18 +1658,18 @@ $( function()
|
|||||||
var jc = this;
|
var jc = this;
|
||||||
var $form = this.$content.find( 'form' );
|
var $form = this.$content.find( 'form' );
|
||||||
var $inputField = this.$content.find( '.name' );
|
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 $description = this.$content.find( '.description' );
|
||||||
var $productUrl = this.$content.find( '.product-url' );
|
var $productUrl = this.$content.find( '.product-url' );
|
||||||
var $googleCategory = this.$content.find( '.google-category' );
|
var $googleCategory = this.$content.find( '.google-category' );
|
||||||
var $titleAlternatives = this.$content.find( '.title-ai-alternatives' );
|
var $titleAlternatives = this.$content.find( '.title-ai-alternatives' );
|
||||||
|
var originalProductName = current_product_name;
|
||||||
var product_id = $inputField.attr( 'product_id' );
|
var product_id = $inputField.attr( 'product_id' );
|
||||||
|
|
||||||
function set_title_value( value ) {
|
function set_title_value( value ) {
|
||||||
value = String( value || '' );
|
value = String( value || '' );
|
||||||
$inputField.val( value );
|
$inputField.val( value );
|
||||||
var len = value.length;
|
var len = value.length;
|
||||||
$charCount.text( len + '/150 znaków' );
|
|
||||||
$inputField.toggleClass( 'is-invalid', len > 150 );
|
$inputField.toggleClass( 'is-invalid', len > 150 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1713,6 +1719,10 @@ $( function()
|
|||||||
success: function( response ) {
|
success: function( response ) {
|
||||||
var data = JSON.parse( response );
|
var data = JSON.parse( response );
|
||||||
if ( data.status == 'ok' ) {
|
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 ) {
|
if ( data.product_details.title ) {
|
||||||
set_title_value( data.product_details.title );
|
set_title_value( data.product_details.title );
|
||||||
}
|
}
|
||||||
@@ -1744,7 +1754,6 @@ $( function()
|
|||||||
|
|
||||||
$inputField.on( 'input', function() {
|
$inputField.on( 'input', function() {
|
||||||
var len = $( this ).val().length;
|
var len = $( this ).val().length;
|
||||||
$charCount.text( len + '/150 znaków' );
|
|
||||||
$( this ).toggleClass( 'is-invalid', len > 150 );
|
$( this ).toggleClass( 'is-invalid', len > 150 );
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1831,12 +1840,49 @@ $( function()
|
|||||||
: '<i class="fa-solid fa-list"></i> Pokaż alternatywy (' + $list.find( '.js-title-alt-apply' ).length + ')'
|
: '<i class="fa-solid fa-list"></i> Pokaż alternatywy (' + $list.find( '.js-title-alt-apply' ).length + ')'
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
this.$content.on( 'click', '.js-title-alt-apply', function() {
|
this.$content.on( 'click', '.js-title-alt-apply', function() {
|
||||||
var selectedTitle = $( this ).attr( 'data-title-alt' ) || '';
|
var selectedTitle = $( this ).attr( 'data-title-alt' ) || '';
|
||||||
set_title_value( selectedTitle );
|
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 = $( '<textarea>' ).css({
|
||||||
|
position: 'fixed',
|
||||||
|
opacity: 0,
|
||||||
|
pointerEvents: 'none'
|
||||||
|
}).val( originalTitle ).appendTo( 'body' );
|
||||||
|
|
||||||
|
$tmp.trigger( 'focus' );
|
||||||
|
$tmp.trigger( 'select' );
|
||||||
|
|
||||||
|
try {
|
||||||
|
var copied = document.execCommand( 'copy' );
|
||||||
|
show_toast( copied ? 'Oryginalny tytul skopiowany.' : 'Nie udalo sie skopiowac tytulu.', copied ? 'success' : 'error' );
|
||||||
|
} catch ( err ) {
|
||||||
|
show_toast( 'Nie udalo sie skopiowac tytulu.', 'error' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmp.remove();
|
||||||
|
} );
|
||||||
|
|
||||||
$form.on( 'submit', function( e ) {
|
$form.on( 'submit', function( e ) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
jc.$$formSubmit.trigger( 'click' );
|
jc.$$formSubmit.trigger( 'click' );
|
||||||
|
|||||||
Reference in New Issue
Block a user