> For the complete documentation index, see [llms.txt](https://docs.stylemixthemes.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stylemixthemes.com/masterstudy-lms/developers-guide/masterstudy-lms-hooks/course-bundles.md).

# Course Bundles

The [**Course Bundle**](/masterstudy-lms/lms-pro-addons/course-bundles.md) addon exposes multiple action hooks that let you respond to lifecycle events such as order confirmation, cancellation, bundle creation, saving, validation, deletion, and status changes. These hooks are useful for integrating with WooCommerce, adding custom logic, or triggering external system updates.

## Actions

1. `stm_lms_woocommerce_order_approved`

**Type:** action\
**When it runs:** after a WooCommerce order is successfully confirmed\
**Parameters:**

* `$course_data` (array) order and bundle details
* `$user_id` (int) ID of the purchasing user

**Example:**

```php
add_action( 'stm_lms_woocommerce_order_approved', 'stm_lms_woocommerce_order_approved_function', 10, 2 );

function stm_lms_woocommerce_order_approved_function( $course_data, $user_id ) {
	if ( ! empty( $course_data['bundle_id'] ) ) {
		$courses = get_post_meta( $course_data['bundle_id'], \STM_LMS_My_Bundle::bundle_courses_key(), true );

		if ( ! empty( $courses ) ) {
			foreach ( $courses as $course_id ) {
				if ( get_post_type( $course_id ) === 'stm-courses' ) {
					$user_id = 444;
					\STM_LMS_Course::add_user_course( $course_id, $user_id, 0, 0, false, '', $course_data['bundle_id'] );
					\STM_LMS_Course::add_student( $course_id );
				}
			}
		}
	}
}
```

2. `stm_lms_woocommerce_order_cancelled`

**Type:** action\
**When it runs:** when a WooCommerce order for a bundle is cancelled\
**Parameters:**

* `$course_data` (array) order and bundle details
* `$user_id` (int) ID of the user

**Example:**

```php
add_action( 'stm_lms_woocommerce_order_cancelled', 'stm_lms_woocommerce_order_cancelled_function', 10, 2 );
function stm_lms_woocommerce_order_cancelled_function( $course_data, $user_id ) {
	if ( ! empty( $course_data['bundle_id'] ) ) {
		$bundle_id = intval( $course_data['bundle_id'] );
		if ( ! \STM_LMS_Woocommerce::has_course_been_purchased( $user_id, $bundle_id ) ) {
				$bundle_courses = get_post_meta( $bundle_id, \STM_LMS_My_Bundle::bundle_courses_key(), true );
			if ( ! empty( $bundle_courses ) ) {
				foreach ( $bundle_courses as $id ) {
					global $wpdb;
					$table = $wpdb->prefix . 'stm_lms_user_courses';

					$user_id = 22;
					$wpdb->delete(
						$table,
						array(
							'user_id'   => $user_id,
							'course_id' => $id,
							'bundle_id' => $bundle_id,
						)
					);
				}
			}
		}
	}
}
```

3. `stm_lms_single_bundle_start`

**Type:** action\
**When it runs:** when a new WooCommerce product is created for a course bundle\
**Parameters:**

* `$bundle_id` (int) the ID of the bundle

**Example:**

```php
add_action( 'stm_lms_single_bundle_start', 'stm_lms_single_bundle_start_function', 10, 1 );

function stm_lms_single_bundle_start_function( $bundle_id ) {
	if ( $bundle_id == 22 ) {
		if ( class_exists( 'STM_LMS_Woocommerce' ) ) {
			\STM_LMS_Woocommerce::create_product( $bundle_id );
		}
	}
}
```

4. `stm_lms_save_bundle`

**Type:** action\
**When it runs:** after a bundle is saved\
**Parameters:**

* `$_POST` (array) posted data during bundle save

**Example:**

```php
add_action( 'stm_lms_save_bundle', 'stm_lms_save_bundle_function' );
	function stm_lms_save_bundle_function(){
		$id = $_POST['id'];
		$name = $_POST['name'];
		$response = wp_remote_post(
			'https://demo-website.com/',
			array( 'body' => 'Bundle by name - ' . $name.' and id '.$id.' has been saved' ),
		);
		$body     = wp_remote_retrieve_body( $response );

		if ( is_wp_error( $response ) || is_wp_error( $body ) ) {
		$errors[] = 'There was an error occurred after sening a request';
		return $errors;
		}
	}
```

5. `stm_lms_bundle_data_validated`

**Type:** action\
**When it runs:** after bundle data is validated\
**Parameters:**

* `$data` (array) validated bundle data

**Example:**

```php
add_action( 'stm_lms_bundle_data_validated', 'stm_lms_bundle_data_validated_function', 10, 1);
	function stm_lms_bundle_data_validated_function($data){
		$response = wp_remote_post(
			'https://demo-website.com/',
			array( 'body' => $data),
		);
		$body     = wp_remote_retrieve_body( $response );

		if ( is_wp_error( $response ) || is_wp_error( $body ) ) {
		$errors[] = 'There was an error occurred after sending a request';
		return $errors;
		}
		return $data;	
	}
```

6. `stm_lms_delete_bundle`

**Type:** action\
**When it runs:** after a bundle is deleted\
**Parameters:**

* `$_GET` (array) request data containing the bundle ID

**Example:**

```php
add_action( 'stm_lms_delete_bundle','stm_lms_delete_bundle_function');
	function sstm_lms_delete_bundle_function(){
		$bundle_id = intval( $_GET['bundle_id'] );
		$response = wp_remote_post(
			'https://demo-website.com/',
			array( 'body' => 'Bundle ID' .$bundle_id. 'has been deleted'),
		);
		$body     = wp_remote_retrieve_body( $response );

		if ( is_wp_error( $response ) || is_wp_error( $body ) ) {
		$errors[] = 'There was an error occurred after sending a request';
			return $errors;
		}

	}
```

7. `stm_lms_change_bundle_status`

**Type:** action\
**When it runs:** when a bundle status is changed\
**Parameters:**

* `$_GET` (array) request data containing the bundle ID

**Example:**

```php
add_action( 'stm_lms_change_bundle_status', 'stm_lms_change_bundle_status_function' );

function stm_lms_change_bundle_status_function() {
    $bundle_id     = intval( $_GET['bundle_id'] );
    $bundle_status = get_post_status( $bundle_id );

    $post_status = 'draft';

    if ( 'draft' === $bundle_status && STM_LMS_My_Bundle::get_available_quota() ) {
        $post_status = 'publish';
    }

    wp_update_post(
        array(
            'ID'          => $bundle_id,
            'post_status' => $post_status,
        )
    );

    wp_send_json( 'OK' );
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.stylemixthemes.com/masterstudy-lms/developers-guide/masterstudy-lms-hooks/course-bundles.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
