I am trying to do the pagination with google-ads-php at the bottom of my page in php, so I get through my ads, like PREVIOUS 1,2,3 NEXT
So this is my code:
public function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
{
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
// Creates a query that retrieves all ads.
$query = "SELECT campaign.name, ad_group.name, "
. "ad_group_ad.ad.responsive_display_ad.marketing_images, "
. "ad_group_ad.ad.app_ad.images, ad_group_ad.ad.app_ad.youtube_videos, "
. "ad_group_ad.ad.responsive_display_ad.youtube_videos, ad_group_ad.ad.local_ad.videos, "
. "ad_group_ad.ad.video_responsive_ad.videos, ad_group_ad.ad.video_ad.media_file, "
. "ad_group_ad.ad.app_engagement_ad.images, ad_group_ad.ad.app_engagement_ad.videos, "
. "ad_group_ad.ad.display_upload_ad.media_bundle, ad_group_ad.ad.gmail_ad.product_images, "
. "ad_group_ad.ad.gmail_ad.product_videos, ad_group_ad.ad.gmail_ad.teaser.logo_image, "
. "ad_group_ad.ad.image_ad.image_url, ad_group_ad.ad.legacy_responsive_display_ad.square_marketing_image, "
. "ad_group_ad.ad.local_ad.marketing_images, ad_group_ad.ad.responsive_display_ad.logo_images, "
. "ad_group_ad.ad.responsive_display_ad.square_logo_images, "
. "ad_group_ad.ad.responsive_display_ad.square_marketing_images, "
. "ad_group_ad.ad.responsive_display_ad.youtube_videos, "
. "metrics.impressions, campaign.campaign_budget, campaign.status, "
. "campaign.start_date, campaign.end_date, metrics.all_conversions, "
. "metrics.average_cost, ad_group_ad.ad.type, ad_group_ad.ad.id, "
. "campaign.campaign_budget, metrics.cost_micros, ad_group_ad.status, metrics.impressions "
. "FROM ad_group_ad "
. "WHERE segments.date >= '{$this->from}' AND segments.date <= '{$this->to}' "
. "ORDER BY campaign.name ASC";
// Issues a search stream request.
/** #var GoogleAdsServerStreamDecorator $stream */
$stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 10]);
$ads = [];
foreach ($stream->iterateAllElements() as $googleAdsRow) {
dump($googleAdsRow->serializeToJsonString());
/** #var GoogleAdsRow $googleAdsRow */
$ads[] = json_decode($googleAdsRow->serializeToJsonString(), true);
}
As you see the pageSize is set to 10, so it will be 23 pages, because I have 230 ads.
How can I do the pagination, now the $stream returns all ads in one response. How can return only 10 ads, and then when user click for example second page button, it will return the next 10 ads, and so on?
Thanks in advance!
here is how it can be done in Python though -
import sys
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
client = GoogleAdsClient.load_from_storage()
ga_service = client.get_service("GoogleAdsService")
search_request = client.get_type("SearchGoogleAdsRequest")
try:
search_request.query = QUERY_STRING
search_request.customer_id = CUSOMER_ID
search_request.page_size = PAGE_SIZE
df = pd.DataFrame()
while True:
response = ga_service.search(search_request)
dictobj = MessageToDict(response._pb)
df = df.append(pd.json_normalize(dictobj,record_path=['results']))
if response.next_page_token == '':
break
else:
search_request.page_token = response.next_page_token
except GoogleAdsException as ex:
print(ex)
To achieve pagination, you may slightly change the display.
Say, if you want to display 10 records per page, so for the 2nd page, it will be
records 11 to 20.
So , to display page 2, you may revising the part :
foreach ($stream->iterateAllElements() as $googleAdsRow) {
dump($googleAdsRow->serializeToJsonString());
/** #var GoogleAdsRow $googleAdsRow */
$ads[] = json_decode($googleAdsRow->serializeToJsonString(), true);
}
to
$index=0;
foreach ($stream->iterateAllElements() as $googleAdsRow) {
$index++;
if ($index >=11 && $index <=20) {
dump($googleAdsRow->serializeToJsonString());
/** #var GoogleAdsRow $googleAdsRow */
$ads[] = json_decode($googleAdsRow->serializeToJsonString(), true);
}
}
Please see whether the above works, and if so, you may amend the codes to show the data according to page number
Google Ads API provides native pagination that as of now is not very well documented. However, you can only paginate by "next" and "previous" pages.
Here is a working example on keywords since that's the use case most people probably get stuck upon.
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
$query =
'SELECT ad_group.id, '
. 'ad_group_criterion.type, '
. 'ad_group_criterion.criterion_id, '
. 'ad_group_criterion.keyword.text, '
. 'ad_group_criterion.keyword.match_type '
. 'FROM ad_group_criterion '
. 'WHERE ad_group_criterion.type = KEYWORD';
// Get the stream
$stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 1000]);
// Get the first page
$page = $stream->getPage();
foreach ($page->getIterator() as $googleAdsRow) {
// Iterating over the first page of 1000 keywords.
}
// Get the next page token
$nextPageToken = $page->getNextPageToken();
// Get the second page
$page = $stream->getPage();
$stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 1000, 'pageToken' => $nextPageToken]);
foreach ($page->getIterator() as $googleAdsRow) {
// Iterating over the second page of 1000 keywords.
}
Note that you have to use search() and not searchStream() and iterator of the actual page instead of iterateAllElements()
I'm using the Petfinder API for Wordpress plugin. The plugin defaults to listing animals based on how old the Petfinder entries are, from oldest to newest. I'm trying to figure out a way to either do newest to oldest, or alphabetize based on animal names.
The data is loaded via the following code:
function get_petfinder_data($api_key, $shelter_id, $count, $pet = '') {
// If no specific pet is specified
if ( $pet == '' ) {
// Create request URL for all pets from the shelter
$request_url = 'http://api.petfinder.com/shelter.getPets?key=' . $api_key . '&count=' . $count . '&id=' . $shelter_id . '&status=A&output=full';
}
// If a specific pet IS specified
else {
// Create a request URL for that specific pet's data
$request_url = 'http://api.petfinder.com/pet.get?key=' . $api_key . '&id=' . $pet;
}
// Request data from Petfinder
$petfinder_data = #simplexml_load_file( $request_url );
// If data not available, don't display errors on page
if ($petfinder_data === false) {}
return $petfinder_data;
And the code that creates the list looks like this:
function get_all_pets($pets) {
foreach( $pets as $pet ) {
// Define Variables
$pet_name = get_pet_name($pet->name);
$pet_type = get_pet_type($pet->animal);
$pet_size = get_pet_size($pet->size);
$pet_age = get_pet_age($pet->age);
$pet_gender = get_pet_gender($pet->sex);
$pet_options = get_pet_options_list($pet);
$pet_description = get_pet_description($pet->description);
$pet_photo_thumbnail = get_pet_photos($pet, 'medium');
$pet_photo_all = get_pet_photos ($pet, 'large', false);
$pet_more_url = get_site_url() . '/adopt/adoptable-dogs/?view=pet-details&id=' . $pet->id;
$pet_pf_url = 'http://www.petfinder.com/petdetail/' . $pet->id;
// Create breed classes
$pet_breeds_condensed = '';
foreach( $pet->breeds->breed as $breed ) {
$pet_breeds_condensed .= pet_value_condensed($breed) . ' ';
}
// Create options classes
$pet_options_condensed = '';
foreach( $pet->options->option as $option ) {
$option = get_pet_option($option);
if ( $option != '' ) {
$pet_options_condensed .= pet_value_condensed($option) . ' ';
}
}
// Compile pet info
// Add $pet_options and $pet_breeds as classes and meta info
$pet_list .= '<div class="vc_col-sm-3 petfinder ' . pet_value_condensed($pet_age) . ' ' . pet_value_condensed($pet_gender) . ' ' . $pet_breeds_condensed . ' ' . $pet_options_condensed . '">' .
'<div class="dogthumbnail">' .
'' . $pet_photo_thumbnail . '<br>' .
'</div>' .
'<a class="dogname" href="' . $pet_more_url . '">' . $pet_name . '</a><br>' .
'<span> ' . $pet_age . ' • ' . $pet_gender . '<br>' .
'<div class="dogbreed">' . $pet_breeds_condensed . '</div>' .
'<a class="morelink" href="' . $pet_more_url . '">Learn More <i class="fas fa-angle-right"></i></a><br>' .
'</div>';
}
// Return pet list
return $pet_list;
Here's an example of the XML that the Petfinder API spits out (right now there are 25 pet entries in the full thing):
<petfinder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://api.petfinder.com/schemas/0.9/petfinder.xsd">
<header>
<version>0.1</version>
<timestamp>2018-06-11T17:32:34Z</timestamp>
<status>
<code>100</code>
<message/>
</status>
</header>
<lastOffset>25</lastOffset>
<pets>
<pet>
<id>31035385</id>
<shelterId>IL687</shelterId>
<shelterPetId/>
<name>Chanel</name>
<animal>Dog</animal>
<breeds>...</breeds>
<mix>yes</mix>
<age>Adult</age>
<sex>F</sex>
<size>M</size>
<options>...</options>
<description>...</description>
<lastUpdate>2014-12-14T17:59:49Z</lastUpdate>
<status>A</status>
<media>...</media>
<contact>...</contact>
</pet>
</pets>
</petfinder>
I'd like to sort all entries by either "name" or "lastUpdate". I've been looking at a lot of posts about sorting XML element objects but they either don't seem to work or I can't figure out how to apply them specifically to my code. I'm not super well-versed in this stuff, so any assistance is much appreciated!!
After a LOT of research and trial and error, I figured out how to organize alphabetically by animal name. Posting this in case anybody is ever trying to figure out the same.
First of all, I was wrong in my assumption of which sections I might need to be editing. It was actually line 723 of the plugin file. Here's how I modified the code for that section:
// Display a list of all available dogs
else {
// Access Petfinder Data
$petfinder_data = get_petfinder_data($api_key, $shelter_id, $count);
// If the API returns without errors
if( $petfinder_data->header->status->code == '100' ) {
// If there is at least one animal
if( count( $petfinder_data->pets->pet ) > 0 ) {
//Sort list of dogs ALPHABETICALLY by NAME
$petSXE = $petfinder_data->pets->children();
$petArray = array();
foreach($petSXE->pet as $d) {
$petArray[] = $d;
}
function name_cmp($a, $b) {
$va = (string) $a->name;
$vb = (string) $b->name;
if ($va===$vb) {
return 0;
}
return ($va<$vb) ? -1 : 1;
}
usort($petArray, 'name_cmp');
$pets = $petArray;
// Compile information that you want to include
$petfinder_list = get_type_list($pets).
get_age_list($pets) .
get_size_list($pets) .
get_gender_list($pets) .
get_options_list($pets) .
get_breed_list($pets) .
get_all_pets($pets);
}
This is adapting the solution I found in this thread: sort xml div by child node PHP SimpleXML
i'm relatively new to laravel and i'm having issues when trying to convert this function to laravel's query builder. This is the function i've been given which also runs a python script to decrypt the database.
Using the documentation from laravel.com you can do something like this:
function call($unitId)
{
$pfContact = DB::table('PFContact')
->where('UnitID', $unitId)
->latest() // Order by created_at
->first([ // Only retrieve these columns
'Send',
'Receive',
'Core',
'lock'
]);
$pfReadings = DB::table('PFReadings')
->get();
$rowCount = $pfReadings->count();
foreach ($pfReadings as $i => $reading) {
echo $i < count($reading) / $rowCount;
foreach ($reading as $column => $value) {
echo shell_exec(
'python3 enc.py ' . $value
. ' ' . $pfContact->Send
. ' ' . $pfContact->Receive
. ' ' . $pfContact->Core
. ' ' . $pfContact->lock . ' '
. $unitId . ' l'
) . '~';
}
echo ';';
}
}
And although I do not know what arguments this pyhton script needs you should really think this through. Why would you use PHP for this and not just handle everything from the python (or php) side because this looks over complicated to me.
I have this script and i need this result:
Numelem / Title / ElmPoste
foreach ( $jobPrintingInfos as $jobprinting_index => $jobprinting ) {
$machine = $jobprinting ['ElmPoste'];
//var_dump($machine);
// var_dump($machine);
}
foreach ( $GetJobResult->Components->Component as $component_index => $component ) {
$quote_support ='';
$quote_impression = '';
$quote_title = ($component->NumElem) . ' / ' . $component->Title . ' ' .$machine. "\r\n";
var_dump($quote_title);
}
but when i do var_dump($quote_title) i have the last machine not all the machine :such as
1/Dessus /Nesspresso
2/Inter/Nesspresso
3/Assem/Nesspresso
Thanks in advance
i dont know the idea behind that script... but if you want that $quote_title <-- is one long String then you need to add a .
like this:
$quote_title .= ($component->NumElem) . ' / ' . $component->Title . ' ' .$machine. "\r\n";
--------------------^
or as array, then its easyer to use a for loop
I have been trying to get the PayOne FrontEnd interface to accept the hash value from my request, to absolutely no avail. I have a support ticket open but need a solution relatively quick, so here I am.
The error returned is "Hashwert Nicht Korrekt" (Hash value incorrect).
Here is my code:
$request="authorization";
$portalid = 2017373;
$aid = 24413;
$key = "secretkeychangedforsecuritoyreasons"; // Key (configurable in the payment portal)
$id[1]= "PART_100";
$pr[1]= 2000;
$no[1] = 1;
$de[1] = "Registration Fee";
$va[1] = 19;
$amount = round($pr[1]*$no[1]);
$clearingtype = "cc";
$mode = "test";
$currency="EUR";
$reference="24393";
$customerid="24393";
$hash = md5(
$aid .
$amount .
$currency .
$customerid .
$clearingtype .
$de[1] .
$id[1] .
$mode .
$no[1] .
$portalid .
$pr[1] .
$reference .
$request .
$va[1] .
$key
);
$url="https://secure.pay1.de/frontend/?request=" . $request .
"&aid=" . $aid .
"&mode=" . $mode .
"&clearingtype=" . $clearingtype .
"&portalid=" . $portalid .
"&customerid=" . $customerid .
"¤cy=" . $currency .
"&amount=" . $amount .
"&reference=" . $reference .
"&id[1]=" . $id[1] .
"&pr[1]=" . $pr[1] .
"&no[1]=" . $no[1] .
"&de[1]=" . $de[1] .
"&va[1]=" . $va[1] .
"&hash=" . $hash;
header("Location: $url");
I have checked and re checked the docs and can find no errors in the way I am puttign it together. If I change single values like portalid, etc. it throws the appropriate error.
Any help would be appreciated.
I found the following section in the client-api-documentation:
Attention:
PAYONE Platform expects the calculated
hash
value
converted
to
lower
case;
e.g.
87dbc7c369b85b7a699adff1a2b27bab
Maybe you have some capital letter in your hash? I do an ".toLowerCase()" (in Java) on the encrypted hash.
One other option: you forgot some parameters.
on the first look i can't see the following: mid
We use the following:
$req['aid'] = 09876; // Sub-AccountID
$req['portalid'] = 6789012; // portal-ID
$req['mode'] = "live"; // Live || test
$req['request'] = "authorization"; // Request
$req['id[1]'] = $YourProductID; // e.g. articleno
$req['pr[1]'] = $singleprice;
$req['no[1]'] = $count; // count or pieces
$req['de[1]'] = $articledescription;
$req['amount'] = $summary; // price summary
$req['currency'] = "EUR";
$req['reference'] = $unique_ref.$YourProductId; //my unique is time()
$req['customerid'] = $userId;
$req['clearingtype'] = $clearing; // cc || wlt
$req['encoding'] = "UTF-8";
$req['targetwindow'] = "top";
ksort($req); //so i know its important to sort
//building the hash
foreach ($req as $key => $val) {
$req['hash'] = $req['hash'] . $val;
}
// all in md5() ... note your own payment ID
$req['hash'] = md5($req['hash'] . $YourPayOneID);
Hope it helps ;)