> 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
