How do I make a plugin to add to the "Node Actions" list?

I would like to make a plugin to add some actions to the Node Actions list for all nodes.

For example I thought it might be cool to add a “swap inputs” function to the right-click Node Actions menu.

I’ve found the function GetContextMenuActions in the engine that seems to populate the list for each node type, but how can I get my plugin to wrap/override this function?

+1 for this, would like to know how to extend an engine class from a plugin.

It can be done through GraphEditorModule, here’s an example on how to add your own extender:

#pragma once

#include "CoreMinimal.h"

class FExtender;
class FUICommandList;
class UEdGraph;
class UEdGraphNode;
class UEdGraphPin;

class FYourExtension
{
public:
	void Install();
	void Uninstall();

private:
	static TSharedRef<FExtender> HandleOnExtendGraphEditorContextMenu(
		const TSharedRef<FUICommandList> CommandList,
		const UEdGraph* Graph,
		const UEdGraphNode* Node,
		const UEdGraphPin* Pin,
		bool bIsConst);

	static void HandleOnExtendContextMenu(FMenuBuilder& MenuBuilder);
};

#include "YourExtension.h"

#include "GraphEditorModule.h"
// #include "EdGraph/EdGraph.h"
// #include "EdGraph/EdGraphNode.h"
// #include "EdGraph/EdGraphPin.h"

#define LOCTEXT_NAMESPACE "Editor.YourExtension"

DEFINE_LOG_CATEGORY_STATIC(LogYourExtension, Log, All);

const FName GraphEditorModuleName(TEXT("GraphEditor"));

void FYourExtension::Install()
{
	auto& GraphEditorModule = FModuleManager::LoadModuleChecked<FGraphEditorModule>(GraphEditorModuleName);
	GraphEditorModule.GetAllGraphEditorContextMenuExtender().Add(
		FGraphEditorModule::FGraphEditorMenuExtender_SelectedNode::CreateStatic(
			&FYourExtension::HandleOnExtendGraphEditorContextMenu));
}

TSharedRef<FExtender> FYourExtension::HandleOnExtendGraphEditorContextMenu(
	const TSharedRef<FUICommandList> CommandList,
	const UEdGraph* Graph,
	const UEdGraphNode* Node,
	const UEdGraphPin* Pin,
	bool bIsConst)
{
	TSharedRef<FExtender> Extender = MakeShared<FExtender>();

	// you'll have to check the extension points for the specific node you are interested in, this one works for blueprint nodes for example
	const FName ExtensionHook(TEXT("EdGraphSchemaNodeActions")); 
	Extender->AddMenuExtension(
		ExtensionHook,
		EExtensionHook::Before,
		CommandList,
		FMenuExtensionDelegate::CreateStatic(&FYourExtension::HandleOnExtendContextMenu));

	return Extender;
}



void FYourExtension::HandleOnExtendContextMenu(FMenuBuilder& MenuBuilder)
{
	MenuBuilder.BeginSection(NAME_None, LOCTEXT("SectionName", "YourSection"));

	MenuBuilder.AddMenuEntry(
		LOCTEXT("ActionLocKey", "your action"),
		LOCTEXT("ActionTooltipLockKey", "tooltip for your action"),
		FSlateIcon(),
		FUIAction(FExecuteAction::CreateLambda([]() {
			// do your thing
		})));

	MenuBuilder.EndSection();
}

void FYourExtension::Uninstall()
{
	if (auto GraphEditorModule = FModuleManager::GetModulePtr<FGraphEditorModule>(GraphEditorModuleName))
	{
		GraphEditorModule->GetAllGraphEditorContextMenuExtender().RemoveAll(
			[](const FGraphEditorModule::FGraphEditorMenuExtender_SelectedNode& Delegate) {
				return (Delegate.TryGetBoundFunctionName() == GET_FUNCTION_NAME_CHECKED(FYourExtension, HandleOnExtendGraphEditorContextMenu));
			});
	}
}

#undef LOCTEXT_NAMESPACE