- Nowy moduł CampaignTerms z widokiem grup reklam, fraz wyszukiwanych i fraz wykluczających - Frazy wyszukiwane dodane do wykluczonych oznaczane czerwonym kolorem w tabeli - Instalator migracji (install.php) z obsługą schema_migrations - Migracja 003 dla tabel campaign_ad_groups, campaign_search_terms, campaign_negative_keywords - CLAUDE.md z dokumentacją architektury projektu - Aktualizacja layoutu, stylów i konfiguracji Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
178 lines
5.5 KiB
PHP
178 lines
5.5 KiB
PHP
<?php
|
|
namespace controls;
|
|
|
|
class CampaignTerms
|
|
{
|
|
static public function main_view()
|
|
{
|
|
return \Tpl::view( 'campaign_terms/main_view', [
|
|
'clients' => \factory\Campaigns::get_clients(),
|
|
] );
|
|
}
|
|
|
|
static public function get_campaigns_list()
|
|
{
|
|
$client_id = (int) \S::get( 'client_id' );
|
|
echo json_encode( [ 'campaigns' => \factory\Campaigns::get_campaigns_list( $client_id ) ] );
|
|
exit;
|
|
}
|
|
|
|
static public function get_campaign_ad_groups()
|
|
{
|
|
$campaign_id = (int) \S::get( 'campaign_id' );
|
|
|
|
if ( $campaign_id <= 0 )
|
|
{
|
|
echo json_encode( [ 'ad_groups' => [] ] );
|
|
exit;
|
|
}
|
|
|
|
echo json_encode( [ 'ad_groups' => \factory\Campaigns::get_campaign_ad_groups( $campaign_id ) ] );
|
|
exit;
|
|
}
|
|
|
|
static public function get_campaign_phrase_details()
|
|
{
|
|
$campaign_id = (int) \S::get( 'campaign_id' );
|
|
$ad_group_id = (int) \S::get( 'ad_group_id' );
|
|
|
|
if ( $campaign_id <= 0 )
|
|
{
|
|
echo json_encode( [ 'search_terms' => [], 'negative_keywords' => [] ] );
|
|
exit;
|
|
}
|
|
|
|
echo json_encode( [
|
|
'search_terms' => \factory\Campaigns::get_campaign_search_terms( $campaign_id, $ad_group_id ),
|
|
'negative_keywords' => \factory\Campaigns::get_campaign_negative_keywords( $campaign_id, $ad_group_id )
|
|
] );
|
|
exit;
|
|
}
|
|
|
|
static public function add_negative_keyword()
|
|
{
|
|
$search_term_id = (int) \S::get( 'search_term_id' );
|
|
$match_type = strtoupper( trim( (string) \S::get( 'match_type' ) ) );
|
|
$scope = strtolower( trim( (string) \S::get( 'scope' ) ) );
|
|
|
|
if ( $search_term_id <= 0 )
|
|
{
|
|
echo json_encode( [ 'success' => false, 'message' => 'Nie podano frazy do wykluczenia.' ] );
|
|
exit;
|
|
}
|
|
|
|
if ( !in_array( $match_type, [ 'PHRASE', 'EXACT', 'BROAD' ], true ) )
|
|
{
|
|
$match_type = 'PHRASE';
|
|
}
|
|
if ( !in_array( $scope, [ 'campaign', 'ad_group' ], true ) )
|
|
{
|
|
$scope = 'campaign';
|
|
}
|
|
|
|
$context = \factory\Campaigns::get_search_term_context( $search_term_id );
|
|
if ( !$context )
|
|
{
|
|
echo json_encode( [ 'success' => false, 'message' => 'Nie znaleziono danych frazy.' ] );
|
|
exit;
|
|
}
|
|
|
|
$customer_id = trim( (string) ( $context['google_ads_customer_id'] ?? '' ) );
|
|
$campaign_external_id = trim( (string) ( $context['external_campaign_id'] ?? '' ) );
|
|
$ad_group_external_id = trim( (string) ( $context['external_ad_group_id'] ?? '' ) );
|
|
$keyword_text = trim( (string) ( $context['search_term'] ?? '' ) );
|
|
|
|
$missing_data = ( $customer_id === '' || $keyword_text === '' );
|
|
if ( $scope === 'campaign' && $campaign_external_id === '' )
|
|
{
|
|
$missing_data = true;
|
|
}
|
|
if ( $scope === 'ad_group' && $ad_group_external_id === '' )
|
|
{
|
|
$missing_data = true;
|
|
}
|
|
|
|
if ( $missing_data )
|
|
{
|
|
echo json_encode( [
|
|
'success' => false,
|
|
'message' => 'Brak wymaganych danych Google Ads dla tej frazy.',
|
|
'debug' => [
|
|
'customer_id' => $customer_id,
|
|
'campaign_external_id' => $campaign_external_id,
|
|
'ad_group_external_id' => $ad_group_external_id,
|
|
'keyword_text' => $keyword_text,
|
|
'scope' => $scope,
|
|
'context' => $context
|
|
]
|
|
] );
|
|
exit;
|
|
}
|
|
|
|
$api = new \services\GoogleAdsApi();
|
|
if ( !$api -> is_configured() )
|
|
{
|
|
echo json_encode( [ 'success' => false, 'message' => 'Google Ads API nie jest skonfigurowane.' ] );
|
|
exit;
|
|
}
|
|
|
|
if ( $scope === 'campaign' )
|
|
{
|
|
$api_result = $api -> add_negative_keyword_to_campaign( $customer_id, $campaign_external_id, $keyword_text, $match_type );
|
|
}
|
|
else
|
|
{
|
|
$api_result = $api -> add_negative_keyword_to_ad_group( $customer_id, $ad_group_external_id, $keyword_text, $match_type );
|
|
}
|
|
|
|
if ( !( $api_result['success'] ?? false ) )
|
|
{
|
|
$last_error = \services\GoogleAdsApi::get_setting( 'google_ads_last_error' );
|
|
echo json_encode( [
|
|
'success' => false,
|
|
'message' => 'Nie udalo sie zapisac frazy wykluczajacej w Google Ads.',
|
|
'error' => $last_error,
|
|
'debug' => [
|
|
'customer_id' => $customer_id,
|
|
'campaign_external_id' => $campaign_external_id,
|
|
'ad_group_external_id' => $ad_group_external_id,
|
|
'keyword_text' => $keyword_text,
|
|
'match_type' => $match_type,
|
|
'scope' => $scope,
|
|
'api_result' => $api_result
|
|
]
|
|
] );
|
|
exit;
|
|
}
|
|
|
|
\factory\Campaigns::upsert_campaign_negative_keyword(
|
|
(int) $context['db_campaign_id'],
|
|
$scope === 'campaign' ? null : (int) $context['db_ad_group_id'],
|
|
$scope,
|
|
$keyword_text,
|
|
$match_type
|
|
);
|
|
|
|
$scope_label = $scope === 'campaign' ? 'kampanii' : 'grupy reklam';
|
|
|
|
echo json_encode( [
|
|
'success' => true,
|
|
'message' => ( $api_result['duplicate'] ?? false ) ? 'Fraza byla juz wykluczona na poziomie ' . $scope_label . '.' : 'Fraza zostala dodana do wykluczajacych na poziomie ' . $scope_label . '.',
|
|
'duplicate' => (bool) ( $api_result['duplicate'] ?? false ),
|
|
'match_type' => $match_type,
|
|
'scope' => $scope,
|
|
'debug' => [
|
|
'customer_id' => $customer_id,
|
|
'campaign_external_id' => $campaign_external_id,
|
|
'ad_group_external_id' => $ad_group_external_id,
|
|
'keyword_text' => $keyword_text,
|
|
'scope' => $scope,
|
|
'api_response' => $api_result['response'] ?? null,
|
|
'sent_operation' => $api_result['sent_operation'] ?? null,
|
|
'verification' => $api_result['verification'] ?? null
|
|
]
|
|
] );
|
|
exit;
|
|
}
|
|
}
|