How to create a "pay per node" "pay to publish" type flow in Commerce 2? I'm experimenting with Commerce 2 and Drupal 8.

I want to set up a flow where people can pay for a node-- use cases like classified ad listing (pay per post), event signup (pay to register), and so on.

Here's what I did so far.


Create a content type classified ad.
Create a product 1 month of ad exposure.
Add an entity reference field on classified ad with the default value set to 1 month of ad exposure.  Set the display widget for this field to rendered entity. Hide this field with field permissions. (This allows the user to create a classified ad node and then see an Add to cart button for the correct product after saving.)


So far, so good.  But, with this configuration, the order doesn't have any information about the original node (content type: classified ad).   I need to know which node the purchase/order was made for because I want to publish that node.

So, I changed the default order type: I added an entity reference to content of type classified ad. But how do I populate this entity reference field with the correct node?  Or is there a better way to link the node for which the product was purchased with the order?
You need to create an order and an order item yourself and then add those values, I assume you need to do this from the context of your node anyway and not use a standard "buy this product" form.

A snippet from a project:

$order_item_values = [
  'type' =&gt; 'order_item_type',
  'title' =&gt; 'label',
  'unit_price' =&gt; new Price(...),
  ...
];
$order_item = $this-&gt;entityTypeManager()-&gt;getStorage('commerce_order_item')-&gt;create($order_item_values);
$order_item-&gt;save();

$order_type = $this-&gt;orderTypeResolver-&gt;resolve($order_item);

$stores = $this-&gt;entityTypeManager()-&gt;getStorage('commerce_store')-&gt;loadMultiple();
$store = reset($stores);

// Create the new order.
/** @var \Drupal\commerce_order\Entity\OrderInterface $order */
$order = $this-&gt;entityTypeManager()-&gt;getStorage('commerce_order')-&gt;create([
  'type' =&gt; $order_type,
  'store_id' =&gt; $store-&gt;id(),
  'uid' =&gt; $this-&gt;currentUser()-&gt;id(),
  'cart' =&gt; FALSE,
]);

$order-&gt;addItem($order_item);
$order-&gt;save();

$this-&gt;cartSession-&gt;addCartId($order-&gt;id(), CartSessionInterface::COMPLETED);

return $this-&gt;redirect('commerce_checkout.form', ['commerce_order' =&gt; $order-&gt;id()]);


You don't even need to use products, you can define an order item that just has a price and reference to your node. But you can also use products to define e.g. the length/price.