diff --git a/src/core/siteplugins/components/course-format/course-format.ts b/src/core/siteplugins/components/course-format/course-format.ts
index 964b9300f..1ed9bdf59 100644
--- a/src/core/siteplugins/components/course-format/course-format.ts
+++ b/src/core/siteplugins/components/course-format/course-format.ts
@@ -63,6 +63,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnInit {
      * @return {Promise<any>} Promise resolved when done.
      */
     doRefresh(refresher?: any, done?: () => void): Promise<any> {
-        return Promise.resolve(this.content.refreshData());
+        return Promise.resolve(this.content.refreshContent(false));
     }
 }
diff --git a/src/core/siteplugins/components/course-option/course-option.ts b/src/core/siteplugins/components/course-option/course-option.ts
index 27725faba..e577e6202 100644
--- a/src/core/siteplugins/components/course-option/course-option.ts
+++ b/src/core/siteplugins/components/course-option/course-option.ts
@@ -59,7 +59,7 @@ export class CoreSitePluginsCourseOptionComponent implements OnInit {
      * @param {any} refresher Refresher.
      */
     refreshData(refresher: any): void {
-        this.content.refreshData().finally(() => {
+        this.content.refreshContent(false).finally(() => {
             refresher.complete();
         });
     }
diff --git a/src/core/siteplugins/components/module-index/module-index.ts b/src/core/siteplugins/components/module-index/module-index.ts
index d1b77d2a6..5f7c07602 100644
--- a/src/core/siteplugins/components/module-index/module-index.ts
+++ b/src/core/siteplugins/components/module-index/module-index.ts
@@ -89,7 +89,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
         if (this.content) {
             this.refreshIcon = 'spinner';
 
-            return Promise.resolve(this.content.refreshData()).finally(() => {
+            return Promise.resolve(this.content.refreshContent(false)).finally(() => {
                 refresher && refresher.complete();
                 done && done();
             });
diff --git a/src/core/siteplugins/components/plugin-content/plugin-content.ts b/src/core/siteplugins/components/plugin-content/plugin-content.ts
index 60e01389a..1f89b1ea3 100644
--- a/src/core/siteplugins/components/plugin-content/plugin-content.ts
+++ b/src/core/siteplugins/components/plugin-content/plugin-content.ts
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { Component, OnInit, Input, Output, EventEmitter, Optional } from '@angular/core';
+import { NavController } from 'ionic-angular';
 import { CoreDomUtilsProvider } from '@providers/utils/dom';
 import { CoreSitePluginsProvider } from '../../providers/siteplugins';
 import { Subject } from 'rxjs';
@@ -39,7 +40,8 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
     invalidateObservable: Subject<void>; // An observable to notify observers when to invalidate data.
     jsData: any; // Data to pass to the component.
 
-    constructor(protected domUtils: CoreDomUtilsProvider, protected sitePluginsProvider: CoreSitePluginsProvider) {
+    constructor(protected domUtils: CoreDomUtilsProvider, protected sitePluginsProvider: CoreSitePluginsProvider,
+            @Optional() protected navCtrl: NavController) {
         this.onContentLoaded = new EventEmitter();
         this.onLoadingContent = new EventEmitter();
         this.invalidateObservable = new Subject<void>();
@@ -67,6 +69,11 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
             this.otherData = result.otherdata;
             this.jsData = this.sitePluginsProvider.createDataForJS(this.initResult, result);
 
+            // Pass some methods as jsData so they can be called from the template too.
+            this.jsData.openContent = this.openContent.bind(this);
+            this.jsData.refreshContent = this.refreshContent.bind(this);
+            this.jsData.updateContent = this.updateContent.bind(this);
+
             this.onContentLoaded.emit(refresh);
         }).catch((error) => {
             this.domUtils.showErrorModalDefault(error, 'core.errorloadingcontent', true);
@@ -75,12 +82,30 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
         });
     }
 
+    /**
+     * Open a new page with a new content.
+     *
+     * @param {string} title The title to display with the new content.
+     * @param {any} args New params.
+     * @param {string} [component] New component. If not provided, current component
+     * @param {string} [method] New method. If not provided, current method
+     */
+    openContent(title: string, args: any, component?: string, method?: string): void {
+        this.navCtrl.push('CoreSitePluginsPluginPage', {
+            title: title,
+            component: component || this.component,
+            method: method || this.method,
+            args: args,
+            initResult: this.initResult
+        });
+    }
+
     /**
      * Refresh the data.
      *
-     * @param {boolean} [showSpinner] Whether to show spinner while refreshing.
+     * @param {boolean} [showSpinner=true] Whether to show spinner while refreshing.
      */
-    refreshData(showSpinner?: boolean): Promise<any> {
+    refreshContent(showSpinner: boolean = true): Promise<any> {
         if (showSpinner) {
             this.dataLoaded = false;
         }
@@ -95,13 +120,13 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
     /**
      * Update the content, usually with a different method or params.
      *
-     * @param {string} component New component.
-     * @param {string} method New method.
      * @param {any} args New params.
+     * @param {string} [component] New component. If not provided, current component
+     * @param {string} [method] New method. If not provided, current method
      */
-    updateContent(component: string, method: string, args: any): void {
-        this.component = component;
-        this.method = method;
+    updateContent(args: any, component?: string, method?: string): void {
+        this.component = component || this.component;
+        this.method = method || this.method;
         this.args = args;
         this.dataLoaded = false;
 
diff --git a/src/core/siteplugins/directives/call-ws-new-content.ts b/src/core/siteplugins/directives/call-ws-new-content.ts
index 44f918f60..9d67ccba0 100644
--- a/src/core/siteplugins/directives/call-ws-new-content.ts
+++ b/src/core/siteplugins/directives/call-ws-new-content.ts
@@ -53,8 +53,8 @@ import { CoreSitePluginsPluginContentComponent } from '../components/plugin-cont
     selector: '[core-site-plugins-call-ws-new-content]'
 })
 export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCallWSOnClickBaseDirective {
-    @Input() component: string; // The component of the new content.
-    @Input() method: string; // The method to get the new content.
+    @Input() component: string; // The component of the new content. If not provided, use the same component as current page.
+    @Input() method: string; // The method to get the new content. If not provided, use the same method as current page.
     @Input() args: any; // The params to get the new content.
     @Input() title: string; // The title to display with the new content. Only if samePage=false.
     @Input() samePage: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
@@ -84,13 +84,13 @@ export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCal
         if (this.utils.isTrueOrOne(this.samePage)) {
             // Update the parent content (if it exists).
             if (this.parentContent) {
-                this.parentContent.updateContent(this.component, this.method, args);
+                this.parentContent.updateContent(args, this.component, this.method);
             }
         } else {
             this.navCtrl.push('CoreSitePluginsPluginPage', {
                 title: this.title,
-                component: this.component,
-                method: this.method,
+                component: this.component || (this.parentContent && this.parentContent.component),
+                method: this.method || (this.parentContent && this.parentContent.method),
                 args: args,
                 initResult: this.parentContent && this.parentContent.initResult
             });
diff --git a/src/core/siteplugins/directives/call-ws.ts b/src/core/siteplugins/directives/call-ws.ts
index ee6034380..7880ad64a 100644
--- a/src/core/siteplugins/directives/call-ws.ts
+++ b/src/core/siteplugins/directives/call-ws.ts
@@ -74,7 +74,7 @@ export class CoreSitePluginsCallWSDirective extends CoreSitePluginsCallWSOnClick
         if (this.utils.isTrueOrOne(this.goBackOnSuccess)) {
             this.navCtrl.pop();
         } else if (this.utils.isTrueOrOne(this.refreshOnSuccess) && this.parentContent) {
-            this.parentContent.refreshData(true);
+            this.parentContent.refreshContent(true);
         }
     }
 }
diff --git a/src/core/siteplugins/directives/new-content.ts b/src/core/siteplugins/directives/new-content.ts
index 3f7e5933d..edb7d5f3e 100644
--- a/src/core/siteplugins/directives/new-content.ts
+++ b/src/core/siteplugins/directives/new-content.ts
@@ -43,8 +43,8 @@ import { CoreSitePluginsPluginContentComponent } from '../components/plugin-cont
     selector: '[core-site-plugins-new-content]'
 })
 export class CoreSitePluginsNewContentDirective implements OnInit {
-    @Input() component: string; // The component of the new content.
-    @Input() method: string; // The method to get the new content.
+    @Input() component: string; // The component of the new content. If not provided, use the same component as current page.
+    @Input() method: string; // The method to get the new content. If not provided, use the same method as current page.
     @Input() args: any; // The params to get the new content.
     @Input() title: string; // The title to display with the new content. Only if samePage=false.
     @Input() samePage: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
@@ -81,13 +81,13 @@ export class CoreSitePluginsNewContentDirective implements OnInit {
             if (this.utils.isTrueOrOne(this.samePage)) {
                 // Update the parent content (if it exists).
                 if (this.parentContent) {
-                    this.parentContent.updateContent(this.component, this.method, args);
+                    this.parentContent.updateContent(args, this.component, this.method);
                 }
             } else {
                 this.navCtrl.push('CoreSitePluginsPluginPage', {
                     title: this.title,
-                    component: this.component,
-                    method: this.method,
+                    component: this.component || (this.parentContent && this.parentContent.component),
+                    method: this.method || (this.parentContent && this.parentContent.method),
                     args: args,
                     initResult: this.parentContent && this.parentContent.initResult
                 });
diff --git a/src/core/siteplugins/pages/plugin-page/plugin-page.ts b/src/core/siteplugins/pages/plugin-page/plugin-page.ts
index 0b02ad00a..32f5db12e 100644
--- a/src/core/siteplugins/pages/plugin-page/plugin-page.ts
+++ b/src/core/siteplugins/pages/plugin-page/plugin-page.ts
@@ -48,7 +48,7 @@ export class CoreSitePluginsPluginPage {
      * @param {any} refresher Refresher.
      */
     refreshData(refresher: any): void {
-        this.content.refreshData().finally(() => {
+        this.content.refreshContent(false).finally(() => {
             refresher.complete();
         });
     }