This plugin is used to import a project snapshot into your woocommerce website. It uses the wordpress tables so you can use it the way you are used to. All field data is saved into the object meta table. You can create a project snapshot (and the corresponding token) using the Snapshot feature in OnPage.
When you import your snapshots, the plugin will generate Eloquent Models for your data, in the plugin directory db-models/
these models are updated every time you import your data.
You can view the models generated for your project in the plugin import page. For each model, you'll find the list of relations and fields imported.
Before importing the data, you should specify how to import each resource (in your functions.php
).
Resources that are not listed here will still be imported in a custom op_things
table (which makes them invisible to wordpress, and faster to import).
You should only list those resources that will have their own page.
For example, if you plan to have a page for each "Category" and one for each "Product", you can do it as follows (the format is "resource alias" => "import method").
add_filter('op_resource_types', function() {
return [
'product' => 'post', // "post" = woocommerce product
'category' => 'term', // "term" = woocommerce category
// all other resources will be imported in a hidden plugin table with high performance
];
});
For instance, assuming you want to select all your products (codenamed Product
), you can run:
$prods = Op\Product::get(); // a collection of products
By default, no ordering is used (fastest method).
The order is only applied when accessing relations (e.g. $product->variants()->get()
), and not for global order.
If you need to maintain On Page global order, you should also add ->sorted()
to the query like so:
$prods = Op\Product::sorted()->get(); // a collection of products sorted with the global ordering
You can also sort results by field value:
$prods = Op\Product::orderByField('price')->get();
// Sort in descending order:
$prods = Op\Product::orderByField('price', 'desc')->get();
You can get each record values through the ->val(field_name, language)
function:
foreach ($prods as $prod) {
// get the name in the current language - will fallback on the primary language if no translation is found
echo $prod->val('name')."<br>\n";
// get the name in a custom language - will never fallback on other languages
echo $prod->val('name', 'zh')."<br>\n";
// get the name in the current language, disabling fallback
echo $prod->val('name', false)."<br>\n";
// access relation values (will return the value from the first relation)
echo $prod->val('category.name')."<br>\n";
// Gets a file name
echo $p->file('info_file')->name; // e.g. MK100.pdf
// Gets the original image/file url
echo '<a href="'. $p->file('info_file')->link() .'">Download PDF</a>'
// This will generate open the file in the browser instead of downloading it
echo '<a href="'. $p->file('info_file')->link(true) .'">Open PDF</a>'
// Resize image to width 100 and automatic height (generated in run-time and cached)
echo '<img src="'. $p->file('cover')->thumb(100) .'">'
// Generate thumbnail cropping (zooming) the image
echo '<img src="'. $p->file('cover')->thumb(200, 100) .'">'
// Generate thumbnail containing (out-zooming) the image
echo '<img src="'. $p->file('cover')->thumb(200, 100, true) .'">'
// You can get information about the files:
$file = $p->file('cover');
$file->getWidth();
$file->getHeight();
$file->getAverageColor();
// Get all variant colors
$available_colors = $p->getRelatedItems('variants.colors');
// Get the product category passing by the subcategory
$cat = $p->getRelatedItems('subcategory.category')->first();
In On Page you can create field folders, and mark them as "default" for any element you have. You can easily access the folder name and the folder fields just like in the following example:
// Not all items have a default folder set, so be careful!
if ($folder = $prod->getDefaultFolder()) {
echo "Default folder: ";
// show the translated folder label
echo op_label($folder);
echo "<br>";
// Get the fields in this folder
foreach ($folder->fields as $field) {
// show the translated field label
echo op_label($field);
echo ": ";
// use the field name to access the item values
echo $prod->val($field->name);
echo "<br>";
}
// echo "<hr>";
}
Files and thumbnails will not be downloaded during the import process, instead they are downloaded and stored when you reference them.
So, when you do something like $prod->file('main_image')->link()
or $prod->file('main_image')->thumb(200)
for the first time, the file will be downloaded in the plugin folder, so the page may take a while to load. Later calls will be instantaneous because the file has already been downloaded.
While this is very handful, original files can be very heavy to store on your server.
You can change the behaviour and use On Page as a CDN, so the ->link()
function will return the url from the On Page servers directly, without storing anything on your server:
define('OP_DISABLE_ORIGINAL_FILE_IMPORT', true);
Note: in this scenario, $file->thumb(...)
will still ask On Page to generate the thumbnail, and the thumbnail will be saved in the plugin folder.
On Page supports uploading files to external CDNs.
You can get the image url from the CDN simply calling $p->file('info_file')->cdn()
.
If you use multiple CDN, you can specify the CDN name like so: $p->file('info_file')->link('my_custom_cdn')
.
Thumbnails will by default use the original file format,
but you can force png, jpg, or webp using the OP_THUMBNAIL_FORMAT
constant, like so:
define('OP_THUMBNAIL_FORMAT', 'webp');
You can use the pluckField
method to get the field from the query.
$prods = Op\Product::pluckField('name'); // ['Product A', 'Product B', 'Product C']
NOTE: All the above functions will return the value as is, so if the name contains special characters, they will not be returned as HTML entities (&
becomes &
). You have the responsibility to escape the output with functions such as htmlentities
or the shorthand op_e($string)
.
NOTE: All the above functions will return an array of values if the field is set to multiple.
You can use all the eloquent methods to filter your data, but because the fields are stored inside the meta table, we provide some helper functions as follow:
// Get the first chapter named "Boats"
$prods = Op\Chapter::whereField('name', 'Boats')->first()
// Get all the elements longer than 10cm
$prods = Op\Chapter::whereField('length', '>', 10)->get()
// Get elements using in operator
$prods = Op\Chapter::whereFieldIn('name', ['Boats', 'Spacecrafts'])->get()
// Full text search in all the fields (will search for %boa% in all fields)
$prods = Op\Chapter::search('boa')->get()
// Full text search only in some attributes
$prods = Op\Chapter::search('boa', ['name', 'description'])->get()
// Filter by related items (get products that have a color in the category "Dark colors")
$prods = Op\Product::whereField('colors.category.name', 'Dark colors')->get();
// Filter by On Page ID
$prods = Op\Product::whereField('_id', 1872378)->get();
// Filter by Wordpress ID
$prods = Op\Product::whereField('_wp_id', 6123)->get();
// Join filters using OR
$prods = Op\Product::where(function($q) {
$q->whereField('length', '>', 10);
$q->orWhereField('height', '>', 10);
})->get();
// Use deep where to customize the final query
$prods = Op\Product::deepWhere('colors.category', function($q) {
$q->whereField('name', 'Dark colors');
})->get();
You can easily access related elements using the relation name
// Get all the products for the given category
$products = $category->products;
// Query all the products
$products = $category->products()->search('MK1')->get();
All the query seen so far automatically preload all the meta attributes, to reduce the amount of stress on the database.
// the following line runs two queries, one for the products on wp_posts, the second to fetch all the metadata on wp_post_meta
$prods = Op\Product::all();
The related elements are not preloaded, so the following code will result in 2 + N*2 queries where N is the number of products.
$prods = Op\Product::all();
foreach ($prods as $p) {
foreach ($p->colors as $p) {
echo $p->val('name')."<br>";
}
}
To reduce the number of queries, you can easily preload the related elements (this only produces 2 or 4 queries - depending on whether the relation is post->post
/term->term
, or post->term
/term->post
):
$prods = Op\Product::with(['colors'])->get();
foreach ($prods as $p) {
foreach ($p->colors as $p) {
echo $p->val('name')."<br>";
}
}
// You can preload as much data as you need:
$prods = Op\Product::with([
'colors',
'subcategory.category',
'variants.colors',
])->get();
The schema is the structure of the data, it is composed by an array of resources, which in turn contain an array of fields.
// Iterate all available resources and fields
foreach (op_schema()->resources as $res)
echo $res->name;
echo op_label($res); // resource label in current language
echo op_label($res, 'it'); // resource label in custom language
// Iterate resource fields
foreach ($res->fields as $field) {
echo $field->name;
echo $field->type; // string | text | int | real | file | image | ...
echo $field->unit; // cm | kg | W | ...
echo op_label($field); // field label in current language
echo op_label($field, 'it'); // field label in custom language
}
}
// Find resource by name
$res = op_schema()->name_to_res['colors'];
// Find field by name
$field = $res->name_to_field['description'];
// Access field folders in a resource
foreach ($res->field_folders as $folder) {
echo op_label($folder);
foreach ($folder->fields as $field) echo op_label($field);
}
You can use the normal woocommerce templating system as you're used to. The only thing you need is to obtain an instance of the eloquent model. You can easily do so by using the following functions:
// To retrieve the model from a term
op_category('slug', 'the-category-slug'); // will return an instance to Op\MyCategory
// To retrieve the model from a post
op_product('ID', 123); // will return an instance to Op\MyProduct
// Notice you can use any column name as the first argument
$cat = op_category('term_id', 123);
$cat->getResource()->name; // 'my_category'
$cat->val('name'); // 'The Category Name'
$cat->products; // A collection of products
A hook called whenever an import has completed, you can use it to regenerate the cache of the website.
add_action('op_import_completed', function() {
clear_my_caches();
notify_admin();
});
By default, slugs are generated using the format "ID-NAME-LANG". To customize how the slugs are generated,
you can use the op_gen_slug
function as follows.
NOTE: Slugs for existing items do not get updated unless you tick the "Force slug regeneration" option in the import panel.
In the op_gen_slug
you can return any string (e.g. "My Product"), and the plugin will convert it to its slug form (e.g. "my-product").
If null
is returned, the original slug is used.
add_action('op_gen_slug', function($item) {
if ($item instanceof \Op\Product) {
return "{$item->val('name')}-{$item->val('titolo')}";
} else if($item instanceof \Op\Category) {
return "{$item->val('description')}";
} else if($item instanceof \Op\Color) {
return "{$item->val('name')}";
} else {
// Generic handler
return "{$item->val('nome')}";
}
});
The following hook will import only the resource 'shoes' and 't_shirts' as product, and any other resource will be imported as a category.
add_filter('on_page_product_resources', function() {
return ['shoes', 't_shirts']; // list of resource names (not labels)
});
Wordpress relations (e.g. linking products with categories) is not be imported by default. You can specify, for each resource, wich relation to set the term parent.
add_action('op_import_relations', function() {
return [
// On Page resource name => // On Page parent relation name
'products' => 'subcategories',
'subcategories' => 'categories',
];
});
By default, if no value is found in the current project, the system will fallback to the main project language. If the current language is country-specific (e.g. de_AU) then the system will also try the country-free alternative "de". If you need to use alternative languages when translations are missing, you can setup your own fallback languages:
// When Norwegian is empty, try to find a value in the English or Italian language
op_set_fallback_lang('no', ['en', 'it']);
You can map WPML locales to a specific On Page language just like the following:
// a map of WPML_LOCALE => OP_LANGUAGE to use
set_op_locale_to_lang([
'en' => 'en_gb',
]);
<?php
foreach (Op\Category::all() as $cat): ?>
<a href="<?= $cat->permalink() ?>">
<?= $cat->val('name') ?>
</a>
<?php endforeach; ?>
$category = op_category('slug', $term->slug);
<h1><?= $category->val('name') ?></h1>
<?php
foreach ($category->products as $prod): ?>
<a href="<?= $prod->link() ?>">
<?= $prod->val('name') ?>
</a>
<?php endforeach; ?>
<?php get_footer(); ?>
You should understand the way it works by now. Simply use the ->link()
method to get the link to the item.
First of all, define a random token in your theme functions.php:
define('OP_API_TOKEN', '0T780347N89YGA78EYN');
You can do a POST call to your website passing the following parameters:
Command:
op-api
: import
Your secret token:
op-token
: 0T780347N89YGA78EYN
Generate a new snapshot before importing:
regen-snapshot
: true/false
Import even if there are no updates from On Page:
force
: true/false
Regenerate all slugs:
force-slug-regen
: true/false
If you are using cron or similar, you can use the CURL command:
curl -X POST 'https://yourwebsite/?op-api=import&op-token=0T780347N89YGA78EYN®en-snapshot=true&force=false'
You can easily automate the snapshot through wp-cli using the command wp onpage import
.
By default, the import will exit instantly if there is no new data to be imported.
This is useful because you can run this command in a cron every minute, and it will only actually import your data when a new snapshot is available.
If you want to ovverride this behaviour and import data anyway, you can add use the wp onpage import --force
command, wich will re-import all your data.
You can also force the regeneration of a new snapshot before importing, which would be wp onpage import --regen-snapshot
.
If you are on development and want the existing slugs to be updated as well, you can add the --force-slug-regen
flag to the command.
wp onpage reset # Delete all the products and categories in WooCommerce
wp onpage listmedia # List the files imported in WooCommerce
- Functions and other plugin methods that are not documented here are subject to change and therefore should not be used.
- The plugin will modify the posts and terms table and add some custom columns